executable-stories-react 0.6.0 → 0.8.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.
@@ -264,7 +264,7 @@ function DocLink({ entry }) {
264
264
  // src/components/doc/DocSection.tsx
265
265
  var import_marked = require("marked");
266
266
 
267
- // src/lib/url.ts
267
+ // ../executable-stories-core/dist/utils/url.js
268
268
  function safeUrl(value) {
269
269
  if (!value) return void 0;
270
270
  const trimmed = value.trim();
@@ -422,17 +422,29 @@ function DocHtml({ entry }) {
422
422
  ] });
423
423
  }
424
424
 
425
- // src/components/doc/DocCustom.tsx
425
+ // src/components/doc/DocState.tsx
426
426
  var import_jsx_runtime13 = require("react/jsx-runtime");
427
+ function DocState({ entry }) {
428
+ let json;
429
+ try {
430
+ json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
431
+ } catch {
432
+ json = String(entry.value);
433
+ }
434
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
435
+ }
436
+
437
+ // src/components/doc/DocCustom.tsx
438
+ var import_jsx_runtime14 = require("react/jsx-runtime");
427
439
  function DocCustom({ entry }) {
428
440
  const renderers = useCustomRenderers();
429
441
  const renderer = renderers[entry.type];
430
442
  if (renderer) {
431
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: renderer(entry) });
443
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: renderer(entry) });
432
444
  }
433
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
434
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
435
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
445
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
446
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
447
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
436
448
  ] });
437
449
  }
438
450
  function safeStringify(value) {
@@ -444,45 +456,47 @@ function safeStringify(value) {
444
456
  }
445
457
 
446
458
  // src/components/doc/DocEntry.tsx
447
- var import_jsx_runtime14 = require("react/jsx-runtime");
459
+ var import_jsx_runtime15 = require("react/jsx-runtime");
448
460
  function DocEntry({ entry }) {
449
461
  switch (entry.kind) {
450
462
  case "note":
451
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocNote, { entry });
463
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
452
464
  case "tag":
453
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTag, { entry });
465
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
454
466
  case "kv":
455
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocKv, { entry });
467
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
456
468
  case "code":
457
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCode, { entry });
469
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
458
470
  case "table":
459
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocTable, { entry });
471
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
460
472
  case "link":
461
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocLink, { entry });
473
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
462
474
  case "section":
463
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocSection, { entry });
475
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
464
476
  case "mermaid":
465
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocMermaid, { entry });
477
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
466
478
  case "screenshot":
467
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocScreenshot, { entry });
479
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
468
480
  case "video":
469
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocVideo, { entry });
481
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
470
482
  case "html":
471
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocHtml, { entry });
483
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocHtml, { entry });
484
+ case "state":
485
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocState, { entry });
472
486
  case "custom":
473
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocCustom, { entry });
487
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
474
488
  }
475
489
  }
476
490
 
477
491
  // src/components/ReportDocEntries.tsx
478
- var import_jsx_runtime15 = require("react/jsx-runtime");
492
+ var import_jsx_runtime16 = require("react/jsx-runtime");
479
493
  function ReportDocEntries({ entries }) {
480
494
  if (entries.length === 0) return null;
481
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocEntry, { entry }, i)) });
495
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocEntry, { entry }, i)) });
482
496
  }
483
497
 
484
498
  // src/lib/step-params.tsx
485
- var import_jsx_runtime16 = require("react/jsx-runtime");
499
+ var import_jsx_runtime17 = require("react/jsx-runtime");
486
500
  var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
487
501
  function highlightStepParams(text) {
488
502
  const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
@@ -494,7 +508,7 @@ function highlightStepParams(text) {
494
508
  const end = start + match[0].length;
495
509
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
496
510
  nodes.push(
497
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
511
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
498
512
  );
499
513
  lastIndex = end;
500
514
  });
@@ -503,7 +517,7 @@ function highlightStepParams(text) {
503
517
  }
504
518
 
505
519
  // src/components/ReportSteps.tsx
506
- var import_jsx_runtime17 = require("react/jsx-runtime");
520
+ var import_jsx_runtime18 = require("react/jsx-runtime");
507
521
  var STEP_GLYPH = {
508
522
  passed: "\u2713",
509
523
  failed: "\u2717",
@@ -518,21 +532,21 @@ var STEP_GLYPH_COLOR = {
518
532
  };
519
533
  function ReportSteps({ scenario }) {
520
534
  if (scenario.steps.length === 0) return null;
521
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReportStepItem, { step }, step.id)) });
535
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportStepItem, { step }, step.id)) });
522
536
  }
523
537
  function ReportStepItem({ step }) {
524
538
  const kw = step.keyword.toLowerCase();
525
539
  const continuation = kw === "and" || kw === "but";
526
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
540
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
527
541
  "li",
528
542
  {
529
543
  id: step.id,
530
544
  "data-status": step.status,
531
545
  className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
532
546
  children: [
533
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-baseline gap-2", children: [
534
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
535
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
547
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-baseline gap-2", children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
549
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
536
550
  "span",
537
551
  {
538
552
  className: cn(
@@ -542,10 +556,10 @@ function ReportStepItem({ step }) {
542
556
  children: step.keyword
543
557
  }
544
558
  ),
545
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
546
- step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
559
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
560
+ step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
547
561
  ] }),
548
- step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
562
+ step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
549
563
  "pre",
550
564
  {
551
565
  role: "alert",
@@ -553,24 +567,255 @@ function ReportStepItem({ step }) {
553
567
  children: step.errorMessage
554
568
  }
555
569
  ) : null,
556
- step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
570
+ step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
557
571
  ]
558
572
  }
559
573
  );
560
574
  }
561
575
 
