executable-stories-react 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,9 +7,9 @@ import {
7
7
  useCallback as useCallback5,
8
8
  useDeferredValue,
9
9
  useId as useId2,
10
- useMemo as useMemo3,
11
- useRef as useRef6,
12
- useState as useState11
10
+ useMemo as useMemo4,
11
+ useRef as useRef7,
12
+ useState as useState12
13
13
  } from "react";
14
14
 
15
15
  // src/components/ui/empty.tsx
@@ -384,12 +384,29 @@ function DocVideo({ entry }) {
384
384
  }
385
385
 
386
386
  // src/components/doc/DocHtml.tsx
387
+ import { useEffect, useRef, useState } from "react";
387
388
  import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
389
+ var MEASURE_SCRIPT = "<script>(function(){if(parent===window)return;var last=0,queued=false;var measure=function(){var kids=document.body.children,h=0;for(var i=0;i<kids.length;i++)h=Math.max(h,kids[i].getBoundingClientRect().bottom);return Math.ceil(h||document.body.getBoundingClientRect().bottom)};var post=function(){queued=false;var h=measure();if(h===last)return;last=h;parent.postMessage({__esHtmlHeight:h},'*')};var schedule=function(){if(queued)return;queued=true;requestAnimationFrame(post)};var start=function(){new ResizeObserver(schedule).observe(document.body);new MutationObserver(schedule).observe(document.body,{subtree:true,childList:true,attributes:true,characterData:true});addEventListener('load',schedule);post()};if(document.body)start();else addEventListener('DOMContentLoaded',start)})();</script>";
390
+ var MAX_MEASURED_HEIGHT = 5e3;
388
391
  function DocHtml({ entry }) {
389
- const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
392
+ const declaredHeight = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
390
393
  const title = entry.title ?? "Embedded HTML";
391
394
  const safeHref = safeUrl(entry.url ?? entry.path);
392
- const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
395
+ const frameRef = useRef(null);
396
+ const [measuredHeight, setMeasuredHeight] = useState();
397
+ useEffect(() => {
398
+ if (entry.content === void 0) return;
399
+ const onMessage = (event) => {
400
+ if (event.source !== frameRef.current?.contentWindow) return;
401
+ const reported = event.data?.__esHtmlHeight;
402
+ if (typeof reported !== "number" || !Number.isFinite(reported) || reported <= 0) return;
403
+ setMeasuredHeight(Math.min(reported, MAX_MEASURED_HEIGHT));
404
+ };
405
+ window.addEventListener("message", onMessage);
406
+ return () => window.removeEventListener("message", onMessage);
407
+ }, [entry.content]);
408
+ const height = measuredHeight === void 0 ? declaredHeight : `${measuredHeight}px`;
409
+ const frameProps = entry.content !== void 0 ? { srcDoc: entry.content + MEASURE_SCRIPT } : { src: safeHref ?? "" };
393
410
  return /* @__PURE__ */ jsxs8("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
394
411
  /* @__PURE__ */ jsxs8("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
395
412
  /* @__PURE__ */ jsx14("span", { children: entry.title ?? "HTML" }),
@@ -409,6 +426,7 @@ function DocHtml({ entry }) {
409
426
  /* @__PURE__ */ jsx14(
410
427
  "iframe",
411
428
  {
429
+ ref: frameRef,
412
430
  ...frameProps,
413
431
  sandbox: "allow-scripts",
414
432
  loading: "lazy",
@@ -975,7 +993,7 @@ function ScenarioRunHistory({ scenarioId }) {
975
993
  }
976
994
 
977
995
  // src/components/ScenarioStaleness.tsx
978
- import { useEffect, useState } from "react";
996
+ import { useEffect as useEffect2, useState as useState2 } from "react";
979
997
 
980
998
  // src/lib/provenance.ts
981
999
  function reportLastRunMs(report) {
@@ -1039,8 +1057,8 @@ import { jsxs as jsxs15 } from "react/jsx-runtime";
1039
1057
  function ScenarioStaleness({ scenario }) {
1040
1058
  const freshness = useScenarioFreshness();
1041
1059
  const fixedNow = freshness?.nowMs;
1042
- const [now, setNow] = useState(fixedNow);
1043
- useEffect(() => {
1060
+ const [now, setNow] = useState2(fixedNow);
1061
+ useEffect2(() => {
1044
1062
  if (fixedNow === void 0) setNow(Date.now());
1045
1063
  }, [fixedNow]);
1046
1064
  if (!freshness || now === void 0) return null;
@@ -1054,7 +1072,7 @@ function ScenarioStaleness({ scenario }) {
1054
1072
  }
1055
1073
 
1056
1074
  // src/interactive/collapse-context.ts
1057
- import { createContext as createContext4, useCallback, useContext as useContext5, useState as useState2 } from "react";
1075
+ import { createContext as createContext4, useCallback, useContext as useContext5, useState as useState3 } from "react";
1058
1076
  var CollapseContext = createContext4(null);
1059
1077
  var CollapseProvider = CollapseContext.Provider;
1060
1078
  function useCollapse() {
@@ -1078,7 +1096,7 @@ function persist(ids) {
1078
1096
  }
1079
1097
  }
1080
1098
  function useCollapseState(computeDefault) {
1081
- const [collapsed, setCollapsed] = useState2(
1099
+ const [collapsed, setCollapsed] = useState3(
1082
1100
  () => readPersisted() ?? computeDefault?.() ?? /* @__PURE__ */ new Set()
1083
1101
  );
1084
1102
  const isCollapsed = useCallback((id) => collapsed.has(id), [collapsed]);
@@ -1652,15 +1670,75 @@ function ReportErrorShell({
1652
1670
  return /* @__PURE__ */ jsx34("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx34(ReportSchemaError, { error }) });
1653
1671
  }
1654
1672
 
1673
+ // src/components/ReportSpanGraph.tsx
1674
+ import { deriveSpanGraph, spanGraphNodeMark, spanGraphToMermaid } from "executable-stories-core/span-graph";
1675
+ import { useMemo } from "react";
1676
+ import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
1677
+ var LANE_LABEL = {
1678
+ edge: "Edge",
1679
+ service: "Service",
1680
+ queue: "Queue",
1681
+ datastore: "Data"
1682
+ };
1683
+ var MARK_LABEL = {
1684
+ failing: "Failing",
1685
+ added: "New",
1686
+ changed: "Changed"
1687
+ };
1688
+ var MARK_CLASS = {
1689
+ failing: "text-fail",
1690
+ added: "text-pass",
1691
+ changed: "text-pend"
1692
+ };
1693
+ function MarkBadge({ node }) {
1694
+ const mark = spanGraphNodeMark(node);
1695
+ if (!mark) return null;
1696
+ return /* @__PURE__ */ jsx35("span", { className: cn("ml-2 text-xs font-medium", MARK_CLASS[mark]), children: MARK_LABEL[mark] });
1697
+ }
1698
+ function ReportSpanGraph() {
1699
+ const report = useReport();
1700
+ const { code, graph, titleById } = useMemo(() => {
1701
+ const scenarios = report.features.flatMap((feature) => feature.scenarios);
1702
+ const derived = deriveSpanGraph(scenarios);
1703
+ return {
1704
+ graph: derived,
1705
+ code: spanGraphToMermaid(derived),
1706
+ titleById: new Map(scenarios.map((scenario) => [scenario.id, scenario.title]))
1707
+ };
1708
+ }, [report]);
1709
+ if (code === "") return null;
1710
+ return /* @__PURE__ */ jsxs24("section", { className: "es-span-graph mt-6", "aria-labelledby": "es-span-graph-heading", children: [
1711
+ /* @__PURE__ */ jsx35("h2", { id: "es-span-graph-heading", className: "text-base font-semibold text-foreground", children: "Architecture, as it ran" }),
1712
+ /* @__PURE__ */ jsx35("p", { className: "mt-1 text-sm text-muted-foreground", children: "Derived from this run\u2019s traces. Every component was named by a span while a scenario ran, so nothing here is inferred from the code. Instrumented, exercised paths only: a component no scenario reaches does not appear." }),
1713
+ /* @__PURE__ */ jsx35(DocMermaid, { entry: { kind: "mermaid", phase: "static", code } }),
1714
+ /* @__PURE__ */ jsxs24("table", { className: "mt-2 w-full border-collapse text-left text-sm", children: [
1715
+ /* @__PURE__ */ jsx35("caption", { className: "sr-only", children: "Each component and the scenarios that exercised it" }),
1716
+ /* @__PURE__ */ jsx35("thead", { children: /* @__PURE__ */ jsxs24("tr", { className: "text-xs text-muted-foreground", children: [
1717
+ /* @__PURE__ */ jsx35("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Component" }),
1718
+ /* @__PURE__ */ jsx35("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Lane" }),
1719
+ /* @__PURE__ */ jsx35("th", { scope: "col", className: "py-1 font-medium", children: "Covered by" })
1720
+ ] }) }),
1721
+ /* @__PURE__ */ jsx35("tbody", { children: graph.nodes.map((node) => /* @__PURE__ */ jsxs24("tr", { className: "border-t border-border align-top", children: [
1722
+ /* @__PURE__ */ jsxs24("th", { scope: "row", className: "py-1.5 pr-4 font-mono text-xs font-normal", children: [
1723
+ node.id,
1724
+ /* @__PURE__ */ jsx35(MarkBadge, { node })
1725
+ ] }),
1726
+ /* @__PURE__ */ jsx35("td", { className: "py-1.5 pr-4 text-xs text-muted-foreground", children: LANE_LABEL[node.kind] }),
1727
+ /* @__PURE__ */ jsx35("td", { className: "py-1.5", children: /* @__PURE__ */ jsx35("ul", { className: "flex flex-col gap-0.5", children: node.scenarioIds.map((id) => /* @__PURE__ */ jsx35("li", { children: /* @__PURE__ */ jsx35("a", { href: `#${id}`, className: "text-xs text-link underline underline-offset-2 hover:text-foreground", children: titleById.get(id) ?? id }) }, id)) }) })
1728
+ ] }, node.id)) })
1729
+ ] })
1730
+ ] });
1731
+ }
1732
+
1655
1733
  // src/components/ui/switch.tsx
1656
1734
  import "react";
1657
1735
  import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
1658
- import { jsx as jsx35 } from "react/jsx-runtime";
1736
+ import { jsx as jsx36 } from "react/jsx-runtime";
1659
1737
  function Switch({
1660
1738
  className,
1661
1739
  ...props
1662
1740
  }) {
1663
- return /* @__PURE__ */ jsx35(
1741
+ return /* @__PURE__ */ jsx36(
1664
1742
  SwitchPrimitive.Root,
1665
1743
  {
1666
1744
  "data-slot": "switch",
@@ -1669,7 +1747,7 @@ function Switch({
1669
1747
  className
1670
1748
  ),
1671
1749
  ...props,
1672
- children: /* @__PURE__ */ jsx35(
1750
+ children: /* @__PURE__ */ jsx36(
1673
1751
  SwitchPrimitive.Thumb,
1674
1752
  {
1675
1753
  "data-slot": "switch-thumb",
@@ -1685,7 +1763,7 @@ import * as React5 from "react";
1685
1763
  import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
1686
1764
  import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
1687
1765
  import { cva as cva3 } from "class-variance-authority";
1688
- import { jsx as jsx36 } from "react/jsx-runtime";
1766
+ import { jsx as jsx37 } from "react/jsx-runtime";
1689
1767
  var toggleItemVariants = cva3(
1690
1768
  "inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1691
1769
  {
@@ -1707,13 +1785,13 @@ function ToggleGroup({
1707
1785
  children,
1708
1786
  ...props
1709
1787
  }) {
1710
- return /* @__PURE__ */ jsx36(
1788
+ return /* @__PURE__ */ jsx37(
1711
1789
  ToggleGroupPrimitive,
1712
1790
  {
1713
1791
  "data-slot": "toggle-group",
1714
1792
  className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
1715
1793
  ...props,
1716
- children: /* @__PURE__ */ jsx36(ToggleGroupContext.Provider, { value: { size }, children })
1794
+ children: /* @__PURE__ */ jsx37(ToggleGroupContext.Provider, { value: { size }, children })
1717
1795
  }
1718
1796
  );
1719
1797
  }
@@ -1724,7 +1802,7 @@ function ToggleGroupItem({
1724
1802
  ...props
1725
1803
  }) {
1726
1804
  const context = React5.useContext(ToggleGroupContext);
1727
- return /* @__PURE__ */ jsx36(
1805
+ return /* @__PURE__ */ jsx37(
1728
1806
  TogglePrimitive,
1729
1807
  {
1730
1808
  "data-slot": "toggle-group-item",
@@ -1736,10 +1814,10 @@ function ToggleGroupItem({
1736
1814
  }
1737
1815
 
1738
1816
  // src/context/ReportRoot.tsx
1739
- import { useMemo } from "react";
1817
+ import { useMemo as useMemo2 } from "react";
1740
1818
 
1741
1819
  // src/components/doc/NarrativeBlocks.tsx
1742
- import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1820
+ import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
1743
1821
  var FILE_TREE_TYPE = "file-tree";
1744
1822
  var DATA_MODEL_TYPE = "data-model";
1745
1823
  function isChangeKind(value) {
@@ -1753,23 +1831,23 @@ function str(value) {
1753
1831
  }
1754
1832
  function AuthoredMarker({ authored }) {
1755
1833
  if (authored !== "agent") return null;
1756
- return /* @__PURE__ */ jsx37(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
1834
+ return /* @__PURE__ */ jsx38(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
1757
1835
  }
1758
1836
  function BlockFrame({
1759
1837
  title,
1760
1838
  authored,
1761
1839
  children
1762
1840
  }) {
1763
- return /* @__PURE__ */ jsxs24("figure", { className: "my-3", children: [
1764
- title || authored === "agent" ? /* @__PURE__ */ jsxs24("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
1765
- title ? /* @__PURE__ */ jsx37("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
1766
- /* @__PURE__ */ jsx37(AuthoredMarker, { authored })
1841
+ return /* @__PURE__ */ jsxs25("figure", { className: "my-3", children: [
1842
+ title || authored === "agent" ? /* @__PURE__ */ jsxs25("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
1843
+ title ? /* @__PURE__ */ jsx38("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
1844
+ /* @__PURE__ */ jsx38(AuthoredMarker, { authored })
1767
1845
  ] }) : null,
1768
1846
  children
1769
1847
  ] });
1770
1848
  }
1771
1849
  function ChangeBadge({ change }) {
1772
- return /* @__PURE__ */ jsx37(Badge, { variant: "tag", className: "text-[10px]", children: change });
1850
+ return /* @__PURE__ */ jsx38(Badge, { variant: "tag", className: "text-[10px]", children: change });
1773
1851
  }
1774
1852
  function parseFileTree(data) {
1775
1853
  if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
@@ -1818,11 +1896,11 @@ function sortedChildren(node) {
1818
1896
  }
1819
1897
  function TreeBranch({ node, depth }) {
1820
1898
  const children = sortedChildren(node);
1821
- return /* @__PURE__ */ jsx37("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
1899
+ return /* @__PURE__ */ jsx38("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
1822
1900
  const isDir = child.children.size > 0;
1823
- return /* @__PURE__ */ jsxs24("li", { children: [
1824
- /* @__PURE__ */ jsxs24("div", { className: "flex flex-wrap items-baseline gap-2", children: [
1825
- /* @__PURE__ */ jsx37(
1901
+ return /* @__PURE__ */ jsxs25("li", { children: [
1902
+ /* @__PURE__ */ jsxs25("div", { className: "flex flex-wrap items-baseline gap-2", children: [
1903
+ /* @__PURE__ */ jsx38(
1826
1904
  "span",
1827
1905
  {
1828
1906
  className: cn(
@@ -1832,17 +1910,17 @@ function TreeBranch({ node, depth }) {
1832
1910
  children: isDir ? `${child.name}/` : child.name
1833
1911
  }
1834
1912
  ),
1835
- child.file?.change ? /* @__PURE__ */ jsx37(ChangeBadge, { change: child.file.change }) : null,
1836
- child.file?.note ? /* @__PURE__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
1913
+ child.file?.change ? /* @__PURE__ */ jsx38(ChangeBadge, { change: child.file.change }) : null,
1914
+ child.file?.note ? /* @__PURE__ */ jsx38("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
1837
1915
  ] }),
1838
- isDir ? /* @__PURE__ */ jsx37(TreeBranch, { node: child, depth: depth + 1 }) : null
1916
+ isDir ? /* @__PURE__ */ jsx38(TreeBranch, { node: child, depth: depth + 1 }) : null
1839
1917
  ] }, child.name);
1840
1918
  }) });
1841
1919
  }
1842
1920
  function FileTreeBlock({ entry }) {
1843
1921
  const data = parseFileTree(entry.data);
1844
- if (!data) return /* @__PURE__ */ jsx37(UnreadableBlock, { entry });
1845
- return /* @__PURE__ */ jsx37(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ jsx37("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ jsx37(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
1922
+ if (!data) return /* @__PURE__ */ jsx38(UnreadableBlock, { entry });
1923
+ return /* @__PURE__ */ jsx38(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ jsx38("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ jsx38(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
1846
1924
  }
1847
1925
  function parseDataModel(data) {
1848
1926
  if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
@@ -1868,31 +1946,31 @@ function parseDataModel(data) {
1868
1946
  }
1869
1947
  function DataModelBlock({ entry }) {
1870
1948
  const data = parseDataModel(entry.data);
1871
- if (!data) return /* @__PURE__ */ jsx37(UnreadableBlock, { entry });
1949
+ if (!data) return /* @__PURE__ */ jsx38(UnreadableBlock, { entry });
1872
1950
  const hasNotes = data.fields.some((f) => f.note);
1873
- return /* @__PURE__ */ jsx37(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ jsx37("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs24("table", { className: "w-full border-collapse text-sm", children: [
1874
- /* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsxs24("tr", { className: "bg-muted/50", children: [
1875
- /* @__PURE__ */ jsx37("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
1876
- /* @__PURE__ */ jsx37("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
1877
- hasNotes ? /* @__PURE__ */ jsx37("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
1951
+ return /* @__PURE__ */ jsx38(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ jsx38("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs25("table", { className: "w-full border-collapse text-sm", children: [
1952
+ /* @__PURE__ */ jsx38("thead", { children: /* @__PURE__ */ jsxs25("tr", { className: "bg-muted/50", children: [
1953
+ /* @__PURE__ */ jsx38("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
1954
+ /* @__PURE__ */ jsx38("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
1955
+ hasNotes ? /* @__PURE__ */ jsx38("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
1878
1956
  ] }) }),
1879
- /* @__PURE__ */ jsx37("tbody", { children: data.fields.map((field) => /* @__PURE__ */ jsxs24("tr", { children: [
1880
- /* @__PURE__ */ jsx37("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs24("span", { className: "flex flex-wrap items-center gap-2", children: [
1881
- /* @__PURE__ */ jsx37("span", { className: "font-mono text-xs text-foreground", children: field.name }),
1882
- field.change ? /* @__PURE__ */ jsx37(ChangeBadge, { change: field.change }) : null
1957
+ /* @__PURE__ */ jsx38("tbody", { children: data.fields.map((field) => /* @__PURE__ */ jsxs25("tr", { children: [
1958
+ /* @__PURE__ */ jsx38("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs25("span", { className: "flex flex-wrap items-center gap-2", children: [
1959
+ /* @__PURE__ */ jsx38("span", { className: "font-mono text-xs text-foreground", children: field.name }),
1960
+ field.change ? /* @__PURE__ */ jsx38(ChangeBadge, { change: field.change }) : null
1883
1961
  ] }) }),
1884
- /* @__PURE__ */ jsx37("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
1885
- hasNotes ? /* @__PURE__ */ jsx37("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
1962
+ /* @__PURE__ */ jsx38("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
1963
+ hasNotes ? /* @__PURE__ */ jsx38("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
1886
1964
  ] }, field.name)) })
1887
1965
  ] }) }) });
1888
1966
  }
1889
1967
  function UnreadableBlock({ entry }) {
1890
- return /* @__PURE__ */ jsxs24("div", { className: "my-2", "data-type": entry.type, children: [
1891
- /* @__PURE__ */ jsxs24("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
1968
+ return /* @__PURE__ */ jsxs25("div", { className: "my-2", "data-type": entry.type, children: [
1969
+ /* @__PURE__ */ jsxs25("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
1892
1970
  entry.type,
1893
1971
  " (unrecognised shape)"
1894
1972
  ] }),
1895
- /* @__PURE__ */ jsx37(
1973
+ /* @__PURE__ */ jsx38(
1896
1974
  "pre",
1897
1975
  {
1898
1976
  tabIndex: 0,
@@ -1910,12 +1988,12 @@ function safeStringify2(value) {
1910
1988
  }
1911
1989
  }
1912
1990
  var narrativeBlockRenderers = {
1913
- [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ jsx37(FileTreeBlock, { entry }),
1914
- [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ jsx37(DataModelBlock, { entry })
1991
+ [FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ jsx38(FileTreeBlock, { entry }),
1992
+ [DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ jsx38(DataModelBlock, { entry })
1915
1993
  };
1916
1994
 
1917
1995
  // src/context/ReportRoot.tsx
1918
- import { jsx as jsx38 } from "react/jsx-runtime";
1996
+ import { jsx as jsx39 } from "react/jsx-runtime";
1919
1997
  var EMPTY_RENDERERS2 = {};
1920
1998
  function ReportRoot({
1921
1999
  report,
@@ -1923,7 +2001,7 @@ function ReportRoot({
1923
2001
  renderers,
1924
2002
  children
1925
2003
  }) {
1926
- const value = useMemo(
2004
+ const value = useMemo2(
1927
2005
  () => ({
1928
2006
  report,
1929
2007
  // Narrative blocks render everywhere the report does (static SSR, the
@@ -1934,7 +2012,7 @@ function ReportRoot({
1934
2012
  }),
1935
2013
  [report, customRenderers, renderers]
1936
2014
  );
1937
- return /* @__PURE__ */ jsx38(ReportContext.Provider, { value, children });
2015
+ return /* @__PURE__ */ jsx39(ReportContext.Provider, { value, children });
1938
2016
  }
1939
2017
 
1940
2018
  // src/lib/hash-state.ts
@@ -2120,7 +2198,7 @@ function listFailures(report) {
2120
2198
 
2121
2199
  // src/interactive/ReportAgentFilterNotice.tsx
2122
2200
  import { Bot, X } from "lucide-react";
2123
- import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
2201
+ import { Fragment as Fragment11, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
2124
2202
  function ReportAgentFilterNotice({
2125
2203
  applied,
2126
2204
  onReset,
@@ -2130,23 +2208,23 @@ function ReportAgentFilterNotice({
2130
2208
  if (applied.search) terms.push(`matching \u201C${applied.search}\u201D`);
2131
2209
  if (applied.status !== "all") terms.push(applied.status);
2132
2210
  if (applied.tags.length > 0) terms.push(applied.tags.join(", "));
2133
- return /* @__PURE__ */ jsxs25(
2211
+ return /* @__PURE__ */ jsxs26(
2134
2212
  "div",
2135
2213
  {
2136
2214
  role: "status",
2137
2215
  "aria-live": "polite",
2138
2216
  className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-primary/40 bg-primary/5 px-3 py-2 text-sm",
2139
2217
  children: [
2140
- /* @__PURE__ */ jsx39(Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
2141
- /* @__PURE__ */ jsxs25("span", { className: "min-w-0 flex-1", children: [
2218
+ /* @__PURE__ */ jsx40(Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
2219
+ /* @__PURE__ */ jsxs26("span", { className: "min-w-0 flex-1", children: [
2142
2220
  "An agent filtered this report",
2143
- terms.length > 0 ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
2221
+ terms.length > 0 ? /* @__PURE__ */ jsxs26(Fragment11, { children: [
2144
2222
  " to ",
2145
2223
  terms.join(" \xB7 ")
2146
2224
  ] }) : null,
2147
2225
  " \u2014",
2148
2226
  " ",
2149
- /* @__PURE__ */ jsxs25("span", { className: "tabular-nums", children: [
2227
+ /* @__PURE__ */ jsxs26("span", { className: "tabular-nums", children: [
2150
2228
  applied.matched,
2151
2229
  " of ",
2152
2230
  applied.total,
@@ -2154,7 +2232,7 @@ function ReportAgentFilterNotice({
2154
2232
  ] }),
2155
2233
  "."
2156
2234
  ] }),
2157
- /* @__PURE__ */ jsx39(
2235
+ /* @__PURE__ */ jsx40(
2158
2236
  "button",
2159
2237
  {
2160
2238
  type: "button",
@@ -2163,14 +2241,14 @@ function ReportAgentFilterNotice({
2163
2241
  children: "Show all"
2164
2242
  }
2165
2243
  ),
2166
- /* @__PURE__ */ jsx39(
2244
+ /* @__PURE__ */ jsx40(
2167
2245
  "button",
2168
2246
  {
2169
2247
  type: "button",
2170
2248
  onClick: onDismiss,
2171
2249
  "aria-label": "Dismiss",
2172
2250
  className: "cursor-pointer rounded-md p-1 text-muted-foreground hover:text-foreground",
2173
- children: /* @__PURE__ */ jsx39(X, { "aria-hidden": true, className: "size-4" })
2251
+ children: /* @__PURE__ */ jsx40(X, { "aria-hidden": true, className: "size-4" })
2174
2252
  }
2175
2253
  )
2176
2254
  ]
@@ -2180,7 +2258,7 @@ function ReportAgentFilterNotice({
2180
2258
 
2181
2259
  // src/interactive/ReportFailureBanner.tsx
2182
2260
  import { useCallback as useCallback2 } from "react";
2183
- import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
2261
+ import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
2184
2262
  function ReportFailureBanner({ failures, onCopyAll }) {
2185
2263
  const first = failures[0];
2186
2264
  const jumpToFirst = useCallback2(() => {
@@ -2188,7 +2266,7 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2188
2266
  scrollToScenarioId(first.scenarioId);
2189
2267
  }, [first]);
2190
2268
  if (failures.length === 0) return null;
2191
- return /* @__PURE__ */ jsxs26(
2269
+ return /* @__PURE__ */ jsxs27(
2192
2270
  "div",
2193
2271
  {
2194
2272
  className: "es-failure-banner",
@@ -2196,13 +2274,13 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2196
2274
  "aria-live": "polite",
2197
2275
  "aria-label": "Failure summary",
2198
2276
  children: [
2199
- /* @__PURE__ */ jsxs26("span", { className: "es-failure-banner-text", children: [
2200
- /* @__PURE__ */ jsx40("strong", { children: failures.length }),
2277
+ /* @__PURE__ */ jsxs27("span", { className: "es-failure-banner-text", children: [
2278
+ /* @__PURE__ */ jsx41("strong", { children: failures.length }),
2201
2279
  " ",
2202
2280
  "failure",
2203
2281
  failures.length === 1 ? "" : "s"
2204
2282
  ] }),
2205
- /* @__PURE__ */ jsx40(
2283
+ /* @__PURE__ */ jsx41(
2206
2284
  "button",
2207
2285
  {
2208
2286
  type: "button",
@@ -2212,7 +2290,7 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2212
2290
  children: "View first failure \u2193"
2213
2291
  }
2214
2292
  ),
2215
- onCopyAll ? /* @__PURE__ */ jsxs26(
2293
+ onCopyAll ? /* @__PURE__ */ jsxs27(
2216
2294
  "button",
2217
2295
  {
2218
2296
  type: "button",
@@ -2234,8 +2312,8 @@ function ReportFailureBanner({ failures, onCopyAll }) {
2234
2312
  }
2235
2313
 
2236
2314
  // src/interactive/ReportFilters.tsx
2237
- import { useState as useState3 } from "react";
2238
- import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
2315
+ import { useState as useState4 } from "react";
2316
+ import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2239
2317
  var TAG_LIMIT = 12;
2240
2318
  function ReportFilters({
2241
2319
  statuses,
@@ -2245,14 +2323,14 @@ function ReportFilters({
2245
2323
  activeTags,
2246
2324
  onToggleTag
2247
2325
  }) {
2248
- const [showAllTags, setShowAllTags] = useState3(false);
2326
+ const [showAllTags, setShowAllTags] = useState4(false);
2249
2327
  if (statuses.length === 0 && tags.length === 0) return null;
2250
2328
  const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
2251
2329
  const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
2252
- return /* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-2", children: [
2253
- statuses.length > 0 ? /* @__PURE__ */ jsx41("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2330
+ return /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-2", children: [
2331
+ statuses.length > 0 ? /* @__PURE__ */ jsx42("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2254
2332
  const active = status === opt.key;
2255
- return /* @__PURE__ */ jsxs27(
2333
+ return /* @__PURE__ */ jsxs28(
2256
2334
  "button",
2257
2335
  {
2258
2336
  type: "button",
@@ -2264,23 +2342,23 @@ function ReportFilters({
2264
2342
  ),
2265
2343
  children: [
2266
2344
  opt.label,
2267
- /* @__PURE__ */ jsx41("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2345
+ /* @__PURE__ */ jsx42("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2268
2346
  ]
2269
2347
  },
2270
2348
  opt.key
2271
2349
  );
2272
2350
  }) }) : null,
2273
- tags.length > 0 ? /* @__PURE__ */ jsxs27("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2351
+ tags.length > 0 ? /* @__PURE__ */ jsxs28("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2274
2352
  visibleTags.map((tag) => {
2275
2353
  const active = activeTags.includes(tag);
2276
- return /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
2354
+ return /* @__PURE__ */ jsx42("li", { children: /* @__PURE__ */ jsx42(
2277
2355
  "button",
2278
2356
  {
2279
2357
  type: "button",
2280
2358
  "aria-pressed": active,
2281
2359
  onClick: () => onToggleTag(tag),
2282
2360
  className: "cursor-pointer",
2283
- children: /* @__PURE__ */ jsx41(
2361
+ children: /* @__PURE__ */ jsx42(
2284
2362
  Badge,
2285
2363
  {
2286
2364
  variant: "tag",
@@ -2293,7 +2371,7 @@ function ReportFilters({
2293
2371
  }
2294
2372
  ) }, tag);
2295
2373
  }),
2296
- tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
2374
+ tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx42("li", { children: /* @__PURE__ */ jsx42(
2297
2375
  "button",
2298
2376
  {
2299
2377
  type: "button",
@@ -2308,16 +2386,16 @@ function ReportFilters({
2308
2386
  }
2309
2387
 
2310
2388
  // src/interactive/ReportFreshness.tsx
2311
- import { useEffect as useEffect2, useState as useState4 } from "react";
2312
- import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2389
+ import { useEffect as useEffect3, useState as useState5 } from "react";
2390
+ import { Fragment as Fragment12, jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
2313
2391
  function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2314
- const [now, setNow] = useState4(nowMs);
2315
- useEffect2(() => {
2392
+ const [now, setNow] = useState5(nowMs);
2393
+ useEffect3(() => {
2316
2394
  if (nowMs === void 0) setNow(Date.now());
2317
2395
  }, [nowMs]);
2318
2396
  if (lastRunMs === void 0 || now === void 0) return null;
2319
2397
  const age = formatRelativeAge(lastRunMs, now);
2320
- const runLink = ciUrl ? /* @__PURE__ */ jsx42(
2398
+ const runLink = ciUrl ? /* @__PURE__ */ jsx43(
2321
2399
  "a",
2322
2400
  {
2323
2401
  href: ciUrl,
@@ -2328,9 +2406,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2328
2406
  }
2329
2407
  ) : null;
2330
2408
  if (isReportStale(lastRunMs, staleAfterDays, now)) {
2331
- return /* @__PURE__ */ jsxs28("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2332
- /* @__PURE__ */ jsxs28("span", { children: [
2333
- /* @__PURE__ */ jsxs28("strong", { children: [
2409
+ return /* @__PURE__ */ jsxs29("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2410
+ /* @__PURE__ */ jsxs29("span", { children: [
2411
+ /* @__PURE__ */ jsxs29("strong", { children: [
2334
2412
  "Last verified ",
2335
2413
  age,
2336
2414
  "."
@@ -2340,10 +2418,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2340
2418
  runLink
2341
2419
  ] });
2342
2420
  }
2343
- return /* @__PURE__ */ jsxs28("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2421
+ return /* @__PURE__ */ jsxs29("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2344
2422
  "Verified ",
2345
2423
  age,
2346
- runLink ? /* @__PURE__ */ jsxs28(Fragment12, { children: [
2424
+ runLink ? /* @__PURE__ */ jsxs29(Fragment12, { children: [
2347
2425
  " \xB7 ",
2348
2426
  runLink
2349
2427
  ] }) : null
@@ -2351,15 +2429,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
2351
2429
  }
2352
2430
 
2353
2431
  // src/interactive/ReportLastRunDelta.tsx
2354
- import { Fragment as Fragment13, jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
2432
+ import { Fragment as Fragment13, jsx as jsx44, jsxs as jsxs30 } from "react/jsx-runtime";
2355
2433
  var MAX_LINKS = 5;
2356
2434
  function ScenarioLinks({ scenarios, tone }) {
2357
- return /* @__PURE__ */ jsxs29(Fragment13, { children: [
2358
- scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs29("span", { children: [
2435
+ return /* @__PURE__ */ jsxs30(Fragment13, { children: [
2436
+ scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs30("span", { children: [
2359
2437
  i > 0 ? ", " : "",
2360
- /* @__PURE__ */ jsx43("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2438
+ /* @__PURE__ */ jsx44("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2361
2439
  ] }, s.id)),
2362
- scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs29("span", { children: [
2440
+ scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs30("span", { children: [
2363
2441
  " and ",
2364
2442
  scenarios.length - MAX_LINKS,
2365
2443
  " more"
@@ -2376,23 +2454,23 @@ function ReportLastRunDelta({
2376
2454
  if (!delta) return null;
2377
2455
  const { newlyFailing, newlyPassing, added } = delta;
2378
2456
  if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
2379
- return /* @__PURE__ */ jsx43("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2457
+ return /* @__PURE__ */ jsx44("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2380
2458
  }
2381
- return /* @__PURE__ */ jsxs29("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2382
- /* @__PURE__ */ jsx43("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2383
- newlyFailing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-fail", children: [
2459
+ return /* @__PURE__ */ jsxs30("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2460
+ /* @__PURE__ */ jsx44("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2461
+ newlyFailing.length > 0 ? /* @__PURE__ */ jsxs30("span", { className: "ml-2 text-fail", children: [
2384
2462
  newlyFailing.length,
2385
2463
  " newly failing (",
2386
- /* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2464
+ /* @__PURE__ */ jsx44(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2387
2465
  ")"
2388
2466
  ] }) : null,
2389
- newlyPassing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-pass", children: [
2467
+ newlyPassing.length > 0 ? /* @__PURE__ */ jsxs30("span", { className: "ml-2 text-pass", children: [
2390
2468
  newlyPassing.length,
2391
2469
  " fixed (",
2392
- /* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2470
+ /* @__PURE__ */ jsx44(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2393
2471
  ")"
2394
2472
  ] }) : null,
2395
- added.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2", children: [
2473
+ added.length > 0 ? /* @__PURE__ */ jsxs30("span", { className: "ml-2", children: [
2396
2474
  added.length,
2397
2475
  " new"
2398
2476
  ] }) : null
@@ -2408,9 +2486,9 @@ import { Search } from "lucide-react";
2408
2486
 
2409
2487
  // src/components/ui/input.tsx
2410
2488
  import "react";
2411
- import { jsx as jsx44 } from "react/jsx-runtime";
2489
+ import { jsx as jsx45 } from "react/jsx-runtime";
2412
2490
  function Input({ className, type, ...props }) {
2413
- return /* @__PURE__ */ jsx44(
2491
+ return /* @__PURE__ */ jsx45(
2414
2492
  "input",
2415
2493
  {
2416
2494
  type,
@@ -2427,7 +2505,7 @@ function Input({ className, type, ...props }) {
2427
2505
  }
2428
2506
 
2429
2507
  // src/interactive/ReportSearch.tsx
2430
- import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2508
+ import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2431
2509
  var ReportSearch = forwardRef(
2432
2510
  function ReportSearch2(props, ref) {
2433
2511
  const {
@@ -2449,17 +2527,17 @@ var ReportSearch = forwardRef(
2449
2527
  e.preventDefault();
2450
2528
  }
2451
2529
  }
2452
- return /* @__PURE__ */ jsxs30("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2453
- /* @__PURE__ */ jsx45("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2454
- /* @__PURE__ */ jsxs30("div", { className: "relative w-full sm:w-72", children: [
2455
- /* @__PURE__ */ jsx45(
2530
+ return /* @__PURE__ */ jsxs31("div", { className: cn("es-search flex flex-col gap-1", className), children: [
2531
+ /* @__PURE__ */ jsx46("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
2532
+ /* @__PURE__ */ jsxs31("div", { className: "relative w-full sm:w-72", children: [
2533
+ /* @__PURE__ */ jsx46(
2456
2534
  Search,
2457
2535
  {
2458
2536
  "aria-hidden": true,
2459
2537
  className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
2460
2538
  }
2461
2539
  ),
2462
- /* @__PURE__ */ jsx45(
2540
+ /* @__PURE__ */ jsx46(
2463
2541
  Input,
2464
2542
  {
2465
2543
  ref,
@@ -2476,7 +2554,7 @@ var ReportSearch = forwardRef(
2476
2554
  }
2477
2555
  )
2478
2556
  ] }),
2479
- showCounts ? /* @__PURE__ */ jsxs30(
2557
+ showCounts ? /* @__PURE__ */ jsxs31(
2480
2558
  "span",
2481
2559
  {
2482
2560
  className: "text-xs tabular-nums text-muted-foreground",
@@ -2495,7 +2573,7 @@ var ReportSearch = forwardRef(
2495
2573
 
2496
2574
  // src/interactive/ReportShare.tsx
2497
2575
  import { Share2 } from "lucide-react";
2498
- import { useEffect as useEffect3, useRef, useState as useState5 } from "react";
2576
+ import { useEffect as useEffect4, useRef as useRef2, useState as useState6 } from "react";
2499
2577
 
2500
2578
  // src/components/ui/button.tsx
2501
2579
  import "react";
@@ -2551,22 +2629,22 @@ function Button({
2551
2629
  }
2552
2630
 
2553
2631
  // src/interactive/ReportShare.tsx
2554
- import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2632
+ import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2555
2633
  var DEFAULT_SHARE_COMMAND = "npx executable-stories share reports/";
2556
2634
  function ReportShare({
2557
2635
  command = DEFAULT_SHARE_COMMAND,
2558
2636
  onCopy
2559
2637
  }) {
2560
- const [open, setOpen] = useState5(false);
2561
- const dialogRef = useRef(null);
2562
- useEffect3(() => {
2638
+ const [open, setOpen] = useState6(false);
2639
+ const dialogRef = useRef2(null);
2640
+ useEffect4(() => {
2563
2641
  const dialog = dialogRef.current;
2564
2642
  if (!dialog) return;
2565
2643
  if (open && !dialog.open) dialog.showModal();
2566
2644
  else if (!open && dialog.open) dialog.close();
2567
2645
  }, [open]);
2568
- return /* @__PURE__ */ jsxs31(Fragment14, { children: [
2569
- /* @__PURE__ */ jsxs31(
2646
+ return /* @__PURE__ */ jsxs32(Fragment14, { children: [
2647
+ /* @__PURE__ */ jsxs32(
2570
2648
  Button,
2571
2649
  {
2572
2650
  type: "button",
@@ -2576,12 +2654,12 @@ function ReportShare({
2576
2654
  title: "Share this report",
2577
2655
  onClick: () => setOpen(true),
2578
2656
  children: [
2579
- /* @__PURE__ */ jsx46(Share2, { "aria-hidden": "true", className: "size-4" }),
2580
- /* @__PURE__ */ jsx46("span", { className: "sr-only sm:not-sr-only", children: "Share" })
2657
+ /* @__PURE__ */ jsx47(Share2, { "aria-hidden": "true", className: "size-4" }),
2658
+ /* @__PURE__ */ jsx47("span", { className: "sr-only sm:not-sr-only", children: "Share" })
2581
2659
  ]
2582
2660
  }
2583
2661
  ),
2584
- /* @__PURE__ */ jsxs31(
2662
+ /* @__PURE__ */ jsxs32(
2585
2663
  "dialog",
2586
2664
  {
2587
2665
  ref: dialogRef,
@@ -2589,11 +2667,11 @@ function ReportShare({
2589
2667
  "aria-label": "Share this report",
2590
2668
  onClose: () => setOpen(false),
2591
2669
  children: [
2592
- /* @__PURE__ */ jsx46("h2", { className: "text-base font-semibold", children: "Share this report" }),
2593
- /* @__PURE__ */ jsx46("p", { className: "mt-2 text-sm text-muted-foreground", children: "Publish it to Executable Stories Cloud and send a link. Screenshots and videos go with it. Run this from your project:" }),
2594
- /* @__PURE__ */ jsxs31("div", { className: "mt-4 flex items-center gap-2", children: [
2595
- /* @__PURE__ */ jsx46("code", { className: "min-w-0 flex-1 truncate rounded border border-border bg-muted px-3 py-2 font-mono text-xs", children: command }),
2596
- /* @__PURE__ */ jsx46(
2670
+ /* @__PURE__ */ jsx47("h2", { className: "text-base font-semibold", children: "Share this report" }),
2671
+ /* @__PURE__ */ jsx47("p", { className: "mt-2 text-sm text-muted-foreground", children: "Publish it to Executable Stories Cloud and send a link. Screenshots and videos go with it. Run this from your project:" }),
2672
+ /* @__PURE__ */ jsxs32("div", { className: "mt-4 flex items-center gap-2", children: [
2673
+ /* @__PURE__ */ jsx47("code", { className: "min-w-0 flex-1 truncate rounded border border-border bg-muted px-3 py-2 font-mono text-xs", children: command }),
2674
+ /* @__PURE__ */ jsx47(
2597
2675
  Button,
2598
2676
  {
2599
2677
  type: "button",
@@ -2603,9 +2681,9 @@ function ReportShare({
2603
2681
  }
2604
2682
  )
2605
2683
  ] }),
2606
- /* @__PURE__ */ jsx46("p", { className: "mt-3 text-xs text-muted-foreground", children: "The file you are reading cannot upload itself, so the command does it: only the CLI can read the assets this report links to." }),
2607
- /* @__PURE__ */ jsxs31("div", { className: "mt-6 flex items-center justify-between gap-4", children: [
2608
- /* @__PURE__ */ jsx46(
2684
+ /* @__PURE__ */ jsx47("p", { className: "mt-3 text-xs text-muted-foreground", children: "The file you are reading cannot upload itself, so the command does it: only the CLI can read the assets this report links to." }),
2685
+ /* @__PURE__ */ jsxs32("div", { className: "mt-6 flex items-center justify-between gap-4", children: [
2686
+ /* @__PURE__ */ jsx47(
2609
2687
  "a",
2610
2688
  {
2611
2689
  className: "text-xs underline underline-offset-2",
@@ -2615,7 +2693,7 @@ function ReportShare({
2615
2693
  children: "How sharing works"
2616
2694
  }
2617
2695
  ),
2618
- /* @__PURE__ */ jsx46(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2696
+ /* @__PURE__ */ jsx47(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), children: "Close" })
2619
2697
  ] })
2620
2698
  ]
2621
2699
  }
@@ -2624,7 +2702,7 @@ function ReportShare({
2624
2702
  }
2625
2703
 
2626
2704
  // src/interactive/ReportSinceLastVisit.tsx
2627
- import { useEffect as useEffect4, useState as useState6 } from "react";
2705
+ import { useEffect as useEffect5, useState as useState7 } from "react";
2628
2706
 
2629
2707
  // src/interactive/last-visit.ts
2630
2708
  function snapshotOf(report, atMs) {
@@ -2660,7 +2738,7 @@ function diffSinceVisit(previous, report) {
2660
2738
  }
2661
2739
 
2662
2740
  // src/interactive/ReportSinceLastVisit.tsx
2663
- import { Fragment as Fragment15, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2741
+ import { Fragment as Fragment15, jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2664
2742
  var KEY = "es-last-visit";
2665
2743
  var MAX_LINKS2 = 5;
2666
2744
  function readVisit() {
@@ -2685,12 +2763,12 @@ function writeVisit(snapshot) {
2685
2763
  }
2686
2764
  }
2687
2765
  function ScenarioLinks2({ scenarios, tone }) {
2688
- return /* @__PURE__ */ jsxs32(Fragment15, { children: [
2689
- scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ jsxs32("span", { children: [
2766
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2767
+ scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ jsxs33("span", { children: [
2690
2768
  i > 0 ? ", " : "",
2691
- /* @__PURE__ */ jsx47("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2769
+ /* @__PURE__ */ jsx48("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2692
2770
  ] }, s.id)),
2693
- scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ jsxs32("span", { children: [
2771
+ scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ jsxs33("span", { children: [
2694
2772
  " and ",
2695
2773
  scenarios.length - MAX_LINKS2,
2696
2774
  " more"
@@ -2698,9 +2776,9 @@ function ScenarioLinks2({ scenarios, tone }) {
2698
2776
  ] });
2699
2777
  }
2700
2778
  function ReportSinceLastVisit({ report }) {
2701
- const [delta, setDelta] = useState6(null);
2702
- const [nowMs, setNowMs] = useState6(0);
2703
- useEffect4(() => {
2779
+ const [delta, setDelta] = useState7(null);
2780
+ const [nowMs, setNowMs] = useState7(0);
2781
+ useEffect5(() => {
2704
2782
  const now = Date.now();
2705
2783
  setDelta(diffSinceVisit(readVisit(), report));
2706
2784
  setNowMs(now);
@@ -2708,25 +2786,25 @@ function ReportSinceLastVisit({ report }) {
2708
2786
  }, [report]);
2709
2787
  if (!delta) return null;
2710
2788
  const { newlyFailing, newlyPassing, added } = delta;
2711
- return /* @__PURE__ */ jsxs32("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2712
- /* @__PURE__ */ jsxs32("span", { className: "font-medium text-foreground", children: [
2789
+ return /* @__PURE__ */ jsxs33("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
2790
+ /* @__PURE__ */ jsxs33("span", { className: "font-medium text-foreground", children: [
2713
2791
  "Since your last visit (",
2714
2792
  formatRelativeAge(delta.sinceMs, nowMs),
2715
2793
  "):"
2716
2794
  ] }),
2717
- newlyFailing.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2 text-fail", children: [
2795
+ newlyFailing.length > 0 ? /* @__PURE__ */ jsxs33("span", { className: "ml-2 text-fail", children: [
2718
2796
  newlyFailing.length,
2719
2797
  " started failing (",
2720
- /* @__PURE__ */ jsx47(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2798
+ /* @__PURE__ */ jsx48(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
2721
2799
  ")"
2722
2800
  ] }) : null,
2723
- newlyPassing.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2 text-pass", children: [
2801
+ newlyPassing.length > 0 ? /* @__PURE__ */ jsxs33("span", { className: "ml-2 text-pass", children: [
2724
2802
  newlyPassing.length,
2725
2803
  " fixed (",
2726
- /* @__PURE__ */ jsx47(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2804
+ /* @__PURE__ */ jsx48(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
2727
2805
  ")"
2728
2806
  ] }) : null,
2729
- added.length > 0 ? /* @__PURE__ */ jsxs32("span", { className: "ml-2", children: [
2807
+ added.length > 0 ? /* @__PURE__ */ jsxs33("span", { className: "ml-2", children: [
2730
2808
  added.length,
2731
2809
  " new"
2732
2810
  ] }) : null
@@ -2734,8 +2812,8 @@ function ReportSinceLastVisit({ report }) {
2734
2812
  }
2735
2813
 
2736
2814
  // src/interactive/ReportShortcutsHelp.tsx
2737
- import { useEffect as useEffect5, useRef as useRef2 } from "react";
2738
- import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2815
+ import { useEffect as useEffect6, useRef as useRef3 } from "react";
2816
+ import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2739
2817
  var SHORTCUTS = [
2740
2818
  { keys: "/", description: "Focus search" },
2741
2819
  { keys: "f", description: "Jump to next failure" },
@@ -2747,20 +2825,20 @@ var SHORTCUTS = [
2747
2825
  ];
2748
2826
  function Keys({ keys }) {
2749
2827
  const parts = keys.split(" ");
2750
- return /* @__PURE__ */ jsx48("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs33("span", { className: "inline-flex items-center gap-1", children: [
2751
- i > 0 ? /* @__PURE__ */ jsx48("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2752
- /* @__PURE__ */ jsx48("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2828
+ return /* @__PURE__ */ jsx49("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs34("span", { className: "inline-flex items-center gap-1", children: [
2829
+ i > 0 ? /* @__PURE__ */ jsx49("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2830
+ /* @__PURE__ */ jsx49("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
2753
2831
  ] }, k)) });
2754
2832
  }
2755
2833
  function ReportShortcutsHelp({ open, onClose }) {
2756
- const dialogRef = useRef2(null);
2757
- useEffect5(() => {
2834
+ const dialogRef = useRef3(null);
2835
+ useEffect6(() => {
2758
2836
  const dialog = dialogRef.current;
2759
2837
  if (!dialog) return;
2760
2838
  if (open && !dialog.open) dialog.showModal();
2761
2839
  else if (!open && dialog.open) dialog.close();
2762
2840
  }, [open]);
2763
- return /* @__PURE__ */ jsxs33(
2841
+ return /* @__PURE__ */ jsxs34(
2764
2842
  "dialog",
2765
2843
  {
2766
2844
  ref: dialogRef,
@@ -2768,20 +2846,20 @@ function ReportShortcutsHelp({ open, onClose }) {
2768
2846
  "aria-label": "Keyboard shortcuts",
2769
2847
  onClose,
2770
2848
  children: [
2771
- /* @__PURE__ */ jsx48("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2772
- /* @__PURE__ */ jsx48("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs33("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2773
- /* @__PURE__ */ jsx48("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx48(Keys, { keys: s.keys }) }),
2774
- /* @__PURE__ */ jsx48("dd", { className: "text-sm text-muted-foreground", children: s.description })
2849
+ /* @__PURE__ */ jsx49("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2850
+ /* @__PURE__ */ jsx49("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs34("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2851
+ /* @__PURE__ */ jsx49("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx49(Keys, { keys: s.keys }) }),
2852
+ /* @__PURE__ */ jsx49("dd", { className: "text-sm text-muted-foreground", children: s.description })
2775
2853
  ] }, s.keys)) }),
2776
- /* @__PURE__ */ jsx48("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx48(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2854
+ /* @__PURE__ */ jsx49("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx49(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2777
2855
  ]
2778
2856
  }
2779
2857
  );
2780
2858
  }
2781
2859
 
2782
2860
  // src/interactive/ReportToc.tsx
2783
- import { useEffect as useEffect6, useMemo as useMemo2, useState as useState7 } from "react";
2784
- import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2861
+ import { useEffect as useEffect7, useMemo as useMemo3, useState as useState8 } from "react";
2862
+ import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
2785
2863
  var DOT = {
2786
2864
  passed: "bg-pass",
2787
2865
  failed: "bg-fail",
@@ -2790,31 +2868,55 @@ var DOT = {
2790
2868
  };
2791
2869
  function TocContent({ onNavigate }) {
2792
2870
  const report = useReport();
2793
- const [activeId, setActiveId] = useState7(null);
2794
- const scenarioIds = useMemo2(
2871
+ const [activeId, setActiveId] = useState8(null);
2872
+ const scenarioIds = useMemo3(
2795
2873
  () => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
2796
2874
  [report]
2797
2875
  );
2798
- useEffect6(() => {
2799
- if (typeof IntersectionObserver === "undefined") return;
2876
+ useEffect7(() => {
2877
+ if (typeof window === "undefined") return;
2800
2878
  const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
2801
2879
  if (els.length === 0) return;
2802
- const observer = new IntersectionObserver(
2803
- (entries) => {
2804
- const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
2805
- if (visible[0]) setActiveId(visible[0].target.id);
2806
- },
2807
- { rootMargin: "-8% 0px -80% 0px" }
2808
- );
2809
- els.forEach((el) => observer.observe(el));
2810
- return () => observer.disconnect();
2880
+ let frame = 0;
2881
+ const update = () => {
2882
+ frame = 0;
2883
+ const atBottom = window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 2;
2884
+ const line = atBottom ? window.innerHeight : window.innerHeight * 0.2;
2885
+ let active = els[0];
2886
+ let best = -Infinity;
2887
+ let firstId = null;
2888
+ let firstTop = Infinity;
2889
+ for (const el of els) {
2890
+ const top = el.getBoundingClientRect().top;
2891
+ if (top <= line && top > best) {
2892
+ best = top;
2893
+ active = el;
2894
+ }
2895
+ if (top < firstTop) {
2896
+ firstTop = top;
2897
+ firstId = el.id;
2898
+ }
2899
+ }
2900
+ setActiveId(best === -Infinity ? firstId : active.id);
2901
+ };
2902
+ const onScroll = () => {
2903
+ if (frame === 0) frame = requestAnimationFrame(update);
2904
+ };
2905
+ update();
2906
+ window.addEventListener("scroll", onScroll, { passive: true });
2907
+ window.addEventListener("resize", onScroll);
2908
+ return () => {
2909
+ window.removeEventListener("scroll", onScroll);
2910
+ window.removeEventListener("resize", onScroll);
2911
+ if (frame !== 0) cancelAnimationFrame(frame);
2912
+ };
2811
2913
  }, [scenarioIds]);
2812
2914
  if (report.features.length === 0) return null;
2813
- return /* @__PURE__ */ jsx49("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs34("li", { children: [
2814
- /* @__PURE__ */ jsx49("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2815
- /* @__PURE__ */ jsx49("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2915
+ return /* @__PURE__ */ jsx50("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs35("li", { children: [
2916
+ /* @__PURE__ */ jsx50("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2917
+ /* @__PURE__ */ jsx50("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2816
2918
  const active = activeId === scenario.id;
2817
- return /* @__PURE__ */ jsx49("li", { children: /* @__PURE__ */ jsxs34(
2919
+ return /* @__PURE__ */ jsx50("li", { children: /* @__PURE__ */ jsxs35(
2818
2920
  "a",
2819
2921
  {
2820
2922
  href: `#${scenario.id}`,
@@ -2829,14 +2931,14 @@ function TocContent({ onNavigate }) {
2829
2931
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2830
2932
  ),
2831
2933
  children: [
2832
- /* @__PURE__ */ jsx49(
2934
+ /* @__PURE__ */ jsx50(
2833
2935
  "span",
2834
2936
  {
2835
2937
  "aria-hidden": true,
2836
2938
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2837
2939
  }
2838
2940
  ),
2839
- /* @__PURE__ */ jsx49("span", { className: "break-words", children: scenario.title })
2941
+ /* @__PURE__ */ jsx50("span", { className: "break-words", children: scenario.title })
2840
2942
  ]
2841
2943
  }
2842
2944
  ) }, scenario.id);
@@ -2846,48 +2948,48 @@ function TocContent({ onNavigate }) {
2846
2948
  function ReportToc() {
2847
2949
  const report = useReport();
2848
2950
  if (report.features.length === 0) return null;
2849
- return /* @__PURE__ */ jsxs34(
2951
+ return /* @__PURE__ */ jsxs35(
2850
2952
  "nav",
2851
2953
  {
2852
2954
  "aria-label": "Table of contents",
2853
2955
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2854
2956
  children: [
2855
- /* @__PURE__ */ jsx49("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2856
- /* @__PURE__ */ jsx49(TocContent, {})
2957
+ /* @__PURE__ */ jsx50("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2958
+ /* @__PURE__ */ jsx50(TocContent, {})
2857
2959
  ]
2858
2960
  }
2859
2961
  );
2860
2962
  }
2861
2963
 
2862
2964
  // src/interactive/ReportTocDrawer.tsx
2863
- import { useState as useState8 } from "react";
2965
+ import { useState as useState9 } from "react";
2864
2966
  import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
2865
2967
  import { ListIcon, XIcon } from "lucide-react";
2866
- import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
2968
+ import { jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
2867
2969
  function ReportTocDrawer() {
2868
2970
  const report = useReport();
2869
- const [open, setOpen] = useState8(false);
2971
+ const [open, setOpen] = useState9(false);
2870
2972
  if (report.features.length === 0) return null;
2871
- return /* @__PURE__ */ jsxs35(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2872
- /* @__PURE__ */ jsxs35(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2873
- /* @__PURE__ */ jsx50(ListIcon, { "aria-hidden": true }),
2973
+ return /* @__PURE__ */ jsxs36(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
2974
+ /* @__PURE__ */ jsxs36(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
2975
+ /* @__PURE__ */ jsx51(ListIcon, { "aria-hidden": true }),
2874
2976
  " Contents"
2875
2977
  ] }),
2876
- /* @__PURE__ */ jsxs35(DialogPrimitive.Portal, { children: [
2877
- /* @__PURE__ */ jsx50(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2878
- /* @__PURE__ */ jsxs35(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2879
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center justify-between", children: [
2880
- /* @__PURE__ */ jsx50(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2881
- /* @__PURE__ */ jsx50(
2978
+ /* @__PURE__ */ jsxs36(DialogPrimitive.Portal, { children: [
2979
+ /* @__PURE__ */ jsx51(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2980
+ /* @__PURE__ */ jsxs36(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
2981
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-between", children: [
2982
+ /* @__PURE__ */ jsx51(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2983
+ /* @__PURE__ */ jsx51(
2882
2984
  DialogPrimitive.Close,
2883
2985
  {
2884
2986
  "aria-label": "Close contents",
2885
2987
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2886
- children: /* @__PURE__ */ jsx50(XIcon, { "aria-hidden": true })
2988
+ children: /* @__PURE__ */ jsx51(XIcon, { "aria-hidden": true })
2887
2989
  }
2888
2990
  )
2889
2991
  ] }),
2890
- /* @__PURE__ */ jsx50(TocContent, { onNavigate: () => setOpen(false) })
2992
+ /* @__PURE__ */ jsx51(TocContent, { onNavigate: () => setOpen(false) })
2891
2993
  ] })
2892
2994
  ] })
2893
2995
  ] });
@@ -2921,10 +3023,10 @@ function failuresFirst(report) {
2921
3023
  }
2922
3024
 
2923
3025
  // src/interactive/use-deep-link-scroll.ts
2924
- import { useEffect as useEffect7, useRef as useRef3 } from "react";
3026
+ import { useEffect as useEffect8, useRef as useRef4 } from "react";
2925
3027
  function useDeepLinkScroll() {
2926
- const lastAnchor = useRef3(null);
2927
- useEffect7(() => {
3028
+ const lastAnchor = useRef4(null);
3029
+ useEffect8(() => {
2928
3030
  function scrollToHash() {
2929
3031
  const { anchor } = splitHash(window.location.hash);
2930
3032
  if (!anchor || anchor === lastAnchor.current) return;
@@ -2940,7 +3042,7 @@ function useDeepLinkScroll() {
2940
3042
  }
2941
3043
 
2942
3044
  // src/interactive/use-keyboard-shortcuts.ts
2943
- import { useEffect as useEffect8, useRef as useRef4 } from "react";
3045
+ import { useEffect as useEffect9, useRef as useRef5 } from "react";
2944
3046
  function isEditableTarget(target) {
2945
3047
  if (!(target instanceof HTMLElement)) return false;
2946
3048
  const tag = target.tagName;
@@ -2949,9 +3051,9 @@ function isEditableTarget(target) {
2949
3051
  return false;
2950
3052
  }
2951
3053
  function useKeyboardShortcuts(handlers) {
2952
- const ref = useRef4(handlers);
3054
+ const ref = useRef5(handlers);
2953
3055
  ref.current = handlers;
2954
- useEffect8(() => {
3056
+ useEffect9(() => {
2955
3057
  function onKeyDown(e) {
2956
3058
  const h = ref.current;
2957
3059
  if (e.key === "Escape") {
@@ -2995,7 +3097,7 @@ function useKeyboardShortcuts(handlers) {
2995
3097
  }
2996
3098
 
2997
3099
  // src/interactive/use-theme.ts
2998
- import { useCallback as useCallback3, useEffect as useEffect9, useState as useState9 } from "react";
3100
+ import { useCallback as useCallback3, useEffect as useEffect10, useState as useState10 } from "react";
2999
3101
  var KEY2 = "es-theme";
3000
3102
  function systemDark() {
3001
3103
  return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
@@ -3016,13 +3118,13 @@ function initialPref() {
3016
3118
  return "system";
3017
3119
  }
3018
3120
  function useTheme() {
3019
- const [pref, setPrefState] = useState9("system");
3020
- useEffect9(() => {
3121
+ const [pref, setPrefState] = useState10("system");
3122
+ useEffect10(() => {
3021
3123
  const p = initialPref();
3022
3124
  setPrefState(p);
3023
3125
  applyTheme(p);
3024
3126
  }, []);
3025
- useEffect9(() => {
3127
+ useEffect10(() => {
3026
3128
  if (typeof matchMedia === "undefined") return;
3027
3129
  const mq = matchMedia("(prefers-color-scheme: dark)");
3028
3130
  const onChange = () => {
@@ -3043,19 +3145,19 @@ function useTheme() {
3043
3145
  }
3044
3146
 
3045
3147
  // src/interactive/use-url-state.ts
3046
- import { useCallback as useCallback4, useEffect as useEffect10, useRef as useRef5, useState as useState10 } from "react";
3148
+ import { useCallback as useCallback4, useEffect as useEffect11, useRef as useRef6, useState as useState11 } from "react";
3047
3149
  var WRITE_DELAY_MS = 250;
3048
3150
  function useUrlState() {
3049
- const [state, setState] = useState10(DEFAULT_URL_STATE);
3050
- const ready = useRef5(false);
3051
- useEffect10(() => {
3151
+ const [state, setState] = useState11(DEFAULT_URL_STATE);
3152
+ const ready = useRef6(false);
3153
+ useEffect11(() => {
3052
3154
  const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
3053
3155
  read();
3054
3156
  ready.current = true;
3055
3157
  window.addEventListener("hashchange", read);
3056
3158
  return () => window.removeEventListener("hashchange", read);
3057
3159
  }, []);
3058
- useEffect10(() => {
3160
+ useEffect11(() => {
3059
3161
  if (!ready.current) return;
3060
3162
  const timer = setTimeout(
3061
3163
  () => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
@@ -3291,12 +3393,12 @@ function reportTools(deps) {
3291
3393
  }
3292
3394
 
3293
3395
  // src/interactive/ReportInteractive.tsx
3294
- import { Fragment as Fragment16, jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
3396
+ import { Fragment as Fragment16, jsx as jsx52, jsxs as jsxs37 } from "react/jsx-runtime";
3295
3397
  function ReportInteractive(props) {
3296
3398
  const { report, className, title, dataTheme } = props;
3297
3399
  const result = unwrapReport(report);
3298
3400
  if (!result.ok) {
3299
- return /* @__PURE__ */ jsx51(
3401
+ return /* @__PURE__ */ jsx52(
3300
3402
  ReportErrorShell,
3301
3403
  {
3302
3404
  error: result.error,
@@ -3306,7 +3408,7 @@ function ReportInteractive(props) {
3306
3408
  }
3307
3409
  );
3308
3410
  }
3309
- return /* @__PURE__ */ jsx51(ReportInteractiveView, { ...props, report: result.data });
3411
+ return /* @__PURE__ */ jsx52(ReportInteractiveView, { ...props, report: result.data });
3310
3412
  }
3311
3413
  var THEME_OPTIONS = [
3312
3414
  { value: "light", label: "Light", Icon: Sun },
@@ -3317,7 +3419,7 @@ function ThemeSegment({
3317
3419
  pref,
3318
3420
  onPref
3319
3421
  }) {
3320
- return /* @__PURE__ */ jsx51(
3422
+ return /* @__PURE__ */ jsx52(
3321
3423
  ToggleGroup,
3322
3424
  {
3323
3425
  size: "sm",
@@ -3327,14 +3429,14 @@ function ThemeSegment({
3327
3429
  if (next) onPref(next);
3328
3430
  },
3329
3431
  "aria-label": "Color theme",
3330
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx51(
3432
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx52(
3331
3433
  ToggleGroupItem,
3332
3434
  {
3333
3435
  value,
3334
3436
  "aria-label": label,
3335
3437
  title: label,
3336
3438
  className: "px-2",
3337
- children: /* @__PURE__ */ jsx51(Icon, {})
3439
+ children: /* @__PURE__ */ jsx52(Icon, {})
3338
3440
  },
3339
3441
  value
3340
3442
  ))
@@ -3353,6 +3455,7 @@ function ReportInteractiveView({
3353
3455
  staleAfterDays = 7,
3354
3456
  scenarioHistory,
3355
3457
  share = false,
3458
+ architecture = false,
3356
3459
  shareCommand
3357
3460
  }) {
3358
3461
  const [urlState, setUrlState] = useUrlState();
@@ -3369,14 +3472,14 @@ function ReportInteractiveView({
3369
3472
  (next) => setUrlState({ detail: next }),
3370
3473
  [setUrlState]
3371
3474
  );
3372
- const [helpOpen, setHelpOpen] = useState11(false);
3475
+ const [helpOpen, setHelpOpen] = useState12(false);
3373
3476
  const { pref: themePref, setPref: setThemePref } = useTheme();
3374
- const searchRef = useRef6(null);
3477
+ const searchRef = useRef7(null);
3375
3478
  const expandId = useId2();
3376
3479
  const docsId = useId2();
3377
3480
  const deferredQuery = useDeferredValue(query);
3378
- const failures = useMemo3(() => listFailures(report), [report]);
3379
- const filtered = useMemo3(
3481
+ const failures = useMemo4(() => listFailures(report), [report]);
3482
+ const filtered = useMemo4(
3380
3483
  // Features carrying failures float to the top so the first thing on screen
3381
3484
  // is the thing that needs attention; an all-green run keeps source order.
3382
3485
  () => failuresFirst(
@@ -3389,7 +3492,7 @@ function ReportInteractiveView({
3389
3492
  [report, deferredQuery, statusFilter, activeTags]
3390
3493
  );
3391
3494
  const isFiltering = query !== deferredQuery;
3392
- const statusOptions = useMemo3(() => {
3495
+ const statusOptions = useMemo4(() => {
3393
3496
  const s = report.summary;
3394
3497
  const opts = [
3395
3498
  { key: "all", label: "All", count: s.total }
@@ -3404,15 +3507,15 @@ function ReportInteractiveView({
3404
3507
  opts.push({ key: "pending", label: "Pending", count: s.pending });
3405
3508
  return opts;
3406
3509
  }, [report]);
3407
- const tagOptions = useMemo3(() => allTags(report), [report]);
3510
+ const tagOptions = useMemo4(() => allTags(report), [report]);
3408
3511
  const toggleTag = useCallback5(
3409
3512
  (tag) => setUrlState({
3410
3513
  tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
3411
3514
  }),
3412
3515
  [activeTags, setUrlState]
3413
3516
  );
3414
- const [toast, setToast] = useState11(null);
3415
- const toastTimer = useRef6(null);
3517
+ const [toast, setToast] = useState12(null);
3518
+ const toastTimer = useRef7(null);
3416
3519
  const showToast = useCallback5((msg) => {
3417
3520
  setToast(msg);
3418
3521
  if (toastTimer.current) clearTimeout(toastTimer.current);
@@ -3429,7 +3532,7 @@ function ReportInteractiveView({
3429
3532
  },
3430
3533
  [showToast]
3431
3534
  );
3432
- const scenarioActions = useMemo3(
3535
+ const scenarioActions = useMemo4(
3433
3536
  () => ({
3434
3537
  copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
3435
3538
  copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
@@ -3441,8 +3544,8 @@ function ReportInteractiveView({
3441
3544
  () => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
3442
3545
  [copy, filtered]
3443
3546
  );
3444
- const failureIndexRef = useRef6(0);
3445
- const allCollapsibleIds = useMemo3(
3547
+ const failureIndexRef = useRef7(0);
3548
+ const allCollapsibleIds = useMemo4(
3446
3549
  () => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
3447
3550
  [report]
3448
3551
  );
@@ -3450,7 +3553,7 @@ function ReportInteractiveView({
3450
3553
  useCallback5(() => defaultCollapsedIds(report), [report])
3451
3554
  );
3452
3555
  const revealFilteredResults = deferredQuery.trim() !== "" || statusFilter !== "all" || activeTags.length > 0;
3453
- const visibleCollapse = useMemo3(
3556
+ const visibleCollapse = useMemo4(
3454
3557
  () => revealFilteredResults ? { ...collapse.api, isCollapsed: () => false } : collapse.api,
3455
3558
  [collapse.api, revealFilteredResults]
3456
3559
  );
@@ -3458,7 +3561,7 @@ function ReportInteractiveView({
3458
3561
  () => collapse.collapseAll(allCollapsibleIds),
3459
3562
  [collapse, allCollapsibleIds]
3460
3563
  );
3461
- const [expandedAll, setExpandedAll] = useState11(
3564
+ const [expandedAll, setExpandedAll] = useState12(
3462
3565
  () => report.summary.failed === 0
3463
3566
  );
3464
3567
  const setExpanded = useCallback5(
@@ -3469,7 +3572,7 @@ function ReportInteractiveView({
3469
3572
  },
3470
3573
  [collapse, collapseAll]
3471
3574
  );
3472
- const [agentFilter, setAgentFilter] = useState11(null);
3575
+ const [agentFilter, setAgentFilter] = useState12(null);
3473
3576
  useTools(
3474
3577
  reportTools({
3475
3578
  report,
@@ -3516,13 +3619,13 @@ function ReportInteractiveView({
3516
3619
  const totalScenarios = report.summary.total;
3517
3620
  const matchedScenarios = filtered.summary.total;
3518
3621
  const showToc = !hideToc && totalScenarios > 3;
3519
- return /* @__PURE__ */ jsx51(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx51(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx51(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx51(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx51(
3622
+ return /* @__PURE__ */ jsx52(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx52(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx52(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx52(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx52(
3520
3623
  ReportRoot,
3521
3624
  {
3522
3625
  report: filtered,
3523
3626
  customRenderers,
3524
3627
  renderers,
3525
- children: /* @__PURE__ */ jsxs36(
3628
+ children: /* @__PURE__ */ jsxs37(
3526
3629
  "main",
3527
3630
  {
3528
3631
  className: cn("es-report", "es-report-interactive", className),
@@ -3531,8 +3634,8 @@ function ReportInteractiveView({
3531
3634
  "data-theme": dataTheme,
3532
3635
  "data-detail-level": detail,
3533
3636
  children: [
3534
- /* @__PURE__ */ jsxs36("header", { className: "es-report-header", children: [
3535
- /* @__PURE__ */ jsxs36(
3637
+ /* @__PURE__ */ jsxs37("header", { className: "es-report-header", children: [
3638
+ /* @__PURE__ */ jsxs37(
3536
3639
  "div",
3537
3640
  {
3538
3641
  "data-es-navbar": true,
@@ -3541,9 +3644,9 @@ function ReportInteractiveView({
3541
3644
  hideHeader ? "justify-end" : "justify-between"
3542
3645
  ),
3543
3646
  children: [
3544
- hideHeader ? null : /* @__PURE__ */ jsx51("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3545
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3546
- /* @__PURE__ */ jsx51(
3647
+ hideHeader ? null : /* @__PURE__ */ jsx52("h1", { className: "min-w-0", children: title ?? "Story Report" }),
3648
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
3649
+ /* @__PURE__ */ jsx52(
3547
3650
  ReportSearch,
3548
3651
  {
3549
3652
  ref: searchRef,
@@ -3553,17 +3656,18 @@ function ReportInteractiveView({
3553
3656
  totalCount: totalScenarios
3554
3657
  }
3555
3658
  ),
3556
- share ? /* @__PURE__ */ jsx51(ReportShare, { command: shareCommand, onCopy: copy }) : null,
3557
- /* @__PURE__ */ jsx51(ThemeSegment, { pref: themePref, onPref: setThemePref })
3659
+ share ? /* @__PURE__ */ jsx52(ReportShare, { command: shareCommand, onCopy: copy }) : null,
3660
+ /* @__PURE__ */ jsx52(ThemeSegment, { pref: themePref, onPref: setThemePref })
3558
3661
  ] })
3559
3662
  ]
3560
3663
  }
3561
3664
  ),
3562
- hideHeader ? null : /* @__PURE__ */ jsxs36(Fragment16, { children: [
3563
- /* @__PURE__ */ jsx51(ReportSummary, {}),
3564
- /* @__PURE__ */ jsx51(ReportMeta, {})
3665
+ hideHeader ? null : /* @__PURE__ */ jsxs37(Fragment16, { children: [
3666
+ /* @__PURE__ */ jsx52(ReportSummary, {}),
3667
+ /* @__PURE__ */ jsx52(ReportMeta, {})
3565
3668
  ] }),
3566
- /* @__PURE__ */ jsx51(
3669
+ architecture ? /* @__PURE__ */ jsx52(ReportSpanGraph, {}) : null,
3670
+ /* @__PURE__ */ jsx52(
3567
3671
  ReportFreshness,
3568
3672
  {
3569
3673
  lastRunMs: reportLastRunMs(report),
@@ -3571,15 +3675,15 @@ function ReportInteractiveView({
3571
3675
  staleAfterDays
3572
3676
  }
3573
3677
  ),
3574
- /* @__PURE__ */ jsx51(
3678
+ /* @__PURE__ */ jsx52(
3575
3679
  ReportLastRunDelta,
3576
3680
  {
3577
3681
  history: scenarioHistory,
3578
3682
  report
3579
3683
  }
3580
3684
  ),
3581
- /* @__PURE__ */ jsx51(ReportSinceLastVisit, { report }),
3582
- /* @__PURE__ */ jsx51(
3685
+ /* @__PURE__ */ jsx52(ReportSinceLastVisit, { report }),
3686
+ /* @__PURE__ */ jsx52(
3583
3687
  ReportFilters,
3584
3688
  {
3585
3689
  statuses: statusOptions,
@@ -3590,10 +3694,10 @@ function ReportInteractiveView({
3590
3694
  onToggleTag: toggleTag
3591
3695
  }
3592
3696
  ),
3593
- /* @__PURE__ */ jsxs36("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3594
- showToc ? /* @__PURE__ */ jsx51(ReportTocDrawer, {}) : null,
3595
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3596
- /* @__PURE__ */ jsx51(
3697
+ /* @__PURE__ */ jsxs37("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
3698
+ showToc ? /* @__PURE__ */ jsx52(ReportTocDrawer, {}) : null,
3699
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
3700
+ /* @__PURE__ */ jsx52(
3597
3701
  Switch,
3598
3702
  {
3599
3703
  id: expandId,
@@ -3601,7 +3705,7 @@ function ReportInteractiveView({
3601
3705
  onCheckedChange: setExpanded
3602
3706
  }
3603
3707
  ),
3604
- /* @__PURE__ */ jsx51(
3708
+ /* @__PURE__ */ jsx52(
3605
3709
  "label",
3606
3710
  {
3607
3711
  htmlFor: expandId,
@@ -3610,8 +3714,8 @@ function ReportInteractiveView({
3610
3714
  }
3611
3715
  )
3612
3716
  ] }),
3613
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
3614
- /* @__PURE__ */ jsx51(
3717
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
3718
+ /* @__PURE__ */ jsx52(
3615
3719
  Switch,
3616
3720
  {
3617
3721
  id: docsId,
@@ -3619,7 +3723,7 @@ function ReportInteractiveView({
3619
3723
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
3620
3724
  }
3621
3725
  ),
3622
- /* @__PURE__ */ jsx51(
3726
+ /* @__PURE__ */ jsx52(
3623
3727
  "label",
3624
3728
  {
3625
3729
  htmlFor: docsId,
@@ -3630,7 +3734,7 @@ function ReportInteractiveView({
3630
3734
  ] })
3631
3735
  ] })
3632
3736
  ] }),
3633
- showAgentFilter ? /* @__PURE__ */ jsx51(
3737
+ showAgentFilter ? /* @__PURE__ */ jsx52(
3634
3738
  ReportAgentFilterNotice,
3635
3739
  {
3636
3740
  applied: agentFilter,
@@ -3638,17 +3742,17 @@ function ReportInteractiveView({
3638
3742
  onDismiss: () => setAgentFilter(null)
3639
3743
  }
3640
3744
  ) : null,
3641
- /* @__PURE__ */ jsx51(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3642
- hasContent ? showToc ? /* @__PURE__ */ jsxs36("div", { className: "flex gap-6", children: [
3643
- /* @__PURE__ */ jsx51(ReportToc, {}),
3644
- /* @__PURE__ */ jsx51("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx51(ReportFeatureList, {}) })
3645
- ] }) : /* @__PURE__ */ jsx51("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx51(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx51(
3745
+ /* @__PURE__ */ jsx52(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
3746
+ hasContent ? showToc ? /* @__PURE__ */ jsxs37("div", { className: "flex gap-6", children: [
3747
+ /* @__PURE__ */ jsx52(ReportToc, {}),
3748
+ /* @__PURE__ */ jsx52("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx52(ReportFeatureList, {}) })
3749
+ ] }) : /* @__PURE__ */ jsx52("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx52(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx52(
3646
3750
  ReportEmpty,
3647
3751
  {
3648
3752
  message: query ? "No scenarios match the search." : void 0
3649
3753
  }
3650
3754
  ),
3651
- /* @__PURE__ */ jsx51(
3755
+ /* @__PURE__ */ jsx52(
3652
3756
  "button",
3653
3757
  {
3654
3758
  type: "button",
@@ -3659,14 +3763,14 @@ function ReportInteractiveView({
3659
3763
  children: "?"
3660
3764
  }
3661
3765
  ),
3662
- /* @__PURE__ */ jsx51(
3766
+ /* @__PURE__ */ jsx52(
3663
3767
  ReportShortcutsHelp,
3664
3768
  {
3665
3769
  open: helpOpen,
3666
3770
  onClose: () => setHelpOpen(false)
3667
3771
  }
3668
3772
  ),
3669
- toast ? /* @__PURE__ */ jsx51(
3773
+ toast ? /* @__PURE__ */ jsx52(
3670
3774
  "div",
3671
3775
  {
3672
3776
  role: "status",
@@ -3683,14 +3787,14 @@ function ReportInteractiveView({
3683
3787
  }
3684
3788
 
3685
3789
  // src/interactive/ReportInteractiveIsland.tsx
3686
- import { useMemo as useMemo4 } from "react";
3790
+ import { useMemo as useMemo5 } from "react";
3687
3791
 
3688
3792
  // src/interactive/island-renderers.tsx
3689
- import { createElement, useEffect as useEffect12, useState as useState13 } from "react";
3793
+ import { createElement, useEffect as useEffect13, useState as useState14 } from "react";
3690
3794
 
3691
3795
  // src/components/doc/MermaidView.tsx
3692
- import { useEffect as useEffect11, useRef as useRef7, useState as useState12 } from "react";
3693
- import { Fragment as Fragment17, jsx as jsx52, jsxs as jsxs37 } from "react/jsx-runtime";
3796
+ import { useEffect as useEffect12, useRef as useRef8, useState as useState13 } from "react";
3797
+ import { Fragment as Fragment17, jsx as jsx53, jsxs as jsxs38 } from "react/jsx-runtime";
3694
3798
  function prefersDark(el) {
3695
3799
  const themed = el?.closest("[data-theme]");
3696
3800
  if (themed?.dataset.theme === "dark") return true;
@@ -3698,10 +3802,10 @@ function prefersDark(el) {
3698
3802
  return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
3699
3803
  }
3700
3804
  function MermaidView({ entry, load }) {
3701
- const ref = useRef7(null);
3702
- const [svg, setSvg] = useState12(null);
3703
- const [error, setError] = useState12(null);
3704
- useEffect11(() => {
3805
+ const ref = useRef8(null);
3806
+ const [svg, setSvg] = useState13(null);
3807
+ const [error, setError] = useState13(null);
3808
+ useEffect12(() => {
3705
3809
  let cancelled = false;
3706
3810
  const draw = async () => {
3707
3811
  let mermaid;
@@ -3718,7 +3822,10 @@ function MermaidView({ entry, load }) {
3718
3822
  mermaid.initialize({
3719
3823
  startOnLoad: false,
3720
3824
  securityLevel: "strict",
3721
- theme: prefersDark(ref.current) ? "dark" : "default"
3825
+ // "neutral" in light: the same theme the static, no-JS render uses
3826
+ // in ssr-entry, so a diagram keeps its colours when the island takes
3827
+ // over.
3828
+ theme: prefersDark(ref.current) ? "dark" : "neutral"
3722
3829
  });
3723
3830
  await mermaid.parse(entry.code);
3724
3831
  const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
@@ -3744,9 +3851,9 @@ function MermaidView({ entry, load }) {
3744
3851
  };
3745
3852
  }, [entry.code, load]);
3746
3853
  if (svg) {
3747
- return /* @__PURE__ */ jsxs37("figure", { ref, className: "my-3", children: [
3748
- entry.title ? /* @__PURE__ */ jsx52("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3749
- /* @__PURE__ */ jsx52(
3854
+ return /* @__PURE__ */ jsxs38("figure", { ref, className: "my-3", children: [
3855
+ entry.title ? /* @__PURE__ */ jsx53("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3856
+ /* @__PURE__ */ jsx53(
3750
3857
  "div",
3751
3858
  {
3752
3859
  role: "img",
@@ -3757,8 +3864,8 @@ function MermaidView({ entry, load }) {
3757
3864
  )
3758
3865
  ] });
3759
3866
  }
3760
- return /* @__PURE__ */ jsxs37(Fragment17, { children: [
3761
- error ? /* @__PURE__ */ jsxs37(
3867
+ return /* @__PURE__ */ jsxs38(Fragment17, { children: [
3868
+ error ? /* @__PURE__ */ jsxs38(
3762
3869
  "p",
3763
3870
  {
3764
3871
  role: "alert",
@@ -3770,14 +3877,14 @@ function MermaidView({ entry, load }) {
3770
3877
  ]
3771
3878
  }
3772
3879
  ) : null,
3773
- /* @__PURE__ */ jsx52(MermaidSource, { entry, ref })
3880
+ /* @__PURE__ */ jsx53(MermaidSource, { entry, ref })
3774
3881
  ] });
3775
3882
  }
3776
3883
 
3777
3884
  // src/interactive/island-renderers.tsx
3778
- import { jsx as jsx53 } from "react/jsx-runtime";
3885
+ import { jsx as jsx54 } from "react/jsx-runtime";
3779
3886
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
3780
- var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
3887
+ var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
3781
3888
  function cachedCdnModule(url) {
3782
3889
  let loader;
3783
3890
  return () => {
@@ -3792,8 +3899,8 @@ function cachedCdnModule(url) {
3792
3899
  var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
3793
3900
  var loadHljs = cachedCdnModule(HLJS_ESM);
3794
3901
  function CdnHighlightedCode({ entry }) {
3795
- const [html, setHtml] = useState13(null);
3796
- useEffect12(() => {
3902
+ const [html, setHtml] = useState14(null);
3903
+ useEffect13(() => {
3797
3904
  let cancelled = false;
3798
3905
  void (async () => {
3799
3906
  try {
@@ -3809,13 +3916,13 @@ function CdnHighlightedCode({ entry }) {
3809
3916
  cancelled = true;
3810
3917
  };
3811
3918
  }, [entry.content, entry.lang]);
3812
- return /* @__PURE__ */ jsx53(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx53(
3919
+ return /* @__PURE__ */ jsx54(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx54(
3813
3920
  "code",
3814
3921
  {
3815
3922
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
3816
3923
  dangerouslySetInnerHTML: { __html: html }
3817
3924
  }
3818
- ) : /* @__PURE__ */ jsx53("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3925
+ ) : /* @__PURE__ */ jsx54("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3819
3926
  }
3820
3927
  function buildIslandRenderers(opts) {
3821
3928
  const renderers = {};
@@ -3829,7 +3936,7 @@ function buildIslandRenderers(opts) {
3829
3936
  }
3830
3937
 
3831
3938
  // src/interactive/ReportInteractiveIsland.tsx
3832
- import { jsx as jsx54 } from "react/jsx-runtime";
3939
+ import { jsx as jsx55 } from "react/jsx-runtime";
3833
3940
  function ReportInteractiveIsland({
3834
3941
  report,
3835
3942
  title,
@@ -3839,11 +3946,11 @@ function ReportInteractiveIsland({
3839
3946
  syntaxHighlighting = true,
3840
3947
  mermaid = true
3841
3948
  }) {
3842
- const renderers = useMemo4(
3949
+ const renderers = useMemo5(
3843
3950
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
3844
3951
  [syntaxHighlighting, mermaid]
3845
3952
  );
3846
- return /* @__PURE__ */ jsx54(
3953
+ return /* @__PURE__ */ jsx55(
3847
3954
  ReportInteractive,
3848
3955
  {
3849
3956
  report,