576
+ // ../executable-stories-core/dist/state-diff.js
577
+ var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
578
+ function deepEqual(a, b) {
579
+ if (Object.is(a, b)) return true;
580
+ if (Array.isArray(a) && Array.isArray(b)) {
581
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
582
+ }
583
+ if (isPlainObject(a) && isPlainObject(b)) {
584
+ const ak = Object.keys(a);
585
+ const bk = Object.keys(b);
586
+ return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
587
+ }
588
+ return false;
589
+ }
590
+ var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
591
+ function walk(path, before, after, out) {
592
+ if (Object.is(before, after)) return;
593
+ if (Array.isArray(before) && Array.isArray(after)) {
594
+ const shared = Math.min(before.length, after.length);
595
+ for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
596
+ for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
597
+ for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
598
+ return;
599
+ }
600
+ if (isPlainObject(before) && isPlainObject(after)) {
601
+ for (const key of Object.keys(after)) {
602
+ const p = joinKey(path, key);
603
+ if (key in before) walk(p, before[key], after[key], out);
604
+ else out.push({ path: p, kind: "added", after: after[key] });
605
+ }
606
+ for (const key of Object.keys(before)) {
607
+ if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
608
+ }
609
+ return;
610
+ }
611
+ if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
612
+ }
613
+ function diffStateValues(before, after) {
614
+ const out = [];
615
+ walk("", before, after, out);
616
+ return out;
617
+ }
618
+ function formatStateValue(value, maxLen = 60) {
619
+ const s = value === void 0 ? "undefined" : JSON.stringify(value);
620
+ return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
621
+ }
622
+ function summarizeStateChanges(changes) {
623
+ return changes.map((c) => {
624
+ const at = c.path === "" ? "(root)" : c.path;
625
+ switch (c.kind) {
626
+ case "added":
627
+ return `+ ${at}: ${formatStateValue(c.after)}`;
628
+ case "removed":
629
+ return `\u2212 ${at}`;
630
+ case "changed":
631
+ return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
632
+ }
633
+ });
634
+ }
635
+
636
+ // ../executable-stories-core/dist/storyboard.js
637
+ function findScreenshot(entries) {
638
+ for (const entry of entries) {
639
+ if (entry.kind === "screenshot") return entry;
640
+ if (entry.children) {
641
+ const nested = findScreenshot(entry.children);
642
+ if (nested) return nested;
643
+ }
644
+ }
645
+ return void 0;
646
+ }
647
+ function findStates(entries, out = []) {
648
+ for (const entry of entries) {
649
+ if (entry.kind === "state") out.push(entry);
650
+ if (entry.children) findStates(entry.children, out);
651
+ }
652
+ return out;
653
+ }
654
+ var laneOf = (label) => label ?? "";
655
+ function extractStoryboardFrames(scenario) {
656
+ const frames = [];
657
+ const laneOrder = [];
658
+ const previous = /* @__PURE__ */ new Map();
659
+ for (const step of scenario.steps) {
660
+ const shot = findScreenshot(step.docEntries);
661
+ const stateDocs = findStates(step.docEntries);
662
+ if (!shot && stateDocs.length === 0) continue;
663
+ const byLane = /* @__PURE__ */ new Map();
664
+ for (const doc of stateDocs) {
665
+ const lane = laneOf(doc.label);
666
+ if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
667
+ byLane.set(lane, doc);
668
+ }
669
+ const states = [];
670
+ for (const lane of laneOrder) {
671
+ const doc = byLane.get(lane);
672
+ if (!doc) continue;
673
+ const card = {
674
+ ...doc.label !== void 0 && { label: doc.label },
675
+ value: doc.value
676
+ };
677
+ if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
678
+ previous.set(lane, doc.value);
679
+ states.push(card);
680
+ }
681
+ frames.push({
682
+ stepId: step.id,
683
+ stepIndex: step.index,
684
+ keyword: step.keyword,
685
+ text: step.text,
686
+ status: step.status,
687
+ ...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
688
+ states
689
+ });
690
+ }
691
+ return frames;
692
+ }
693
+
694
+ // src/components/ReportStoryboard.tsx
695
+ var import_jsx_runtime19 = require("react/jsx-runtime");
696
+ var FRAME_GLYPH = {
697
+ passed: "\u2713",
698
+ failed: "\u2717",
699
+ skipped: "\u25CB",
700
+ pending: "\u25CB"
701
+ };
702
+ var FRAME_GLYPH_COLOR = {
703
+ passed: "text-pass",
704
+ failed: "text-fail",
705
+ skipped: "text-skip",
706
+ pending: "text-pend"
707
+ };
708
+ function ReportStoryboard({ scenario }) {
709
+ const frames = extractStoryboardFrames(scenario);
710
+ if (frames.length < 2) return null;
711
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
712
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
713
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
714
+ ] });
715
+ }
716
+ function StoryboardFrameItem({ frame }) {
717
+ const label = `${frame.keyword} ${frame.text}`;
718
+ const hasStates = frame.states.length > 0;
719
+ const caption = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
723
+ " ",
724
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
725
+ ] })
726
+ ] });
727
+ return (
728
+ // State cards need room for diff rows; screenshot-only frames keep the
729
+ // original narrow film-cell width (and DOM) unchanged.
730
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
731
+ frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrameScreenshot, { frame, label }) : null,
732
+ hasStates ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
733
+ frame.screenshot ? caption : (
734
+ // No screenshot means no image anchor, so the caption carries the
735
+ // jump-to-step link instead.
736
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
737
+ )
738
+ ] })
739
+ );
740
+ }
741
+ function FrameScreenshot({ frame, label }) {
742
+ const path = frame.screenshot?.path ?? "";
743
+ const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
744
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
745
+ "a",
746
+ {
747
+ href: `#${frame.stepId}`,
748
+ "aria-label": `Jump to step: ${label}`,
749
+ className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
750
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
751
+ "img",
752
+ {
753
+ src,
754
+ alt: frame.screenshot?.alt ?? label,
755
+ loading: "lazy",
756
+ className: "h-24 w-full bg-muted object-cover object-top"
757
+ }
758
+ ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
759
+ }
760
+ );
761
+ }
762
+ var CHANGE_TONE = {
763
+ added: "bg-pass-bg text-pass",
764
+ removed: "bg-fail-bg text-fail",
765
+ changed: "bg-skip-bg text-skip"
766
+ };
767
+ function prettyJson(value) {
768
+ try {
769
+ return JSON.stringify(value, null, 2) ?? String(value);
770
+ } catch {
771
+ return String(value);
772
+ }
773
+ }
774
+ function StateCardView({ card }) {
775
+ const json = prettyJson(card.value);
776
+ const firstCapture = card.changes === void 0;
777
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
778
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
779
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
780
+ firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
781
+ ] }),
782
+ !firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
783
+ "li",
784
+ {
785
+ className: cn(
786
+ "rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
787
+ CHANGE_TONE[change.kind]
788
+ ),
789
+ children: summarizeStateChanges([change])[0]
790
+ },
791
+ i
792
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
793
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
794
+ "details",
795
+ {
796
+ open: firstCapture && json.length <= 240,
797
+ className: cn(firstCapture ? "mt-1.5" : "mt-1"),
798
+ children: [
799
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
800
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
801
+ ]
802
+ }
803
+ )
804
+ ] });
805
+ }
806
+
562
807
  // src/components/ReportAttachments.tsx
563
- var import_jsx_runtime18 = require("react/jsx-runtime");
808
+ var import_jsx_runtime20 = require("react/jsx-runtime");
564
809
  function ReportAttachments({ attachments }) {
565
810
  if (attachments.length === 0) return null;
566
811
  return (
567
812
  // role="group" (not a labelled <section>) so multiple scenarios' attachment
568
813
  // blocks don't create duplicate "Attachments" region landmarks.
569
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
814
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
570
815
  const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
571
816
  const isImage = att.mediaType.startsWith("image/");
572
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
573
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
817
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
818
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
574
819
  "img",
575
820
  {
576
821
  src: dataUri,
@@ -579,8 +824,8 @@ function ReportAttachments({ attachments }) {
579
824
  className: "max-w-full rounded-md border border-border"
580
825
  }
581
826
  ),
582
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
583
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
827
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
828
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
584
829
  "a",
585
830
  {
586
831
  href: dataUri,
@@ -589,7 +834,7 @@ function ReportAttachments({ attachments }) {
589
834
  children: [
590
835
  att.name,
591
836
  " ",
592
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "text-muted-foreground", children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
593
838
  "(",
594
839
  att.mediaType,
595
840
  ")"
@@ -653,15 +898,15 @@ function toTraceRows(spans) {
653
898
  roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
654
899
  const rows = [];
655
900
  const seen = /* @__PURE__ */ new Set();
656
- const walk = (node, depth) => {
901
+ const walk2 = (node, depth) => {
657
902
  if (seen.has(node.span.spanId)) return;
658
903
  seen.add(node.span.spanId);
659
904
  rows.push({ ...node.span, depth });
660
- for (const child of node.children) walk(child, depth + 1);
905
+ for (const child of node.children) walk2(child, depth + 1);
661
906
  };
662
- for (const root of roots) walk(root, 0);
907
+ for (const root of roots) walk2(root, 0);
663
908
  for (const node of byId.values()) {
664
- if (!seen.has(node.span.spanId)) walk(node, 0);
909
+ if (!seen.has(node.span.spanId)) walk2(node, 0);
665
910
  }
666
911
  return rows;
667
912
  }
@@ -677,7 +922,7 @@ function traceWindow(rows) {
677
922
  }
678
923
 
679
924
  // src/components/ReportTrace.tsx
680
- var import_jsx_runtime19 = require("react/jsx-runtime");
925
+ var import_jsx_runtime21 = require("react/jsx-runtime");
681
926
  var BAR_COLOR = {
682
927
  ok: "bg-pass",
683
928
  error: "bg-fail",
@@ -688,8 +933,8 @@ function ReportTrace({ spans }) {
688
933
  const rows = toTraceRows(spans);
689
934
  if (rows.length === 0) return null;
690
935
  const { minStartMs, totalMs } = traceWindow(rows);
691
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
692
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
936
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
693
938
  "Trace (",
694
939
  rows.length,
695
940
  " span",
@@ -698,11 +943,11 @@ function ReportTrace({ spans }) {
698
943
  formatDuration(totalMs),
699
944
  ")"
700
945
  ] }),
701
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
946
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
702
947
  const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
703
948
  const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
704
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "flex items-center gap-2", children: [
705
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
949
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
950
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
706
951
  "span",
707
952
  {
708
953
  className: "min-w-0 flex-1 truncate text-foreground",
@@ -711,14 +956,14 @@ function ReportTrace({ spans }) {
711
956
  children: row.name
712
957
  }
713
958
  ),
714
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
959
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
715
960
  "span",
716
961
  {
717
962
  className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
718
963
  style: { left: `${leftPct}%`, width: `${widthPct}%` }
719
964
  }
720
965
  ) }),
721
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
966
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
722
967
  ] }, `${row.spanId}-${i}`);
723
968
  }) })
724
969
  ] });
@@ -787,7 +1032,7 @@ function diffSinceLastRun(history2, scenarios) {
787
1032
  }
788
1033
 
789
1034
  // src/components/ScenarioRunHistory.tsx
790
- var import_jsx_runtime20 = require("react/jsx-runtime");
1035
+ var import_jsx_runtime22 = require("react/jsx-runtime");
791
1036
  var MAX_DOTS = 10;
792
1037
  var DOT_COLOR = {
793
1038
  passed: "bg-pass",
@@ -807,16 +1052,16 @@ function ScenarioRunHistory({ scenarioId }) {
807
1052
  const recent = entries.slice(-MAX_DOTS);
808
1053
  const flaky = flakinessOf(recent) === "flaky";
809
1054
  const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
810
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
811
- flaky ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
812
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1055
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
1056
+ flaky ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
1057
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
813
1058
  "span",
814
1059
  {
815
1060
  role: "img",
816
1061
  "aria-label": `Run history: ${summary}`,
817
1062
  title: summary,
818
1063
  className: "flex shrink-0 items-center gap-[3px]",
819
- children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1064
+ children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
820
1065
  "span",
821
1066
  {
822
1067
  "aria-hidden": true,
@@ -907,7 +1152,7 @@ function stringify(value) {
907
1152
  return String(value);
908
1153
  }
909
1154
  }
910
- function docEntryToMarkdown(entry) {
1155
+ function docEntryToMarkdown(entry, stateLanes) {
911
1156
  const lines = [];
912
1157
  switch (entry.kind) {
913
1158
  case "note":
@@ -959,13 +1204,24 @@ function docEntryToMarkdown(entry) {
959
1204
  case "custom":
960
1205
  lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
961
1206
  break;
1207
+ case "state": {
1208
+ const lane = entry.label ?? "";
1209
+ lines.push(`**${entry.label ?? "State"}**`);
1210
+ if (stateLanes?.has(lane)) {
1211
+ const summary = summarizeStateChanges(diffStateValues(stateLanes.get(lane), entry.value));
1212
+ if (summary.length > 0) lines.push("", ...summary.map((l) => `- ${l}`));
1213
+ }
1214
+ stateLanes?.set(lane, entry.value);
1215
+ lines.push("", "<details>", "<summary>snapshot</summary>", "", "```json", stringify(entry.value ?? null), "```", "", "</details>");
1216
+ break;
1217
+ }
962
1218
  }
963
1219
  for (const child of entry.children ?? []) {
964
- lines.push("", ...docEntryToMarkdown(child));
1220
+ lines.push("", ...docEntryToMarkdown(child, stateLanes));
965
1221
  }
966
1222
  return lines;
967
1223
  }
968
- function stepLines(step, ordinal, full) {
1224
+ function stepLines(step, ordinal, full, stateLanes) {
969
1225
  const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
970
1226
  const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
971
1227
  if (!full) return lines;
@@ -973,7 +1229,7 @@ function stepLines(step, ordinal, full) {
973
1229
  lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
974
1230
  }
975
1231
  for (const entry of step.docEntries) {
976
- lines.push("", ...docEntryToMarkdown(entry).map((l) => l === "" ? l : ` ${l}`));
1232
+ lines.push("", ...docEntryToMarkdown(entry, stateLanes).map((l) => l === "" ? l : ` ${l}`));
977
1233
  }
978
1234
  return lines;
979
1235
  }
@@ -982,9 +1238,10 @@ function scenarioToMarkdown(scenario, options = {}) {
982
1238
  const full = variant === "full";
983
1239
  const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
984
1240
  if (full && meta.length > 0) lines.push(...meta);
1241
+ const stateLanes = /* @__PURE__ */ new Map();
985
1242
  if (scenario.steps.length > 0) {
986
1243
  if (full) lines.push("", "## Steps", "");
987
- scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full)));
1244
+ scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full, stateLanes)));
988
1245
  }
989
1246
  if (scenario.errorMessage) {
990
1247
  if (full) lines.push("", "## Failure", "");
@@ -993,7 +1250,7 @@ function scenarioToMarkdown(scenario, options = {}) {
993
1250
  }
994
1251
  if (full && scenario.docEntries.length > 0) {
995
1252
  lines.push("", "## Docs", "");
996
- for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry), "");
1253
+ for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry, stateLanes), "");
997
1254
  }
998
1255
  return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
999
1256
  }
@@ -1033,9 +1290,9 @@ function scenarioPermalink(scenario) {
1033
1290
 
1034
1291
  // src/components/ui/card.tsx
1035
1292
  var React2 = require("react");
1036
- var import_jsx_runtime21 = require("react/jsx-runtime");
1293
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1037
1294
  function Card({ className, ...props }) {
1038
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1295
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1039
1296
  "div",
1040
1297
  {
1041
1298
  "data-slot": "card",
@@ -1048,7 +1305,7 @@ function Card({ className, ...props }) {
1048
1305
  );
1049
1306
  }
1050
1307
  function CardHeader({ className, ...props }) {
1051
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1308
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1052
1309
  "div",
1053
1310
  {
1054
1311
  "data-slot": "card-header",
@@ -1061,7 +1318,7 @@ function CardHeader({ className, ...props }) {
1061
1318
  );
1062
1319
  }
1063
1320
  function CardContent({ className, ...props }) {
1064
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1321
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1065
1322
  "div",
1066
1323
  {
1067
1324
  "data-slot": "card-content",
@@ -1075,13 +1332,13 @@ function CardContent({ className, ...props }) {
1075
1332
  var React3 = require("react");
1076
1333
  var import_menu = require("@base-ui/react/menu");
1077
1334
  var import_lucide_react = require("lucide-react");
1078
- var import_jsx_runtime22 = require("react/jsx-runtime");
1335
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1079
1336
  var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
1080
1337
  function DropdownMenu(props) {
1081
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
1082
1339
  }
1083
1340
  function DropdownMenuTrigger(props) {
1084
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1341
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1085
1342
  }
1086
1343
  function DropdownMenuContent({
1087
1344
  className,
@@ -1089,14 +1346,14 @@ function DropdownMenuContent({
1089
1346
  sideOffset = 4,
1090
1347
  ...props
1091
1348
  }) {
1092
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1349
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1093
1350
  import_menu.Menu.Positioner,
1094
1351
  {
1095
1352
  "data-slot": "dropdown-menu-positioner",
1096
1353
  className: "z-50",
1097
1354
  align,
1098
1355
  sideOffset,
1099
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1356
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1100
1357
  import_menu.Menu.Popup,
1101
1358
  {
1102
1359
  "data-slot": "dropdown-menu-content",
@@ -1114,7 +1371,7 @@ function DropdownMenuItem({
1114
1371
  className,
1115
1372
  ...props
1116
1373
  }) {
1117
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1374
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1118
1375
  import_menu.Menu.Item,
1119
1376
  {
1120
1377
  "data-slot": "dropdown-menu-item",
@@ -1126,7 +1383,7 @@ function DropdownMenuItem({
1126
1383
 
1127
1384
  // src/components/ReportScenario.tsx
1128
1385
  var import_lucide_react2 = require("lucide-react");
1129
- var import_jsx_runtime23 = require("react/jsx-runtime");
1386
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1130
1387
  var STATUS_META = {
1131
1388
  passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
1132
1389
  failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
@@ -1142,7 +1399,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
1142
1399
  const collapsible = collapse !== null && !hideTitle;
1143
1400
  const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
1144
1401
  const actions = useScenarioActions();
1145
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1146
1403
  Card,
1147
1404
  {
1148
1405
  id: scenario.id,
@@ -1150,10 +1407,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
1150
1407
  ...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
1151
1408
  className: "gap-0 py-0",
1152
1409
  children: [
1153
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1154
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1155
- hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1156
- collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1410
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardHeader, { className: "px-4 py-3", children: [
1411
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
1412
+ hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
1413
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1157
1414
  "button",
1158
1415
  {
1159
1416
  type: "button",
@@ -1162,49 +1419,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
1162
1419
  "aria-controls": bodyId,
1163
1420
  "aria-label": `Toggle ${scenario.title}`,
1164
1421
  className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
1165
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1422
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
1166
1423
  }
1167
1424
  ) : null,
1168
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1169
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
1425
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
1426
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: scenario.title })
1170
1427
  ] }),
1171
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1172
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1173
- scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1174
- meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1175
- actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
1176
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1428
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
1429
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
1430
+ scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
1431
+ meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
1432
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenu, { children: [
1433
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1177
1434
  DropdownMenuTrigger,
1178
1435
  {
1179
1436
  "aria-label": `Actions for ${scenario.title}`,
1180
1437
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
1181
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1438
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
1182
1439
  }
1183
1440
  ),
1184
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
1185
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1186
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
1441
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuContent, { align: "end", children: [
1442
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
1443
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.LinkIcon, {}),
1187
1444
  " Copy link"
1188
1445
  ] }),
1189
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1190
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
1446
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
1447
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.FileTextIcon, {}),
1191
1448
  " Copy as Markdown"
1192
1449
  ] }),
1193
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1194
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
1450
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
1451
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.SparklesIcon, {}),
1195
1452
  " Explain with AI"
1196
1453
  ] })
1197
1454
  ] })
1198
1455
  ] }) : null
1199
1456
  ] })
1200
1457
  ] }),
1201
- scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1202
- scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1203
- (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1458
+ scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
1459
+ scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
1460
+ (scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
1204
1461
  ] }) : null
1205
1462
  ] }),
1206
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1207
- scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1463
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
1464
+ scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1208
1465
  "pre",
1209
1466
  {
1210
1467
  role: "alert",
@@ -1212,10 +1469,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
1212
1469
  children: scenario.errorMessage
1213
1470
  }
1214
1471
  ) : null,
1215
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
1216
- scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1217
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1218
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
1472
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportStoryboard, { scenario }),
1473
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSteps, { scenario }),
1474
+ scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
1475
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportAttachments, { attachments: scenario.attachments }),
1476
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportTrace, { spans: scenario.otelSpans })
1219
1477
  ] })
1220
1478
  ]
1221
1479
  }
@@ -1223,13 +1481,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
1223
1481
  }
1224
1482
 
1225
1483
  // src/components/ReportScenarioList.tsx
1226
- var import_jsx_runtime24 = require("react/jsx-runtime");
1484
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1227
1485
  function ReportScenarioList({ feature }) {
1228
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenario, { scenario }, scenario.id)) });
1486
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenario, { scenario }, scenario.id)) });
1229
1487
  }
1230
1488
 
1231
1489
  // src/components/ReportFeature.tsx
1232
- var import_jsx_runtime25 = require("react/jsx-runtime");
1490
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1233
1491
  function ReportFeature({ feature }) {
1234
1492
  const titleId = `${feature.id}-title`;
1235
1493
  const bodyId = `${feature.id}-body`;
@@ -1240,7 +1498,7 @@ function ReportFeature({ feature }) {
1240
1498
  return (
1241
1499
  // Suite = a section heading + a divider, NOT another bordered card. Drops a
1242
1500
  // layer of nesting so the scenario cards below read as the primary unit.
1243
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1501
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1244
1502
  "section",
1245
1503
  {
1246
1504
  id: feature.id,
@@ -1248,9 +1506,9 @@ function ReportFeature({ feature }) {
1248
1506
  "aria-labelledby": titleId,
1249
1507
  className: "flex flex-col gap-3",
1250
1508
  children: [
1251
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1252
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
1253
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1509
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
1510
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "min-w-0", children: [
1511
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1254
1512
  "button",
1255
1513
  {
1256
1514
  type: "button",
@@ -1259,31 +1517,31 @@ function ReportFeature({ feature }) {
1259
1517
  "aria-controls": bodyId,
1260
1518
  className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
1261
1519
  children: [
1262
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1263
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
1520
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
1521
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: feature.title })
1264
1522
  ]
1265
1523
  }
1266
1524
  ) : feature.title }),
1267
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1525
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
1268
1526
  ] }),
1269
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1527
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1270
1528
  "p",
1271
1529
  {
1272
1530
  className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
1273
1531
  "aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
1274
1532
  children: [
1275
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1533
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1276
1534
  s.passed,
1277
1535
  " passed"
1278
1536
  ] }),
1279
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1280
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1537
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1538
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
1281
1539
  s.failed,
1282
1540
  " failed"
1283
1541
  ] }),
1284
- skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
1285
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1286
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
1542
+ skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
1543
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
1544
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
1287
1545
  skipped,
1288
1546
  " skipped"
1289
1547
  ] })
@@ -1292,7 +1550,7 @@ function ReportFeature({ feature }) {
1292
1550
  }
1293
1551
  )
1294
1552
  ] }),
1295
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenarioList, { feature }) })
1553
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenarioList, { feature }) })
1296
1554
  ]
1297
1555
  }
1298
1556
  )
@@ -1300,17 +1558,17 @@ function ReportFeature({ feature }) {
1300
1558
  }
1301
1559
 
1302
1560
  // src/components/ReportFeatureList.tsx
1303
- var import_jsx_runtime26 = require("react/jsx-runtime");
1561
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1304
1562
  function ReportFeatureList() {
1305
1563
  const report = useReport();
1306
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportFeature, { feature }, feature.id)) });
1564
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportFeature, { feature }, feature.id)) });
1307
1565
  }
1308
1566
 
1309
1567
  // src/components/ui/empty.tsx
1310
1568
  var import_class_variance_authority2 = require("class-variance-authority");
1311
- var import_jsx_runtime27 = require("react/jsx-runtime");
1569
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1312
1570
  function Empty({ className, ...props }) {
1313
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1571
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1314
1572
  "div",
1315
1573
  {
1316
1574
  "data-slot": "empty",
@@ -1323,7 +1581,7 @@ function Empty({ className, ...props }) {
1323
1581
  );
1324
1582
  }
1325
1583
  function EmptyHeader({ className, ...props }) {
1326
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1584
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1327
1585
  "div",
1328
1586
  {
1329
1587
  "data-slot": "empty-header",
@@ -1350,7 +1608,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
1350
1608
  }
1351
1609
  );
1352
1610
  function EmptyTitle({ className, ...props }) {
1353
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1611
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1354
1612
  "div",
1355
1613
  {
1356
1614
  "data-slot": "empty-title",
@@ -1361,16 +1619,16 @@ function EmptyTitle({ className, ...props }) {
1361
1619
  }
1362
1620
 
1363
1621
  // src/components/ReportEmpty.tsx
1364
- var import_jsx_runtime28 = require("react/jsx-runtime");
1622
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1365
1623
  function ReportEmpty({ message }) {
1366
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1624
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
1367
1625
  }
1368
1626
 
1369
1627
  // src/components/ReportSummary.tsx
1370
- var import_jsx_runtime29 = require("react/jsx-runtime");
1628
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1371
1629
  function ReportSummary({ className }) {
1372
1630
  const report = useReport();
1373
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1631
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1374
1632
  ReportSummaryView,
1375
1633
  {
1376
1634
  summary: report.summary,
@@ -1396,7 +1654,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1396
1654
  if (summary.pending > 0) {
1397
1655
  cards.push({ status: "pending", label: "Pending", value: summary.pending });
1398
1656
  }
1399
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1400
1658
  "dl",
1401
1659
  {
1402
1660
  className: cn(
@@ -1409,17 +1667,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
1409
1667
  "aria-label": ariaLabel,
1410
1668
  children: cards.map((c) => {
1411
1669
  const tone = TONE[c.status];
1412
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1670
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1413
1671
  "div",
1414
1672
  {
1415
1673
  "data-status": c.status,
1416
1674
  className: "rounded-lg border bg-card px-4 py-3",
1417
1675
  children: [
1418
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1419
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1677
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
1420
1678
  c.label
1421
1679
  ] }),
1422
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1680
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
1423
1681
  ]
1424
1682
  },
1425
1683
  c.status
@@ -1479,7 +1737,7 @@ function prUrl(ci) {
1479
1737
  }
1480
1738
 
1481
1739
  // src/components/ReportMeta.tsx
1482
- var import_jsx_runtime30 = require("react/jsx-runtime");
1740
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1483
1741
  function ReportMeta() {
1484
1742
  const report = useReport();
1485
1743
  const items = [];
@@ -1502,13 +1760,13 @@ function ReportMeta() {
1502
1760
  const short = sha.slice(0, 8);
1503
1761
  items.push({
1504
1762
  label: "Commit",
1505
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1763
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
1506
1764
  });
1507
1765
  }
1508
1766
  if (report.ci) {
1509
1767
  items.push({
1510
1768
  label: "CI",
1511
- value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1769
+ value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
1512
1770
  ciDisplayName(report.ci.name),
1513
1771
  report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
1514
1772
  ] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
@@ -1519,7 +1777,7 @@ function ReportMeta() {
1519
1777
  const label = `#${report.ci.prNumber}`;
1520
1778
  items.push({
1521
1779
  label: "PR",
1522
- value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1780
+ value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
1523
1781
  });
1524
1782
  }
1525
1783
  if (items.length === 0) return null;
@@ -1527,50 +1785,50 @@ function ReportMeta() {
1527
1785
  // Run metadata is useful but secondary to "what failed" — tuck it into a
1528
1786
  // collapsed disclosure so it doesn't push the result down. Native <details>
1529
1787
  // so it works with no JS (the SSR/no-hydration report still toggles).
1530
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1531
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1532
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
1789
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
1790
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
1533
1791
  "Run details"
1534
1792
  ] }),
1535
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1536
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
1537
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1793
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
1538
1796
  ] }, item.label)) })
1539
1797
  ] })
1540
1798
  );
1541
1799
  }
1542
1800
 
1543
1801
  // src/components/ReportSchemaError.tsx
1544
- var import_jsx_runtime31 = require("react/jsx-runtime");
1802
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1545
1803
  function ReportSchemaError({ error }) {
1546
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1547
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
1548
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
1549
- error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
1804
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
1805
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Report could not be displayed." }) }),
1806
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: error.message }),
1807
+ error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { children: [
1550
1808
  "The report bundle is newer than this version of ",
1551
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
1809
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
1552
1810
  ". Upgrade the package, or regenerate the report with an older formatters CLI."
1553
1811
  ] }) : null,
1554
- error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
1555
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
1812
+ error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { children: [
1813
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
1556
1814
  error.issues.length,
1557
1815
  " validation issue",
1558
1816
  error.issues.length === 1 ? "" : "s"
1559
1817
  ] }),
1560
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1818
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
1561
1819
  ] }) : null
1562
1820
  ] });
1563
1821
  }
1564
1822
 
1565
1823
  // src/components/ReportShell.tsx
1566
- var import_jsx_runtime32 = require("react/jsx-runtime");
1824
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1567
1825
  function ReportErrorShell({
1568
1826
  error,
1569
1827
  className,
1570
1828
  title,
1571
1829
  dataTheme
1572
1830
  }) {
1573
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSchemaError, { error }) });
1831
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSchemaError, { error }) });
1574
1832
  }
1575
1833
 
1576
1834
  // src/interactive/ReportInteractive.tsx
@@ -1579,12 +1837,12 @@ var import_lucide_react5 = require("lucide-react");
1579
1837
  // src/components/ui/switch.tsx
1580
1838
  var React4 = require("react");
1581
1839
  var import_switch = require("@base-ui/react/switch");
1582
- var import_jsx_runtime33 = require("react/jsx-runtime");
1840
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1583
1841
  function Switch({
1584
1842
  className,
1585
1843
  ...props
1586
1844
  }) {
1587
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1845
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1588
1846
  import_switch.Switch.Root,
1589
1847
  {
1590
1848
  "data-slot": "switch",
@@ -1593,7 +1851,7 @@ function Switch({
1593
1851
  className
1594
1852
  ),
1595
1853
  ...props,
1596
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1854
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1597
1855
  import_switch.Switch.Thumb,
1598
1856
  {
1599
1857
  "data-slot": "switch-thumb",
@@ -1609,7 +1867,7 @@ var React5 = __toESM(require("react"), 1);
1609
1867
  var import_toggle_group = require("@base-ui/react/toggle-group");
1610
1868
  var import_toggle = require("@base-ui/react/toggle");
1611
1869
  var import_class_variance_authority3 = require("class-variance-authority");
1612
- var import_jsx_runtime34 = require("react/jsx-runtime");
1870
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1613
1871
  var toggleItemVariants = (0, import_class_variance_authority3.cva)(
1614
1872
  "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",
1615
1873
  {
@@ -1631,13 +1889,13 @@ function ToggleGroup({
1631
1889
  children,
1632
1890
  ...props
1633
1891
  }) {
1634
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1892
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1635
1893
  import_toggle_group.ToggleGroup,
1636
1894
  {
1637
1895
  "data-slot": "toggle-group",
1638
1896
  className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
1639
1897
  ...props,
1640
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
1898
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
1641
1899
  }
1642
1900
  );
1643
1901
  }
@@ -1648,7 +1906,7 @@ function ToggleGroupItem({
1648
1906
  ...props
1649
1907
  }) {
1650
1908
  const context = React5.useContext(ToggleGroupContext);
1651
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1909
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1652
1910
  import_toggle.Toggle,
1653
1911
  {
1654
1912
  "data-slot": "toggle-group-item",
@@ -1665,9 +1923,9 @@ var import_lucide_react3 = require("lucide-react");
1665
1923
 
1666
1924
  // src/components/ui/input.tsx
1667
1925
  var React6 = require("react");
1668
- var import_jsx_runtime35 = require("react/jsx-runtime");
1926
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1669
1927
  function Input({ className, type, ...props }) {
1670
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1928
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1671
1929
  "input",
1672
1930
  {
1673
1931
  type,
@@ -1684,7 +1942,7 @@ function Input({ className, type, ...props }) {
1684
1942
  }
1685
1943
 
1686
1944
  // src/interactive/ReportSearch.tsx
1687
- var import_jsx_runtime36 = require("react/jsx-runtime");
1945
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1688
1946
  var ReportSearch = (0, import_react8.forwardRef)(
1689
1947
  function ReportSearch2(props, ref) {
1690
1948
  const {
@@ -1706,17 +1964,17 @@ var ReportSearch = (0, import_react8.forwardRef)(
1706
1964
  e.preventDefault();
1707
1965
  }
1708
1966
  }
1709
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
1710
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
1711
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "relative w-full sm:w-72", children: [
1712
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1967
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
1968
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
1969
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "relative w-full sm:w-72", children: [
1970
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1713
1971
  import_lucide_react3.Search,
1714
1972
  {
1715
1973
  "aria-hidden": true,
1716
1974
  className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
1717
1975
  }
1718
1976
  ),
1719
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1977
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1720
1978
  Input,
1721
1979
  {
1722
1980
  ref,
@@ -1733,7 +1991,7 @@ var ReportSearch = (0, import_react8.forwardRef)(
1733
1991
  }
1734
1992
  )
1735
1993
  ] }),
1736
- showCounts ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
1994
+ showCounts ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
1737
1995
  "span",
1738
1996
  {
1739
1997
  className: "text-xs tabular-nums text-muted-foreground",
@@ -1774,7 +2032,7 @@ function scrollToScenarioId(scenarioId, options = {}) {
1774
2032
  }
1775
2033
 
1776
2034
  // src/interactive/ReportFailureBanner.tsx
1777
- var import_jsx_runtime37 = require("react/jsx-runtime");
2035
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1778
2036
  function ReportFailureBanner({ failures }) {
1779
2037
  const first = failures[0];
1780
2038
  const jumpToFirst = (0, import_react9.useCallback)(() => {
@@ -1782,7 +2040,7 @@ function ReportFailureBanner({ failures }) {
1782
2040
  scrollToScenarioId(first.scenarioId);
1783
2041
  }, [first]);
1784
2042
  if (failures.length === 0) return null;
1785
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
2043
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
1786
2044
  "div",
1787
2045
  {
1788
2046
  className: "es-failure-banner",
@@ -1790,13 +2048,13 @@ function ReportFailureBanner({ failures }) {
1790
2048
  "aria-live": "polite",
1791
2049
  "aria-label": "Failure summary",
1792
2050
  children: [
1793
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "es-failure-banner-text", children: [
1794
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("strong", { children: failures.length }),
2051
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "es-failure-banner-text", children: [
2052
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: failures.length }),
1795
2053
  " ",
1796
2054
  "failure",
1797
2055
  failures.length === 1 ? "" : "s"
1798
2056
  ] }),
1799
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2057
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1800
2058
  "button",
1801
2059
  {
1802
2060
  type: "button",
@@ -1813,7 +2071,7 @@ function ReportFailureBanner({ failures }) {
1813
2071
 
1814
2072
  // src/interactive/ReportFreshness.tsx
1815
2073
  var import_react10 = require("react");
1816
- var import_jsx_runtime38 = require("react/jsx-runtime");
2074
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1817
2075
  function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
1818
2076
  const [now, setNow] = (0, import_react10.useState)(nowMs);
1819
2077
  (0, import_react10.useEffect)(() => {
@@ -1821,7 +2079,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
1821
2079
  }, [nowMs]);
1822
2080
  if (lastRunMs === void 0 || now === void 0) return null;
1823
2081
  const age = formatRelativeAge(lastRunMs, now);
1824
- const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2082
+ const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
1825
2083
  "a",
1826
2084
  {
1827
2085
  href: ciUrl,
@@ -1832,9 +2090,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
1832
2090
  }
1833
2091
  ) : null;
1834
2092
  if (isReportStale(lastRunMs, staleAfterDays, now)) {
1835
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
1836
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { children: [
1837
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("strong", { children: [
2093
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
2094
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { children: [
2095
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("strong", { children: [
1838
2096
  "Last verified ",
1839
2097
  age,
1840
2098
  "."
@@ -1844,10 +2102,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
1844
2102
  runLink
1845
2103
  ] });
1846
2104
  }
1847
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
2105
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
1848
2106
  "Verified ",
1849
2107
  age,
1850
- runLink ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
2108
+ runLink ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
1851
2109
  " \xB7 ",
1852
2110
  runLink
1853
2111
  ] }) : null
@@ -1855,15 +2113,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
1855
2113
  }
1856
2114
 
1857
2115
  // src/interactive/ReportLastRunDelta.tsx
1858
- var import_jsx_runtime39 = require("react/jsx-runtime");
2116
+ var import_jsx_runtime41 = require("react/jsx-runtime");
1859
2117
  var MAX_LINKS = 5;
1860
2118
  function ScenarioLinks({ scenarios, tone }) {
1861
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
1862
- scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
2119
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
2120
+ scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { children: [
1863
2121
  i > 0 ? ", " : "",
1864
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
2122
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
1865
2123
  ] }, s.id)),
1866
- scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
2124
+ scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { children: [
1867
2125
  " and ",
1868
2126
  scenarios.length - MAX_LINKS,
1869
2127
  " more"
@@ -1880,23 +2138,23 @@ function ReportLastRunDelta({
1880
2138
  if (!delta) return null;
1881
2139
  const { newlyFailing, newlyPassing, added } = delta;
1882
2140
  if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
1883
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
2141
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
1884
2142
  }
1885
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
1886
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
1887
- newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-fail", children: [
2143
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
2144
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
2145
+ newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "ml-2 text-fail", children: [
1888
2146
  newlyFailing.length,
1889
2147
  " newly failing (",
1890
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
1891
2149
  ")"
1892
2150
  ] }) : null,
1893
- newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-pass", children: [
2151
+ newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "ml-2 text-pass", children: [
1894
2152
  newlyPassing.length,
1895
2153
  " fixed (",
1896
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
1897
2155
  ")"
1898
2156
  ] }) : null,
1899
- added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2", children: [
2157
+ added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "ml-2", children: [
1900
2158
  added.length,
1901
2159
  " new"
1902
2160
  ] }) : null
@@ -1960,7 +2218,7 @@ function Button({
1960
2218
  }
1961
2219
 
1962
2220
  // src/interactive/ReportShortcutsHelp.tsx
1963
- var import_jsx_runtime40 = require("react/jsx-runtime");
2221
+ var import_jsx_runtime42 = require("react/jsx-runtime");
1964
2222
  var SHORTCUTS = [
1965
2223
  { keys: "/", description: "Focus search" },
1966
2224
  { keys: "f", description: "Jump to next failure" },
@@ -1972,9 +2230,9 @@ var SHORTCUTS = [
1972
2230
  ];
1973
2231
  function Keys({ keys }) {
1974
2232
  const parts = keys.split(" ");
1975
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1976
- i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
1977
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("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 })
2233
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
2234
+ i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
2235
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("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 })
1978
2236
  ] }, k)) });
1979
2237
  }
1980
2238
  function ReportShortcutsHelp({ open, onClose }) {
@@ -1985,7 +2243,7 @@ function ReportShortcutsHelp({ open, onClose }) {
1985
2243
  if (open && !dialog.open) dialog.showModal();
1986
2244
  else if (!open && dialog.open) dialog.close();
1987
2245
  }, [open]);
1988
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2246
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
1989
2247
  "dialog",
1990
2248
  {
1991
2249
  ref: dialogRef,
@@ -1993,12 +2251,12 @@ function ReportShortcutsHelp({ open, onClose }) {
1993
2251
  "aria-label": "Keyboard shortcuts",
1994
2252
  onClose,
1995
2253
  children: [
1996
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
1997
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
1998
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Keys, { keys: s.keys }) }),
1999
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
2254
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
2255
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
2256
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Keys, { keys: s.keys }) }),
2257
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
2000
2258
  ] }, s.keys)) }),
2001
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2259
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
2002
2260
  ]
2003
2261
  }
2004
2262
  );
@@ -2199,7 +2457,7 @@ function failuresFirst(report) {
2199
2457
 
2200
2458
  // src/interactive/ReportFilters.tsx
2201
2459
  var import_react14 = require("react");
2202
- var import_jsx_runtime41 = require("react/jsx-runtime");
2460
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2203
2461
  var TAG_LIMIT = 12;
2204
2462
  function ReportFilters({
2205
2463
  statuses,
@@ -2213,10 +2471,10 @@ function ReportFilters({
2213
2471
  if (statuses.length === 0 && tags.length === 0) return null;
2214
2472
  const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
2215
2473
  const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
2216
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-col gap-2", children: [
2217
- statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2474
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-col gap-2", children: [
2475
+ statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
2218
2476
  const active = status === opt.key;
2219
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2477
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
2220
2478
  "button",
2221
2479
  {
2222
2480
  type: "button",
@@ -2228,23 +2486,23 @@ function ReportFilters({
2228
2486
  ),
2229
2487
  children: [
2230
2488
  opt.label,
2231
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2489
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
2232
2490
  ]
2233
2491
  },
2234
2492
  opt.key
2235
2493
  );
2236
2494
  }) }) : null,
2237
- tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2495
+ tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
2238
2496
  visibleTags.map((tag) => {
2239
2497
  const active = activeTags.includes(tag);
2240
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2498
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2241
2499
  "button",
2242
2500
  {
2243
2501
  type: "button",
2244
2502
  "aria-pressed": active,
2245
2503
  onClick: () => onToggleTag(tag),
2246
2504
  className: "cursor-pointer",
2247
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2505
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2248
2506
  Badge,
2249
2507
  {
2250
2508
  variant: "tag",
@@ -2257,7 +2515,7 @@ function ReportFilters({
2257
2515
  }
2258
2516
  ) }, tag);
2259
2517
  }),
2260
- tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2518
+ tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2261
2519
  "button",
2262
2520
  {
2263
2521
  type: "button",
@@ -2273,7 +2531,7 @@ function ReportFilters({
2273
2531
 
2274
2532
  // src/interactive/ReportToc.tsx
2275
2533
  var import_react15 = require("react");
2276
- var import_jsx_runtime42 = require("react/jsx-runtime");
2534
+ var import_jsx_runtime44 = require("react/jsx-runtime");
2277
2535
  var DOT = {
2278
2536
  passed: "bg-pass",
2279
2537
  failed: "bg-fail",
@@ -2302,11 +2560,11 @@ function TocContent({ onNavigate }) {
2302
2560
  return () => observer.disconnect();
2303
2561
  }, [scenarioIds]);
2304
2562
  if (report.features.length === 0) return null;
2305
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { children: [
2306
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2307
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2563
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { children: [
2564
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
2565
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
2308
2566
  const active = activeId === scenario.id;
2309
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2567
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2310
2568
  "a",
2311
2569
  {
2312
2570
  href: `#${scenario.id}`,
@@ -2321,14 +2579,14 @@ function TocContent({ onNavigate }) {
2321
2579
  active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
2322
2580
  ),
2323
2581
  children: [
2324
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2582
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2325
2583
  "span",
2326
2584
  {
2327
2585
  "aria-hidden": true,
2328
2586
  className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
2329
2587
  }
2330
2588
  ),
2331
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "break-words", children: scenario.title })
2589
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "break-words", children: scenario.title })
2332
2590
  ]
2333
2591
  }
2334
2592
  ) }, scenario.id);
@@ -2338,14 +2596,14 @@ function TocContent({ onNavigate }) {
2338
2596
  function ReportToc() {
2339
2597
  const report = useReport();
2340
2598
  if (report.features.length === 0) return null;
2341
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2599
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2342
2600
  "nav",
2343
2601
  {
2344
2602
  "aria-label": "Table of contents",
2345
2603
  className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
2346
2604
  children: [
2347
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TocContent, {})
2605
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
2606
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(TocContent, {})
2349
2607
  ]
2350
2608
  }
2351
2609
  );
@@ -2355,31 +2613,31 @@ function ReportToc() {
2355
2613
  var import_react16 = require("react");
2356
2614
  var import_dialog = require("@base-ui/react/dialog");
2357
2615
  var import_lucide_react4 = require("lucide-react");
2358
- var import_jsx_runtime43 = require("react/jsx-runtime");
2616
+ var import_jsx_runtime45 = require("react/jsx-runtime");
2359
2617
  function ReportTocDrawer() {
2360
2618
  const report = useReport();
2361
2619
  const [open, setOpen] = (0, import_react16.useState)(false);
2362
2620
  if (report.features.length === 0) return null;
2363
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
2364
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.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: [
2365
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.ListIcon, { "aria-hidden": true }),
2621
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
2622
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_dialog.Dialog.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: [
2623
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react4.ListIcon, { "aria-hidden": true }),
2366
2624
  " Contents"
2367
2625
  ] }),
2368
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Portal, { children: [
2369
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2370
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.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: [
2371
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between", children: [
2372
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2373
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2626
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_dialog.Dialog.Portal, { children: [
2627
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
2628
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_dialog.Dialog.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: [
2629
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between", children: [
2630
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2374
2632
  import_dialog.Dialog.Close,
2375
2633
  {
2376
2634
  "aria-label": "Close contents",
2377
2635
  className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
2378
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.XIcon, { "aria-hidden": true })
2636
+ children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react4.XIcon, { "aria-hidden": true })
2379
2637
  }
2380
2638
  )
2381
2639
  ] }),
2382
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TocContent, { onNavigate: () => setOpen(false) })
2640
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TocContent, { onNavigate: () => setOpen(false) })
2383
2641
  ] })
2384
2642
  ] })
2385
2643
  ] });
@@ -2434,14 +2692,14 @@ function useTheme() {
2434
2692
  }
2435
2693
 
2436
2694
  // src/interactive/ReportInteractive.tsx
2437
- var import_jsx_runtime44 = require("react/jsx-runtime");
2695
+ var import_jsx_runtime46 = require("react/jsx-runtime");
2438
2696
  function ReportInteractive(props) {
2439
2697
  const { report, className, title, dataTheme } = props;
2440
2698
  const result = unwrapReport(report);
2441
2699
  if (!result.ok) {
2442
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
2700
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
2443
2701
  }
2444
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportInteractiveView, { ...props, report: result.data });
2702
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportInteractiveView, { ...props, report: result.data });
2445
2703
  }
2446
2704
  var THEME_OPTIONS = [
2447
2705
  { value: "light", label: "Light", Icon: import_lucide_react5.Sun },
@@ -2449,7 +2707,7 @@ var THEME_OPTIONS = [
2449
2707
  { value: "dark", label: "Dark", Icon: import_lucide_react5.Moon }
2450
2708
  ];
2451
2709
  function ThemeSegment({ pref, onPref }) {
2452
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2710
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2453
2711
  ToggleGroup,
2454
2712
  {
2455
2713
  size: "sm",
@@ -2459,7 +2717,7 @@ function ThemeSegment({ pref, onPref }) {
2459
2717
  if (next) onPref(next);
2460
2718
  },
2461
2719
  "aria-label": "Color theme",
2462
- children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Icon, {}) }, value))
2720
+ children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Icon, {}) }, value))
2463
2721
  }
2464
2722
  );
2465
2723
  }
@@ -2581,13 +2839,13 @@ function ReportInteractiveView({
2581
2839
  const totalScenarios = report.summary.total;
2582
2840
  const matchedScenarios = filtered.summary.total;
2583
2841
  const showToc = !hideToc && totalScenarios > 3;
2584
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2842
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2585
2843
  ReportRoot,
2586
2844
  {
2587
2845
  report: filtered,
2588
2846
  customRenderers,
2589
2847
  renderers,
2590
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2848
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
2591
2849
  "main",
2592
2850
  {
2593
2851
  className: cn("es-report", "es-report-interactive", className),
@@ -2596,8 +2854,8 @@ function ReportInteractiveView({
2596
2854
  "data-theme": dataTheme,
2597
2855
  "data-detail-level": detail,
2598
2856
  children: [
2599
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("header", { className: "es-report-header", children: [
2600
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2857
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("header", { className: "es-report-header", children: [
2858
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
2601
2859
  "div",
2602
2860
  {
2603
2861
  "data-es-navbar": true,
@@ -2606,9 +2864,9 @@ function ReportInteractiveView({
2606
2864
  hideHeader ? "justify-end" : "justify-between"
2607
2865
  ),
2608
2866
  children: [
2609
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
2610
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
2611
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2867
+ hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
2868
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
2869
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2612
2870
  ReportSearch,
2613
2871
  {
2614
2872
  ref: searchRef,
@@ -2618,16 +2876,16 @@ function ReportInteractiveView({
2618
2876
  totalCount: totalScenarios
2619
2877
  }
2620
2878
  ),
2621
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
2879
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
2622
2880
  ] })
2623
2881
  ]
2624
2882
  }
2625
2883
  ),
2626
- hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
2627
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportSummary, {}),
2628
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportMeta, {})
2884
+ hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
2885
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportSummary, {}),
2886
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportMeta, {})
2629
2887
  ] }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2888
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2631
2889
  ReportFreshness,
2632
2890
  {
2633
2891
  lastRunMs: reportLastRunMs(report),
@@ -2635,8 +2893,8 @@ function ReportInteractiveView({
2635
2893
  staleAfterDays
2636
2894
  }
2637
2895
  ),
2638
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
2639
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2896
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
2897
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2640
2898
  ReportFilters,
2641
2899
  {
2642
2900
  statuses: statusOptions,
@@ -2647,14 +2905,14 @@ function ReportInteractiveView({
2647
2905
  onToggleTag: toggleTag
2648
2906
  }
2649
2907
  ),
2650
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
2651
- showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportTocDrawer, {}) : null,
2652
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
2653
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
2654
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
2908
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
2909
+ showToc ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportTocDrawer, {}) : null,
2910
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
2911
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
2912
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
2655
2913
  ] }),
2656
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
2657
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2914
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
2915
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2658
2916
  Switch,
2659
2917
  {
2660
2918
  id: docsId,
@@ -2662,16 +2920,16 @@ function ReportInteractiveView({
2662
2920
  onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
2663
2921
  }
2664
2922
  ),
2665
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
2923
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
2666
2924
  ] })
2667
2925
  ] })
2668
2926
  ] }),
2669
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFailureBanner, { failures }),
2670
- hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex gap-6", children: [
2671
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportToc, {}),
2672
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFeatureList, {}) })
2673
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
2674
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2927
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportFailureBanner, { failures }),
2928
+ hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex gap-6", children: [
2929
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportToc, {}),
2930
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportFeatureList, {}) })
2931
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
2932
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2675
2933
  "button",
2676
2934
  {
2677
2935
  type: "button",
@@ -2682,8 +2940,8 @@ function ReportInteractiveView({
2682
2940
  children: "?"
2683
2941
  }
2684
2942
  ),
2685
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
2686
- toast ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2943
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
2944
+ toast ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2687
2945
  "div",
2688
2946
  {
2689
2947
  role: "status",
@@ -2707,7 +2965,7 @@ var import_react20 = require("react");
2707
2965
 
2708
2966
  // src/components/doc/MermaidView.tsx
2709
2967
  var import_react19 = require("react");
2710
- var import_jsx_runtime45 = require("react/jsx-runtime");
2968
+ var import_jsx_runtime47 = require("react/jsx-runtime");
2711
2969
  function prefersDark(el) {
2712
2970
  const themed = el?.closest("[data-theme]");
2713
2971
  if (themed?.dataset.theme === "dark") return true;
@@ -2744,9 +3002,9 @@ function MermaidView({ entry, load }) {
2744
3002
  };
2745
3003
  }, [entry.code, load]);
2746
3004
  if (svg) {
2747
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("figure", { ref, className: "my-3", children: [
2748
- entry.title ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
2749
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3005
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("figure", { ref, className: "my-3", children: [
3006
+ entry.title ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
3007
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2750
3008
  "div",
2751
3009
  {
2752
3010
  role: "img",
@@ -2757,11 +3015,11 @@ function MermaidView({ entry, load }) {
2757
3015
  )
2758
3016
  ] });
2759
3017
  }
2760
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(MermaidSource, { entry, ref });
3018
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(MermaidSource, { entry, ref });
2761
3019
  }
2762
3020
 
2763
3021
  // src/interactive/island-renderers.tsx
2764
- var import_jsx_runtime46 = require("react/jsx-runtime");
3022
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2765
3023
  var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
2766
3024
  var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
2767
3025
  function cachedCdnModule(url) {
@@ -2795,13 +3053,13 @@ function CdnHighlightedCode({ entry }) {
2795
3053
  cancelled = true;
2796
3054
  };
2797
3055
  }, [entry.content, entry.lang]);
2798
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3056
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2799
3057
  "code",
2800
3058
  {
2801
3059
  className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
2802
3060
  dangerouslySetInnerHTML: { __html: html }
2803
3061
  }
2804
- ) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
3062
+ ) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
2805
3063
  }
2806
3064
  function buildIslandRenderers(opts) {
2807
3065
  const renderers = {};
@@ -2815,7 +3073,7 @@ function buildIslandRenderers(opts) {
2815
3073
  }
2816
3074
 
2817
3075
  // src/interactive/ReportInteractiveIsland.tsx
2818
- var import_jsx_runtime47 = require("react/jsx-runtime");
3076
+ var import_jsx_runtime49 = require("react/jsx-runtime");
2819
3077
  function ReportInteractiveIsland({
2820
3078
  report,
2821
3079
  title,
@@ -2829,7 +3087,7 @@ function ReportInteractiveIsland({
2829
3087
  () => buildIslandRenderers({ syntaxHighlighting, mermaid }),
2830
3088
  [syntaxHighlighting, mermaid]
2831
3089
  );
2832
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3090
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2833
3091
  ReportInteractive,
2834
3092
  {
2835
3093
  report,