executable-stories-react 0.13.0 → 0.14.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.
package/dist/ssr.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ssr-entry.ts","../src/result.ts","../src/context/ReportRoot.tsx","../src/context/ReportContext.ts","../src/components/ui/badge.tsx","../src/lib/utils.ts","../src/components/doc/NarrativeBlocks.tsx","../src/hooks/useReport.ts","../src/components/ReportScenario.tsx","../src/lib/step-params.tsx","../src/components/ReportSteps.tsx","../src/components/doc/DocNote.tsx","../src/components/doc/DocTag.tsx","../src/components/doc/DocKv.tsx","../src/hooks/useRenderers.ts","../src/components/doc/DocCode.tsx","../src/components/doc/DocTable.tsx","../src/components/doc/DocLink.tsx","../src/lib/markdown.ts","../src/lib/url.ts","../src/components/doc/DocSection.tsx","../src/components/doc/DocMermaid.tsx","../src/components/doc/DocScreenshot.tsx","../src/components/doc/DocVideo.tsx","../src/components/doc/DocHtml.tsx","../src/components/doc/DocState.tsx","../src/components/doc/DocCustom.tsx","../src/components/doc/DocEntry.tsx","../src/components/ReportDocEntries.tsx","../src/components/ReportStoryboard.tsx","../src/components/ReportAttachments.tsx","../src/components/ReportTrace.tsx","../src/lib/trace.ts","../src/interactive/scenario-history-context.ts","../src/lib/run-history.ts","../src/components/ScenarioRunHistory.tsx","../src/components/ScenarioStaleness.tsx","../src/lib/provenance.ts","../src/interactive/scenario-freshness-context.tsx","../src/interactive/collapse-context.ts","../src/interactive/scenario-actions.tsx","../src/components/ui/card.tsx","../src/components/ui/dropdown-menu.tsx","../src/components/ReportScenarioList.tsx","../src/components/ReportFeatureIntro.tsx","../src/components/ReportFeature.tsx","../src/components/ReportFeatureList.tsx","../src/components/ui/empty.tsx","../src/components/ReportEmpty.tsx","../src/components/ReportSummary.tsx","../src/components/ReportMeta.tsx","../src/components/ReportSchemaError.tsx","../src/components/ReportShell.tsx","../src/components/Report.tsx"],"sourcesContent":["/**\n * Server-only entry: render a StoryReport to a standalone HTML document string.\n *\n * This is the single rendering path shared by the CLI's standalone `.html`\n * output and (later) the Astro docs site — both render the same <Report/>\n * component tree, so there is no second renderer to drift from.\n *\n * No fs, no client code. The caller supplies the stylesheet text (read once\n * from `executable-stories-react/tailwind.css`) so this module stays pure and\n * bundler-agnostic. The interactive hydration island is injected via\n * `bodyExtra` in a later phase; this entry renders static markup only.\n */\n\nimport { createElement } from \"react\";\nimport { renderToStaticMarkup } from \"react-dom/server\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"./result\";\nimport { unwrapReport } from \"./result\";\nimport { Report } from \"./components/Report\";\nimport type { ScenarioHistoryMap, ScenarioRunEvent } from \"./lib/run-history\";\n\nexport type { ScenarioHistoryMap, ScenarioRunEvent };\n\nexport interface RenderReportToHtmlOptions {\n /** Document <title> and the report's <h1>. */\n title?: string;\n /** Stylesheet text inlined into <head> (e.g. executable-stories-react/tailwind.css). */\n css?: string;\n /** Force a theme; defaults to \"light\" (CSS still honours prefers-color-scheme). */\n theme?: \"light\" | \"dark\";\n /** Raw HTML injected at the end of <head> (font links, CDN module scripts). */\n headExtra?: string;\n /** Raw HTML injected before </body> (the hydration island <script>, later phases). */\n bodyExtra?: string;\n /** Document language attribute. */\n lang?: string;\n /** Load highlight.js to colour code blocks (default true). */\n syntaxHighlighting?: boolean;\n /** Load mermaid to render `pre[data-mermaid]` diagrams (default true). */\n mermaid?: boolean;\n /**\n * When set, embed the report JSON + this inlined IIFE bundle text\n * (executable-stories-react/report-island.js) so the static markup is\n * upgraded to the interactive tree on load. The static render stays as the\n * no-JS fallback.\n */\n islandScript?: string;\n /**\n * Days before the interactive report flags itself as stale (\"Last verified\n * N days ago\" warning banner). 0 disables the warning. Default 7.\n */\n staleAfterDays?: number;\n /**\n * Recent run events per scenario id (joined from the CLI's --history-file\n * store). Embedded as JSON next to the report data; the interactive island\n * renders a run-over-run timeline strip on each scenario card. Ignored for\n * static (non-island) output.\n */\n scenarioHistory?: ScenarioHistoryMap;\n}\n\nconst ROOT_ID = \"es-report-root\";\nconst DATA_ID = \"es-report-data\";\nconst HISTORY_ID = \"es-report-history\";\n\n/** Escape a JSON string for safe embedding inside a <script> element. */\nfunction escapeJsonForScript(json: string): string {\n return json.replace(/[<\\u2028\\u2029]/g, (c) => \"\\\\u\" + c.charCodeAt(0).toString(16).padStart(4, \"0\"));\n}\n\nconst HLJS_URL = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js\";\nconst HLJS_CSS_LIGHT = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css\";\nconst HLJS_CSS_DARK = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\";\nconst MERMAID_URL = \"https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs\";\n\n/** Build the CDN <head> styles + the bottom-of-body init module script. */\nfunction cdnAssets(syntaxHighlighting: boolean, mermaid: boolean): { head: string; body: string } {\n const headParts: string[] = [];\n const imports: string[] = [];\n const init: string[] = [];\n\n if (syntaxHighlighting) {\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_LIGHT}\">`);\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_DARK}\" media=\"(prefers-color-scheme: dark)\">`);\n imports.push(`import hljs from \"${HLJS_URL}\";`);\n init.push(\"document.querySelectorAll('pre code').forEach((el) => hljs.highlightElement(el));\");\n }\n if (mermaid) {\n imports.push(`import mermaid from \"${MERMAID_URL}\";`);\n init.push(\"mermaid.initialize({ startOnLoad: false, theme: 'neutral' });\");\n init.push('await mermaid.run({ querySelector: \"pre[data-mermaid]\" });');\n }\n\n const body = imports.length\n ? `<script type=\"module\">\\n${imports.join(\"\\n\")}\\n${init.join(\"\\n\")}\\n</script>`\n : \"\";\n return { head: headParts.join(\"\\n\"), body };\n}\n\nconst HTML_ESCAPES: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n};\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (ch) => HTML_ESCAPES[ch] ?? ch);\n}\n\n/**\n * Render a StoryReport (or a parse Result) to a complete, self-contained HTML\n * document. The report markup is wrapped in `.es-report-island` so the scoped\n * Tailwind/shadcn resets and utilities apply without leaking onto a host page.\n */\nexport function renderReportToHtml(\n report: StoryReport | Result<StoryReport>,\n options: RenderReportToHtmlOptions = {},\n): string {\n const {\n title = \"Story Report\",\n css = \"\",\n theme = \"light\",\n headExtra = \"\",\n bodyExtra = \"\",\n lang = \"en\",\n syntaxHighlighting = true,\n mermaid = true,\n islandScript = \"\",\n staleAfterDays = 7,\n scenarioHistory,\n } = options;\n\n const markup = renderToStaticMarkup(\n createElement(Report, { report, title }),\n );\n\n const cdn = cdnAssets(syntaxHighlighting, mermaid);\n\n // Interactive island: embed the report JSON + the inlined IIFE so the static\n // markup is upgraded to <ReportInteractive> on load (static = no-JS fallback).\n // <Report> already normalizes the same input internally; we re-normalize here\n // only to recover the bare report for the JSON payload.\n const parsed = unwrapReport(report);\n const rawReport: StoryReport | undefined = parsed.ok ? parsed.data : undefined;\n const interactive = islandScript.length > 0 && rawReport !== undefined;\n // Emitted whenever there is a report to emit, not only when the island will\n // hydrate. The JSON is already serialised, so it costs nothing, and it is the\n // difference between a JS-less report an agent can parse and one where the\n // only machine-readable copy of the run has been thrown away.\n const dataScript =\n rawReport !== undefined\n ? `<script type=\"application/json\" id=\"${DATA_ID}\">${escapeJsonForScript(JSON.stringify(rawReport))}</script>`\n : \"\";\n const historyScript =\n interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0\n ? `<script type=\"application/json\" id=\"${HISTORY_ID}\">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>`\n : \"\";\n const islandTag = interactive ? `<script>${islandScript}</script>` : \"\";\n // When interactive, the React island OWNS the doc-entry DOM via createRoot.\n // Highlighting + mermaid therefore render inside the React tree (the island\n // reads these flags and wires the matching renderers); the CDN post-processor\n // module (cdn.body) would race the client takeover and is dropped. The hljs\n // stylesheet (cdn.head) is still required to colour the React-owned tokens.\n const cdnBody = interactive ? \"\" : cdn.body;\n const islandConfigAttrs = interactive\n ? ` data-es-syntax=\"${syntaxHighlighting ? \"true\" : \"false\"}\" data-es-mermaid=\"${mermaid ? \"true\" : \"false\"}\" data-es-stale-days=\"${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}\"`\n : \"\";\n const rootAttrs = interactive\n ? ` id=\"${ROOT_ID}\" data-title=\"${escapeHtml(title)}\"${islandConfigAttrs}`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"${escapeHtml(lang)}\" data-theme=\"${theme === \"dark\" ? \"dark\" : \"light\"}\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"color-scheme\" content=\"light dark\">\n<title>${escapeHtml(title)}</title>\n${cdn.head}\n${headExtra}\n<style>${css}</style>\n</head>\n<body>\n<div${rootAttrs} class=\"es-report-island font-sans text-foreground\">${markup}</div>\n${dataScript}\n${historyScript}\n${bodyExtra}\n${cdnBody}\n${islandTag}\n</body>\n</html>`;\n}\n","/**\n * Result<T> — explicit success/error type matching the cookbook convention.\n *\n * Used at the boundary where a StoryReport is parsed: the consumer hands us\n * an unknown value (file contents, fetch body, prop) and we return a Result.\n */\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport type Result<T, E = ReportParseError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\nexport interface ReportParseError {\n message: string;\n code: ReportParseErrorCode;\n issues?: readonly { path: string; message: string }[];\n}\n\nexport type ReportParseErrorCode =\n | \"INVALID_INPUT\"\n | \"SCHEMA_VERSION_MISMATCH\"\n | \"VALIDATION_FAILED\";\n\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\nexport const err = (error: ReportParseError): Result<never> => ({ ok: false, error });\n\n/**\n * Normalize the `StoryReport | Result<StoryReport>` prop accepted across the\n * render entrypoints (`Report`, `ReportInteractive`, `renderReportToHtml`) into\n * a single `Result`. A bare report becomes `ok(report)`; an already-wrapped\n * value passes through. One place owns the \"is this a Result?\" discrimination.\n */\nexport function unwrapReport(value: StoryReport | Result<StoryReport>): Result<StoryReport> {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n return value as Result<StoryReport>;\n }\n return ok(value as StoryReport);\n}\n","import { useMemo, type ReactNode } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportContext, type ReportContextValue } from \"./ReportContext\";\nimport { narrativeBlockRenderers } from \"../components/doc/NarrativeBlocks\";\n\nexport interface ReportRootProps {\n report: StoryReport;\n customRenderers?: CustomRenderers;\n renderers?: BuiltinRenderers;\n children: ReactNode;\n}\n\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function ReportRoot({\n report,\n customRenderers,\n renderers,\n children,\n}: ReportRootProps) {\n const value = useMemo<ReportContextValue>(\n () => ({\n report,\n // Narrative blocks render everywhere the report does (static SSR, the\n // island, Astro) without every host wiring them up. A host renderer for\n // the same type still wins.\n customRenderers: { ...narrativeBlockRenderers, ...customRenderers },\n renderers: renderers ?? EMPTY_RENDERERS,\n }),\n [report, customRenderers, renderers],\n );\n return <ReportContext.Provider value={value}>{children}</ReportContext.Provider>;\n}\n","import { createContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nexport interface ReportContextValue {\n report: StoryReport;\n customRenderers: CustomRenderers;\n renderers: BuiltinRenderers;\n}\n\nexport const ReportContext = createContext<ReportContextValue | null>(null);\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { useRender } from \"@base-ui/react/use-render\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n \"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90\",\n outline:\n \"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n ghost: \"[a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 [a&]:hover:underline\",\n // Pass/skip/pending are the quiet states: outline + coloured text, no\n // fill, so a green report reads calm. Only `failed` keeps a tinted\n // fill, making it the single loud badge on the page, so red pops the\n // instant something breaks. Colour-as-accent, matching the KPI cards.\n passed: \"border-pass-border text-pass font-mono uppercase\",\n failed: \"border-fail-border bg-fail-bg text-fail font-mono uppercase\",\n skipped: \"border-skip-border text-skip font-mono uppercase\",\n pending: \"border-pend-border text-pend font-mono uppercase\",\n tag: \"border-border text-muted-foreground font-mono font-medium [a&]:hover:bg-muted\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & {\n // Base UI composition: pass `render={<a … />}` to swap the underlying tag —\n // replaces Radix's `asChild`. See rules/base-vs-radix.md.\n render?: useRender.RenderProp\n }) {\n return useRender({\n defaultTagName: \"span\",\n render,\n props: {\n \"data-slot\": \"badge\",\n \"data-variant\": variant,\n className: cn(badgeVariants({ variant }), className),\n ...props,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class names with Tailwind-aware conflict resolution (shadcn `cn`). */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Renderers for the two narrative block types an agent reaches for when it\n * explains a change: a file map and a data shape.\n *\n * They ride on `story.custom({ type, data })`, so every adapter can already\n * emit them with no API change; only the renderer is new. Register them with\n * `customRenderers` (the standalone report island does this by default).\n *\n * These blocks describe, they do not prove. Nothing here executed, so a block\n * whose `data.authored` says an agent wrote it renders a visible marker. A\n * picture that looks as trustworthy as a passing test, without being one, is\n * the failure mode this whole report exists to avoid.\n */\n\nimport type { ReportDocCustom } from \"executable-stories-core\";\nimport { Badge } from \"../ui/badge\";\nimport { cn } from \"../../lib/utils\";\n\nexport const FILE_TREE_TYPE = \"file-tree\";\nexport const DATA_MODEL_TYPE = \"data-model\";\n\n/** Change annotation shared by both blocks. */\ntype ChangeKind = \"added\" | \"modified\" | \"removed\" | \"renamed\";\n\nfunction isChangeKind(value: unknown): value is ChangeKind {\n return value === \"added\" || value === \"modified\" || value === \"removed\" || value === \"renamed\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\n/**\n * \"Written by an agent, not verified by a run.\" Only rendered when the author\n * says so; there is no way to detect it after the fact, which is exactly why\n * the authoring skills are told to set it.\n */\nfunction AuthoredMarker({ authored }: { authored?: string }) {\n if (authored !== \"agent\") return null;\n return (\n <Badge variant=\"outline\" className=\"border-border text-[10px] text-muted-foreground\">\n AI-authored, not verified by a run\n </Badge>\n );\n}\n\nfunction BlockFrame({\n title,\n authored,\n children,\n}: {\n title?: string;\n authored?: string;\n children: React.ReactNode;\n}) {\n return (\n <figure className=\"my-3\">\n {title || authored === \"agent\" ? (\n <figcaption className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n {title ? <span className=\"text-xs font-medium text-muted-foreground\">{title}</span> : null}\n <AuthoredMarker authored={authored} />\n </figcaption>\n ) : null}\n {children}\n </figure>\n );\n}\n\n/**\n * Deliberately uncoloured. In this report colour carries test status, so a\n * green \"added\" badge beside a failing scenario would read as a pass. The word\n * does the work.\n */\nfunction ChangeBadge({ change }: { change: ChangeKind }) {\n return (\n <Badge variant=\"tag\" className=\"text-[10px]\">\n {change}\n </Badge>\n );\n}\n\n// ---------------------------------------------------------------------------\n// file-tree\n// ---------------------------------------------------------------------------\n\ninterface FileEntry {\n path: string;\n change?: ChangeKind;\n note?: string;\n}\n\nexport interface FileTreeData {\n title?: string;\n authored?: string;\n files: FileEntry[];\n}\n\nexport function parseFileTree(data: unknown): FileTreeData | undefined {\n if (!isRecord(data) || !Array.isArray(data.files)) return undefined;\n const files: FileEntry[] = [];\n for (const raw of data.files) {\n // A bare string is a path; anything without one is not a file.\n if (typeof raw === \"string\") {\n if (raw) files.push({ path: raw });\n continue;\n }\n if (!isRecord(raw)) continue;\n const path = str(raw.path);\n if (!path) continue;\n files.push({\n path,\n change: isChangeKind(raw.change) ? raw.change : undefined,\n note: str(raw.note),\n });\n }\n if (files.length === 0) return undefined;\n return { title: str(data.title), authored: str(data.authored), files };\n}\n\ninterface TreeNode {\n name: string;\n children: Map<string, TreeNode>;\n file?: FileEntry;\n}\n\n/** Flat paths in, nested directories out. Sorting puts folders before files. */\nfunction buildTree(files: FileEntry[]): TreeNode {\n const root: TreeNode = { name: \"\", children: new Map() };\n for (const file of files) {\n const segments = file.path.split(\"/\").filter(Boolean);\n let node = root;\n segments.forEach((segment, index) => {\n let child = node.children.get(segment);\n if (!child) {\n child = { name: segment, children: new Map() };\n node.children.set(segment, child);\n }\n if (index === segments.length - 1) child.file = file;\n node = child;\n });\n }\n return root;\n}\n\nfunction sortedChildren(node: TreeNode): TreeNode[] {\n return [...node.children.values()].sort((a, b) => {\n const aDir = a.children.size > 0;\n const bDir = b.children.size > 0;\n if (aDir !== bDir) return aDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n}\n\nfunction TreeBranch({ node, depth }: { node: TreeNode; depth: number }) {\n const children = sortedChildren(node);\n return (\n <ul className={cn(\"space-y-0.5\", depth > 0 && \"ml-3 border-l border-border/60 pl-3\")}>\n {children.map((child) => {\n const isDir = child.children.size > 0;\n return (\n <li key={child.name}>\n <div className=\"flex flex-wrap items-baseline gap-2\">\n <span\n className={cn(\n \"font-mono text-xs\",\n isDir ? \"text-muted-foreground\" : \"text-foreground\",\n )}\n >\n {isDir ? `${child.name}/` : child.name}\n </span>\n {child.file?.change ? <ChangeBadge change={child.file.change} /> : null}\n {child.file?.note ? (\n <span className=\"text-xs text-muted-foreground\">{child.file.note}</span>\n ) : null}\n </div>\n {isDir ? <TreeBranch node={child} depth={depth + 1} /> : null}\n </li>\n );\n })}\n </ul>\n );\n}\n\nexport function FileTreeBlock({ entry }: { entry: ReportDocCustom }) {\n const data = parseFileTree(entry.data);\n if (!data) return <UnreadableBlock entry={entry} />;\n return (\n <BlockFrame title={data.title ?? \"Files changed\"} authored={data.authored}>\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border bg-card p-3\">\n <TreeBranch node={buildTree(data.files)} depth={0} />\n </div>\n </BlockFrame>\n );\n}\n\n// ---------------------------------------------------------------------------\n// data-model\n// ---------------------------------------------------------------------------\n\ninterface ModelField {\n name: string;\n type?: string;\n note?: string;\n change?: ChangeKind;\n}\n\nexport interface DataModelData {\n title?: string;\n authored?: string;\n name?: string;\n fields: ModelField[];\n}\n\nexport function parseDataModel(data: unknown): DataModelData | undefined {\n if (!isRecord(data) || !Array.isArray(data.fields)) return undefined;\n const fields: ModelField[] = [];\n for (const raw of data.fields) {\n if (!isRecord(raw)) continue;\n const name = str(raw.name);\n if (!name) continue;\n fields.push({\n name,\n type: str(raw.type),\n note: str(raw.note),\n change: isChangeKind(raw.change) ? raw.change : undefined,\n });\n }\n if (fields.length === 0) return undefined;\n return {\n title: str(data.title),\n authored: str(data.authored),\n name: str(data.name),\n fields,\n };\n}\n\nexport function DataModelBlock({ entry }: { entry: ReportDocCustom }) {\n const data = parseDataModel(entry.data);\n if (!data) return <UnreadableBlock entry={entry} />;\n const hasNotes = data.fields.some((f) => f.note);\n return (\n <BlockFrame title={data.title ?? data.name ?? \"Data model\"} authored={data.authored}>\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Field\n </th>\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Type\n </th>\n {hasNotes ? (\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Note\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {data.fields.map((field) => (\n <tr key={field.name}>\n <td className=\"border-b border-border px-3 py-2\">\n <span className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-mono text-xs text-foreground\">{field.name}</span>\n {field.change ? <ChangeBadge change={field.change} /> : null}\n </span>\n </td>\n <td className=\"border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground\">\n {field.type ?? \"\"}\n </td>\n {hasNotes ? (\n <td className=\"border-b border-border px-3 py-2 text-foreground\">\n {field.note ?? \"\"}\n </td>\n ) : null}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </BlockFrame>\n );\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Shape we could not read. Show the raw data rather than nothing: a malformed\n * block is a bug in whatever wrote it, and hiding it hides the bug.\n */\nfunction UnreadableBlock({ entry }: { entry: ReportDocCustom }) {\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">\n {entry.type} (unrecognised shape)\n </p>\n <pre\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * The narrative block renderers, ready to spread into `customRenderers`.\n * Consumer-supplied renderers for the same type win, so a project can swap\n * either one out.\n */\nexport const narrativeBlockRenderers = {\n [FILE_TREE_TYPE]: (entry: ReportDocCustom) => <FileTreeBlock entry={entry} />,\n [DATA_MODEL_TYPE]: (entry: ReportDocCustom) => <DataModelBlock entry={entry} />,\n};\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\n\nexport function useReport() {\n const ctx = useContext(ReportContext);\n if (!ctx) {\n throw new Error(\n \"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those.\",\n );\n }\n return ctx.report;\n}\n","import type { ReportScenario as ReportScenarioT } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportSteps } from \"./ReportSteps\";\nimport { ReportStoryboard } from \"./ReportStoryboard\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { ReportAttachments } from \"./ReportAttachments\";\nimport { ReportTrace } from \"./ReportTrace\";\nimport { ScenarioRunHistory } from \"./ScenarioRunHistory\";\nimport { ScenarioStaleness } from \"./ScenarioStaleness\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { useScenarioActions } from \"../interactive/scenario-actions\";\nimport { Card, CardContent, CardHeader } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportScenarioProps {\n scenario: ReportScenarioT;\n /**\n * Omit the card's own title row (status badge + tags still render). Use when\n * the surrounding page already shows the scenario title as its heading — e.g.\n * the Astro detail page, where Starlight renders the title as the page `h1`.\n */\n hideTitle?: boolean;\n}\n\ntype Status = ReportScenarioT[\"status\"];\n\ninterface StatusMeta {\n label: string;\n glyph: string;\n glyphColor: string;\n badgeVariant: \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n /**\n * Whether to render the status as a visible pill. Passing scenarios drop it:\n * the green ✓ glyph + title already carry the status, so the pill would be\n * pure redundancy on every (usually passing) row, and dropping it keeps a\n * green run calm while the failure pill stays the one loud badge. A\n * non-showPill status still exposes an sr-only label for screen readers.\n */\n showPill: boolean;\n}\n\nconst STATUS_META: Record<Status, StatusMeta> = {\n passed: { label: \"Passed\", glyph: \"✓\", glyphColor: \"text-pass\", badgeVariant: \"passed\", showPill: false },\n failed: { label: \"Failed\", glyph: \"✗\", glyphColor: \"text-fail\", badgeVariant: \"failed\", showPill: true },\n skipped: { label: \"Skipped\", glyph: \"○\", glyphColor: \"text-skip\", badgeVariant: \"skipped\", showPill: true },\n pending: { label: \"Pending\", glyph: \"○\", glyphColor: \"text-pend\", badgeVariant: \"pending\", showPill: true },\n};\n\nexport function ReportScenario({ scenario, hideTitle = false }: ReportScenarioProps) {\n const titleId = `${scenario.id}-title`;\n const bodyId = `${scenario.id}-body`;\n const meta = STATUS_META[scenario.status];\n // A planned scenario (it.todo) is canonically \"pending\", but the reader\n // should see intent, not limbo.\n const label = scenario.planned ? \"Planned\" : meta.label;\n const collapse = useCollapse();\n const collapsible = collapse !== null && !hideTitle;\n const collapsed = collapsible ? collapse!.isCollapsed(scenario.id) : false;\n const actions = useScenarioActions();\n return (\n <Card\n id={scenario.id}\n data-status={scenario.status}\n {...(hideTitle\n ? { \"aria-label\": `${scenario.title}, ${label}` }\n : { \"aria-labelledby\": titleId })}\n className=\"gap-0 py-0\"\n >\n <CardHeader className=\"px-4 py-3\">\n <div className={cn(\"flex items-start gap-4\", hideTitle ? \"justify-end\" : \"justify-between\")}>\n {hideTitle ? null : (\n <h3 id={titleId} className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => collapse!.toggle(scenario.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${scenario.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <span aria-hidden className={cn(\"text-sm leading-none\", meta.glyphColor)}>\n {meta.glyph}\n </span>\n <span>{scenario.title}</span>\n </h3>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n <ScenarioRunHistory scenarioId={scenario.id} />\n <ScenarioStaleness scenario={scenario} />\n {scenario.durationMs > 0 ? (\n <span className=\"whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(scenario.durationMs)}\n </span>\n ) : null}\n {meta.showPill ? (\n <Badge variant={meta.badgeVariant} aria-label={`Status: ${label}`}>\n {label}\n </Badge>\n ) : (\n <span className=\"sr-only\">{`Status: ${label}`}</span>\n )}\n {actions ? (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={`Actions for ${scenario.title}`}\n className=\"cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4\"\n >\n <MoreHorizontalIcon aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => actions.copyLink(scenario)}>\n <LinkIcon /> Copy link\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => actions.copyMarkdown(scenario)}>\n <FileTextIcon /> Copy as Markdown\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => actions.copyPrompt(scenario)}>\n <SparklesIcon /> Explain with AI\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n </div>\n {scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? (\n <ul aria-label=\"Tags and tickets\" className=\"flex flex-wrap gap-1.5\">\n {scenario.tags.map((t) => (\n <li key={`tag-${t}`}>\n <Badge variant=\"tag\">{t}</Badge>\n </li>\n ))}\n {(scenario.tickets ?? []).map((ticket) => (\n <li key={`ticket-${ticket.id}`}>\n {ticket.url ? (\n <a href={ticket.url} target=\"_blank\" rel=\"noreferrer noopener\">\n <Badge variant=\"outline\">{ticket.id}</Badge>\n </a>\n ) : (\n <Badge variant=\"outline\">{ticket.id}</Badge>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n </CardHeader>\n <CardContent id={bodyId} hidden={collapsed} className=\"px-4 pt-0 pb-4\">\n {scenario.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mb-1 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {scenario.errorMessage}\n </pre>\n ) : null}\n <ReportStoryboard scenario={scenario} />\n <ReportSteps scenario={scenario} />\n {scenario.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-3\">\n <ReportDocEntries entries={scenario.docEntries} />\n </div>\n ) : null}\n <ReportAttachments attachments={scenario.attachments} />\n <ReportTrace spans={scenario.otelSpans} />\n </CardContent>\n </Card>\n );\n}\n","import type { ReactNode } from \"react\";\n\n/**\n * Highlight step parameters (double-quoted strings, standalone numbers) in step\n * text — the React equivalent of the report's highlightStepParams. Returns a\n * node array so the matched params can be wrapped in a styled <span> without\n * dangerouslySetInnerHTML.\n *\n * Regex mirrors the string renderer exactly:\n * - `\"[^\"]*\"` double-quoted strings (numbers inside quotes stay part of the string)\n * - `(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])` standalone numbers, dot/word-boundary aware\n */\nconst STEP_PARAM_PATTERN = /\"[^\"]*\"|(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])/g;\n\nexport function highlightStepParams(text: string): ReactNode {\n const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));\n if (matches.length === 0) return text;\n\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n matches.forEach((match, i) => {\n const start = match.index;\n const end = start + match[0].length;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(\n <span key={i} className=\"font-medium text-step-param italic\">\n {match[0]}\n </span>,\n );\n lastIndex = end;\n });\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n","import { highlightStepParams } from '@/lib/step-params';\nimport { cn } from '@/lib/utils';\nimport type { ReportScenario, ReportStep } from 'executable-stories-core';\nimport {\n assertionState,\n assertiveSteps,\n} from 'executable-stories-core/utils/assertive-steps';\nimport { formatDuration } from 'executable-stories-core/utils/duration';\nimport { ReportDocEntries } from './ReportDocEntries';\n\nexport interface ReportStepsProps {\n scenario: ReportScenario;\n}\n\nconst STEP_GLYPH: Record<string, string> = {\n passed: '✓',\n failed: '✗',\n skipped: '○',\n pending: '○',\n};\n\nconst STEP_GLYPH_COLOR: Record<string, string> = {\n passed: 'text-pass',\n failed: 'text-fail',\n skipped: 'text-skip',\n pending: 'text-pend',\n};\n\nexport function ReportSteps({ scenario }: ReportStepsProps) {\n if (scenario.steps.length === 0) return null;\n const unasserted = new Set(\n assertionState(scenario.steps) === 'unasserted'\n ? assertiveSteps(scenario.steps).map((step) => step.id)\n : [],\n );\n return (\n <ol data-slot=\"steps\" className=\"flex flex-col\">\n {scenario.steps.map((step) => (\n <ReportStepItem\n key={step.id}\n step={step}\n unasserted={unasserted.has(step.id)}\n />\n ))}\n </ol>\n );\n}\n\nexport function ReportStepItem({\n step,\n unasserted = false,\n}: {\n step: ReportStep;\n unasserted?: boolean;\n}) {\n // And/But (incl. auto-And repeats) read as continuations of the prior step —\n // indented with a muted keyword, matching the report's `.step.continuation`.\n const kw = step.keyword.toLowerCase();\n const continuation = kw === 'and' || kw === 'but';\n return (\n <li\n id={step.id}\n data-status={step.status}\n className={cn(\n 'py-1.5 text-[0.8125rem] leading-normal',\n continuation && 'pl-5',\n )}\n >\n <div className=\"flex items-baseline gap-2\">\n <span\n aria-hidden\n className={cn(\n 'w-4 shrink-0 text-center text-xs',\n STEP_GLYPH_COLOR[step.status],\n )}\n >\n {STEP_GLYPH[step.status] ?? '○'}\n </span>\n <span\n className={cn(\n 'min-w-[52px] shrink-0 font-mono text-xs font-semibold capitalize',\n continuation ? 'font-medium text-muted-foreground' : 'text-keyword',\n )}\n >\n {step.keyword}\n </span>\n <span className=\"flex-1 text-foreground\">\n {highlightStepParams(step.text)}\n </span>\n {unasserted ? (\n <span className=\"shrink-0 rounded-full border border-pend-border bg-pend-bg px-2 py-0.5 text-[0.6875rem] font-medium text-pend\">\n No assertion\n </span>\n ) : null}\n {step.durationMs > 0 ? (\n <span className=\"shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(step.durationMs)}\n </span>\n ) : null}\n </div>\n {step.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mt-2.5 ml-6 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {step.errorMessage}\n </pre>\n ) : null}\n {step.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-2 ml-6\">\n <ReportDocEntries entries={step.docEntries} />\n </div>\n ) : null}\n </li>\n );\n}\n","import type { ReportDocNote } from \"executable-stories-core\";\n\nexport function DocNote({ entry }: { entry: ReportDocNote }) {\n return <p className=\"my-2 text-sm text-muted-foreground\">{entry.text}</p>;\n}\n","import type { ReportDocTag } from \"executable-stories-core\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport function DocTag({ entry }: { entry: ReportDocTag }) {\n return (\n <ul className=\"my-2 flex flex-wrap gap-1.5\" aria-label=\"Tags\">\n {entry.names.map((n) => (\n <li key={n}>\n <Badge variant=\"tag\">{n}</Badge>\n </li>\n ))}\n </ul>\n );\n}\n","import type { ReportDocKv } from \"executable-stories-core\";\n\nfunction formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport function DocKv({ entry }: { entry: ReportDocKv }) {\n return (\n <dl className=\"my-2 flex flex-wrap items-baseline gap-x-2 text-sm\">\n <dt className=\"font-semibold text-muted-foreground\">{entry.label}</dt>\n <dd className=\"font-mono text-foreground\">{formatValue(entry.value)}</dd>\n </dl>\n );\n}\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function useCustomRenderers(): CustomRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.customRenderers ?? EMPTY_CUSTOM;\n}\n\nexport function useBuiltinRenderers(): BuiltinRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.renderers ?? EMPTY_RENDERERS;\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportDocCode } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Shared shell for code blocks: optional label + the scrollable `<pre>`. Both\n * the static `DocCode` and the island's CDN-highlighted variant render their\n * `<code>` into this so the two can never drift in spacing or chrome.\n */\nexport function CodeFigure({ label, children }: { label?: string; children: ReactNode }) {\n return (\n <figure className=\"my-3\">\n {label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{label}</figcaption>\n ) : null}\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3\">\n {children}\n </pre>\n </figure>\n );\n}\n\nexport function DocCode({ entry }: { entry: ReportDocCode }) {\n const renderers = useBuiltinRenderers();\n if (renderers.code) {\n return <>{renderers.code(entry)}</>;\n }\n return (\n <CodeFigure label={entry.label}>\n <code className={cn(\"font-mono text-xs\", entry.lang && `language-${entry.lang}`)}>\n {entry.content}\n </code>\n </CodeFigure>\n );\n}\n","import type { ReportDocTable } from \"executable-stories-core\";\n\nexport function DocTable({ entry }: { entry: ReportDocTable }) {\n return (\n <figure className=\"my-3\">\n {entry.label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">\n {entry.label}\n </figcaption>\n ) : null}\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n {entry.columns.map((c) => (\n <th key={c} scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n {c}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {entry.rows.map((row, i) => (\n <tr key={i}>\n {row.map((cell, j) => (\n <td key={j} className=\"border-b border-border px-3 py-2 text-foreground\">\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </figure>\n );\n}\n","import type { ReportDocLink } from \"executable-stories-core\";\n\nexport function DocLink({ entry }: { entry: ReportDocLink }) {\n return (\n <a\n className=\"text-sm font-medium text-primary underline underline-offset-2 hover:no-underline\"\n href={entry.url}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n {entry.label}\n </a>\n );\n}\n","import { marked } from \"marked\";\nimport { safeUrl } from \"./url\";\n\n/**\n * Best-effort sanitizer for marked-generated HTML. The markdown we render is\n * authored in test source (developer-trusted), so this is defense-in-depth,\n * not a hard boundary against hostile input. It:\n * - drops <script>/<style> and other active elements (iframe/object/embed/form)\n * - strips on* event-handler attributes\n * - neutralizes any non-http(s) scheme on href/src via the shared `safeUrl`\n * allow-list (covers javascript:/data:/vbscript:/file:, not just javascript:)\n *\n * It is NOT a substitute for a full HTML sanitizer (it won't catch entity-\n * obfuscated schemes). For untrusted markdown, supply your own renderer.\n */\nexport function safeMarkdownHtml(markdown: string): string {\n const raw = marked.parse(markdown, { async: false }) as string;\n return raw\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<\\/?(?:iframe|object|embed|form|base)\\b[^>]*>/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*\"[^\"]*\"/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*'[^']*'/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*[^\\s>]+/gi, \"\")\n .replace(/(href|src)\\s*=\\s*\"([^\"]*)\"/gi, (_m, attr, val) => `${attr}=\"${neutralizeUrl(val)}\"`)\n .replace(/(href|src)\\s*=\\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);\n}\n\n/**\n * Strip the leading indentation a template literal picks up from its source.\n *\n * Narratives are written inline in test files, so they arrive indented to match\n * the surrounding code. Left alone, four spaces make Markdown render the whole\n * paragraph as a code block.\n */\nexport function dedent(text: string): string {\n const lines = text.replace(/\\t/g, \" \").split(\"\\n\");\n const indents = lines\n .filter((line) => line.trim().length > 0)\n .map((line) => line.length - line.trimStart().length);\n const shortest = indents.length > 0 ? Math.min(...indents) : 0;\n return lines\n .map((line) => line.slice(shortest))\n .join(\"\\n\")\n .trim();\n}\n\nfunction neutralizeUrl(value: string): string {\n return safeUrl(value) ?? \"#\";\n}\n","/**\n * URL trust boundary for report-sourced strings reaching the DOM. The\n * implementation lives in executable-stories-core/utils/url (shared with the\n * Astro state-catalog thumbnails); this module stays as the package-local\n * import point. Subpath import: the core package root pulls in Node-only\n * converters, which breaks browser bundles.\n */\nexport { safeUrl, safeImageUrl, isLocalFsPath } from \"executable-stories-core/utils/url\";\n","import type { ReportDocSection } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { safeMarkdownHtml } from \"../../lib/markdown\";\n\nexport function DocSection({ entry }: { entry: ReportDocSection }) {\n const renderers = useBuiltinRenderers();\n if (renderers.section) {\n return <>{renderers.section(entry)}</>;\n }\n const html = safeMarkdownHtml(entry.markdown);\n return (\n <section className=\"my-3 text-sm\" aria-label={entry.title}>\n {entry.title ? <h4 className=\"mb-1 font-semibold text-foreground\">{entry.title}</h4> : null}\n <div\n className=\"es-doc-prose prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n </section>\n );\n}\n","import type { Ref } from \"react\";\nimport type { ReportDocMermaid } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\n\n/**\n * The raw mermaid source as a semantic `<pre data-mermaid>`. This is the\n * default render and the universal fallback: AI agents, screen readers, and\n * no-JS views all get the readable source. `<MermaidDiagram>` upgrades this to\n * a drawn diagram on the client.\n */\nexport function MermaidSource({ entry, ref }: { entry: ReportDocMermaid; ref?: Ref<HTMLElement> }) {\n return (\n <figure ref={ref} className=\"my-3\" aria-label={entry.title ?? \"Diagram\"}>\n {entry.title ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{entry.title}</figcaption>\n ) : null}\n <pre\n data-mermaid\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {entry.code}\n </pre>\n </figure>\n );\n}\n\n/**\n * Renders mermaid source as a semantic `<pre data-mermaid>` by default.\n *\n * To draw the diagram, supply a `renderers.mermaid` prop — e.g. the shipped\n * `MermaidDiagram` (`renderers={{ mermaid: (e) => <MermaidDiagram entry={e} /> }}`).\n */\nexport function DocMermaid({ entry }: { entry: ReportDocMermaid }) {\n const renderers = useBuiltinRenderers();\n if (renderers.mermaid) {\n return <>{renderers.mermaid(entry)}</>;\n }\n return <MermaidSource entry={entry} />;\n}\n","import type { ReportDocScreenshot } from \"executable-stories-core\";\nimport { isLocalFsPath, safeImageUrl } from \"../../lib/url\";\n\n/**\n * A screenshot that's still an absolute local filesystem path by the time it\n * reaches this component means the report's asset bundler couldn't find the\n * file to inline/copy it (deleted, moved, or never captured — see\n * inlineScreenshotIfPossible in executable-stories-playwright). `<img src>`\n * would 404 against a path from the machine that generated the report, so\n * show a placeholder instead of a broken image.\n */\nexport function DocScreenshot({ entry }: { entry: ReportDocScreenshot }) {\n const src = isLocalFsPath(entry.path) ? undefined : safeImageUrl(entry.path);\n\n if (!src) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Screenshot unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs\">{entry.alt}</figcaption> : null}\n </figure>\n );\n }\n\n return (\n <figure className=\"my-3\">\n <img\n src={src}\n alt={entry.alt ?? \"\"}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs text-muted-foreground\">{entry.alt}</figcaption> : null}\n </figure>\n );\n}\n","import type { ReportDocVideo } from \"executable-stories-core\";\nimport { isLocalFsPath, safeUrl } from \"../../lib/url\";\n\n/**\n * Renders a video doc entry. Video bytes are large and never inlined; `path` is\n * a URL or a path that resolves alongside the report. Both `path` and `poster`\n * are adapter-supplied, so they go through the same scheme allow-list as the\n * DocHtml iframe src (no `javascript:`/`data:` URLs reach the DOM).\n *\n * An absolute local filesystem path means the report's asset bundler\n * couldn't find/copy the file — a `<video src>` pointed at a runner-local\n * path would just fail to load, so show a placeholder instead.\n */\nexport function DocVideo({ entry }: { entry: ReportDocVideo }) {\n if (isLocalFsPath(entry.path)) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Video unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.caption ? <figcaption className=\"mt-1.5 text-xs\">{entry.caption}</figcaption> : null}\n </figure>\n );\n }\n\n const src = safeUrl(entry.path);\n const poster = safeUrl(entry.poster);\n return (\n <figure className=\"my-3\">\n <video\n controls\n preload=\"metadata\"\n {...(src ? { src } : {})}\n {...(poster ? { poster } : {})}\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.caption ? (\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{entry.caption}</figcaption>\n ) : null}\n </figure>\n );\n}\n","import type { ReportDocHtml } from \"executable-stories-core\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Renders an embedded-HTML doc entry inside a SANDBOXED iframe. All embedded\n * HTML is untrusted, so the frame is `sandbox=\"allow-scripts\"` only (no\n * allow-same-origin) — embedded scripts run (charts work) but can't touch the\n * report DOM, cookies, or storage. Inline `content` → srcdoc (keeps the report\n * self-contained); `url`/`path` → src (scheme-validated).\n */\nexport function DocHtml({ entry }: { entry: ReportDocHtml }) {\n const height = typeof entry.height === \"number\" ? `${entry.height}px` : (entry.height ?? \"400px\");\n const title = entry.title ?? \"Embedded HTML\";\n const safeHref = safeUrl(entry.url ?? entry.path);\n\n // Exactly one of content / url / path is set. A url/path with an unsafe\n // scheme yields no src (the figure still renders, just empty).\n const frameProps = entry.content !== undefined ? { srcDoc: entry.content } : { src: safeHref ?? \"\" };\n\n return (\n <figure className=\"my-3 overflow-hidden rounded-md border border-border\">\n <figcaption className=\"flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground\">\n <span>{entry.title ?? \"HTML\"}</span>\n {safeHref ? (\n <a\n href={safeHref}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n className=\"text-primary\"\n >\n ↗\n </a>\n ) : null}\n </figcaption>\n <iframe\n {...frameProps}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n title={title}\n className=\"block w-full border-0\"\n style={{ height }}\n />\n </figure>\n );\n}\n","import type { ReportDocState } from \"executable-stories-core\";\nimport { CodeFigure } from \"./DocCode\";\n\n/**\n * A `story.state()` snapshot in the step detail: label + pretty JSON, same\n * chrome as `code(json)`. Frame-to-frame diffs are the storyboard's job —\n * here the entry just shows what was captured at this step.\n */\nexport function DocState({ entry }: { entry: ReportDocState }) {\n let json: string;\n try {\n json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);\n } catch {\n json = String(entry.value);\n }\n return (\n <CodeFigure label={entry.label ?? \"State\"}>\n <code className=\"font-mono text-xs language-json\">{json}</code>\n </CodeFigure>\n );\n}\n","import type { ReportDocCustom } from \"executable-stories-core\";\nimport { useCustomRenderers } from \"../../hooks/useRenderers\";\n\nexport function DocCustom({ entry }: { entry: ReportDocCustom }) {\n const renderers = useCustomRenderers();\n const renderer = renderers[entry.type];\n if (renderer) {\n return <>{renderer(entry)}</>;\n }\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">{entry.type}</p>\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\">\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocNote } from \"./DocNote\";\nimport { DocTag } from \"./DocTag\";\nimport { DocKv } from \"./DocKv\";\nimport { DocCode } from \"./DocCode\";\nimport { DocTable } from \"./DocTable\";\nimport { DocLink } from \"./DocLink\";\nimport { DocSection } from \"./DocSection\";\nimport { DocMermaid } from \"./DocMermaid\";\nimport { DocScreenshot } from \"./DocScreenshot\";\nimport { DocVideo } from \"./DocVideo\";\nimport { DocHtml } from \"./DocHtml\";\nimport { DocState } from \"./DocState\";\nimport { DocCustom } from \"./DocCustom\";\n\nexport function DocEntry({ entry }: { entry: ReportDocEntry }) {\n switch (entry.kind) {\n case \"note\":\n return <DocNote entry={entry} />;\n case \"tag\":\n return <DocTag entry={entry} />;\n case \"kv\":\n return <DocKv entry={entry} />;\n case \"code\":\n return <DocCode entry={entry} />;\n case \"table\":\n return <DocTable entry={entry} />;\n case \"link\":\n return <DocLink entry={entry} />;\n case \"section\":\n return <DocSection entry={entry} />;\n case \"mermaid\":\n return <DocMermaid entry={entry} />;\n case \"screenshot\":\n return <DocScreenshot entry={entry} />;\n case \"video\":\n return <DocVideo entry={entry} />;\n case \"html\":\n return <DocHtml entry={entry} />;\n case \"state\":\n return <DocState entry={entry} />;\n case \"custom\":\n return <DocCustom entry={entry} />;\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocEntry } from \"./doc/DocEntry\";\n\nexport interface ReportDocEntriesProps {\n entries: readonly ReportDocEntry[];\n}\n\nexport function ReportDocEntries({ entries }: ReportDocEntriesProps) {\n if (entries.length === 0) return null;\n return (\n <>\n {entries.map((entry, i) => (\n <DocEntry key={i} entry={entry} />\n ))}\n </>\n );\n}\n","import type { ReportScenario } from \"executable-stories-core\";\n// Subpath import: the core package root pulls in Node-only converters\n// (node:crypto), which breaks browser bundles — see formatDuration's import.\nimport { extractStoryboardFrames } from \"executable-stories-core/storyboard\";\nimport type { StoryboardFrame, StoryboardStateCard } from \"executable-stories-core/storyboard\";\nimport { summarizeStateChanges } from \"executable-stories-core/state-diff\";\nimport type { StateChangeKind } from \"executable-stories-core/state-diff\";\nimport { isLocalFsPath, safeImageUrl } from \"executable-stories-core/utils/url\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportStoryboardProps {\n scenario: ReportScenario;\n}\n\nconst FRAME_GLYPH: Record<string, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst FRAME_GLYPH_COLOR: Record<string, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\n/**\n * Storyboard — a horizontal filmstrip of the scenario's step evidence\n * (Given → When → Then), derived from the same step docs the vertical step\n * list renders. A frame is a container: the step's screenshot (when present)\n * plus its `story.state()` snapshot cards, so data-only scenarios get\n * filmstrips too. Each frame links to its step's anchor.\n *\n * Renders nothing below 2 frames: a single capture is evidence, not a\n * walkthrough, and it already shows under its step.\n *\n * Must stay hydration-free: the Astro story pages render this inside a static\n * (no client JS) island, so navigation is plain anchors and snapshot expansion\n * is a native <details> — no lightbox or toggle state.\n */\nexport function ReportStoryboard({ scenario }: ReportStoryboardProps) {\n const frames = extractStoryboardFrames(scenario);\n if (frames.length < 2) return null;\n return (\n <section data-slot=\"storyboard\" aria-label=\"Storyboard\" className=\"mb-3\">\n <h4 className=\"mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase\">\n Storyboard\n </h4>\n <ol className=\"flex items-start gap-3 overflow-x-auto pb-2\">\n {frames.map((frame) => (\n <StoryboardFrameItem key={frame.stepId} frame={frame} />\n ))}\n </ol>\n </section>\n );\n}\n\nfunction StoryboardFrameItem({ frame }: { frame: StoryboardFrame }) {\n const label = `${frame.keyword} ${frame.text}`;\n const hasStates = frame.states.length > 0;\n const caption = (\n <p className=\"mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug\">\n <span aria-hidden className={cn(\"shrink-0\", FRAME_GLYPH_COLOR[frame.status])}>\n {FRAME_GLYPH[frame.status] ?? \"○\"}\n </span>\n <span className=\"min-w-0\">\n <span className=\"font-mono font-semibold text-keyword\">{frame.keyword}</span>{\" \"}\n <span className=\"text-muted-foreground\">{frame.screenshot?.alt ?? frame.text}</span>\n </span>\n </p>\n );\n return (\n // State cards need room for diff rows; screenshot-only frames keep the\n // original narrow film-cell width (and DOM) unchanged.\n <li className={cn(\"shrink-0\", hasStates ? \"w-64\" : \"w-40\")}>\n {frame.screenshot ? (\n <FrameScreenshot frame={frame} label={label} />\n ) : null}\n {hasStates ? (\n <div className={cn(\"flex flex-col gap-1.5\", frame.screenshot && \"mt-1.5\")}>\n {frame.states.map((card, i) => (\n <StateCardView key={card.label ?? i} card={card} />\n ))}\n </div>\n ) : null}\n {frame.screenshot ? (\n caption\n ) : (\n // No screenshot means no image anchor, so the caption carries the\n // jump-to-step link instead.\n <a href={`#${frame.stepId}`} aria-label={`Jump to step: ${label}`} className=\"block hover:underline\">\n {caption}\n </a>\n )}\n </li>\n );\n}\n\nfunction FrameScreenshot({ frame, label }: { frame: StoryboardFrame; label: string }) {\n const path = frame.screenshot?.path ?? \"\";\n const src = isLocalFsPath(path) ? undefined : safeImageUrl(path);\n return (\n <a\n href={`#${frame.stepId}`}\n aria-label={`Jump to step: ${label}`}\n className=\"block overflow-hidden rounded-md border border-border transition-colors hover:border-ring\"\n >\n {src ? (\n <img\n src={src}\n alt={frame.screenshot?.alt ?? label}\n loading=\"lazy\"\n className=\"h-24 w-full bg-muted object-cover object-top\"\n />\n ) : (\n <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\">\n Screenshot unavailable\n </span>\n )}\n </a>\n );\n}\n\n// Same accent scheme as the status badges/KPI cards: green = new, red = gone,\n// amber (skip tokens) = changed. Text + bg pairs are the AA-audited --es-*\n// combinations from tailwind.css.\nconst CHANGE_TONE: Record<StateChangeKind, string> = {\n added: \"bg-pass-bg text-pass\",\n removed: \"bg-fail-bg text-fail\",\n changed: \"bg-skip-bg text-skip\",\n};\n\nfunction prettyJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * One `story.state()` snapshot card: label chip, then what changed since the\n * previous frame's snapshot of the same label (changed fields first, full\n * snapshot behind a disclosure). First appearance shows the snapshot itself\n * with a \"first capture\" hint — there is nothing to diff against yet.\n */\nfunction StateCardView({ card }: { card: StoryboardStateCard }) {\n const json = prettyJson(card.value);\n const firstCapture = card.changes === undefined;\n return (\n <div data-slot=\"state-card\" className=\"rounded-md border border-border bg-card p-2\">\n <p className=\"flex flex-wrap items-baseline gap-1.5\">\n <span className=\"inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground\">\n {card.label ?? \"State\"}\n </span>\n {firstCapture ? (\n <span className=\"text-[0.625rem] text-muted-foreground italic\">first capture</span>\n ) : null}\n </p>\n {!firstCapture &&\n (card.changes && card.changes.length > 0 ? (\n <ul className=\"mt-1.5 flex flex-col gap-0.5\">\n {card.changes.map((change, i) => (\n <li\n key={i}\n className={cn(\n \"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all\",\n CHANGE_TONE[change.kind]\n )}\n >\n {summarizeStateChanges([change])[0]}\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"mt-1.5 text-[0.625rem] text-muted-foreground\">No changes</p>\n ))}\n <details\n // First capture opens short snapshots by default: it IS the card's\n // content. Diff cards keep the snapshot collapsed — the rows above\n // already tell the story.\n open={firstCapture && json.length <= 240}\n className={cn(firstCapture ? \"mt-1.5\" : \"mt-1\")}\n >\n <summary className=\"cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground\">\n Snapshot\n </summary>\n <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\">\n {json}\n </pre>\n </details>\n </div>\n );\n}\n","import type { ReportAttachment } from \"executable-stories-core\";\n\n/**\n * Renders scenario attachments. Base64 images embed inline; everything else\n * becomes a labelled data-URI download link. Mirrors the report's attachments\n * block (which also inlines images and links other media).\n */\nexport function ReportAttachments({ attachments }: { attachments: ReportAttachment[] }) {\n if (attachments.length === 0) return null;\n return (\n // role=\"group\" (not a labelled <section>) so multiple scenarios' attachment\n // blocks don't create duplicate \"Attachments\" region landmarks.\n <div role=\"group\" aria-label=\"Attachments\" className=\"mt-3 flex flex-col gap-2\">\n {attachments.map((att, i) => {\n const dataUri =\n att.contentEncoding === \"BASE64\"\n ? `data:${att.mediaType};base64,${att.body}`\n : `data:${att.mediaType},${encodeURIComponent(att.body)}`;\n const isImage = att.mediaType.startsWith(\"image/\");\n return (\n <figure key={`${att.name}-${i}`} className=\"m-0\">\n {isImage ? (\n <>\n <img\n src={dataUri}\n alt={att.name}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{att.name}</figcaption>\n </>\n ) : (\n <a\n href={dataUri}\n download={att.name}\n className=\"text-xs text-link underline underline-offset-2\"\n >\n {att.name} <span className=\"text-muted-foreground\">({att.mediaType})</span>\n </a>\n )}\n </figure>\n );\n })}\n </div>\n );\n}\n","import type { OtelSpan } from \"executable-stories-core/types/otel\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { toTraceRows, traceWindow } from \"@/lib/trace\";\nimport { cn } from \"@/lib/utils\";\n\nconst BAR_COLOR: Record<string, string> = {\n ok: \"bg-pass\",\n error: \"bg-fail\",\n unset: \"bg-skip\",\n};\n\n/**\n * OTel trace waterfall. Collapsed by default (native <details>, no JS) so it\n * renders in both the static and interactive reports. Each span is a row with a\n * depth-indented name and a bar positioned/sized by its time window.\n */\nexport function ReportTrace({ spans }: { spans: readonly OtelSpan[] | undefined }) {\n if (!spans || spans.length === 0) return null;\n const rows = toTraceRows(spans);\n if (rows.length === 0) return null;\n const { minStartMs, totalMs } = traceWindow(rows);\n\n return (\n <details className=\"mt-3 rounded-md border border-border bg-muted/30\">\n <summary className=\"cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground\">\n Trace ({rows.length} span{rows.length === 1 ? \"\" : \"s\"}, {formatDuration(totalMs)})\n </summary>\n <ul className=\"flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]\">\n {rows.map((row, i) => {\n const leftPct = ((row.startTimeMs - minStartMs) / totalMs) * 100;\n const widthPct = Math.max((row.durationMs / totalMs) * 100, 0.5);\n return (\n <li key={`${row.spanId}-${i}`} className=\"flex items-center gap-2\">\n <span\n className=\"min-w-0 flex-1 truncate text-foreground\"\n style={{ paddingLeft: `${row.depth * 12}px` }}\n title={row.statusMessage ? `${row.name}: ${row.statusMessage}` : row.name}\n >\n {row.name}\n </span>\n <span className=\"relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40\">\n <span\n className={cn(\"absolute top-0 h-full rounded-sm\", BAR_COLOR[row.status])}\n style={{ left: `${leftPct}%`, width: `${widthPct}%` }}\n />\n </span>\n <span className=\"w-16 shrink-0 text-right text-muted-foreground\">\n {formatDuration(row.durationMs)}\n </span>\n </li>\n );\n })}\n </ul>\n </details>\n );\n}\n","/**\n * Pure span normalization + tree building for the OTel trace waterfall.\n * Ported from the formatters trace-view renderer so the React waterfall shows\n * the same structure. Side-effect-free for unit testing.\n */\n\nimport type { OtelSpan } from \"executable-stories-core/types/otel\";\n\nexport interface NormalizedSpan {\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeMs: number;\n durationMs: number;\n status: \"ok\" | \"error\" | \"unset\";\n statusMessage?: string;\n}\n\nexport interface TraceRow extends NormalizedSpan {\n depth: number;\n}\n\nconst VALID = new Set([\"ok\", \"error\", \"unset\"]);\nconst safeStatus = (s: string): NormalizedSpan[\"status\"] => (VALID.has(s) ? (s as NormalizedSpan[\"status\"]) : \"unset\");\n\nexport function normalizeSpans(spans: readonly OtelSpan[]): NormalizedSpan[] {\n const out: NormalizedSpan[] = [];\n for (const span of spans) {\n if (!span || typeof span.spanId !== \"string\" || typeof span.name !== \"string\") continue;\n let startTimeMs: number;\n let durationMs: number;\n if (span.startTimeMs != null && span.durationMs != null) {\n startTimeMs = span.startTimeMs;\n durationMs = span.durationMs;\n } else if (span.startTimeUnixNano != null && span.endTimeUnixNano != null) {\n startTimeMs = span.startTimeUnixNano / 1e6;\n durationMs = (span.endTimeUnixNano - span.startTimeUnixNano) / 1e6;\n } else {\n continue;\n }\n durationMs = Math.max(0, durationMs);\n if (!isFinite(startTimeMs) || !isFinite(durationMs)) continue;\n out.push({\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n startTimeMs,\n durationMs,\n status: safeStatus(span.status),\n statusMessage: span.statusMessage,\n });\n }\n return out;\n}\n\n/** Flatten spans into rows in tree order with a depth, parent before children. */\nexport function toTraceRows(spans: readonly OtelSpan[]): TraceRow[] {\n const normalized = normalizeSpans(spans);\n if (normalized.length === 0) return [];\n\n interface Node {\n span: NormalizedSpan;\n children: Node[];\n depth: number;\n }\n const byId = new Map<string, Node>();\n for (const span of normalized) {\n let key = span.spanId;\n let suffix = 2;\n while (byId.has(key)) key = `${span.spanId}__dup${suffix++}`;\n byId.set(key, { span: { ...span, spanId: key }, children: [], depth: 0 });\n }\n\n const roots: Node[] = [];\n for (const node of byId.values()) {\n const parent = node.span.parentSpanId ? byId.get(node.span.parentSpanId) : undefined;\n if (parent && parent !== node) parent.children.push(node);\n else roots.push(node);\n }\n for (const node of byId.values()) node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n\n const rows: TraceRow[] = [];\n const seen = new Set<string>();\n const walk = (node: Node, depth: number): void => {\n if (seen.has(node.span.spanId)) return;\n seen.add(node.span.spanId);\n rows.push({ ...node.span, depth });\n for (const child of node.children) walk(child, depth + 1);\n };\n for (const root of roots) walk(root, 0);\n // Orphans from cycles: promote to depth 0.\n for (const node of byId.values()) {\n if (!seen.has(node.span.spanId)) walk(node, 0);\n }\n return rows;\n}\n\nexport interface TraceWindow {\n minStartMs: number;\n totalMs: number;\n}\n\nexport function traceWindow(rows: readonly TraceRow[]): TraceWindow {\n let min = Infinity;\n let max = -Infinity;\n for (const r of rows) {\n min = Math.min(min, r.startTimeMs);\n max = Math.max(max, r.startTimeMs + r.durationMs);\n }\n const total = max - min;\n return { minStartMs: isFinite(min) ? min : 0, totalMs: total > 0 ? total : 1 };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ScenarioHistoryMap } from \"../lib/run-history\";\n\n/**\n * Provided only inside <ReportInteractive> when the CLI embedded a run\n * history (--history-file). When null (the static <Report/> render,\n * Storybook, Astro), scenario cards simply omit the history strip.\n */\nconst ScenarioHistoryContext = createContext<ScenarioHistoryMap | null>(null);\n\nexport const ScenarioHistoryProvider = ScenarioHistoryContext.Provider;\n\nexport function useScenarioHistory(): ScenarioHistoryMap | null {\n return useContext(ScenarioHistoryContext);\n}\n","export type ScenarioRunStatus = \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n\n/** One historical run of a scenario, oldest → newest in a history array. */\nexport interface ScenarioRunEvent {\n /** Epoch ms the run started. */\n timestamp: number;\n status: ScenarioRunStatus;\n runId?: string;\n durationMs?: number;\n commitSha?: string;\n branch?: string;\n}\n\n/** Recent run events keyed by ReportScenario.id. */\nexport type ScenarioHistoryMap = Record<string, ScenarioRunEvent[]>;\n\nexport interface RunStreak {\n status: ScenarioRunStatus;\n /** How many consecutive trailing runs share that status (≥1). */\n count: number;\n}\n\n/** The trailing same-status streak — \"passing for 5 runs\", \"failing for 2\". */\nexport function currentStreak(entries: readonly ScenarioRunEvent[]): RunStreak | undefined {\n const last = entries[entries.length - 1];\n if (!last) return undefined;\n let count = 0;\n for (let i = entries.length - 1; i >= 0 && entries[i]!.status === last.status; i--) count++;\n return { status: last.status, count };\n}\n\nconst STREAK_VERB: Record<ScenarioRunStatus, string> = {\n passed: \"Passing\",\n failed: \"Failing\",\n skipped: \"Skipped\",\n pending: \"Pending\",\n};\n\n/** Short human summary of a history window, used for the strip's tooltip. */\nexport function describeRunHistory(entries: readonly ScenarioRunEvent[]): string {\n const passed = entries.filter((e) => e.status === \"passed\").length;\n const base = `${passed}/${entries.length} runs passed`;\n const streak = currentStreak(entries);\n if (!streak || entries.length < 2) return base;\n return `${base} · ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? \"run\" : `${streak.count} runs`}`;\n}\n\nexport type FlakinessLevel = \"stable\" | \"unstable\" | \"flaky\";\n\n/**\n * Below this many pass/fail samples a scenario is always \"stable\" — mirrors\n * MIN_FLAKINESS_SAMPLES in the formatters history module, which owns the\n * canonical thresholds. Keep the two in sync.\n */\nconst MIN_FLAKINESS_SAMPLES = 3;\n\n/**\n * Status-transition flakiness over a scenario's recent runs. Same\n * classification as the CLI history module (`calculateFlakiness`), ported so\n * the island stays self-sufficient on the embedded history JSON.\n */\nexport function flakinessOf(entries: readonly ScenarioRunEvent[]): FlakinessLevel {\n const countable = entries.filter((e) => e.status === \"passed\" || e.status === \"failed\");\n if (countable.length < MIN_FLAKINESS_SAMPLES) return \"stable\";\n\n let transitions = 0;\n for (let i = 1; i < countable.length; i++) {\n if (countable[i]!.status !== countable[i - 1]!.status) transitions++;\n }\n const transitionScore = transitions / (countable.length - 1);\n const failureRate = countable.filter((e) => e.status === \"failed\").length / countable.length;\n\n if (transitionScore > 0.5 || (transitionScore > 0.3 && failureRate > 0.2)) return \"flaky\";\n if (transitionScore > 0.2 || failureRate > 0.3) return \"unstable\";\n return \"stable\";\n}\n\nexport interface ScenarioRef {\n id: string;\n title: string;\n}\n\nexport interface LastRunDelta {\n /** Failed in this run, not failed in the previous one. */\n newlyFailing: ScenarioRef[];\n /** Passed in this run, failed in the previous one. */\n newlyPassing: ScenarioRef[];\n /** First appearance in the history window — no previous run to compare. */\n added: ScenarioRef[];\n}\n\n/**\n * What changed between the previous run and this one, for the report-header\n * strip. The history store appends the current run before the report is\n * generated, so each scenario's last entry IS this run and the entry before\n * it is the previous run. Returns undefined when no scenario has a previous\n * run to compare against (first run with history enabled).\n */\nexport function diffSinceLastRun(\n history: ScenarioHistoryMap,\n scenarios: readonly ScenarioRef[],\n): LastRunDelta | undefined {\n let hasPreviousRun = false;\n const delta: LastRunDelta = { newlyFailing: [], newlyPassing: [], added: [] };\n\n for (const scenario of scenarios) {\n const entries = history[scenario.id];\n if (!entries || entries.length === 0) continue;\n const last = entries[entries.length - 1]!;\n const prev = entries[entries.length - 2];\n if (!prev) {\n delta.added.push(scenario);\n continue;\n }\n hasPreviousRun = true;\n if (last.status === \"failed\" && prev.status !== \"failed\") delta.newlyFailing.push(scenario);\n else if (last.status === \"passed\" && prev.status === \"failed\") delta.newlyPassing.push(scenario);\n }\n\n return hasPreviousRun ? delta : undefined;\n}\n","import { useScenarioHistory } from \"../interactive/scenario-history-context\";\nimport { describeRunHistory, flakinessOf, type ScenarioRunEvent, type ScenarioRunStatus } from \"../lib/run-history\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\n/** How many trailing runs the strip shows; older entries stay in the tooltip count. */\nconst MAX_DOTS = 10;\n\nconst DOT_COLOR: Record<ScenarioRunStatus, string> = {\n passed: \"bg-pass\",\n failed: \"bg-fail\",\n skipped: \"bg-skip\",\n pending: \"bg-pend\",\n};\n\nfunction dotTitle(e: ScenarioRunEvent): string {\n const parts = [new Date(e.timestamp).toLocaleString(), e.status];\n if (e.commitSha) parts.push(e.commitSha.slice(0, 8));\n return parts.join(\" · \");\n}\n\n/**\n * Compact run-over-run timeline for one scenario: a dot per recent run,\n * oldest → newest. Renders nothing outside <ReportInteractive> or when the\n * report was generated without --history-file — history is presentation-layer\n * data and never part of the StoryReport contract.\n */\nexport function ScenarioRunHistory({ scenarioId }: { scenarioId: string }) {\n const history = useScenarioHistory();\n const entries = history?.[scenarioId];\n if (!entries || entries.length < 2) return null; // one run = no timeline yet\n\n const recent = entries.slice(-MAX_DOTS);\n // Judge flakiness on the same window the dots show, so the badge never\n // contradicts the strip next to it.\n const flaky = flakinessOf(recent) === \"flaky\";\n const summary = flaky ? `${describeRunHistory(recent)} · Flaky` : describeRunHistory(recent);\n\n return (\n <>\n {flaky ? (\n <Badge variant=\"pending\" aria-label=\"Flaky: status flips between recent runs\" title={summary}>\n Flaky\n </Badge>\n ) : null}\n <span\n role=\"img\"\n aria-label={`Run history: ${summary}`}\n title={summary}\n className=\"flex shrink-0 items-center gap-[3px]\"\n >\n {recent.map((e, i) => (\n <span\n key={`${e.timestamp}-${i}`}\n aria-hidden\n title={dotTitle(e)}\n className={cn(\n \"inline-block size-1.5 rounded-full\",\n DOT_COLOR[e.status],\n // The newest run (rightmost dot) is the one the card's status\n // badge already describes; ring it so the timeline reads as\n // \"…leading up to now\".\n i === recent.length - 1 && \"ring-1 ring-border ring-offset-1 ring-offset-card\",\n )}\n />\n ))}\n </span>\n </>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { formatRelativeAge, isReportStale } from \"../lib/provenance\";\nimport { useScenarioFreshness } from \"../interactive/scenario-freshness-context\";\nimport { Badge } from \"@/components/ui/badge\";\n\n/**\n * Per-scenario age signal.\n *\n * A report assembled from accumulated runs can be freshly rendered while some\n * of its scenarios last ran weeks ago. The report-level banner speaks for the\n * run, not for those scenarios, so without this the carried-over ones borrow a\n * freshness they have not earned.\n *\n * Only scenarios that are actually old say anything: a scenario that ran in\n * this run is the normal case and adds no badge. Age is computed on mount for\n * the same reason the report banner does it — static HTML is generated once and\n * read later, so an age baked in at build time would lie.\n */\nexport function ScenarioStaleness({ scenario }: { scenario: { lastRunAtMs?: number } }) {\n const freshness = useScenarioFreshness();\n const fixedNow = freshness?.nowMs;\n const [now, setNow] = useState<number | undefined>(fixedNow);\n\n useEffect(() => {\n if (fixedNow === undefined) setNow(Date.now());\n }, [fixedNow]);\n\n if (!freshness || now === undefined) return null;\n\n // No stamp means the report predates stamping, or came straight from one run.\n // Either way the report-level signal already speaks for it.\n const lastRunAtMs = scenario.lastRunAtMs;\n if (!lastRunAtMs || lastRunAtMs <= 0) return null;\n if (!isReportStale(lastRunAtMs, freshness.staleAfterDays, now)) return null;\n\n return (\n <Badge variant=\"outline\" aria-label=\"Scenario freshness\">\n Last ran {formatRelativeAge(lastRunAtMs, now)}\n </Badge>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\n\ntype ReportCI = NonNullable<StoryReport[\"ci\"]>;\n\n/**\n * Epoch ms of the run the report documents — the staleness reference.\n * Prefers finishedAtMs; falls back to startedAtMs for reports from adapters\n * that only stamp a start time.\n */\nexport function reportLastRunMs(\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">,\n): number | undefined {\n if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;\n if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;\n return undefined;\n}\n\n/**\n * Epoch ms of the run that produced one scenario.\n *\n * A report assembled from accumulated runs holds scenarios that last ran at\n * different times, so the run-level timestamp overstates how fresh most of them\n * are. Falls back to the report for scenarios recorded before stamping, and for\n * reports rendered straight from a single run.\n */\nexport function scenarioLastRunMs(\n scenario: { lastRunAtMs?: number },\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">,\n): number | undefined {\n if (scenario.lastRunAtMs && scenario.lastRunAtMs > 0) return scenario.lastRunAtMs;\n return reportLastRunMs(report);\n}\n\n/**\n * Human-readable age like \"just now\", \"5 minutes ago\", \"3 hours ago\",\n * \"12 days ago\". Clock skew (thenMs in the future) reads as \"just now\".\n */\nexport function formatRelativeAge(thenMs: number, nowMs: number): string {\n const deltaMs = Math.max(0, nowMs - thenMs);\n const minutes = Math.floor(deltaMs / 60_000);\n if (minutes < 1) return \"just now\";\n if (minutes < 60) return `${minutes} minute${minutes === 1 ? \"\" : \"s\"} ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours} hour${hours === 1 ? \"\" : \"s\"} ago`;\n const days = Math.floor(hours / 24);\n return `${days} day${days === 1 ? \"\" : \"s\"} ago`;\n}\n\n/**\n * A report is stale once its run is `staleAfterDays` or more days old.\n * A threshold of 0 (or negative) disables staleness entirely.\n */\nexport function isReportStale(\n lastRunMs: number | undefined,\n staleAfterDays: number,\n nowMs: number,\n): boolean {\n if (lastRunMs === undefined || staleAfterDays <= 0) return false;\n return nowMs - lastRunMs >= staleAfterDays * 86_400_000;\n}\n\n/**\n * StoryReport.ci.name carries the raw transport name — lowercase provider\n * keys (\"github\") from env detection, or a free-form string from older\n * adapters (\"GitHub Actions\"). Map the known keys to display names and pass\n * everything else through.\n */\nconst CI_DISPLAY_NAMES: Record<string, string> = {\n github: \"GitHub Actions\",\n gitlab: \"GitLab CI\",\n circleci: \"CircleCI\",\n jenkins: \"Jenkins\",\n azure: \"Azure DevOps\",\n buildkite: \"Buildkite\",\n travis: \"Travis CI\",\n ci: \"CI\",\n};\n\nexport function ciDisplayName(name: string): string {\n return CI_DISPLAY_NAMES[name] ?? name;\n}\n\n/**\n * Derive a browsable commit URL from the CI run URL, for the providers whose\n * URL structure makes that safe:\n * GitHub Actions …/owner/repo/actions/runs/123 -> …/owner/repo/commit/<sha>\n * GitLab CI …/group/project/-/pipelines/123 -> …/group/project/-/commit/<sha>\n * Other providers return undefined (a wrong link is worse than none).\n */\nexport function commitUrl(ci: ReportCI | undefined, sha: string | undefined): string | undefined {\n const commitSha = ci?.commitSha ?? sha;\n if (!ci?.url || !commitSha) return undefined;\n\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/commit/${commitSha}`;\n\n const gitlab = ci.url.match(/^(https?:\\/\\/.+)\\/-\\/pipelines\\//);\n if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;\n\n return undefined;\n}\n\n/**\n * Derive a pull-request URL for GitHub-shaped CI run URLs. GitLab and the\n * rest return undefined for the same wrong-link-is-worse-than-none reason.\n */\nexport function prUrl(ci: ReportCI | undefined): string | undefined {\n if (!ci?.url || !ci.prNumber) return undefined;\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/pull/${ci.prNumber}`;\n return undefined;\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport interface ScenarioFreshness {\n /** Days before a scenario counts as stale; 0 disables the signal. */\n staleAfterDays: number;\n /** The run being rendered, used for scenarios carrying no stamp of their own. */\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">;\n /** Test seam: fixed \"now\". Left undefined, the badge reads the clock on mount. */\n nowMs?: number;\n}\n\n/**\n * Provided only where a report knows its staleness threshold. When null (a bare\n * <Report/> render, Storybook), scenario cards simply omit the age signal —\n * same shape as the run-history context.\n */\nconst ScenarioFreshnessContext = createContext<ScenarioFreshness | null>(null);\n\nexport const ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;\n\nexport function useScenarioFreshness(): ScenarioFreshness | null {\n return useContext(ScenarioFreshnessContext);\n}\n","\"use client\";\n\nimport { createContext, useCallback, useContext, useState } from \"react\";\n\nexport interface CollapseApi {\n isCollapsed: (id: string) => boolean;\n toggle: (id: string) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (the static <Report/>\n * render, Storybook, Astro), components render fully expanded with no toggle\n * affordance — so the static path and component-tier tests are unaffected.\n */\nconst CollapseContext = createContext<CollapseApi | null>(null);\n\nexport const CollapseProvider = CollapseContext.Provider;\n\nexport function useCollapse(): CollapseApi | null {\n return useContext(CollapseContext);\n}\n\nconst STORAGE_KEY = \"es-collapsed-ids\";\n\n/** Returns the persisted collapsed set, or null when the user has never set one\n * (so the caller can fall back to a data-driven default like failures-first). */\nfunction readPersisted(): Set<string> | null {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n return raw ? new Set(JSON.parse(raw) as string[]) : null;\n } catch {\n return null;\n }\n}\n\nfunction persist(ids: Set<string>): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...ids]));\n } catch {\n /* quota / disabled — collapse still works for the session */\n }\n}\n\n/**\n * Collapse state for the interactive report: a persisted set of collapsed\n * feature/scenario ids, plus expand-all / collapse-all. `computeDefault` seeds\n * the initial set the FIRST time (nothing persisted yet) — the report uses it\n * to open failures and collapse the rest, so a broken run reveals what failed\n * without a click. Once the user toggles anything, their choice persists and\n * wins over the default.\n */\nexport function useCollapseState(computeDefault?: () => Set<string>) {\n const [collapsed, setCollapsed] = useState<Set<string>>(\n () => readPersisted() ?? computeDefault?.() ?? new Set<string>(),\n );\n\n const isCollapsed = useCallback((id: string) => collapsed.has(id), [collapsed]);\n\n const toggle = useCallback((id: string) => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n persist(next);\n return next;\n });\n }, []);\n\n const collapseAll = useCallback((ids: string[]) => {\n setCollapsed(() => {\n const next = new Set(ids);\n persist(next);\n return next;\n });\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsed(() => {\n const next = new Set<string>();\n persist(next);\n return next;\n });\n }, []);\n\n return { api: { isCollapsed, toggle } as CollapseApi, collapseAll, expandAll };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ReportScenario } from \"executable-stories-core\";\n// Deep import, NOT the package barrel: core's index pulls in Node-only modules\n// (attachment resolution reads the filesystem), which a browser bundler cannot\n// resolve. Types erase at compile time, so the type-only import above is safe;\n// this one is a value and must stay on the fs-free subpath.\nimport { scenarioToMarkdown as coreScenarioToMarkdown } from \"executable-stories-core/utils/scenario-markdown\";\n\nexport interface ScenarioActions {\n copyLink: (scenario: ReportScenario) => void;\n copyMarkdown: (scenario: ReportScenario) => void;\n copyPrompt: (scenario: ReportScenario) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (static render), scenarios\n * show no per-scenario action buttons.\n */\nconst ScenarioActionsContext = createContext<ScenarioActions | null>(null);\nexport const ScenarioActionsProvider = ScenarioActionsContext.Provider;\nexport function useScenarioActions(): ScenarioActions | null {\n return useContext(ScenarioActionsContext);\n}\n\n/**\n * A scenario rendered as Markdown — for pasting into PRs / issues / docs.\n *\n * Delegates to the shared serializer in core (`variant: \"compact\"`), the same\n * one behind the Astro site's `<slug>.md` twin endpoints, so what you copy here\n * and what an agent fetches there can never drift.\n */\nexport function scenarioToMarkdown(scenario: ReportScenario): string {\n return coreScenarioToMarkdown(scenario, { variant: \"compact\" });\n}\n\n/**\n * A failed scenario rendered as an investigation prompt for an AI agent — the\n * \"cheap to verify\" loop: hand the agent the failing behaviour + error verbatim.\n */\nexport function scenarioToPrompt(scenario: ReportScenario): string {\n const lines: string[] = [\n `A test scenario is ${scenario.status}. Investigate the likely cause and propose a fix.`,\n \"\",\n `Scenario: ${scenario.title}`,\n \"Steps:\",\n ];\n for (const step of scenario.steps) {\n const mark = step.status === \"failed\" ? \" ⟵ failed here\" : \"\";\n lines.push(` ${step.keyword} ${step.text}${mark}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"Error:\", scenario.errorMessage.trim());\n }\n if (scenario.errorStack) {\n lines.push(\"\", \"Stack:\", scenario.errorStack.trim());\n }\n return lines.join(\"\\n\");\n}\n\n/** Absolute permalink to a scenario in the current document. */\nexport function scenarioPermalink(scenario: ReportScenario): string {\n if (typeof location === \"undefined\") return `#${scenario.id}`;\n return `${location.href.split(\"#\")[0]}#${scenario.id}`;\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport { CheckIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst itemClasses =\n \"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\"\n\nfunction DropdownMenu(props: React.ComponentProps<typeof MenuPrimitive.Root>) {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuTrigger(\n props: React.ComponentProps<typeof MenuPrimitive.Trigger>,\n) {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\n\nfunction DropdownMenuContent({\n className,\n align = \"end\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.Popup> & {\n align?: MenuPrimitive.Positioner.Props[\"align\"]\n sideOffset?: MenuPrimitive.Positioner.Props[\"sideOffset\"]\n}) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n data-slot=\"dropdown-menu-positioner\"\n className=\"z-50\"\n align={align}\n sideOffset={sideOffset}\n >\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n className={cn(\n \"z-50 min-w-[11rem] origin-[var(--transform-origin)] overflow-hidden rounded-md border border-border bg-popover p-1 font-sans text-sm text-popover-foreground shadow-md transition-[opacity,transform] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.Item>) {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n className={cn(itemClasses, className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuLabel({\n className,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.GroupLabel>) {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n className={cn(\"px-2 py-1.5 text-xs font-medium text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\n// Base UI's Menu has no Separator part; a plain divider row is equivalent.\nfunction DropdownMenuSeparator({ className }: { className?: string }) {\n return <div role=\"separator\" className={cn(\"-mx-1 my-1 h-px bg-border\", className)} />\n}\n\nfunction DropdownMenuRadioGroup(\n props: React.ComponentProps<typeof MenuPrimitive.RadioGroup>,\n) {\n return <MenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.RadioItem>) {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(itemClasses, \"pl-8\", className)}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.RadioItemIndicator>\n <CheckIcon className=\"size-4 text-foreground\" />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.CheckboxItem>) {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(itemClasses, \"pl-8\", className)}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon className=\"size-4\" />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuCheckboxItem,\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { ReportScenario } from \"./ReportScenario\";\n\nexport interface ReportScenarioListProps {\n feature: ReportFeature;\n}\n\nexport function ReportScenarioList({ feature }: ReportScenarioListProps) {\n return (\n <>\n {feature.scenarios.map((scenario) => (\n <ReportScenario key={scenario.id} scenario={scenario} />\n ))}\n </>\n );\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { dedent, safeMarkdownHtml } from \"../lib/markdown\";\n\nexport interface ReportFeatureIntroProps {\n feature: ReportFeature;\n}\n\n/**\n * What the feature is for, ahead of the scenarios that prove it.\n *\n * Scenarios answer \"what does it do\". A reader arriving cold needs \"why does\n * this exist and who is it for\" first, which is what `story.feature(...)`\n * records. Renders nothing when a file never declared one, so existing reports\n * look exactly as they did.\n */\nexport function ReportFeatureIntro({ feature }: ReportFeatureIntroProps) {\n const hasNarrative = Boolean(feature.narrative?.trim());\n const hasGlossary = Boolean(feature.glossary?.length);\n if (!hasNarrative && !hasGlossary) return null;\n\n return (\n <div className=\"flex flex-col gap-3 border-l-2 border-border pl-4 text-sm\">\n {hasNarrative ? (\n <div\n className=\"es-doc-prose prose prose-sm max-w-none text-muted-foreground\"\n dangerouslySetInnerHTML={{ __html: safeMarkdownHtml(dedent(feature.narrative!)) }}\n />\n ) : null}\n\n {hasGlossary ? (\n <dl className=\"grid gap-1.5\" aria-label=\"Glossary\">\n {feature.glossary!.map((entry) => (\n <div key={entry.term} className=\"flex flex-wrap gap-x-2 text-xs\">\n <dt className=\"font-medium text-foreground\">{entry.term}</dt>\n <dd className=\"flex-1 text-muted-foreground\">{entry.definition}</dd>\n </div>\n ))}\n </dl>\n ) : null}\n </div>\n );\n}\n\n/**\n * Label the feature the way it was declared.\n *\n * An ability reads as something a person can now do; a business need covers the\n * cross-cutting concerns nobody asks for by name, like security or performance.\n * Naming the kind keeps that distinction visible to a reader who never sees the\n * test code. A derived title gets no badge, since nobody claimed anything.\n */\nexport function featureKindLabel(kind: ReportFeature[\"kind\"]): string | null {\n if (kind === \"ability\") return \"Ability\";\n if (kind === \"business-need\") return \"Business need\";\n if (kind === \"feature\") return \"Feature\";\n return null;\n}\n","import type { ReportFeature as ReportFeatureT } from \"executable-stories-core\";\nimport { ReportScenarioList } from \"./ReportScenarioList\";\nimport { ReportFeatureIntro, featureKindLabel } from \"./ReportFeatureIntro\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportFeatureProps {\n feature: ReportFeatureT;\n}\n\n/**\n * Feature group — the report's `.feature` card: a header bar with the feature\n * title + mono source path and ✓/✗/○ status counts on the right, over a stack\n * of scenario cards. Kept a semantic <section> (a region), not a shadcn Card\n * div, so it stays a landmark and doesn't collide with the scenario cards'\n * `[data-slot=\"card\"]`.\n */\nexport function ReportFeature({ feature }: ReportFeatureProps) {\n const titleId = `${feature.id}-title`;\n const bodyId = `${feature.id}-body`;\n const s = feature.summary;\n const skipped = s.skipped + s.pending;\n const collapse = useCollapse();\n const collapsed = collapse?.isCollapsed(feature.id) ?? false;\n const kindLabel = featureKindLabel(feature.kind);\n return (\n // Suite = a section heading + a divider, NOT another bordered card. Drops a\n // layer of nesting so the scenario cards below read as the primary unit.\n <section\n id={feature.id}\n data-slot=\"feature\"\n aria-labelledby={titleId}\n className=\"flex flex-col gap-3\"\n >\n <div className=\"flex items-end justify-between gap-4 border-b border-border pb-2\">\n <div className=\"min-w-0\">\n {/* The heading itself is the toggle — a wide, obvious hit area rather\n than a lone caret. Kept inside <h2> so it stays a landmark. */}\n <h2 id={titleId} className=\"text-base font-semibold tracking-tight text-foreground\">\n {collapse ? (\n <button\n type=\"button\"\n onClick={() => collapse.toggle(feature.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n className=\"flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80\"\n >\n <span aria-hidden className={cn(\"shrink-0 text-xs text-muted-foreground transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n <span className=\"truncate\">{feature.title}</span>\n </button>\n ) : (\n feature.title\n )}\n </h2>\n <p className={cn(\"mt-0.5 flex items-center gap-2 text-xs text-muted-foreground\", collapse && \"pl-5\")}>\n {kindLabel ? (\n <span className=\"shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground\">\n {kindLabel}\n </span>\n ) : null}\n <span className=\"truncate font-mono\">{feature.sourceFile}</span>\n </p>\n </div>\n {/* Readable, failure-weighted counts — only the failure count carries\n colour, so a broken suite reads at a glance without a colour salad. */}\n <p\n className=\"flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground\"\n aria-label={`${s.passed} passed, ${s.failed} failed, ${skipped} skipped`}\n >\n <span>{s.passed} passed</span>\n <span aria-hidden>·</span>\n <span className={cn(s.failed > 0 && \"font-medium text-fail\")}>{s.failed} failed</span>\n {skipped > 0 ? (\n <>\n <span aria-hidden>·</span>\n <span>{skipped} skipped</span>\n </>\n ) : null}\n </p>\n </div>\n <div id={bodyId} hidden={collapsed} className=\"flex flex-col gap-3\">\n <ReportFeatureIntro feature={feature} />\n <ReportScenarioList feature={feature} />\n </div>\n </section>\n );\n}\n","import { useReport } from \"../hooks/useReport\";\nimport { ReportFeature } from \"./ReportFeature\";\n\nexport function ReportFeatureList() {\n const report = useReport();\n // Roomy gap between features — they're now divider-led sections rather than\n // self-contained cards, so they need clear air to read as separate suites.\n return (\n <div className=\"flex flex-col gap-8\">\n {report.features.map((feature) => (\n <ReportFeature key={feature.id} feature={feature} />\n ))}\n </div>\n );\n}\n","import { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Empty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst emptyMediaVariants = cva(\n \"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction EmptyTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n )\n}\n\nfunction EmptyDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n}\n","import { Empty, EmptyHeader, EmptyTitle } from \"@/components/ui/empty\";\n\nexport interface ReportEmptyProps {\n message?: string;\n}\n\nexport function ReportEmpty({ message }: ReportEmptyProps) {\n return (\n <Empty aria-live=\"polite\" className=\"border\">\n <EmptyHeader>\n <EmptyTitle>{message ?? \"No scenarios in this report.\"}</EmptyTitle>\n </EmptyHeader>\n </Empty>\n );\n}\n","import type { ReportSummary as ReportSummaryT } from \"executable-stories-core\";\nimport { useReport } from \"../hooks/useReport\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportSummaryProps {\n className?: string;\n}\n\nexport function ReportSummary({ className }: ReportSummaryProps) {\n const report = useReport();\n return (\n <ReportSummaryView\n summary={report.summary}\n {...(className !== undefined && { className })}\n ariaLabel=\"Run summary\"\n />\n );\n}\n\nexport interface ReportSummaryViewProps {\n summary: ReportSummaryT;\n className?: string;\n ariaLabel?: string;\n}\n\n/**\n * A single stat card. All cards share the neutral card surface; the status\n * *number* carries the colour (`--es-pass/fail/skip/pend`, mapped to Tailwind\n * in tailwind.css) and a matching leading dot. This drops the earlier pastel\n * fills for the flatter, dashboard-style KPI treatment — a mono micro-label\n * above an oversized tabular number.\n */\nconst TONE = {\n total: { num: \"text-foreground\", dot: \"bg-muted-foreground/50\" },\n passed: { num: \"text-pass\", dot: \"bg-pass\" },\n failed: { num: \"text-fail\", dot: \"bg-fail\" },\n skipped: { num: \"text-skip\", dot: \"bg-skip\" },\n pending: { num: \"text-pend\", dot: \"bg-pend\" },\n} as const;\n\nexport function ReportSummaryView({ summary, className, ariaLabel }: ReportSummaryViewProps) {\n const cards: Array<{ status: keyof typeof TONE; label: string; value: number }> = [\n { status: \"total\", label: \"Total\", value: summary.total },\n { status: \"passed\", label: \"Passed\", value: summary.passed },\n { status: \"failed\", label: \"Failed\", value: summary.failed },\n { status: \"skipped\", label: \"Skipped\", value: summary.skipped },\n ];\n if (summary.pending > 0) {\n cards.push({ status: \"pending\", label: \"Pending\", value: summary.pending });\n }\n return (\n <dl\n className={cn(\n \"grid grid-cols-2 gap-3\",\n // Columns follow the card count so the row is always full — 5 statuses\n // (pending present) never leave a lone orphan card below a row of four.\n cards.length === 5 ? \"sm:grid-cols-5\" : \"sm:grid-cols-4\",\n className,\n )}\n aria-label={ariaLabel}\n >\n {cards.map((c) => {\n const tone = TONE[c.status];\n return (\n <div\n key={c.status}\n data-status={c.status}\n className=\"rounded-lg border bg-card px-4 py-3\"\n >\n <dt className=\"flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground\">\n <span className={cn(\"size-1.5 shrink-0 rounded-full\", tone.dot)} aria-hidden=\"true\" />\n {c.label}\n </dt>\n <dd className={cn(\"mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums\", tone.num)}>\n {c.value}\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n","import { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { useReport } from \"../hooks/useReport\";\nimport { ciDisplayName, commitUrl, prUrl } from \"../lib/provenance\";\n\n/**\n * Run metadata line (started, duration, version, branch, git SHA, CI, PR) —\n * the React equivalent of the report's `.meta-info` block. Reads the top-level\n * StoryReport fields from context. Commit and PR become links when the CI run\n * URL lets us derive them safely (GitHub/GitLab shapes only).\n */\nexport function ReportMeta() {\n const report = useReport();\n\n const items: Array<{ label: string; value: React.ReactNode }> = [];\n const linkClass = \"text-primary underline underline-offset-2\";\n\n if (report.startedAtMs) {\n items.push({ label: \"Started\", value: new Date(report.startedAtMs).toLocaleString() });\n }\n if (report.durationMs) {\n items.push({ label: \"Duration\", value: formatDuration(report.durationMs) });\n }\n if (report.packageVersion) {\n items.push({ label: \"Version\", value: report.packageVersion });\n }\n if (report.ci?.branch) {\n items.push({ label: \"Branch\", value: report.ci.branch });\n }\n const sha = report.ci?.commitSha ?? report.gitSha;\n if (sha) {\n const url = commitUrl(report.ci, report.gitSha);\n const short = sha.slice(0, 8);\n items.push({\n label: \"Commit\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {short}\n </a>\n ) : (\n short\n ),\n });\n }\n if (report.ci) {\n items.push({\n label: \"CI\",\n value: report.ci.url ? (\n <a href={report.ci.url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {ciDisplayName(report.ci.name)}\n {report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}\n </a>\n ) : (\n `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}`\n ),\n });\n }\n if (report.ci?.prNumber) {\n const url = prUrl(report.ci);\n const label = `#${report.ci.prNumber}`;\n items.push({\n label: \"PR\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {label}\n </a>\n ) : (\n label\n ),\n });\n }\n\n if (items.length === 0) return null;\n\n return (\n // Run metadata is useful but secondary to \"what failed\" — tuck it into a\n // collapsed disclosure so it doesn't push the result down. Native <details>\n // so it works with no JS (the SSR/no-hydration report still toggles).\n <details data-es-meta-card className=\"es-run-details group rounded-lg border border-border bg-card text-xs\">\n <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\">\n <span aria-hidden className=\"text-xs transition-transform group-open:rotate-90\">▸</span>\n Run details\n </summary>\n <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\">\n {items.map((item) => (\n <div key={item.label} className=\"flex items-baseline gap-1.5\">\n <dt className=\"font-medium\">{item.label}</dt>\n <dd className=\"font-mono text-foreground\">{item.value}</dd>\n </div>\n ))}\n </dl>\n </details>\n );\n}\n","import type { ReportParseError } from \"../result\";\n\nexport interface ReportSchemaErrorProps {\n error: ReportParseError;\n}\n\nexport function ReportSchemaError({ error }: ReportSchemaErrorProps) {\n return (\n <section className=\"es-schema-error\" role=\"alert\" aria-live=\"assertive\">\n <p>\n <strong>Report could not be displayed.</strong>\n </p>\n <p>{error.message}</p>\n {error.code === \"SCHEMA_VERSION_MISMATCH\" ? (\n <p>\n The report bundle is newer than this version of <code>executable-stories-react</code>.\n Upgrade the package, or regenerate the report with an older formatters CLI.\n </p>\n ) : null}\n {error.issues && error.issues.length > 0 ? (\n <details>\n <summary>{error.issues.length} validation issue{error.issues.length === 1 ? \"\" : \"s\"}</summary>\n <pre>\n {error.issues\n .slice(0, 20)\n .map((i) => `${i.path}: ${i.message}`)\n .join(\"\\n\")}\n </pre>\n </details>\n ) : null}\n </section>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportParseError } from \"../result\";\nimport { cn } from \"../lib/utils\";\nimport { ReportSummary } from \"./ReportSummary\";\nimport { ReportMeta } from \"./ReportMeta\";\nimport { ReportSchemaError } from \"./ReportSchemaError\";\n\n/**\n * The report's title block — `<h1>` + summary + meta. Shared by the static\n * `Report` header and the interactive `ReportInteractive` header so the two\n * views can't drift on the no-JS fallback.\n */\nexport function ReportTitleBlock({ title }: { title?: string }) {\n return (\n <>\n <h1>{title ?? \"Story Report\"}</h1>\n <ReportSummary />\n <ReportMeta />\n </>\n );\n}\n\n/**\n * The `<main>` landmark shown when the report failed to parse. Both entrypoints\n * render the identical shell on a `Result` error, so it lives here once.\n */\nexport function ReportErrorShell({\n error,\n className,\n title,\n dataTheme,\n}: {\n error: ReportParseError;\n className?: string;\n title?: string;\n dataTheme?: \"light\" | \"dark\";\n}): ReactNode {\n return (\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <ReportSchemaError error={error} />\n </main>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"../result\";\nimport { unwrapReport } from \"../result\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportRoot } from \"../context/ReportRoot\";\nimport { ReportFeatureList } from \"./ReportFeatureList\";\nimport { ReportEmpty } from \"./ReportEmpty\";\nimport { ReportTitleBlock, ReportErrorShell } from \"./ReportShell\";\nimport { cn } from \"../lib/utils\";\n\nexport interface ReportProps {\n /** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */\n report: StoryReport | Result<StoryReport>;\n /** Renderers keyed by `story.custom({ type })` strings. */\n customRenderers?: CustomRenderers;\n /** Optional overrides for the heavy built-ins (mermaid, code, section). */\n renderers?: BuiltinRenderers;\n /** Optional class on the <main> landmark for layout positioning. */\n className?: string;\n /** Optional override title. */\n title?: string;\n /** Optional theme attribute scope. Use to force \"light\" or \"dark\". */\n dataTheme?: \"light\" | \"dark\";\n}\n\nexport function Report(props: ReportProps) {\n const { report, customRenderers, renderers, className, title, dataTheme } = props;\n const result = unwrapReport(report);\n if (!result.ok) {\n return <ReportErrorShell error={result.error} className={className} title={title} dataTheme={dataTheme} />;\n }\n const data = result.data;\n const hasContent = data.features.length > 0;\n return (\n <ReportRoot report={data} customRenderers={customRenderers} renderers={renderers}>\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <header className=\"es-report-header\">\n <ReportTitleBlock title={title} />\n </header>\n {hasContent ? <ReportFeatureList /> : <ReportEmpty />}\n </main>\n </ReportRoot>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,IAAAA,iBAA8B;AAC9B,oBAAqC;;;ACS9B,IAAM,KAAK,CAAI,UAAwB,EAAE,IAAI,MAAM,KAAK;AASxD,SAAS,aAAa,OAA+D;AAC1F,MACE,OAAO,UAAU,YACjB,UAAU,QACV,QAAQ,SACR,OAAQ,MAA0B,OAAO,WACzC;AACA,WAAO;AAAA,EACT;AACA,SAAO,GAAG,KAAoB;AAChC;;;AC1CA,IAAAC,gBAAwC;;;ACAxC,mBAA8B;AAUvB,IAAM,oBAAgB,4BAAyC,IAAI;;;ACV1E,YAAuB;AACvB,sCAAuC;AACvC,wBAA0B;;;ACF1B,kBAAsC;AACtC,4BAAwB;AAGjB,SAAS,MAAM,QAA8B;AAClD,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;ADAA,IAAM,oBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,WACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,QACF,OAAO;AAAA,QACP,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,QAKN,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK;AAAA,MACP;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,SAAS,MAAM;AAAA,EACb;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,GAKK;AACH,aAAO,6BAAU;AAAA,IACf,gBAAgB;AAAA,IAChB;AAAA,IACA,OAAO;AAAA,MACL,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,MACnD,GAAG;AAAA,IACL;AAAA,EACF,CAAC;AACH;;;AEdI;AA1BG,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAK/B,SAAS,aAAa,OAAqC;AACzD,SAAO,UAAU,WAAW,UAAU,cAAc,UAAU,aAAa,UAAU;AACvF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,IAAI,OAAoC;AAC/C,SAAO,OAAO,UAAU,YAAY,UAAU,KAAK,QAAQ;AAC7D;AAOA,SAAS,eAAe,EAAE,SAAS,GAA0B;AAC3D,MAAI,aAAa,QAAS,QAAO;AACjC,SACE,4CAAC,SAAM,SAAQ,WAAU,WAAU,mDAAkD,gDAErF;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,6CAAC,YAAO,WAAU,QACf;AAAA,aAAS,aAAa,UACrB,6CAAC,gBAAW,WAAU,4CACnB;AAAA,cAAQ,4CAAC,UAAK,WAAU,6CAA6C,iBAAM,IAAU;AAAA,MACtF,4CAAC,kBAAe,UAAoB;AAAA,OACtC,IACE;AAAA,IACH;AAAA,KACH;AAEJ;AAOA,SAAS,YAAY,EAAE,OAAO,GAA2B;AACvD,SACE,4CAAC,SAAM,SAAQ,OAAM,WAAU,eAC5B,kBACH;AAEJ;AAkBO,SAAS,cAAc,MAAyC;AACrE,MAAI,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,KAAK,KAAK,EAAG,QAAO;AAC1D,QAAM,QAAqB,CAAC;AAC5B,aAAW,OAAO,KAAK,OAAO;AAE5B,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,IAAK,OAAM,KAAK,EAAE,MAAM,IAAI,CAAC;AACjC;AAAA,IACF;AACA,QAAI,CAAC,SAAS,GAAG,EAAG;AACpB,UAAM,OAAO,IAAI,IAAI,IAAI;AACzB,QAAI,CAAC,KAAM;AACX,UAAM,KAAK;AAAA,MACT;AAAA,MACA,QAAQ,aAAa,IAAI,MAAM,IAAI,IAAI,SAAS;AAAA,MAChD,MAAM,IAAI,IAAI,IAAI;AAAA,IACpB,CAAC;AAAA,EACH;AACA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,EAAE,OAAO,IAAI,KAAK,KAAK,GAAG,UAAU,IAAI,KAAK,QAAQ,GAAG,MAAM;AACvE;AASA,SAAS,UAAU,OAA8B;AAC/C,QAAM,OAAiB,EAAE,MAAM,IAAI,UAAU,oBAAI,IAAI,EAAE;AACvD,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,KAAK,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AACpD,QAAI,OAAO;AACX,aAAS,QAAQ,CAAC,SAAS,UAAU;AACnC,UAAI,QAAQ,KAAK,SAAS,IAAI,OAAO;AACrC,UAAI,CAAC,OAAO;AACV,gBAAQ,EAAE,MAAM,SAAS,UAAU,oBAAI,IAAI,EAAE;AAC7C,aAAK,SAAS,IAAI,SAAS,KAAK;AAAA,MAClC;AACA,UAAI,UAAU,SAAS,SAAS,EAAG,OAAM,OAAO;AAChD,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAA4B;AAClD,SAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAChD,UAAM,OAAO,EAAE,SAAS,OAAO;AAC/B,UAAM,OAAO,EAAE,SAAS,OAAO;AAC/B,QAAI,SAAS,KAAM,QAAO,OAAO,KAAK;AACtC,WAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,EACpC,CAAC;AACH;AAEA,SAAS,WAAW,EAAE,MAAM,MAAM,GAAsC;AACtE,QAAM,WAAW,eAAe,IAAI;AACpC,SACE,4CAAC,QAAG,WAAW,GAAG,eAAe,QAAQ,KAAK,qCAAqC,GAChF,mBAAS,IAAI,CAAC,UAAU;AACvB,UAAM,QAAQ,MAAM,SAAS,OAAO;AACpC,WACE,6CAAC,QACC;AAAA,mDAAC,SAAI,WAAU,uCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,QAAQ,0BAA0B;AAAA,YACpC;AAAA,YAEC,kBAAQ,GAAG,MAAM,IAAI,MAAM,MAAM;AAAA;AAAA,QACpC;AAAA,QACC,MAAM,MAAM,SAAS,4CAAC,eAAY,QAAQ,MAAM,KAAK,QAAQ,IAAK;AAAA,QAClE,MAAM,MAAM,OACX,4CAAC,UAAK,WAAU,iCAAiC,gBAAM,KAAK,MAAK,IAC/D;AAAA,SACN;AAAA,MACC,QAAQ,4CAAC,cAAW,MAAM,OAAO,OAAO,QAAQ,GAAG,IAAK;AAAA,SAflD,MAAM,IAgBf;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEO,SAAS,cAAc,EAAE,MAAM,GAA+B;AACnE,QAAM,OAAO,cAAc,MAAM,IAAI;AACrC,MAAI,CAAC,KAAM,QAAO,4CAAC,mBAAgB,OAAc;AACjD,SACE,4CAAC,cAAW,OAAO,KAAK,SAAS,iBAAiB,UAAU,KAAK,UAC/D,sDAAC,SAAI,UAAU,GAAG,WAAU,+DAC1B,sDAAC,cAAW,MAAM,UAAU,KAAK,KAAK,GAAG,OAAO,GAAG,GACrD,GACF;AAEJ;AAoBO,SAAS,eAAe,MAA0C;AACvE,MAAI,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,QAAQ,KAAK,MAAM,EAAG,QAAO;AAC3D,QAAM,SAAuB,CAAC;AAC9B,aAAW,OAAO,KAAK,QAAQ;AAC7B,QAAI,CAAC,SAAS,GAAG,EAAG;AACpB,UAAM,OAAO,IAAI,IAAI,IAAI;AACzB,QAAI,CAAC,KAAM;AACX,WAAO,KAAK;AAAA,MACV;AAAA,MACA,MAAM,IAAI,IAAI,IAAI;AAAA,MAClB,MAAM,IAAI,IAAI,IAAI;AAAA,MAClB,QAAQ,aAAa,IAAI,MAAM,IAAI,IAAI,SAAS;AAAA,IAClD,CAAC;AAAA,EACH;AACA,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SAAO;AAAA,IACL,OAAO,IAAI,KAAK,KAAK;AAAA,IACrB,UAAU,IAAI,KAAK,QAAQ;AAAA,IAC3B,MAAM,IAAI,KAAK,IAAI;AAAA,IACnB;AAAA,EACF;AACF;AAEO,SAAS,eAAe,EAAE,MAAM,GAA+B;AACpE,QAAM,OAAO,eAAe,MAAM,IAAI;AACtC,MAAI,CAAC,KAAM,QAAO,4CAAC,mBAAgB,OAAc;AACjD,QAAM,WAAW,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,IAAI;AAC/C,SACE,4CAAC,cAAW,OAAO,KAAK,SAAS,KAAK,QAAQ,cAAc,UAAU,KAAK,UACzE,sDAAC,SAAI,UAAU,GAAG,WAAU,mDAC1B,uDAAC,WAAM,WAAU,kCACf;AAAA,gDAAC,WACC,uDAAC,QAAG,WAAU,eACZ;AAAA,kDAAC,QAAG,OAAM,OAAM,WAAU,4DAA2D,mBAErF;AAAA,MACA,4CAAC,QAAG,OAAM,OAAM,WAAU,4DAA2D,kBAErF;AAAA,MACC,WACC,4CAAC,QAAG,OAAM,OAAM,WAAU,4DAA2D,kBAErF,IACE;AAAA,OACN,GACF;AAAA,IACA,4CAAC,WACE,eAAK,OAAO,IAAI,CAAC,UAChB,6CAAC,QACC;AAAA,kDAAC,QAAG,WAAU,oCACZ,uDAAC,UAAK,WAAU,qCACd;AAAA,oDAAC,UAAK,WAAU,qCAAqC,gBAAM,MAAK;AAAA,QAC/D,MAAM,SAAS,4CAAC,eAAY,QAAQ,MAAM,QAAQ,IAAK;AAAA,SAC1D,GACF;AAAA,MACA,4CAAC,QAAG,WAAU,4EACX,gBAAM,QAAQ,IACjB;AAAA,MACC,WACC,4CAAC,QAAG,WAAU,oDACX,gBAAM,QAAQ,IACjB,IACE;AAAA,SAdG,MAAM,IAef,CACD,GACH;AAAA,KACF,GACF,GACF;AAEJ;AAQA,SAAS,gBAAgB,EAAE,MAAM,GAA+B;AAC9D,SACE,6CAAC,SAAI,WAAU,QAAO,aAAW,MAAM,MACrC;AAAA,iDAAC,OAAE,WAAU,kDACV;AAAA,YAAM;AAAA,MAAK;AAAA,OACd;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,WAAU;AAAA,QAET,wBAAc,MAAM,IAAI;AAAA;AAAA,IAC3B;AAAA,KACF;AAEJ;AAEA,SAAS,cAAc,OAAwB;AAC7C,MAAI;AACF,WAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAOO,IAAM,0BAA0B;AAAA,EACrC,CAAC,cAAc,GAAG,CAAC,UAA2B,4CAAC,iBAAc,OAAc;AAAA,EAC3E,CAAC,eAAe,GAAG,CAAC,UAA2B,4CAAC,kBAAe,OAAc;AAC/E;;;AJvSS,IAAAC,sBAAA;AAnBT,IAAM,kBAAoC,CAAC;AAEpC,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,YAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA;AAAA;AAAA;AAAA,MAIA,iBAAiB,EAAE,GAAG,yBAAyB,GAAG,gBAAgB;AAAA,MAClE,WAAW,aAAa;AAAA,IAC1B;AAAA,IACA,CAAC,QAAQ,iBAAiB,SAAS;AAAA,EACrC;AACA,SAAO,6CAAC,cAAc,UAAd,EAAuB,OAAe,UAAS;AACzD;;;AKjCA,IAAAC,gBAA2B;AAGpB,SAAS,YAAY;AAC1B,QAAM,UAAM,0BAAW,aAAa;AACpC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,IAAI;AACb;;;ACVA,IAAAC,mBAA+B;;;ACwBzB,IAAAC,sBAAA;AAbN,IAAM,qBAAqB;AAEpB,SAAS,oBAAoB,MAAyB;AAC3D,QAAM,UAAU,MAAM,KAAK,KAAK,SAAS,kBAAkB,CAAC;AAC5D,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAqB,CAAC;AAC5B,MAAI,YAAY;AAChB,UAAQ,QAAQ,CAAC,OAAO,MAAM;AAC5B,UAAM,QAAQ,MAAM;AACpB,UAAM,MAAM,QAAQ,MAAM,CAAC,EAAE;AAC7B,QAAI,QAAQ,UAAW,OAAM,KAAK,KAAK,MAAM,WAAW,KAAK,CAAC;AAC9D,UAAM;AAAA,MACJ,6CAAC,UAAa,WAAU,sCACrB,gBAAM,CAAC,KADC,CAEX;AAAA,IACF;AACA,gBAAY;AAAA,EACd,CAAC;AACD,MAAI,YAAY,KAAK,OAAQ,OAAM,KAAK,KAAK,MAAM,SAAS,CAAC;AAC7D,SAAO;AACT;;;AC9BA,6BAGO;AACP,sBAA+B;;;ACJtB,IAAAC,sBAAA;AADF,SAAS,QAAQ,EAAE,MAAM,GAA6B;AAC3D,SAAO,6CAAC,OAAE,WAAU,sCAAsC,gBAAM,MAAK;AACvE;;;ACIU,IAAAC,sBAAA;AALH,SAAS,OAAO,EAAE,MAAM,GAA4B;AACzD,SACE,6CAAC,QAAG,WAAU,+BAA8B,cAAW,QACpD,gBAAM,MAAM,IAAI,CAAC,MAChB,6CAAC,QACC,uDAAC,SAAM,SAAQ,OAAO,aAAE,KADjB,CAET,CACD,GACH;AAEJ;;;ACEI,IAAAC,sBAAA;AAbJ,SAAS,YAAY,OAAwB;AAC3C,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEO,SAAS,MAAM,EAAE,MAAM,GAA2B;AACvD,SACE,8CAAC,QAAG,WAAU,sDACZ;AAAA,iDAAC,QAAG,WAAU,uCAAuC,gBAAM,OAAM;AAAA,IACjE,6CAAC,QAAG,WAAU,6BAA6B,sBAAY,MAAM,KAAK,GAAE;AAAA,KACtE;AAEJ;;;ACpBA,IAAAC,gBAA2B;AAI3B,IAAM,eAAgC,CAAC;AACvC,IAAMC,mBAAoC,CAAC;AAEpC,SAAS,qBAAsC;AACpD,QAAM,UAAM,0BAAW,aAAa;AACpC,SAAO,KAAK,mBAAmB;AACjC;AAEO,SAAS,sBAAwC;AACtD,QAAM,UAAM,0BAAW,aAAa;AACpC,SAAO,KAAK,aAAaA;AAC3B;;;ACHI,IAAAC,sBAAA;AAFG,SAAS,WAAW,EAAE,OAAO,SAAS,GAA4C;AACvF,SACE,8CAAC,YAAO,WAAU,QACf;AAAA,YACC,6CAAC,gBAAW,WAAU,oDAAoD,iBAAM,IAC9E;AAAA,IACJ,6CAAC,SAAI,UAAU,GAAG,WAAU,2CACzB,UACH;AAAA,KACF;AAEJ;AAEO,SAAS,QAAQ,EAAE,MAAM,GAA6B;AAC3D,QAAM,YAAY,oBAAoB;AACtC,MAAI,UAAU,MAAM;AAClB,WAAO,6EAAG,oBAAU,KAAK,KAAK,GAAE;AAAA,EAClC;AACA,SACE,6CAAC,cAAW,OAAO,MAAM,OACvB,uDAAC,UAAK,WAAW,GAAG,qBAAqB,MAAM,QAAQ,YAAY,MAAM,IAAI,EAAE,GAC5E,gBAAM,SACT,GACF;AAEJ;;;AC7BQ,IAAAC,sBAAA;AAJD,SAAS,SAAS,EAAE,MAAM,GAA8B;AAC7D,SACE,8CAAC,YAAO,WAAU,QACf;AAAA,UAAM,QACL,6CAAC,gBAAW,WAAU,oDACnB,gBAAM,OACT,IACE;AAAA,IACJ,6CAAC,SAAI,UAAU,GAAG,WAAU,mDAC1B,wDAAC,WAAM,WAAU,kCACf;AAAA,mDAAC,WACC,uDAAC,QAAG,WAAU,eACX,gBAAM,QAAQ,IAAI,CAAC,MAClB,6CAAC,QAAW,OAAM,OAAM,WAAU,4DAC/B,eADM,CAET,CACD,GACH,GACF;AAAA,MACA,6CAAC,WACE,gBAAM,KAAK,IAAI,CAAC,KAAK,MACpB,6CAAC,QACE,cAAI,IAAI,CAAC,MAAM,MACd,6CAAC,QAAW,WAAU,oDACnB,kBADM,CAET,CACD,KALM,CAMT,CACD,GACH;AAAA,OACF,GACF;AAAA,KACF;AAEJ;;;AChCI,IAAAC,sBAAA;AAFG,SAAS,QAAQ,EAAE,MAAM,GAA6B;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAM,MAAM;AAAA,MACZ,KAAI;AAAA,MACJ,QAAO;AAAA,MAEN,gBAAM;AAAA;AAAA,EACT;AAEJ;;;ACbA,oBAAuB;;;ACOvB,iBAAqD;;;ADQ9C,SAAS,iBAAiB,UAA0B;AACzD,QAAM,MAAM,qBAAO,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AACnD,SAAO,IACJ,QAAQ,uCAAuC,EAAE,EACjD,QAAQ,qCAAqC,EAAE,EAC/C,QAAQ,mDAAmD,EAAE,EAC7D,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,gCAAgC,CAAC,IAAI,MAAM,QAAQ,GAAG,IAAI,KAAK,cAAc,GAAG,CAAC,GAAG,EAC5F,QAAQ,gCAAgC,CAAC,IAAI,MAAM,QAAQ,GAAG,IAAI,KAAK,cAAc,GAAG,CAAC,GAAG;AACjG;AASO,SAAS,OAAO,MAAsB;AAC3C,QAAM,QAAQ,KAAK,QAAQ,OAAO,IAAI,EAAE,MAAM,IAAI;AAClD,QAAM,UAAU,MACb,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC,EACvC,IAAI,CAAC,SAAS,KAAK,SAAS,KAAK,UAAU,EAAE,MAAM;AACtD,QAAM,WAAW,QAAQ,SAAS,IAAI,KAAK,IAAI,GAAG,OAAO,IAAI;AAC7D,SAAO,MACJ,IAAI,CAAC,SAAS,KAAK,MAAM,QAAQ,CAAC,EAClC,KAAK,IAAI,EACT,KAAK;AACV;AAEA,SAAS,cAAc,OAAuB;AAC5C,aAAO,oBAAQ,KAAK,KAAK;AAC3B;;;AE1CW,IAAAC,uBAAA;AAHJ,SAAS,WAAW,EAAE,MAAM,GAAgC;AACjE,QAAM,YAAY,oBAAoB;AACtC,MAAI,UAAU,SAAS;AACrB,WAAO,+EAAG,oBAAU,QAAQ,KAAK,GAAE;AAAA,EACrC;AACA,QAAM,OAAO,iBAAiB,MAAM,QAAQ;AAC5C,SACE,+CAAC,aAAQ,WAAU,gBAAe,cAAY,MAAM,OACjD;AAAA,UAAM,QAAQ,8CAAC,QAAG,WAAU,sCAAsC,gBAAM,OAAM,IAAQ;AAAA,IACvF;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,yBAAyB,EAAE,QAAQ,KAAK;AAAA;AAAA,IAC1C;AAAA,KACF;AAEJ;;;ACPI,IAAAC,uBAAA;AAFG,SAAS,cAAc,EAAE,OAAO,IAAI,GAAwD;AACjG,SACE,+CAAC,YAAO,KAAU,WAAU,QAAO,cAAY,MAAM,SAAS,WAC3D;AAAA,UAAM,QACL,8CAAC,gBAAW,WAAU,oDAAoD,gBAAM,OAAM,IACpF;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC,gBAAY;AAAA,QACZ,UAAU;AAAA,QACV,WAAU;AAAA,QAET,gBAAM;AAAA;AAAA,IACT;AAAA,KACF;AAEJ;AAQO,SAAS,WAAW,EAAE,MAAM,GAAgC;AACjE,QAAM,YAAY,oBAAoB;AACtC,MAAI,UAAU,SAAS;AACrB,WAAO,+EAAG,oBAAU,QAAQ,KAAK,GAAE;AAAA,EACrC;AACA,SAAO,8CAAC,iBAAc,OAAc;AACtC;;;ACvBM,IAAAC,uBAAA;AALC,SAAS,cAAc,EAAE,MAAM,GAAmC;AACvE,QAAM,UAAM,0BAAc,MAAM,IAAI,IAAI,aAAY,yBAAa,MAAM,IAAI;AAE3E,MAAI,CAAC,KAAK;AACR,WACE,+CAAC,YAAO,WAAU,wFAChB;AAAA,oDAAC,SAAI,WAAU,eAAc,oCAAsB;AAAA,MACnD,8CAAC,SAAI,WAAU,oCAAoC,gBAAM,MAAK;AAAA,MAC7D,MAAM,MAAM,8CAAC,gBAAW,WAAU,kBAAkB,gBAAM,KAAI,IAAgB;AAAA,OACjF;AAAA,EAEJ;AAEA,SACE,+CAAC,YAAO,WAAU,QAChB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,KAAK,MAAM,OAAO;AAAA,QAClB,SAAQ;AAAA,QACR,WAAU;AAAA;AAAA,IACZ;AAAA,IACC,MAAM,MAAM,8CAAC,gBAAW,WAAU,wCAAwC,gBAAM,KAAI,IAAgB;AAAA,KACvG;AAEJ;;;ACnBM,IAAAC,uBAAA;AAHC,SAAS,SAAS,EAAE,MAAM,GAA8B;AAC7D,UAAI,0BAAc,MAAM,IAAI,GAAG;AAC7B,WACE,+CAAC,YAAO,WAAU,wFAChB;AAAA,oDAAC,SAAI,WAAU,eAAc,+BAAiB;AAAA,MAC9C,8CAAC,SAAI,WAAU,oCAAoC,gBAAM,MAAK;AAAA,MAC7D,MAAM,UAAU,8CAAC,gBAAW,WAAU,kBAAkB,gBAAM,SAAQ,IAAgB;AAAA,OACzF;AAAA,EAEJ;AAEA,QAAM,UAAM,oBAAQ,MAAM,IAAI;AAC9B,QAAM,aAAS,oBAAQ,MAAM,MAAM;AACnC,SACE,+CAAC,YAAO,WAAU,QAChB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA,QACR,SAAQ;AAAA,QACP,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;AAAA,QACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,QAC5B,WAAU;AAAA;AAAA,IACZ;AAAA,IACC,MAAM,UACL,8CAAC,gBAAW,WAAU,sCAAsC,gBAAM,SAAQ,IACxE;AAAA,KACN;AAEJ;;;ACnBM,IAAAC,uBAAA;AAXC,SAAS,QAAQ,EAAE,MAAM,GAA6B;AAC3D,QAAM,SAAS,OAAO,MAAM,WAAW,WAAW,GAAG,MAAM,MAAM,OAAQ,MAAM,UAAU;AACzF,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,eAAW,oBAAQ,MAAM,OAAO,MAAM,IAAI;AAIhD,QAAM,aAAa,MAAM,YAAY,SAAY,EAAE,QAAQ,MAAM,QAAQ,IAAI,EAAE,KAAK,YAAY,GAAG;AAEnG,SACE,+CAAC,YAAO,WAAU,wDAChB;AAAA,mDAAC,gBAAW,WAAU,8HACpB;AAAA,oDAAC,UAAM,gBAAM,SAAS,QAAO;AAAA,MAC5B,WACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,cAAW;AAAA,UACX,OAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,MAED,IACE;AAAA,OACN;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,SAAQ;AAAA,QACR,SAAQ;AAAA,QACR;AAAA,QACA,WAAU;AAAA,QACV,OAAO,EAAE,OAAO;AAAA;AAAA,IAClB;AAAA,KACF;AAEJ;;;AC7BM,IAAAC,uBAAA;AATC,SAAS,SAAS,EAAE,MAAM,GAA8B;AAC7D,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,UAAU,MAAM,OAAO,MAAM,CAAC,KAAK,OAAO,MAAM,KAAK;AAAA,EACnE,QAAQ;AACN,WAAO,OAAO,MAAM,KAAK;AAAA,EAC3B;AACA,SACE,8CAAC,cAAW,OAAO,MAAM,SAAS,SAChC,wDAAC,UAAK,WAAU,mCAAmC,gBAAK,GAC1D;AAEJ;;;ACbW,IAAAC,uBAAA;AAJJ,SAAS,UAAU,EAAE,MAAM,GAA+B;AAC/D,QAAM,YAAY,mBAAmB;AACrC,QAAM,WAAW,UAAU,MAAM,IAAI;AACrC,MAAI,UAAU;AACZ,WAAO,+EAAG,mBAAS,KAAK,GAAE;AAAA,EAC5B;AACA,SACE,+CAAC,SAAI,WAAU,QAAO,aAAW,MAAM,MACrC;AAAA,kDAAC,OAAE,WAAU,kDAAkD,gBAAM,MAAK;AAAA,IAC1E,8CAAC,SAAI,UAAU,GAAG,WAAU,6EACzB,UAAAC,eAAc,MAAM,IAAI,GAC3B;AAAA,KACF;AAEJ;AAEA,SAASA,eAAc,OAAwB;AAC7C,MAAI;AACF,WAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;;;ACPa,IAAAC,uBAAA;AAHN,SAAS,SAAS,EAAE,MAAM,GAA8B;AAC7D,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,8CAAC,WAAQ,OAAc;AAAA,IAChC,KAAK;AACH,aAAO,8CAAC,UAAO,OAAc;AAAA,IAC/B,KAAK;AACH,aAAO,8CAAC,SAAM,OAAc;AAAA,IAC9B,KAAK;AACH,aAAO,8CAAC,WAAQ,OAAc;AAAA,IAChC,KAAK;AACH,aAAO,8CAAC,YAAS,OAAc;AAAA,IACjC,KAAK;AACH,aAAO,8CAAC,WAAQ,OAAc;AAAA,IAChC,KAAK;AACH,aAAO,8CAAC,cAAW,OAAc;AAAA,IACnC,KAAK;AACH,aAAO,8CAAC,cAAW,OAAc;AAAA,IACnC,KAAK;AACH,aAAO,8CAAC,iBAAc,OAAc;AAAA,IACtC,KAAK;AACH,aAAO,8CAAC,YAAS,OAAc;AAAA,IACjC,KAAK;AACH,aAAO,8CAAC,WAAQ,OAAc;AAAA,IAChC,KAAK;AACH,aAAO,8CAAC,YAAS,OAAc;AAAA,IACjC,KAAK;AACH,aAAO,8CAAC,aAAU,OAAc;AAAA,EACpC;AACF;;;AClCI,IAAAC,uBAAA;AAHG,SAAS,iBAAiB,EAAE,QAAQ,GAA0B;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SACE,+EACG,kBAAQ,IAAI,CAAC,OAAO,MACnB,8CAAC,YAAiB,SAAH,CAAiB,CACjC,GACH;AAEJ;;;AlBsBQ,IAAAC,uBAAA;AAxBR,IAAM,aAAqC;AAAA,EACzC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEA,IAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEO,SAAS,YAAY,EAAE,SAAS,GAAqB;AAC1D,MAAI,SAAS,MAAM,WAAW,EAAG,QAAO;AACxC,QAAM,aAAa,IAAI;AAAA,QACrB,uCAAe,SAAS,KAAK,MAAM,mBAC/B,uCAAe,SAAS,KAAK,EAAE,IAAI,CAAC,SAAS,KAAK,EAAE,IACpD,CAAC;AAAA,EACP;AACA,SACE,8CAAC,QAAG,aAAU,SAAQ,WAAU,iBAC7B,mBAAS,MAAM,IAAI,CAAC,SACnB;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA,MACA,YAAY,WAAW,IAAI,KAAK,EAAE;AAAA;AAAA,IAF7B,KAAK;AAAA,EAGZ,CACD,GACH;AAEJ;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,aAAa;AACf,GAGG;AAGD,QAAM,KAAK,KAAK,QAAQ,YAAY;AACpC,QAAM,eAAe,OAAO,SAAS,OAAO;AAC5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,KAAK;AAAA,MACT,eAAa,KAAK;AAAA,MAClB,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB;AAAA,MAClB;AAAA,MAEA;AAAA,uDAAC,SAAI,WAAU,6BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,eAAW;AAAA,cACX,WAAW;AAAA,gBACT;AAAA,gBACA,iBAAiB,KAAK,MAAM;AAAA,cAC9B;AAAA,cAEC,qBAAW,KAAK,MAAM,KAAK;AAAA;AAAA,UAC9B;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,eAAe,sCAAsC;AAAA,cACvD;AAAA,cAEC,eAAK;AAAA;AAAA,UACR;AAAA,UACA,8CAAC,UAAK,WAAU,0BACb,8BAAoB,KAAK,IAAI,GAChC;AAAA,UACC,aACC,8CAAC,UAAK,WAAU,iHAAgH,0BAEhI,IACE;AAAA,UACH,KAAK,aAAa,IACjB,8CAAC,UAAK,WAAU,+EACb,8CAAe,KAAK,UAAU,GACjC,IACE;AAAA,WACN;AAAA,QACC,KAAK,eACJ;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YAET,eAAK;AAAA;AAAA,QACR,IACE;AAAA,QACH,KAAK,WAAW,SAAS,IACxB,8CAAC,SAAI,gBAAY,MAAC,WAAU,aAC1B,wDAAC,oBAAiB,SAAS,KAAK,YAAY,GAC9C,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;;;AmBhHA,wBAAwC;AAExC,wBAAsC;AAEtC,IAAAC,cAA4C;AAuCxC,IAAAC,uBAAA;AAhCJ,IAAM,cAAsC;AAAA,EAC1C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEA,IAAM,oBAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAgBO,SAAS,iBAAiB,EAAE,SAAS,GAA0B;AACpE,QAAM,aAAS,2CAAwB,QAAQ;AAC/C,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,SACE,+CAAC,aAAQ,aAAU,cAAa,cAAW,cAAa,WAAU,QAChE;AAAA,kDAAC,QAAG,WAAU,8EAA6E,wBAE3F;AAAA,IACA,8CAAC,QAAG,WAAU,+CACX,iBAAO,IAAI,CAAC,UACX,8CAAC,uBAAuC,SAAd,MAAM,MAAsB,CACvD,GACH;AAAA,KACF;AAEJ;AAEA,SAAS,oBAAoB,EAAE,MAAM,GAA+B;AAClE,QAAM,QAAQ,GAAG,MAAM,OAAO,IAAI,MAAM,IAAI;AAC5C,QAAM,YAAY,MAAM,OAAO,SAAS;AACxC,QAAM,UACJ,+CAAC,OAAE,WAAU,kEACX;AAAA,kDAAC,UAAK,eAAW,MAAC,WAAW,GAAG,YAAY,kBAAkB,MAAM,MAAM,CAAC,GACxE,sBAAY,MAAM,MAAM,KAAK,UAChC;AAAA,IACA,+CAAC,UAAK,WAAU,WACd;AAAA,oDAAC,UAAK,WAAU,wCAAwC,gBAAM,SAAQ;AAAA,MAAQ;AAAA,MAC9E,8CAAC,UAAK,WAAU,yBAAyB,gBAAM,YAAY,OAAO,MAAM,MAAK;AAAA,OAC/E;AAAA,KACF;AAEF;AAAA;AAAA;AAAA,IAGE,+CAAC,QAAG,WAAW,GAAG,YAAY,YAAY,SAAS,MAAM,GACtD;AAAA,YAAM,aACL,8CAAC,mBAAgB,OAAc,OAAc,IAC3C;AAAA,MACH,YACC,8CAAC,SAAI,WAAW,GAAG,yBAAyB,MAAM,cAAc,QAAQ,GACrE,gBAAM,OAAO,IAAI,CAAC,MAAM,MACvB,8CAAC,iBAAoC,QAAjB,KAAK,SAAS,CAAe,CAClD,GACH,IACE;AAAA,MACH,MAAM,aACL;AAAA;AAAA;AAAA,QAIA,8CAAC,OAAE,MAAM,IAAI,MAAM,MAAM,IAAI,cAAY,iBAAiB,KAAK,IAAI,WAAU,yBAC1E,mBACH;AAAA;AAAA,OAEJ;AAAA;AAEJ;AAEA,SAAS,gBAAgB,EAAE,OAAO,MAAM,GAA8C;AACpF,QAAM,OAAO,MAAM,YAAY,QAAQ;AACvC,QAAM,UAAM,2BAAc,IAAI,IAAI,aAAY,0BAAa,IAAI;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,IAAI,MAAM,MAAM;AAAA,MACtB,cAAY,iBAAiB,KAAK;AAAA,MAClC,WAAU;AAAA,MAET,gBACC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,KAAK,MAAM,YAAY,OAAO;AAAA,UAC9B,SAAQ;AAAA,UACR,WAAU;AAAA;AAAA,MACZ,IAEA,8CAAC,UAAK,WAAU,sJAAqJ,oCAErK;AAAA;AAAA,EAEJ;AAEJ;AAKA,IAAM,cAA+C;AAAA,EACnD,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,WAAW,OAAwB;AAC1C,MAAI;AACF,WAAO,KAAK,UAAU,OAAO,MAAM,CAAC,KAAK,OAAO,KAAK;AAAA,EACvD,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAQA,SAAS,cAAc,EAAE,KAAK,GAAkC;AAC9D,QAAM,OAAO,WAAW,KAAK,KAAK;AAClC,QAAM,eAAe,KAAK,YAAY;AACtC,SACE,+CAAC,SAAI,aAAU,cAAa,WAAU,+CACpC;AAAA,mDAAC,OAAE,WAAU,yCACX;AAAA,oDAAC,UAAK,WAAU,oHACb,eAAK,SAAS,SACjB;AAAA,MACC,eACC,8CAAC,UAAK,WAAU,gDAA+C,2BAAa,IAC1E;AAAA,OACN;AAAA,IACC,CAAC,iBACC,KAAK,WAAW,KAAK,QAAQ,SAAS,IACrC,8CAAC,QAAG,WAAU,gCACX,eAAK,QAAQ,IAAI,CAAC,QAAQ,MACzB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW;AAAA,UACT;AAAA,UACA,YAAY,OAAO,IAAI;AAAA,QACzB;AAAA,QAEC,uDAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;AAAA;AAAA,MAN7B;AAAA,IAOP,CACD,GACH,IAEA,8CAAC,OAAE,WAAU,gDAA+C,wBAAU;AAAA,IAE1E;AAAA,MAAC;AAAA;AAAA,QAIC,MAAM,gBAAgB,KAAK,UAAU;AAAA,QACrC,WAAW,GAAG,eAAe,WAAW,MAAM;AAAA,QAE9C;AAAA,wDAAC,aAAQ,WAAU,8EAA6E,sBAEhG;AAAA,UACA,8CAAC,SAAI,UAAU,GAAG,WAAU,gGACzB,gBACH;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AC7Kc,IAAAC,uBAAA;AAfP,SAAS,kBAAkB,EAAE,YAAY,GAAwC;AACtF,MAAI,YAAY,WAAW,EAAG,QAAO;AACrC;AAAA;AAAA;AAAA,IAGE,8CAAC,SAAI,MAAK,SAAQ,cAAW,eAAc,WAAU,4BAClD,sBAAY,IAAI,CAAC,KAAK,MAAM;AAC3B,YAAM,UACJ,IAAI,oBAAoB,WACpB,QAAQ,IAAI,SAAS,WAAW,IAAI,IAAI,KACxC,QAAQ,IAAI,SAAS,IAAI,mBAAmB,IAAI,IAAI,CAAC;AAC3D,YAAM,UAAU,IAAI,UAAU,WAAW,QAAQ;AACjD,aACE,8CAAC,YAAgC,WAAU,OACxC,oBACC,gFACE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,IAAI;AAAA,YACT,SAAQ;AAAA,YACR,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,8CAAC,gBAAW,WAAU,sCAAsC,cAAI,MAAK;AAAA,SACvE,IAEA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,UAAU,IAAI;AAAA,UACd,WAAU;AAAA,UAET;AAAA,gBAAI;AAAA,YAAK;AAAA,YAAC,+CAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,cAAE,IAAI;AAAA,cAAU;AAAA,eAAC;AAAA;AAAA;AAAA,MACtE,KAlBS,GAAG,IAAI,IAAI,IAAI,CAAC,EAoB7B;AAAA,IAEJ,CAAC,GACH;AAAA;AAEJ;;;AC5CA,IAAAC,mBAA+B;;;ACqB/B,IAAM,QAAQ,oBAAI,IAAI,CAAC,MAAM,SAAS,OAAO,CAAC;AAC9C,IAAM,aAAa,CAAC,MAAyC,MAAM,IAAI,CAAC,IAAK,IAAiC;AAEvG,SAAS,eAAe,OAA8C;AAC3E,QAAM,MAAwB,CAAC;AAC/B,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,QAAQ,OAAO,KAAK,WAAW,YAAY,OAAO,KAAK,SAAS,SAAU;AAC/E,QAAI;AACJ,QAAI;AACJ,QAAI,KAAK,eAAe,QAAQ,KAAK,cAAc,MAAM;AACvD,oBAAc,KAAK;AACnB,mBAAa,KAAK;AAAA,IACpB,WAAW,KAAK,qBAAqB,QAAQ,KAAK,mBAAmB,MAAM;AACzE,oBAAc,KAAK,oBAAoB;AACvC,oBAAc,KAAK,kBAAkB,KAAK,qBAAqB;AAAA,IACjE,OAAO;AACL;AAAA,IACF;AACA,iBAAa,KAAK,IAAI,GAAG,UAAU;AACnC,QAAI,CAAC,SAAS,WAAW,KAAK,CAAC,SAAS,UAAU,EAAG;AACrD,QAAI,KAAK;AAAA,MACP,QAAQ,KAAK;AAAA,MACb,cAAc,KAAK;AAAA,MACnB,MAAM,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA,QAAQ,WAAW,KAAK,MAAM;AAAA,MAC9B,eAAe,KAAK;AAAA,IACtB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,YAAY,OAAwC;AAClE,QAAM,aAAa,eAAe,KAAK;AACvC,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AAOrC,QAAM,OAAO,oBAAI,IAAkB;AACnC,aAAW,QAAQ,YAAY;AAC7B,QAAI,MAAM,KAAK;AACf,QAAI,SAAS;AACb,WAAO,KAAK,IAAI,GAAG,EAAG,OAAM,GAAG,KAAK,MAAM,QAAQ,QAAQ;AAC1D,SAAK,IAAI,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,IAAI,GAAG,UAAU,CAAC,GAAG,OAAO,EAAE,CAAC;AAAA,EAC1E;AAEA,QAAM,QAAgB,CAAC;AACvB,aAAW,QAAQ,KAAK,OAAO,GAAG;AAChC,UAAM,SAAS,KAAK,KAAK,eAAe,KAAK,IAAI,KAAK,KAAK,YAAY,IAAI;AAC3E,QAAI,UAAU,WAAW,KAAM,QAAO,SAAS,KAAK,IAAI;AAAA,QACnD,OAAM,KAAK,IAAI;AAAA,EACtB;AACA,aAAW,QAAQ,KAAK,OAAO,EAAG,MAAK,SAAS,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW;AACtG,QAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW;AAE5D,QAAM,OAAmB,CAAC;AAC1B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,MAAY,UAAwB;AAChD,QAAI,KAAK,IAAI,KAAK,KAAK,MAAM,EAAG;AAChC,SAAK,IAAI,KAAK,KAAK,MAAM;AACzB,SAAK,KAAK,EAAE,GAAG,KAAK,MAAM,MAAM,CAAC;AACjC,eAAW,SAAS,KAAK,SAAU,MAAK,OAAO,QAAQ,CAAC;AAAA,EAC1D;AACA,aAAW,QAAQ,MAAO,MAAK,MAAM,CAAC;AAEtC,aAAW,QAAQ,KAAK,OAAO,GAAG;AAChC,QAAI,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM,EAAG,MAAK,MAAM,CAAC;AAAA,EAC/C;AACA,SAAO;AACT;AAOO,SAAS,YAAY,MAAwC;AAClE,MAAI,MAAM;AACV,MAAI,MAAM;AACV,aAAW,KAAK,MAAM;AACpB,UAAM,KAAK,IAAI,KAAK,EAAE,WAAW;AACjC,UAAM,KAAK,IAAI,KAAK,EAAE,cAAc,EAAE,UAAU;AAAA,EAClD;AACA,QAAM,QAAQ,MAAM;AACpB,SAAO,EAAE,YAAY,SAAS,GAAG,IAAI,MAAM,GAAG,SAAS,QAAQ,IAAI,QAAQ,EAAE;AAC/E;;;ADxFM,IAAAC,uBAAA;AAnBN,IAAM,YAAoC;AAAA,EACxC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AACT;AAOO,SAAS,YAAY,EAAE,MAAM,GAA+C;AACjF,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AACzC,QAAM,OAAO,YAAY,KAAK;AAC9B,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,EAAE,YAAY,QAAQ,IAAI,YAAY,IAAI;AAEhD,SACE,+CAAC,aAAQ,WAAU,oDACjB;AAAA,mDAAC,aAAQ,WAAU,sEAAqE;AAAA;AAAA,MAC9E,KAAK;AAAA,MAAO;AAAA,MAAM,KAAK,WAAW,IAAI,KAAK;AAAA,MAAI;AAAA,UAAG,iCAAe,OAAO;AAAA,MAAE;AAAA,OACpF;AAAA,IACA,8CAAC,QAAG,WAAU,8DACX,eAAK,IAAI,CAAC,KAAK,MAAM;AACpB,YAAM,WAAY,IAAI,cAAc,cAAc,UAAW;AAC7D,YAAM,WAAW,KAAK,IAAK,IAAI,aAAa,UAAW,KAAK,GAAG;AAC/D,aACE,+CAAC,QAA8B,WAAU,2BACvC;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,aAAa,GAAG,IAAI,QAAQ,EAAE,KAAK;AAAA,YAC5C,OAAO,IAAI,gBAAgB,GAAG,IAAI,IAAI,KAAK,IAAI,aAAa,KAAK,IAAI;AAAA,YAEpE,cAAI;AAAA;AAAA,QACP;AAAA,QACA,8CAAC,UAAK,WAAU,uEACd;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,oCAAoC,UAAU,IAAI,MAAM,CAAC;AAAA,YACvE,OAAO,EAAE,MAAM,GAAG,OAAO,KAAK,OAAO,GAAG,QAAQ,IAAI;AAAA;AAAA,QACtD,GACF;AAAA,QACA,8CAAC,UAAK,WAAU,kDACb,+CAAe,IAAI,UAAU,GAChC;AAAA,WAhBO,GAAG,IAAI,MAAM,IAAI,CAAC,EAiB3B;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;;;AErDA,IAAAC,gBAA0C;AAQ1C,IAAM,6BAAyB,6BAAyC,IAAI;AAErE,IAAM,0BAA0B,uBAAuB;AAEvD,SAAS,qBAAgD;AAC9D,aAAO,0BAAW,sBAAsB;AAC1C;;;ACOO,SAAS,cAAc,SAA6D;AACzF,QAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACvC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,QAAQ;AACZ,WAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,KAAK,QAAQ,CAAC,EAAG,WAAW,KAAK,QAAQ,IAAK;AACpF,SAAO,EAAE,QAAQ,KAAK,QAAQ,MAAM;AACtC;AAEA,IAAM,cAAiD;AAAA,EACrD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAGO,SAAS,mBAAmB,SAA8C;AAC/E,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE;AAC5D,QAAM,OAAO,GAAG,MAAM,IAAI,QAAQ,MAAM;AACxC,QAAM,SAAS,cAAc,OAAO;AACpC,MAAI,CAAC,UAAU,QAAQ,SAAS,EAAG,QAAO;AAC1C,SAAO,GAAG,IAAI,SAAM,YAAY,OAAO,MAAM,CAAC,iBAAiB,OAAO,UAAU,IAAI,QAAQ,GAAG,OAAO,KAAK,OAAO;AACpH;AASA,IAAM,wBAAwB;AAOvB,SAAS,YAAY,SAAsD;AAChF,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE,WAAW,QAAQ;AACtF,MAAI,UAAU,SAAS,sBAAuB,QAAO;AAErD,MAAI,cAAc;AAClB,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,QAAI,UAAU,CAAC,EAAG,WAAW,UAAU,IAAI,CAAC,EAAG,OAAQ;AAAA,EACzD;AACA,QAAM,kBAAkB,eAAe,UAAU,SAAS;AAC1D,QAAM,cAAc,UAAU,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE,SAAS,UAAU;AAEtF,MAAI,kBAAkB,OAAQ,kBAAkB,OAAO,cAAc,IAAM,QAAO;AAClF,MAAI,kBAAkB,OAAO,cAAc,IAAK,QAAO;AACvD,SAAO;AACT;;;ACpCI,IAAAC,uBAAA;AAjCJ,IAAM,WAAW;AAEjB,IAAM,YAA+C;AAAA,EACnD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,SAAS,GAA6B;AAC7C,QAAM,QAAQ,CAAC,IAAI,KAAK,EAAE,SAAS,EAAE,eAAe,GAAG,EAAE,MAAM;AAC/D,MAAI,EAAE,UAAW,OAAM,KAAK,EAAE,UAAU,MAAM,GAAG,CAAC,CAAC;AACnD,SAAO,MAAM,KAAK,QAAK;AACzB;AAQO,SAAS,mBAAmB,EAAE,WAAW,GAA2B;AACzE,QAAM,UAAU,mBAAmB;AACnC,QAAM,UAAU,UAAU,UAAU;AACpC,MAAI,CAAC,WAAW,QAAQ,SAAS,EAAG,QAAO;AAE3C,QAAM,SAAS,QAAQ,MAAM,CAAC,QAAQ;AAGtC,QAAM,QAAQ,YAAY,MAAM,MAAM;AACtC,QAAM,UAAU,QAAQ,GAAG,mBAAmB,MAAM,CAAC,gBAAa,mBAAmB,MAAM;AAE3F,SACE,gFACG;AAAA,YACC,8CAAC,SAAM,SAAQ,WAAU,cAAW,2CAA0C,OAAO,SAAS,mBAE9F,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY,gBAAgB,OAAO;AAAA,QACnC,OAAO;AAAA,QACP,WAAU;AAAA,QAET,iBAAO,IAAI,CAAC,GAAG,MACd;AAAA,UAAC;AAAA;AAAA,YAEC,eAAW;AAAA,YACX,OAAO,SAAS,CAAC;AAAA,YACjB,WAAW;AAAA,cACT;AAAA,cACA,UAAU,EAAE,MAAM;AAAA;AAAA;AAAA;AAAA,cAIlB,MAAM,OAAO,SAAS,KAAK;AAAA,YAC7B;AAAA;AAAA,UAVK,GAAG,EAAE,SAAS,IAAI,CAAC;AAAA,QAW1B,CACD;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;;;ACnEA,IAAAC,gBAAoC;;;ACmC7B,SAAS,kBAAkB,QAAgB,OAAuB;AACvE,QAAM,UAAU,KAAK,IAAI,GAAG,QAAQ,MAAM;AAC1C,QAAM,UAAU,KAAK,MAAM,UAAU,GAAM;AAC3C,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO,UAAU,YAAY,IAAI,KAAK,GAAG;AACrE,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,GAAI,QAAO,GAAG,KAAK,QAAQ,UAAU,IAAI,KAAK,GAAG;AAC7D,QAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,SAAO,GAAG,IAAI,OAAO,SAAS,IAAI,KAAK,GAAG;AAC5C;AAMO,SAAS,cACd,WACA,gBACA,OACS;AACT,MAAI,cAAc,UAAa,kBAAkB,EAAG,QAAO;AAC3D,SAAO,QAAQ,aAAa,iBAAiB;AAC/C;AAQA,IAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,IAAI;AACN;AAEO,SAAS,cAAc,MAAsB;AAClD,SAAO,iBAAiB,IAAI,KAAK;AACnC;AASO,SAAS,UAAU,IAA0B,KAA6C;AAC/F,QAAM,YAAY,IAAI,aAAa;AACnC,MAAI,CAAC,IAAI,OAAO,CAAC,UAAW,QAAO;AAEnC,QAAM,SAAS,GAAG,IAAI,MAAM,oDAAoD;AAChF,MAAI,OAAQ,QAAO,GAAG,OAAO,CAAC,CAAC,WAAW,SAAS;AAEnD,QAAM,SAAS,GAAG,IAAI,MAAM,kCAAkC;AAC9D,MAAI,OAAQ,QAAO,GAAG,OAAO,CAAC,CAAC,aAAa,SAAS;AAErD,SAAO;AACT;AAMO,SAAS,MAAM,IAA8C;AAClE,MAAI,CAAC,IAAI,OAAO,CAAC,GAAG,SAAU,QAAO;AACrC,QAAM,SAAS,GAAG,IAAI,MAAM,oDAAoD;AAChF,MAAI,OAAQ,QAAO,GAAG,OAAO,CAAC,CAAC,SAAS,GAAG,QAAQ;AACnD,SAAO;AACT;;;AC7GA,IAAAC,gBAA0C;AAiB1C,IAAM,+BAA2B,6BAAwC,IAAI;AAEtE,IAAM,4BAA4B,yBAAyB;AAE3D,SAAS,uBAAiD;AAC/D,aAAO,0BAAW,wBAAwB;AAC5C;;;AFaI,IAAAC,uBAAA;AAlBG,SAAS,kBAAkB,EAAE,SAAS,GAA2C;AACtF,QAAM,YAAY,qBAAqB;AACvC,QAAM,WAAW,WAAW;AAC5B,QAAM,CAAC,KAAK,MAAM,QAAI,wBAA6B,QAAQ;AAE3D,+BAAU,MAAM;AACd,QAAI,aAAa,OAAW,QAAO,KAAK,IAAI,CAAC;AAAA,EAC/C,GAAG,CAAC,QAAQ,CAAC;AAEb,MAAI,CAAC,aAAa,QAAQ,OAAW,QAAO;AAI5C,QAAM,cAAc,SAAS;AAC7B,MAAI,CAAC,eAAe,eAAe,EAAG,QAAO;AAC7C,MAAI,CAAC,cAAc,aAAa,UAAU,gBAAgB,GAAG,EAAG,QAAO;AAEvE,SACE,+CAAC,SAAM,SAAQ,WAAU,cAAW,sBAAqB;AAAA;AAAA,IAC7C,kBAAkB,aAAa,GAAG;AAAA,KAC9C;AAEJ;;;AGxCA,IAAAC,gBAAiE;AAYjE,IAAM,sBAAkB,6BAAkC,IAAI;AAEvD,IAAM,mBAAmB,gBAAgB;AAEzC,SAAS,cAAkC;AAChD,aAAO,0BAAW,eAAe;AACnC;;;AClBA,IAAAC,gBAA0C;AAM1C,+BAA6D;AAY7D,IAAM,6BAAyB,6BAAsC,IAAI;AAClE,IAAM,0BAA0B,uBAAuB;AACvD,SAAS,qBAA6C;AAC3D,aAAO,0BAAW,sBAAsB;AAC1C;;;ACxBA,IAAAC,SAAuB;AAMnB,IAAAC,uBAAA;AAFJ,SAAS,KAAK,EAAE,WAAW,GAAG,MAAM,GAAgC;AAClE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAgC;AACxE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAmCA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAgC;AACzE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,QAAQ,SAAS;AAAA,MAC9B,GAAG;AAAA;AAAA,EACN;AAEJ;;;ACrEA,IAAAC,SAAuB;AACvB,kBAAsC;AACtC,0BAA0B;AAQjB,IAAAC,uBAAA;AAJT,IAAM,cACJ;AAEF,SAAS,aAAa,OAAwD;AAC5E,SAAO,8CAAC,YAAAC,KAAc,MAAd,EAAmB,aAAU,iBAAiB,GAAG,OAAO;AAClE;AAEA,SAAS,oBACP,OACA;AACA,SAAO,8CAAC,YAAAA,KAAc,SAAd,EAAsB,aAAU,yBAAyB,GAAG,OAAO;AAC7E;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,GAAG;AACL,GAGG;AACD,SACE,8CAAC,YAAAA,KAAc,QAAd,EACC;AAAA,IAAC,YAAAA,KAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAU;AAAA,MACV;AAAA,MACA;AAAA,MAEA;AAAA,QAAC,YAAAA,KAAc;AAAA,QAAd;AAAA,UACC,aAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,UACC,GAAG;AAAA;AAAA,MACN;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA,GAAG;AACL,GAAoD;AAClD,SACE;AAAA,IAAC,YAAAA,KAAc;AAAA,IAAd;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,SAAS;AAAA,MACnC,GAAG;AAAA;AAAA,EACN;AAEJ;;;AlC3CA,IAAAC,uBAAyE;AA4D7D,IAAAC,uBAAA;AA9BZ,IAAM,cAA0C;AAAA,EAC9C,QAAQ,EAAE,OAAO,UAAU,OAAO,UAAK,YAAY,aAAa,cAAc,UAAU,UAAU,MAAM;AAAA,EACxG,QAAQ,EAAE,OAAO,UAAU,OAAO,UAAK,YAAY,aAAa,cAAc,UAAU,UAAU,KAAK;AAAA,EACvG,SAAS,EAAE,OAAO,WAAW,OAAO,UAAK,YAAY,aAAa,cAAc,WAAW,UAAU,KAAK;AAAA,EAC1G,SAAS,EAAE,OAAO,WAAW,OAAO,UAAK,YAAY,aAAa,cAAc,WAAW,UAAU,KAAK;AAC5G;AAEO,SAAS,eAAe,EAAE,UAAU,YAAY,MAAM,GAAwB;AACnF,QAAM,UAAU,GAAG,SAAS,EAAE;AAC9B,QAAM,SAAS,GAAG,SAAS,EAAE;AAC7B,QAAM,OAAO,YAAY,SAAS,MAAM;AAGxC,QAAM,QAAQ,SAAS,UAAU,YAAY,KAAK;AAClD,QAAM,WAAW,YAAY;AAC7B,QAAM,cAAc,aAAa,QAAQ,CAAC;AAC1C,QAAM,YAAY,cAAc,SAAU,YAAY,SAAS,EAAE,IAAI;AACrE,QAAM,UAAU,mBAAmB;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,SAAS;AAAA,MACb,eAAa,SAAS;AAAA,MACrB,GAAI,YACD,EAAE,cAAc,GAAG,SAAS,KAAK,KAAK,KAAK,GAAG,IAC9C,EAAE,mBAAmB,QAAQ;AAAA,MACjC,WAAU;AAAA,MAEV;AAAA,uDAAC,cAAW,WAAU,aACpB;AAAA,yDAAC,SAAI,WAAW,GAAG,0BAA0B,YAAY,gBAAgB,iBAAiB,GACvF;AAAA,wBAAY,OACX,+CAAC,QAAG,IAAI,SAAS,WAAU,+DACxB;AAAA,4BACC;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,MAAM,SAAU,OAAO,SAAS,EAAE;AAAA,kBAC3C,iBAAe,CAAC;AAAA,kBAChB,iBAAe;AAAA,kBACf,cAAY,UAAU,SAAS,KAAK;AAAA,kBACpC,WAAU;AAAA,kBAEV,wDAAC,UAAK,eAAW,MAAC,WAAW,GAAG,6CAA6C,CAAC,aAAa,WAAW,GAAG,oBAAC;AAAA;AAAA,cAC5G,IACE;AAAA,cACJ,8CAAC,UAAK,eAAW,MAAC,WAAW,GAAG,wBAAwB,KAAK,UAAU,GACpE,eAAK,OACR;AAAA,cACA,8CAAC,UAAM,mBAAS,OAAM;AAAA,eACxB;AAAA,YAEF,+CAAC,SAAI,WAAU,oCACb;AAAA,4DAAC,sBAAmB,YAAY,SAAS,IAAI;AAAA,cAC7C,8CAAC,qBAAkB,UAAoB;AAAA,cACtC,SAAS,aAAa,IACrB,8CAAC,UAAK,WAAU,sEACb,+CAAe,SAAS,UAAU,GACrC,IACE;AAAA,cACH,KAAK,WACJ,8CAAC,SAAM,SAAS,KAAK,cAAc,cAAY,WAAW,KAAK,IAC5D,iBACH,IAEA,8CAAC,UAAK,WAAU,WAAW,qBAAW,KAAK,IAAG;AAAA,cAE/C,UACC,+CAAC,gBACC;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,cAAY,eAAe,SAAS,KAAK;AAAA,oBACzC,WAAU;AAAA,oBAEV,wDAAC,2CAAmB,eAAW,MAAC;AAAA;AAAA,gBAClC;AAAA,gBACA,+CAAC,uBAAoB,OAAM,OACzB;AAAA,iEAAC,oBAAiB,SAAS,MAAM,QAAQ,SAAS,QAAQ,GACxD;AAAA,kEAAC,iCAAS;AAAA,oBAAE;AAAA,qBACd;AAAA,kBACA,+CAAC,oBAAiB,SAAS,MAAM,QAAQ,aAAa,QAAQ,GAC5D;AAAA,kEAAC,qCAAa;AAAA,oBAAE;AAAA,qBAClB;AAAA,kBACA,+CAAC,oBAAiB,SAAS,MAAM,QAAQ,WAAW,QAAQ,GAC1D;AAAA,kEAAC,qCAAa;AAAA,oBAAE;AAAA,qBAClB;AAAA,mBACF;AAAA,iBACF,IACE;AAAA,eACN;AAAA,aACF;AAAA,UACC,SAAS,KAAK,SAAS,MAAM,SAAS,SAAS,UAAU,KAAK,IAC7D,+CAAC,QAAG,cAAW,oBAAmB,WAAU,0BACzC;AAAA,qBAAS,KAAK,IAAI,CAAC,MAClB,8CAAC,QACC,wDAAC,SAAM,SAAQ,OAAO,aAAE,KADjB,OAAO,CAAC,EAEjB,CACD;AAAA,aACC,SAAS,WAAW,CAAC,GAAG,IAAI,CAAC,WAC7B,8CAAC,QACE,iBAAO,MACN,8CAAC,OAAE,MAAM,OAAO,KAAK,QAAO,UAAS,KAAI,uBACvC,wDAAC,SAAM,SAAQ,WAAW,iBAAO,IAAG,GACtC,IAEA,8CAAC,SAAM,SAAQ,WAAW,iBAAO,IAAG,KAN/B,UAAU,OAAO,EAAE,EAQ5B,CACD;AAAA,aACH,IACE;AAAA,WACN;AAAA,QACA,+CAAC,eAAY,IAAI,QAAQ,QAAQ,WAAW,WAAU,kBACnD;AAAA,mBAAS,eACR;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cAET,mBAAS;AAAA;AAAA,UACZ,IACE;AAAA,UACJ,8CAAC,oBAAiB,UAAoB;AAAA,UACtC,8CAAC,eAAY,UAAoB;AAAA,UAChC,SAAS,WAAW,SAAS,IAC5B,8CAAC,SAAI,gBAAY,MAAC,WAAU,QAC1B,wDAAC,oBAAiB,SAAS,SAAS,YAAY,GAClD,IACE;AAAA,UACJ,8CAAC,qBAAkB,aAAa,SAAS,aAAa;AAAA,UACtD,8CAAC,eAAY,OAAO,SAAS,WAAW;AAAA,WAC1C;AAAA;AAAA;AAAA,EACF;AAEJ;;;AmCzKI,IAAAC,uBAAA;AAFG,SAAS,mBAAmB,EAAE,QAAQ,GAA4B;AACvE,SACE,+EACG,kBAAQ,UAAU,IAAI,CAAC,aACtB,8CAAC,kBAAiC,YAAb,SAAS,EAAwB,CACvD,GACH;AAEJ;;;ACQQ,IAAAC,uBAAA;AARD,SAAS,mBAAmB,EAAE,QAAQ,GAA4B;AACvE,QAAM,eAAe,QAAQ,QAAQ,WAAW,KAAK,CAAC;AACtD,QAAM,cAAc,QAAQ,QAAQ,UAAU,MAAM;AACpD,MAAI,CAAC,gBAAgB,CAAC,YAAa,QAAO;AAE1C,SACE,+CAAC,SAAI,WAAU,6DACZ;AAAA,mBACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,yBAAyB,EAAE,QAAQ,iBAAiB,OAAO,QAAQ,SAAU,CAAC,EAAE;AAAA;AAAA,IAClF,IACE;AAAA,IAEH,cACC,8CAAC,QAAG,WAAU,gBAAe,cAAW,YACrC,kBAAQ,SAAU,IAAI,CAAC,UACtB,+CAAC,SAAqB,WAAU,kCAC9B;AAAA,oDAAC,QAAG,WAAU,+BAA+B,gBAAM,MAAK;AAAA,MACxD,8CAAC,QAAG,WAAU,gCAAgC,gBAAM,YAAW;AAAA,SAFvD,MAAM,IAGhB,CACD,GACH,IACE;AAAA,KACN;AAEJ;AAUO,SAAS,iBAAiB,MAA4C;AAC3E,MAAI,SAAS,UAAW,QAAO;AAC/B,MAAI,SAAS,gBAAiB,QAAO;AACrC,MAAI,SAAS,UAAW,QAAO;AAC/B,SAAO;AACT;;;AChBc,IAAAC,uBAAA;AAvBP,SAAS,cAAc,EAAE,QAAQ,GAAuB;AAC7D,QAAM,UAAU,GAAG,QAAQ,EAAE;AAC7B,QAAM,SAAS,GAAG,QAAQ,EAAE;AAC5B,QAAM,IAAI,QAAQ;AAClB,QAAM,UAAU,EAAE,UAAU,EAAE;AAC9B,QAAM,WAAW,YAAY;AAC7B,QAAM,YAAY,UAAU,YAAY,QAAQ,EAAE,KAAK;AACvD,QAAM,YAAY,iBAAiB,QAAQ,IAAI;AAC/C;AAAA;AAAA;AAAA,IAGE;AAAA,MAAC;AAAA;AAAA,QACC,IAAI,QAAQ;AAAA,QACZ,aAAU;AAAA,QACV,mBAAiB;AAAA,QACjB,WAAU;AAAA,QAEV;AAAA,yDAAC,SAAI,WAAU,oEACb;AAAA,2DAAC,SAAI,WAAU,WAGb;AAAA,4DAAC,QAAG,IAAI,SAAS,WAAU,0DACxB,qBACC;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,MAAM,SAAS,OAAO,QAAQ,EAAE;AAAA,kBACzC,iBAAe,CAAC;AAAA,kBAChB,iBAAe;AAAA,kBACf,WAAU;AAAA,kBAEV;AAAA,kEAAC,UAAK,eAAW,MAAC,WAAW,GAAG,+DAA+D,CAAC,aAAa,WAAW,GAAG,oBAAC;AAAA,oBAC5H,8CAAC,UAAK,WAAU,YAAY,kBAAQ,OAAM;AAAA;AAAA;AAAA,cAC5C,IAEA,QAAQ,OAEZ;AAAA,cACA,+CAAC,OAAE,WAAW,GAAG,gEAAgE,YAAY,MAAM,GAChG;AAAA,4BACC,8CAAC,UAAK,WAAU,0EACb,qBACH,IACE;AAAA,gBACJ,8CAAC,UAAK,WAAU,sBAAsB,kBAAQ,YAAW;AAAA,iBAC3D;AAAA,eACF;AAAA,YAGA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,cAAY,GAAG,EAAE,MAAM,YAAY,EAAE,MAAM,YAAY,OAAO;AAAA,gBAE9D;AAAA,iEAAC,UAAM;AAAA,sBAAE;AAAA,oBAAO;AAAA,qBAAO;AAAA,kBACvB,8CAAC,UAAK,eAAW,MAAC,kBAAC;AAAA,kBACnB,+CAAC,UAAK,WAAW,GAAG,EAAE,SAAS,KAAK,uBAAuB,GAAI;AAAA,sBAAE;AAAA,oBAAO;AAAA,qBAAO;AAAA,kBAC9E,UAAU,IACT,gFACE;AAAA,kEAAC,UAAK,eAAW,MAAC,kBAAC;AAAA,oBACnB,+CAAC,UAAM;AAAA;AAAA,sBAAQ;AAAA,uBAAQ;AAAA,qBACzB,IACE;AAAA;AAAA;AAAA,YACN;AAAA,aACF;AAAA,UACA,+CAAC,SAAI,IAAI,QAAQ,QAAQ,WAAW,WAAU,uBAC5C;AAAA,0DAAC,sBAAmB,SAAkB;AAAA,YACtC,8CAAC,sBAAmB,SAAkB;AAAA,aACxC;AAAA;AAAA;AAAA,IACF;AAAA;AAEJ;;;AC5EQ,IAAAC,uBAAA;AAPD,SAAS,oBAAoB;AAClC,QAAM,SAAS,UAAU;AAGzB,SACE,8CAAC,SAAI,WAAU,uBACZ,iBAAO,SAAS,IAAI,CAAC,YACpB,8CAAC,iBAA+B,WAAZ,QAAQ,EAAsB,CACnD,GACH;AAEJ;;;ACdA,IAAAC,mCAAuC;AAMnC,IAAAC,uBAAA;AAFJ,SAAS,MAAM,EAAE,WAAW,GAAG,MAAM,GAAgC;AACnE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAgC;AACzE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAM,yBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAiBA,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAgC;AACxE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,sCAAsC,SAAS;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;;;AC1DQ,IAAAC,uBAAA;AAJD,SAAS,YAAY,EAAE,QAAQ,GAAqB;AACzD,SACE,8CAAC,SAAM,aAAU,UAAS,WAAU,UAClC,wDAAC,eACC,wDAAC,cAAY,qBAAW,gCAA+B,GACzD,GACF;AAEJ;;;ACHI,IAAAC,uBAAA;AAHG,SAAS,cAAc,EAAE,UAAU,GAAuB;AAC/D,QAAM,SAAS,UAAU;AACzB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,OAAO;AAAA,MACf,GAAI,cAAc,UAAa,EAAE,UAAU;AAAA,MAC5C,WAAU;AAAA;AAAA,EACZ;AAEJ;AAeA,IAAM,OAAO;AAAA,EACX,OAAO,EAAE,KAAK,mBAAmB,KAAK,yBAAyB;AAAA,EAC/D,QAAQ,EAAE,KAAK,aAAa,KAAK,UAAU;AAAA,EAC3C,QAAQ,EAAE,KAAK,aAAa,KAAK,UAAU;AAAA,EAC3C,SAAS,EAAE,KAAK,aAAa,KAAK,UAAU;AAAA,EAC5C,SAAS,EAAE,KAAK,aAAa,KAAK,UAAU;AAC9C;AAEO,SAAS,kBAAkB,EAAE,SAAS,WAAW,UAAU,GAA2B;AAC3F,QAAM,QAA4E;AAAA,IAChF,EAAE,QAAQ,SAAS,OAAO,SAAS,OAAO,QAAQ,MAAM;AAAA,IACxD,EAAE,QAAQ,UAAU,OAAO,UAAU,OAAO,QAAQ,OAAO;AAAA,IAC3D,EAAE,QAAQ,UAAU,OAAO,UAAU,OAAO,QAAQ,OAAO;AAAA,IAC3D,EAAE,QAAQ,WAAW,OAAO,WAAW,OAAO,QAAQ,QAAQ;AAAA,EAChE;AACA,MAAI,QAAQ,UAAU,GAAG;AACvB,UAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,WAAW,OAAO,QAAQ,QAAQ,CAAC;AAAA,EAC5E;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA;AAAA;AAAA,QAGA,MAAM,WAAW,IAAI,mBAAmB;AAAA,QACxC;AAAA,MACF;AAAA,MACA,cAAY;AAAA,MAEX,gBAAM,IAAI,CAAC,MAAM;AAChB,cAAM,OAAO,KAAK,EAAE,MAAM;AAC1B,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,eAAa,EAAE;AAAA,YACf,WAAU;AAAA,YAEV;AAAA,6DAAC,QAAG,WAAU,8GACZ;AAAA,8DAAC,UAAK,WAAW,GAAG,kCAAkC,KAAK,GAAG,GAAG,eAAY,QAAO;AAAA,gBACnF,EAAE;AAAA,iBACL;AAAA,cACA,8CAAC,QAAG,WAAW,GAAG,wEAAwE,KAAK,GAAG,GAC/F,YAAE,OACL;AAAA;AAAA;AAAA,UAVK,EAAE;AAAA,QAWT;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;;;ACjFA,IAAAC,mBAA+B;AAmCvB,IAAAC,uBAAA;AAzBD,SAAS,aAAa;AAC3B,QAAM,SAAS,UAAU;AAEzB,QAAM,QAA0D,CAAC;AACjE,QAAM,YAAY;AAElB,MAAI,OAAO,aAAa;AACtB,UAAM,KAAK,EAAE,OAAO,WAAW,OAAO,IAAI,KAAK,OAAO,WAAW,EAAE,eAAe,EAAE,CAAC;AAAA,EACvF;AACA,MAAI,OAAO,YAAY;AACrB,UAAM,KAAK,EAAE,OAAO,YAAY,WAAO,iCAAe,OAAO,UAAU,EAAE,CAAC;AAAA,EAC5E;AACA,MAAI,OAAO,gBAAgB;AACzB,UAAM,KAAK,EAAE,OAAO,WAAW,OAAO,OAAO,eAAe,CAAC;AAAA,EAC/D;AACA,MAAI,OAAO,IAAI,QAAQ;AACrB,UAAM,KAAK,EAAE,OAAO,UAAU,OAAO,OAAO,GAAG,OAAO,CAAC;AAAA,EACzD;AACA,QAAM,MAAM,OAAO,IAAI,aAAa,OAAO;AAC3C,MAAI,KAAK;AACP,UAAM,MAAM,UAAU,OAAO,IAAI,OAAO,MAAM;AAC9C,UAAM,QAAQ,IAAI,MAAM,GAAG,CAAC;AAC5B,UAAM,KAAK;AAAA,MACT,OAAO;AAAA,MACP,OAAO,MACL,8CAAC,OAAE,MAAM,KAAK,QAAO,UAAS,KAAI,uBAAsB,WAAW,WAChE,iBACH,IAEA;AAAA,IAEJ,CAAC;AAAA,EACH;AACA,MAAI,OAAO,IAAI;AACb,UAAM,KAAK;AAAA,MACT,OAAO;AAAA,MACP,OAAO,OAAO,GAAG,MACf,+CAAC,OAAE,MAAM,OAAO,GAAG,KAAK,QAAO,UAAS,KAAI,uBAAsB,WAAW,WAC1E;AAAA,sBAAc,OAAO,GAAG,IAAI;AAAA,QAC5B,OAAO,GAAG,cAAc,KAAK,OAAO,GAAG,WAAW,KAAK;AAAA,SAC1D,IAEA,GAAG,cAAc,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,cAAc,KAAK,OAAO,GAAG,WAAW,KAAK,EAAE;AAAA,IAEhG,CAAC;AAAA,EACH;AACA,MAAI,OAAO,IAAI,UAAU;AACvB,UAAM,MAAM,MAAM,OAAO,EAAE;AAC3B,UAAM,QAAQ,IAAI,OAAO,GAAG,QAAQ;AACpC,UAAM,KAAK;AAAA,MACT,OAAO;AAAA,MACP,OAAO,MACL,8CAAC,OAAE,MAAM,KAAK,QAAO,UAAS,KAAI,uBAAsB,WAAW,WAChE,iBACH,IAEA;AAAA,IAEJ,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B;AAAA;AAAA;AAAA;AAAA,IAIE,+CAAC,aAAQ,qBAAiB,MAAC,WAAU,wEACnC;AAAA,qDAAC,aAAQ,WAAU,iJACjB;AAAA,sDAAC,UAAK,eAAW,MAAC,WAAU,qDAAoD,oBAAC;AAAA,QAAO;AAAA,SAE1F;AAAA,MACA,8CAAC,QAAG,WAAU,yFAAwF,cAAW,gBAC9G,gBAAM,IAAI,CAAC,SACV,+CAAC,SAAqB,WAAU,+BAC9B;AAAA,sDAAC,QAAG,WAAU,eAAe,eAAK,OAAM;AAAA,QACxC,8CAAC,QAAG,WAAU,6BAA6B,eAAK,OAAM;AAAA,WAF9C,KAAK,KAGf,CACD,GACH;AAAA,OACF;AAAA;AAEJ;;;AClFQ,IAAAC,uBAAA;AAJD,SAAS,kBAAkB,EAAE,MAAM,GAA2B;AACnE,SACE,+CAAC,aAAQ,WAAU,mBAAkB,MAAK,SAAQ,aAAU,aAC1D;AAAA,kDAAC,OACC,wDAAC,YAAO,4CAA8B,GACxC;AAAA,IACA,8CAAC,OAAG,gBAAM,SAAQ;AAAA,IACjB,MAAM,SAAS,4BACd,+CAAC,OAAE;AAAA;AAAA,MAC+C,8CAAC,UAAK,sCAAwB;AAAA,MAAO;AAAA,OAEvF,IACE;AAAA,IACH,MAAM,UAAU,MAAM,OAAO,SAAS,IACrC,+CAAC,aACC;AAAA,qDAAC,aAAS;AAAA,cAAM,OAAO;AAAA,QAAO;AAAA,QAAkB,MAAM,OAAO,WAAW,IAAI,KAAK;AAAA,SAAI;AAAA,MACrF,8CAAC,SACE,gBAAM,OACJ,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE,EACpC,KAAK,IAAI,GACd;AAAA,OACF,IACE;AAAA,KACN;AAEJ;;;AClBI,IAAAC,uBAAA;AAFG,SAAS,iBAAiB,EAAE,MAAM,GAAuB;AAC9D,SACE,gFACE;AAAA,kDAAC,QAAI,mBAAS,gBAAe;AAAA,IAC7B,8CAAC,iBAAc;AAAA,IACf,8CAAC,cAAW;AAAA,KACd;AAEJ;AAMO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKc;AACZ,SACE,8CAAC,UAAK,WAAW,GAAG,aAAa,SAAS,GAAG,cAAY,SAAS,eAAe,cAAY,WAC3F,wDAAC,qBAAkB,OAAc,GACnC;AAEJ;;;ACbW,IAAAC,uBAAA;AAJJ,SAAS,OAAO,OAAoB;AACzC,QAAM,EAAE,QAAQ,iBAAiB,WAAW,WAAW,OAAO,UAAU,IAAI;AAC5E,QAAM,SAAS,aAAa,MAAM;AAClC,MAAI,CAAC,OAAO,IAAI;AACd,WAAO,8CAAC,oBAAiB,OAAO,OAAO,OAAO,WAAsB,OAAc,WAAsB;AAAA,EAC1G;AACA,QAAM,OAAO,OAAO;AACpB,QAAM,aAAa,KAAK,SAAS,SAAS;AAC1C,SACE,8CAAC,cAAW,QAAQ,MAAM,iBAAkC,WAC1D,yDAAC,UAAK,WAAW,GAAG,aAAa,SAAS,GAAG,cAAY,SAAS,eAAe,cAAY,WAC3F;AAAA,kDAAC,YAAO,WAAU,oBAChB,wDAAC,oBAAiB,OAAc,GAClC;AAAA,IACC,aAAa,8CAAC,qBAAkB,IAAK,8CAAC,eAAY;AAAA,KACrD,GACF;AAEJ;;;ArDkBA,IAAM,UAAU;AAChB,IAAM,UAAU;AAChB,IAAM,aAAa;AAGnB,SAAS,oBAAoB,MAAsB;AACjD,SAAO,KAAK,QAAQ,oBAAoB,CAAC,MAAM,QAAQ,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACtG;AAEA,IAAM,WAAW;AACjB,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAGpB,SAAS,UAAU,oBAA6B,SAAkD;AAChG,QAAM,YAAsB,CAAC;AAC7B,QAAM,UAAoB,CAAC;AAC3B,QAAM,OAAiB,CAAC;AAExB,MAAI,oBAAoB;AACtB,cAAU,KAAK,gCAAgC,cAAc,IAAI;AACjE,cAAU,KAAK,gCAAgC,aAAa,yCAAyC;AACrG,YAAQ,KAAK,qBAAqB,QAAQ,IAAI;AAC9C,SAAK,KAAK,mFAAmF;AAAA,EAC/F;AACA,MAAI,SAAS;AACX,YAAQ,KAAK,wBAAwB,WAAW,IAAI;AACpD,SAAK,KAAK,+DAA+D;AACzE,SAAK,KAAK,4DAA4D;AAAA,EACxE;AAEA,QAAM,OAAO,QAAQ,SACjB;AAAA,EAA2B,QAAQ,KAAK,IAAI,CAAC;AAAA,EAAK,KAAK,KAAK,IAAI,CAAC;AAAA,aACjE;AACJ,SAAO,EAAE,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK;AAC5C;AAEA,IAAM,eAAuC;AAAA,EAC3C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,MAAM,QAAQ,YAAY,CAAC,OAAO,aAAa,EAAE,KAAK,EAAE;AACjE;AAOO,SAAS,mBACd,QACA,UAAqC,CAAC,GAC9B;AACR,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB;AAAA,EACF,IAAI;AAEJ,QAAM,aAAS;AAAA,QACb,8BAAc,QAAQ,EAAE,QAAQ,MAAM,CAAC;AAAA,EACzC;AAEA,QAAM,MAAM,UAAU,oBAAoB,OAAO;AAMjD,QAAM,SAAS,aAAa,MAAM;AAClC,QAAM,YAAqC,OAAO,KAAK,OAAO,OAAO;AACrE,QAAM,cAAc,aAAa,SAAS,KAAK,cAAc;AAK7D,QAAM,aACJ,cAAc,SACV,uCAAuC,OAAO,KAAK,oBAAoB,KAAK,UAAU,SAAS,CAAC,CAAC,cACjG;AACN,QAAM,gBACJ,eAAe,mBAAmB,OAAO,KAAK,eAAe,EAAE,SAAS,IACpE,uCAAuC,UAAU,KAAK,oBAAoB,KAAK,UAAU,eAAe,CAAC,CAAC,cAC1G;AACN,QAAM,YAAY,cAAc,WAAW,YAAY,cAAc;AAMrE,QAAM,UAAU,cAAc,KAAK,IAAI;AACvC,QAAM,oBAAoB,cACtB,oBAAoB,qBAAqB,SAAS,OAAO,sBAAsB,UAAU,SAAS,OAAO,yBAAyB,OAAO,SAAS,cAAc,KAAK,kBAAkB,IAAI,iBAAiB,CAAC,MAC7M;AACJ,QAAM,YAAY,cACd,QAAQ,OAAO,iBAAiB,WAAW,KAAK,CAAC,IAAI,iBAAiB,KACtE;AAEJ,SAAO;AAAA,cACK,WAAW,IAAI,CAAC,iBAAiB,UAAU,SAAS,SAAS,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,SAKzE,WAAW,KAAK,CAAC;AAAA,EACxB,IAAI,IAAI;AAAA,EACR,SAAS;AAAA,SACF,GAAG;AAAA;AAAA;AAAA,MAGN,SAAS,uDAAuD,MAAM;AAAA,EAC1E,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA;AAAA;AAGX;","names":["import_react","import_react","import_jsx_runtime","import_react","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","EMPTY_RENDERERS","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","safeStringify","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_url","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","React","import_jsx_runtime","React","import_jsx_runtime","MenuPrimitive","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/ssr-entry.ts","../src/result.ts","../src/context/ReportRoot.tsx","../src/context/ReportContext.ts","../src/components/ui/badge.tsx","../src/lib/utils.ts","../src/components/doc/NarrativeBlocks.tsx","../src/hooks/useReport.ts","../src/components/ReportScenario.tsx","../src/lib/step-params.tsx","../src/components/ReportSteps.tsx","../src/components/doc/DocNote.tsx","../src/components/doc/DocTag.tsx","../src/components/doc/DocKv.tsx","../src/hooks/useRenderers.ts","../src/components/doc/DocCode.tsx","../src/components/doc/DocTable.tsx","../src/components/doc/DocLink.tsx","../src/lib/markdown.ts","../src/lib/url.ts","../src/components/doc/DocSection.tsx","../src/components/doc/DocMermaid.tsx","../src/components/doc/DocScreenshot.tsx","../src/components/doc/DocVideo.tsx","../src/components/doc/DocHtml.tsx","../src/components/doc/DocState.tsx","../src/components/doc/DocCustom.tsx","../src/components/doc/DocEntry.tsx","../src/components/ReportDocEntries.tsx","../src/components/ReportStoryboard.tsx","../src/components/ReportAttachments.tsx","../src/components/ReportTrace.tsx","../src/lib/trace.ts","../src/interactive/scenario-history-context.ts","../src/lib/run-history.ts","../src/components/ScenarioRunHistory.tsx","../src/components/ScenarioStaleness.tsx","../src/lib/provenance.ts","../src/interactive/scenario-freshness-context.tsx","../src/interactive/collapse-context.ts","../src/interactive/scenario-actions.tsx","../src/components/ui/card.tsx","../src/components/ui/dropdown-menu.tsx","../src/components/ReportScenarioList.tsx","../src/components/ReportFeatureIntro.tsx","../src/components/ReportFeature.tsx","../src/components/ReportFeatureList.tsx","../src/components/ui/empty.tsx","../src/components/ReportEmpty.tsx","../src/components/ReportSummary.tsx","../src/components/ReportMeta.tsx","../src/components/ReportSchemaError.tsx","../src/components/ReportShell.tsx","../src/components/Report.tsx"],"sourcesContent":["/**\n * Server-only entry: render a StoryReport to a standalone HTML document string.\n *\n * This is the single rendering path shared by the CLI's standalone `.html`\n * output and (later) the Astro docs site — both render the same <Report/>\n * component tree, so there is no second renderer to drift from.\n *\n * No fs, no client code. The caller supplies the stylesheet text (read once\n * from `executable-stories-react/tailwind.css`) so this module stays pure and\n * bundler-agnostic. The interactive hydration island is injected via\n * `bodyExtra` in a later phase; this entry renders static markup only.\n */\n\nimport { createElement } from \"react\";\nimport { renderToStaticMarkup } from \"react-dom/server\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"./result\";\nimport { unwrapReport } from \"./result\";\nimport { Report } from \"./components/Report\";\nimport type { ScenarioHistoryMap, ScenarioRunEvent } from \"./lib/run-history\";\n\nexport type { ScenarioHistoryMap, ScenarioRunEvent };\n\nexport interface RenderReportToHtmlOptions {\n /** Document <title> and the report's <h1>. */\n title?: string;\n /** Stylesheet text inlined into <head> (e.g. executable-stories-react/tailwind.css). */\n css?: string;\n /** Force a theme; defaults to \"light\" (CSS still honours prefers-color-scheme). */\n theme?: \"light\" | \"dark\";\n /** Raw HTML injected at the end of <head> (font links, CDN module scripts). */\n headExtra?: string;\n /** Raw HTML injected before </body> (the hydration island <script>, later phases). */\n bodyExtra?: string;\n /** Document language attribute. */\n lang?: string;\n /** Load highlight.js to colour code blocks (default true). */\n syntaxHighlighting?: boolean;\n /** Load mermaid to render `pre[data-mermaid]` diagrams (default true). */\n mermaid?: boolean;\n /**\n * When set, embed the report JSON + this inlined IIFE bundle text\n * (executable-stories-react/report-island.js) so the static markup is\n * upgraded to the interactive tree on load. The static render stays as the\n * no-JS fallback.\n */\n islandScript?: string;\n /**\n * Days before the interactive report flags itself as stale (\"Last verified\n * N days ago\" warning banner). 0 disables the warning. Default 7.\n */\n staleAfterDays?: number;\n /**\n * Recent run events per scenario id (joined from the CLI's --history-file\n * store). Embedded as JSON next to the report data; the interactive island\n * renders a run-over-run timeline strip on each scenario card. Ignored for\n * static (non-island) output.\n */\n scenarioHistory?: ScenarioHistoryMap;\n}\n\nconst ROOT_ID = \"es-report-root\";\nconst DATA_ID = \"es-report-data\";\nconst HISTORY_ID = \"es-report-history\";\n\n/** Escape a JSON string for safe embedding inside a <script> element. */\nfunction escapeJsonForScript(json: string): string {\n return json.replace(/[<\\u2028\\u2029]/g, (c) => \"\\\\u\" + c.charCodeAt(0).toString(16).padStart(4, \"0\"));\n}\n\nconst HLJS_URL = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js\";\nconst HLJS_CSS_LIGHT = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css\";\nconst HLJS_CSS_DARK = \"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css\";\nconst MERMAID_URL = \"https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs\";\n\n/** Build the CDN <head> styles + the bottom-of-body init module script. */\nfunction cdnAssets(syntaxHighlighting: boolean, mermaid: boolean): { head: string; body: string } {\n const headParts: string[] = [];\n const imports: string[] = [];\n const init: string[] = [];\n\n if (syntaxHighlighting) {\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_LIGHT}\">`);\n headParts.push(`<link rel=\"stylesheet\" href=\"${HLJS_CSS_DARK}\" media=\"(prefers-color-scheme: dark)\">`);\n imports.push(`import hljs from \"${HLJS_URL}\";`);\n init.push(\"document.querySelectorAll('pre code').forEach((el) => hljs.highlightElement(el));\");\n }\n if (mermaid) {\n imports.push(`import mermaid from \"${MERMAID_URL}\";`);\n init.push(\"mermaid.initialize({ startOnLoad: false, theme: 'neutral' });\");\n init.push('await mermaid.run({ querySelector: \"pre[data-mermaid]\" });');\n }\n\n const body = imports.length\n ? `<script type=\"module\">\\n${imports.join(\"\\n\")}\\n${init.join(\"\\n\")}\\n</script>`\n : \"\";\n return { head: headParts.join(\"\\n\"), body };\n}\n\nconst HTML_ESCAPES: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n};\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (ch) => HTML_ESCAPES[ch] ?? ch);\n}\n\n/**\n * Render a StoryReport (or a parse Result) to a complete, self-contained HTML\n * document. The report markup is wrapped in `.es-report-island` so the scoped\n * Tailwind/shadcn resets and utilities apply without leaking onto a host page.\n */\nexport function renderReportToHtml(\n report: StoryReport | Result<StoryReport>,\n options: RenderReportToHtmlOptions = {},\n): string {\n const {\n title = \"Story Report\",\n css = \"\",\n theme = \"light\",\n headExtra = \"\",\n bodyExtra = \"\",\n lang = \"en\",\n syntaxHighlighting = true,\n mermaid = true,\n islandScript = \"\",\n staleAfterDays = 7,\n scenarioHistory,\n } = options;\n\n const markup = renderToStaticMarkup(\n createElement(Report, { report, title }),\n );\n\n const cdn = cdnAssets(syntaxHighlighting, mermaid);\n\n // Interactive island: embed the report JSON + the inlined IIFE so the static\n // markup is upgraded to <ReportInteractive> on load (static = no-JS fallback).\n // <Report> already normalizes the same input internally; we re-normalize here\n // only to recover the bare report for the JSON payload.\n const parsed = unwrapReport(report);\n const rawReport: StoryReport | undefined = parsed.ok ? parsed.data : undefined;\n const interactive = islandScript.length > 0 && rawReport !== undefined;\n // Emitted whenever there is a report to emit, not only when the island will\n // hydrate. The JSON is already serialised, so it costs nothing, and it is the\n // difference between a JS-less report an agent can parse and one where the\n // only machine-readable copy of the run has been thrown away.\n const dataScript =\n rawReport !== undefined\n ? `<script type=\"application/json\" id=\"${DATA_ID}\">${escapeJsonForScript(JSON.stringify(rawReport))}</script>`\n : \"\";\n const historyScript =\n interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0\n ? `<script type=\"application/json\" id=\"${HISTORY_ID}\">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>`\n : \"\";\n const islandTag = interactive ? `<script>${islandScript}</script>` : \"\";\n // When interactive, the React island OWNS the doc-entry DOM via createRoot.\n // Highlighting + mermaid therefore render inside the React tree (the island\n // reads these flags and wires the matching renderers); the CDN post-processor\n // module (cdn.body) would race the client takeover and is dropped. The hljs\n // stylesheet (cdn.head) is still required to colour the React-owned tokens.\n const cdnBody = interactive ? \"\" : cdn.body;\n const islandConfigAttrs = interactive\n ? ` data-es-syntax=\"${syntaxHighlighting ? \"true\" : \"false\"}\" data-es-mermaid=\"${mermaid ? \"true\" : \"false\"}\" data-es-stale-days=\"${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}\"`\n : \"\";\n const rootAttrs = interactive\n ? ` id=\"${ROOT_ID}\" data-title=\"${escapeHtml(title)}\"${islandConfigAttrs}`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"${escapeHtml(lang)}\" data-theme=\"${theme === \"dark\" ? \"dark\" : \"light\"}\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"color-scheme\" content=\"light dark\">\n<title>${escapeHtml(title)}</title>\n${cdn.head}\n${headExtra}\n<style>${css}</style>\n</head>\n<body>\n<div${rootAttrs} class=\"es-report-island font-sans text-foreground\">${markup}</div>\n${dataScript}\n${historyScript}\n${bodyExtra}\n${cdnBody}\n${islandTag}\n</body>\n</html>`;\n}\n","/**\n * Result<T> — explicit success/error type matching the cookbook convention.\n *\n * Used at the boundary where a StoryReport is parsed: the consumer hands us\n * an unknown value (file contents, fetch body, prop) and we return a Result.\n */\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport type Result<T, E = ReportParseError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\nexport interface ReportParseError {\n message: string;\n code: ReportParseErrorCode;\n issues?: readonly { path: string; message: string }[];\n}\n\nexport type ReportParseErrorCode =\n | \"INVALID_INPUT\"\n | \"SCHEMA_VERSION_MISMATCH\"\n | \"VALIDATION_FAILED\";\n\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\nexport const err = (error: ReportParseError): Result<never> => ({ ok: false, error });\n\n/**\n * Normalize the `StoryReport | Result<StoryReport>` prop accepted across the\n * render entrypoints (`Report`, `ReportInteractive`, `renderReportToHtml`) into\n * a single `Result`. A bare report becomes `ok(report)`; an already-wrapped\n * value passes through. One place owns the \"is this a Result?\" discrimination.\n */\nexport function unwrapReport(value: StoryReport | Result<StoryReport>): Result<StoryReport> {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"ok\" in value &&\n typeof (value as { ok: unknown }).ok === \"boolean\"\n ) {\n return value as Result<StoryReport>;\n }\n return ok(value as StoryReport);\n}\n","import { useMemo, type ReactNode } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportContext, type ReportContextValue } from \"./ReportContext\";\nimport { narrativeBlockRenderers } from \"../components/doc/NarrativeBlocks\";\n\nexport interface ReportRootProps {\n report: StoryReport;\n customRenderers?: CustomRenderers;\n renderers?: BuiltinRenderers;\n children: ReactNode;\n}\n\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function ReportRoot({\n report,\n customRenderers,\n renderers,\n children,\n}: ReportRootProps) {\n const value = useMemo<ReportContextValue>(\n () => ({\n report,\n // Narrative blocks render everywhere the report does (static SSR, the\n // island, Astro) without every host wiring them up. A host renderer for\n // the same type still wins.\n customRenderers: { ...narrativeBlockRenderers, ...customRenderers },\n renderers: renderers ?? EMPTY_RENDERERS,\n }),\n [report, customRenderers, renderers],\n );\n return <ReportContext.Provider value={value}>{children}</ReportContext.Provider>;\n}\n","import { createContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nexport interface ReportContextValue {\n report: StoryReport;\n customRenderers: CustomRenderers;\n renderers: BuiltinRenderers;\n}\n\nexport const ReportContext = createContext<ReportContextValue | null>(null);\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { useRender } from \"@base-ui/react/use-render\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n \"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90\",\n outline:\n \"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n ghost: \"[a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 [a&]:hover:underline\",\n // Pass/skip/pending are the quiet states: outline + coloured text, no\n // fill, so a green report reads calm. Only `failed` keeps a tinted\n // fill, making it the single loud badge on the page, so red pops the\n // instant something breaks. Colour-as-accent, matching the KPI cards.\n passed: \"border-pass-border text-pass font-mono uppercase\",\n failed: \"border-fail-border bg-fail-bg text-fail font-mono uppercase\",\n skipped: \"border-skip-border text-skip font-mono uppercase\",\n pending: \"border-pend-border text-pend font-mono uppercase\",\n tag: \"border-border text-muted-foreground font-mono font-medium [a&]:hover:bg-muted\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & {\n // Base UI composition: pass `render={<a … />}` to swap the underlying tag —\n // replaces Radix's `asChild`. See rules/base-vs-radix.md.\n render?: useRender.RenderProp\n }) {\n return useRender({\n defaultTagName: \"span\",\n render,\n props: {\n \"data-slot\": \"badge\",\n \"data-variant\": variant,\n className: cn(badgeVariants({ variant }), className),\n ...props,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class names with Tailwind-aware conflict resolution (shadcn `cn`). */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Renderers for the two narrative block types an agent reaches for when it\n * explains a change: a file map and a data shape.\n *\n * They ride on `story.custom({ type, data })`, so every adapter can already\n * emit them with no API change; only the renderer is new. Register them with\n * `customRenderers` (the standalone report island does this by default).\n *\n * These blocks describe, they do not prove. Nothing here executed, so a block\n * whose `data.authored` says an agent wrote it renders a visible marker. A\n * picture that looks as trustworthy as a passing test, without being one, is\n * the failure mode this whole report exists to avoid.\n */\n\nimport type { ReportDocCustom } from \"executable-stories-core\";\nimport { Badge } from \"../ui/badge\";\nimport { cn } from \"../../lib/utils\";\n\nexport const FILE_TREE_TYPE = \"file-tree\";\nexport const DATA_MODEL_TYPE = \"data-model\";\n\n/** Change annotation shared by both blocks. */\ntype ChangeKind = \"added\" | \"modified\" | \"removed\" | \"renamed\";\n\nfunction isChangeKind(value: unknown): value is ChangeKind {\n return value === \"added\" || value === \"modified\" || value === \"removed\" || value === \"renamed\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\n/**\n * \"Written by an agent, not verified by a run.\" Only rendered when the author\n * says so; there is no way to detect it after the fact, which is exactly why\n * the authoring skills are told to set it.\n */\nfunction AuthoredMarker({ authored }: { authored?: string }) {\n if (authored !== \"agent\") return null;\n return (\n <Badge variant=\"outline\" className=\"border-border text-[10px] text-muted-foreground\">\n AI-authored, not verified by a run\n </Badge>\n );\n}\n\nfunction BlockFrame({\n title,\n authored,\n children,\n}: {\n title?: string;\n authored?: string;\n children: React.ReactNode;\n}) {\n return (\n <figure className=\"my-3\">\n {title || authored === \"agent\" ? (\n <figcaption className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n {title ? <span className=\"text-xs font-medium text-muted-foreground\">{title}</span> : null}\n <AuthoredMarker authored={authored} />\n </figcaption>\n ) : null}\n {children}\n </figure>\n );\n}\n\n/**\n * Deliberately uncoloured. In this report colour carries test status, so a\n * green \"added\" badge beside a failing scenario would read as a pass. The word\n * does the work.\n */\nfunction ChangeBadge({ change }: { change: ChangeKind }) {\n return (\n <Badge variant=\"tag\" className=\"text-[10px]\">\n {change}\n </Badge>\n );\n}\n\n// ---------------------------------------------------------------------------\n// file-tree\n// ---------------------------------------------------------------------------\n\ninterface FileEntry {\n path: string;\n change?: ChangeKind;\n note?: string;\n}\n\nexport interface FileTreeData {\n title?: string;\n authored?: string;\n files: FileEntry[];\n}\n\nexport function parseFileTree(data: unknown): FileTreeData | undefined {\n if (!isRecord(data) || !Array.isArray(data.files)) return undefined;\n const files: FileEntry[] = [];\n for (const raw of data.files) {\n // A bare string is a path; anything without one is not a file.\n if (typeof raw === \"string\") {\n if (raw) files.push({ path: raw });\n continue;\n }\n if (!isRecord(raw)) continue;\n const path = str(raw.path);\n if (!path) continue;\n files.push({\n path,\n change: isChangeKind(raw.change) ? raw.change : undefined,\n note: str(raw.note),\n });\n }\n if (files.length === 0) return undefined;\n return { title: str(data.title), authored: str(data.authored), files };\n}\n\ninterface TreeNode {\n name: string;\n children: Map<string, TreeNode>;\n file?: FileEntry;\n}\n\n/** Flat paths in, nested directories out. Sorting puts folders before files. */\nfunction buildTree(files: FileEntry[]): TreeNode {\n const root: TreeNode = { name: \"\", children: new Map() };\n for (const file of files) {\n const segments = file.path.split(\"/\").filter(Boolean);\n let node = root;\n segments.forEach((segment, index) => {\n let child = node.children.get(segment);\n if (!child) {\n child = { name: segment, children: new Map() };\n node.children.set(segment, child);\n }\n if (index === segments.length - 1) child.file = file;\n node = child;\n });\n }\n return root;\n}\n\nfunction sortedChildren(node: TreeNode): TreeNode[] {\n return [...node.children.values()].sort((a, b) => {\n const aDir = a.children.size > 0;\n const bDir = b.children.size > 0;\n if (aDir !== bDir) return aDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n}\n\nfunction TreeBranch({ node, depth }: { node: TreeNode; depth: number }) {\n const children = sortedChildren(node);\n return (\n <ul className={cn(\"space-y-0.5\", depth > 0 && \"ml-3 border-l border-border/60 pl-3\")}>\n {children.map((child) => {\n const isDir = child.children.size > 0;\n return (\n <li key={child.name}>\n <div className=\"flex flex-wrap items-baseline gap-2\">\n <span\n className={cn(\n \"font-mono text-xs\",\n isDir ? \"text-muted-foreground\" : \"text-foreground\",\n )}\n >\n {isDir ? `${child.name}/` : child.name}\n </span>\n {child.file?.change ? <ChangeBadge change={child.file.change} /> : null}\n {child.file?.note ? (\n <span className=\"text-xs text-muted-foreground\">{child.file.note}</span>\n ) : null}\n </div>\n {isDir ? <TreeBranch node={child} depth={depth + 1} /> : null}\n </li>\n );\n })}\n </ul>\n );\n}\n\nexport function FileTreeBlock({ entry }: { entry: ReportDocCustom }) {\n const data = parseFileTree(entry.data);\n if (!data) return <UnreadableBlock entry={entry} />;\n return (\n <BlockFrame title={data.title ?? \"Files changed\"} authored={data.authored}>\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border bg-card p-3\">\n <TreeBranch node={buildTree(data.files)} depth={0} />\n </div>\n </BlockFrame>\n );\n}\n\n// ---------------------------------------------------------------------------\n// data-model\n// ---------------------------------------------------------------------------\n\ninterface ModelField {\n name: string;\n type?: string;\n note?: string;\n change?: ChangeKind;\n}\n\nexport interface DataModelData {\n title?: string;\n authored?: string;\n name?: string;\n fields: ModelField[];\n}\n\nexport function parseDataModel(data: unknown): DataModelData | undefined {\n if (!isRecord(data) || !Array.isArray(data.fields)) return undefined;\n const fields: ModelField[] = [];\n for (const raw of data.fields) {\n if (!isRecord(raw)) continue;\n const name = str(raw.name);\n if (!name) continue;\n fields.push({\n name,\n type: str(raw.type),\n note: str(raw.note),\n change: isChangeKind(raw.change) ? raw.change : undefined,\n });\n }\n if (fields.length === 0) return undefined;\n return {\n title: str(data.title),\n authored: str(data.authored),\n name: str(data.name),\n fields,\n };\n}\n\nexport function DataModelBlock({ entry }: { entry: ReportDocCustom }) {\n const data = parseDataModel(entry.data);\n if (!data) return <UnreadableBlock entry={entry} />;\n const hasNotes = data.fields.some((f) => f.note);\n return (\n <BlockFrame title={data.title ?? data.name ?? \"Data model\"} authored={data.authored}>\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Field\n </th>\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Type\n </th>\n {hasNotes ? (\n <th scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n Note\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {data.fields.map((field) => (\n <tr key={field.name}>\n <td className=\"border-b border-border px-3 py-2\">\n <span className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-mono text-xs text-foreground\">{field.name}</span>\n {field.change ? <ChangeBadge change={field.change} /> : null}\n </span>\n </td>\n <td className=\"border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground\">\n {field.type ?? \"\"}\n </td>\n {hasNotes ? (\n <td className=\"border-b border-border px-3 py-2 text-foreground\">\n {field.note ?? \"\"}\n </td>\n ) : null}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </BlockFrame>\n );\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Shape we could not read. Show the raw data rather than nothing: a malformed\n * block is a bug in whatever wrote it, and hiding it hides the bug.\n */\nfunction UnreadableBlock({ entry }: { entry: ReportDocCustom }) {\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">\n {entry.type} (unrecognised shape)\n </p>\n <pre\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * The narrative block renderers, ready to spread into `customRenderers`.\n * Consumer-supplied renderers for the same type win, so a project can swap\n * either one out.\n */\nexport const narrativeBlockRenderers = {\n [FILE_TREE_TYPE]: (entry: ReportDocCustom) => <FileTreeBlock entry={entry} />,\n [DATA_MODEL_TYPE]: (entry: ReportDocCustom) => <DataModelBlock entry={entry} />,\n};\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\n\nexport function useReport() {\n const ctx = useContext(ReportContext);\n if (!ctx) {\n throw new Error(\n \"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those.\",\n );\n }\n return ctx.report;\n}\n","import type { ReportScenario as ReportScenarioT } from \"executable-stories-core\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { ReportSteps } from \"./ReportSteps\";\nimport { ReportStoryboard } from \"./ReportStoryboard\";\nimport { ReportDocEntries } from \"./ReportDocEntries\";\nimport { ReportAttachments } from \"./ReportAttachments\";\nimport { ReportTrace } from \"./ReportTrace\";\nimport { ScenarioRunHistory } from \"./ScenarioRunHistory\";\nimport { ScenarioStaleness } from \"./ScenarioStaleness\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { useScenarioActions } from \"../interactive/scenario-actions\";\nimport { Card, CardContent, CardHeader } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportScenarioProps {\n scenario: ReportScenarioT;\n /**\n * Omit the card's own title row (status badge + tags still render). Use when\n * the surrounding page already shows the scenario title as its heading — e.g.\n * the Astro detail page, where Starlight renders the title as the page `h1`.\n */\n hideTitle?: boolean;\n}\n\ntype Status = ReportScenarioT[\"status\"];\n\ninterface StatusMeta {\n label: string;\n glyph: string;\n glyphColor: string;\n badgeVariant: \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n /**\n * Whether to render the status as a visible pill. Passing scenarios drop it:\n * the green ✓ glyph + title already carry the status, so the pill would be\n * pure redundancy on every (usually passing) row, and dropping it keeps a\n * green run calm while the failure pill stays the one loud badge. A\n * non-showPill status still exposes an sr-only label for screen readers.\n */\n showPill: boolean;\n}\n\nconst STATUS_META: Record<Status, StatusMeta> = {\n passed: { label: \"Passed\", glyph: \"✓\", glyphColor: \"text-pass\", badgeVariant: \"passed\", showPill: false },\n failed: { label: \"Failed\", glyph: \"✗\", glyphColor: \"text-fail\", badgeVariant: \"failed\", showPill: true },\n skipped: { label: \"Skipped\", glyph: \"○\", glyphColor: \"text-skip\", badgeVariant: \"skipped\", showPill: true },\n pending: { label: \"Pending\", glyph: \"○\", glyphColor: \"text-pend\", badgeVariant: \"pending\", showPill: true },\n};\n\nexport function ReportScenario({ scenario, hideTitle = false }: ReportScenarioProps) {\n const titleId = `${scenario.id}-title`;\n const bodyId = `${scenario.id}-body`;\n const meta = STATUS_META[scenario.status];\n // A planned scenario (it.todo) is canonically \"pending\", but the reader\n // should see intent, not limbo.\n const label = scenario.planned ? \"Planned\" : meta.label;\n const collapse = useCollapse();\n const collapsible = collapse !== null && !hideTitle;\n const collapsed = collapsible ? collapse!.isCollapsed(scenario.id) : false;\n const actions = useScenarioActions();\n return (\n <Card\n id={scenario.id}\n data-status={scenario.status}\n {...(hideTitle\n ? { \"aria-label\": `${scenario.title}, ${label}` }\n : { \"aria-labelledby\": titleId })}\n className=\"gap-0 py-0\"\n >\n <CardHeader className=\"px-4 py-3\">\n <div\n className={cn(\n // Wraps rather than squeezing: on a phone the status/duration group\n // is ~160px, which leaves a title column a few characters wide.\n \"flex flex-wrap items-start gap-x-4 gap-y-1\",\n hideTitle ? \"justify-end\" : \"justify-between\",\n )}\n >\n {hideTitle ? null : (\n <h3 id={titleId} className=\"flex min-w-0 flex-1 basis-48 items-center gap-2 text-sm font-medium text-foreground\">\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => collapse!.toggle(scenario.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n aria-label={`Toggle ${scenario.title}`}\n className=\"shrink-0 cursor-pointer text-muted-foreground hover:text-foreground\"\n >\n <span aria-hidden className={cn(\"inline-block text-xs transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n </button>\n ) : null}\n <span aria-hidden className={cn(\"text-sm leading-none\", meta.glyphColor)}>\n {meta.glyph}\n </span>\n <span>{scenario.title}</span>\n </h3>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n <ScenarioRunHistory scenarioId={scenario.id} />\n <ScenarioStaleness scenario={scenario} />\n {scenario.durationMs > 0 ? (\n <span className=\"whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(scenario.durationMs)}\n </span>\n ) : null}\n {meta.showPill ? (\n <Badge variant={meta.badgeVariant} aria-label={`Status: ${label}`}>\n {label}\n </Badge>\n ) : (\n <span className=\"sr-only\">{`Status: ${label}`}</span>\n )}\n {actions ? (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={`Actions for ${scenario.title}`}\n className=\"cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4\"\n >\n <MoreHorizontalIcon aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => actions.copyLink(scenario)}>\n <LinkIcon /> Copy link\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => actions.copyMarkdown(scenario)}>\n <FileTextIcon /> Copy as Markdown\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => actions.copyPrompt(scenario)}>\n <SparklesIcon /> Explain with AI\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n </div>\n {scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? (\n <ul aria-label=\"Tags and tickets\" className=\"flex flex-wrap gap-1.5\">\n {scenario.tags.map((t) => (\n <li key={`tag-${t}`}>\n <Badge variant=\"tag\">{t}</Badge>\n </li>\n ))}\n {(scenario.tickets ?? []).map((ticket) => (\n <li key={`ticket-${ticket.id}`}>\n {ticket.url ? (\n <a href={ticket.url} target=\"_blank\" rel=\"noreferrer noopener\" className=\"inline-flex min-h-6 items-center\">\n <Badge variant=\"outline\">{ticket.id}</Badge>\n </a>\n ) : (\n <Badge variant=\"outline\">{ticket.id}</Badge>\n )}\n </li>\n ))}\n </ul>\n ) : null}\n </CardHeader>\n <CardContent id={bodyId} hidden={collapsed} className=\"px-4 pt-0 pb-4\">\n {scenario.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mb-1 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {scenario.errorMessage}\n </pre>\n ) : null}\n <ReportStoryboard scenario={scenario} />\n <ReportSteps scenario={scenario} />\n {scenario.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-3\">\n <ReportDocEntries entries={scenario.docEntries} />\n </div>\n ) : null}\n <ReportAttachments attachments={scenario.attachments} />\n <ReportTrace spans={scenario.otelSpans} />\n </CardContent>\n </Card>\n );\n}\n","import type { ReactNode } from \"react\";\n\n/**\n * Highlight step parameters (double-quoted strings, standalone numbers) in step\n * text — the React equivalent of the report's highlightStepParams. Returns a\n * node array so the matched params can be wrapped in a styled <span> without\n * dangerouslySetInnerHTML.\n *\n * Regex mirrors the string renderer exactly:\n * - `\"[^\"]*\"` double-quoted strings (numbers inside quotes stay part of the string)\n * - `(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])` standalone numbers, dot/word-boundary aware\n */\nconst STEP_PARAM_PATTERN = /\"[^\"]*\"|(?<![\\w.-])\\d+(?:\\.\\d+)?(?![\\w.-])/g;\n\nexport function highlightStepParams(text: string): ReactNode {\n const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));\n if (matches.length === 0) return text;\n\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n matches.forEach((match, i) => {\n const start = match.index;\n const end = start + match[0].length;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(\n <span key={i} className=\"font-medium text-step-param italic\">\n {match[0]}\n </span>,\n );\n lastIndex = end;\n });\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n","import { highlightStepParams } from '@/lib/step-params';\nimport { cn } from '@/lib/utils';\nimport type { ReportScenario, ReportStep } from 'executable-stories-core';\nimport {\n assertionState,\n assertiveSteps,\n} from 'executable-stories-core/utils/assertive-steps';\nimport { formatDuration } from 'executable-stories-core/utils/duration';\nimport { ReportDocEntries } from './ReportDocEntries';\n\nexport interface ReportStepsProps {\n scenario: ReportScenario;\n}\n\nconst STEP_GLYPH: Record<string, string> = {\n passed: '✓',\n failed: '✗',\n skipped: '○',\n pending: '○',\n};\n\nconst STEP_GLYPH_COLOR: Record<string, string> = {\n passed: 'text-pass',\n failed: 'text-fail',\n skipped: 'text-skip',\n pending: 'text-pend',\n};\n\nexport function ReportSteps({ scenario }: ReportStepsProps) {\n if (scenario.steps.length === 0) return null;\n const unasserted = new Set(\n assertionState(scenario.steps) === 'unasserted'\n ? assertiveSteps(scenario.steps).map((step) => step.id)\n : [],\n );\n return (\n <ol data-slot=\"steps\" className=\"flex flex-col\">\n {scenario.steps.map((step) => (\n <ReportStepItem\n key={step.id}\n step={step}\n unasserted={unasserted.has(step.id)}\n />\n ))}\n </ol>\n );\n}\n\nexport function ReportStepItem({\n step,\n unasserted = false,\n}: {\n step: ReportStep;\n unasserted?: boolean;\n}) {\n // And/But (incl. auto-And repeats) read as continuations of the prior step —\n // indented with a muted keyword, matching the report's `.step.continuation`.\n const kw = step.keyword.toLowerCase();\n const continuation = kw === 'and' || kw === 'but';\n return (\n <li\n id={step.id}\n data-status={step.status}\n className={cn(\n 'py-1.5 text-[0.8125rem] leading-normal',\n continuation && 'pl-5',\n )}\n >\n <div className=\"flex items-baseline gap-2\">\n <span\n aria-hidden\n className={cn(\n 'w-4 shrink-0 text-center text-xs',\n STEP_GLYPH_COLOR[step.status],\n )}\n >\n {STEP_GLYPH[step.status] ?? '○'}\n </span>\n <span\n className={cn(\n 'min-w-[52px] shrink-0 font-mono text-xs font-semibold capitalize',\n continuation ? 'font-medium text-muted-foreground' : 'text-keyword',\n )}\n >\n {step.keyword}\n </span>\n <span className=\"flex-1 text-foreground\">\n {highlightStepParams(step.text)}\n </span>\n {unasserted ? (\n <span className=\"shrink-0 rounded-full border border-pend-border bg-pend-bg px-2 py-0.5 text-[0.6875rem] font-medium text-pend\">\n No assertion\n </span>\n ) : null}\n {step.durationMs > 0 ? (\n <span className=\"shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground\">\n {formatDuration(step.durationMs)}\n </span>\n ) : null}\n </div>\n {step.errorMessage ? (\n <pre\n role=\"alert\"\n className=\"mt-2.5 ml-6 overflow-x-auto rounded-md border border-fail-border bg-fail-bg px-4 py-3.5 font-mono text-xs leading-relaxed whitespace-pre-wrap text-fail\"\n >\n {step.errorMessage}\n </pre>\n ) : null}\n {step.docEntries.length > 0 ? (\n <div data-es-docs className=\"mt-2 ml-6\">\n <ReportDocEntries entries={step.docEntries} />\n </div>\n ) : null}\n </li>\n );\n}\n","import type { ReportDocNote } from \"executable-stories-core\";\n\nexport function DocNote({ entry }: { entry: ReportDocNote }) {\n return <p className=\"my-2 text-sm text-muted-foreground\">{entry.text}</p>;\n}\n","import type { ReportDocTag } from \"executable-stories-core\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport function DocTag({ entry }: { entry: ReportDocTag }) {\n return (\n <ul className=\"my-2 flex flex-wrap gap-1.5\" aria-label=\"Tags\">\n {entry.names.map((n) => (\n <li key={n}>\n <Badge variant=\"tag\">{n}</Badge>\n </li>\n ))}\n </ul>\n );\n}\n","import type { ReportDocKv } from \"executable-stories-core\";\n\nfunction formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport function DocKv({ entry }: { entry: ReportDocKv }) {\n return (\n <dl className=\"my-2 flex flex-wrap items-baseline gap-x-2 text-sm\">\n <dt className=\"font-semibold text-muted-foreground\">{entry.label}</dt>\n <dd className=\"min-w-0 break-words font-mono text-foreground\">{formatValue(entry.value)}</dd>\n </dl>\n );\n}\n","import { useContext } from \"react\";\nimport { ReportContext } from \"../context/ReportContext\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\n\nconst EMPTY_CUSTOM: CustomRenderers = {};\nconst EMPTY_RENDERERS: BuiltinRenderers = {};\n\nexport function useCustomRenderers(): CustomRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.customRenderers ?? EMPTY_CUSTOM;\n}\n\nexport function useBuiltinRenderers(): BuiltinRenderers {\n const ctx = useContext(ReportContext);\n return ctx?.renderers ?? EMPTY_RENDERERS;\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportDocCode } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Shared shell for code blocks: optional label + the scrollable `<pre>`. Both\n * the static `DocCode` and the island's CDN-highlighted variant render their\n * `<code>` into this so the two can never drift in spacing or chrome.\n */\nexport function CodeFigure({ label, children }: { label?: string; children: ReactNode }) {\n return (\n <figure className=\"my-3\">\n {label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{label}</figcaption>\n ) : null}\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3\">\n {children}\n </pre>\n </figure>\n );\n}\n\nexport function DocCode({ entry }: { entry: ReportDocCode }) {\n const renderers = useBuiltinRenderers();\n if (renderers.code) {\n return <>{renderers.code(entry)}</>;\n }\n return (\n <CodeFigure label={entry.label}>\n <code className={cn(\"font-mono text-xs\", entry.lang && `language-${entry.lang}`)}>\n {entry.content}\n </code>\n </CodeFigure>\n );\n}\n","import type { ReportDocTable } from \"executable-stories-core\";\n\nexport function DocTable({ entry }: { entry: ReportDocTable }) {\n return (\n <figure className=\"my-3\">\n {entry.label ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">\n {entry.label}\n </figcaption>\n ) : null}\n <div tabIndex={0} className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-muted/50\">\n {entry.columns.map((c) => (\n <th key={c} scope=\"col\" className=\"border-b border-border px-3 py-2 text-left font-semibold\">\n {c}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {entry.rows.map((row, i) => (\n <tr key={i}>\n {row.map((cell, j) => (\n <td key={j} className=\"border-b border-border px-3 py-2 text-foreground\">\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </figure>\n );\n}\n","import type { ReportDocLink } from \"executable-stories-core\";\n\nexport function DocLink({ entry }: { entry: ReportDocLink }) {\n return (\n <a\n className=\"text-sm font-medium text-primary underline underline-offset-2 hover:no-underline\"\n href={entry.url}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n {entry.label}\n </a>\n );\n}\n","import { marked } from \"marked\";\nimport { safeUrl } from \"./url\";\n\n/**\n * Best-effort sanitizer for marked-generated HTML. The markdown we render is\n * authored in test source (developer-trusted), so this is defense-in-depth,\n * not a hard boundary against hostile input. It:\n * - drops <script>/<style> and other active elements (iframe/object/embed/form)\n * - strips on* event-handler attributes\n * - neutralizes any non-http(s) scheme on href/src via the shared `safeUrl`\n * allow-list (covers javascript:/data:/vbscript:/file:, not just javascript:)\n *\n * It is NOT a substitute for a full HTML sanitizer (it won't catch entity-\n * obfuscated schemes). For untrusted markdown, supply your own renderer.\n */\nexport function safeMarkdownHtml(markdown: string): string {\n const raw = marked.parse(markdown, { async: false }) as string;\n return raw\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<\\/?(?:iframe|object|embed|form|base)\\b[^>]*>/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*\"[^\"]*\"/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*'[^']*'/gi, \"\")\n .replace(/\\son[a-z]+\\s*=\\s*[^\\s>]+/gi, \"\")\n .replace(/(href|src)\\s*=\\s*\"([^\"]*)\"/gi, (_m, attr, val) => `${attr}=\"${neutralizeUrl(val)}\"`)\n .replace(/(href|src)\\s*=\\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);\n}\n\n/**\n * Strip the leading indentation a template literal picks up from its source.\n *\n * Narratives are written inline in test files, so they arrive indented to match\n * the surrounding code. Left alone, four spaces make Markdown render the whole\n * paragraph as a code block.\n */\nexport function dedent(text: string): string {\n const lines = text.replace(/\\t/g, \" \").split(\"\\n\");\n const indents = lines\n .filter((line) => line.trim().length > 0)\n .map((line) => line.length - line.trimStart().length);\n const shortest = indents.length > 0 ? Math.min(...indents) : 0;\n return lines\n .map((line) => line.slice(shortest))\n .join(\"\\n\")\n .trim();\n}\n\nfunction neutralizeUrl(value: string): string {\n return safeUrl(value) ?? \"#\";\n}\n","/**\n * URL trust boundary for report-sourced strings reaching the DOM. The\n * implementation lives in executable-stories-core/utils/url (shared with the\n * Astro state-catalog thumbnails); this module stays as the package-local\n * import point. Subpath import: the core package root pulls in Node-only\n * converters, which breaks browser bundles.\n */\nexport { safeUrl, safeImageUrl, isLocalFsPath } from \"executable-stories-core/utils/url\";\n","import type { ReportDocSection } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\nimport { safeMarkdownHtml } from \"../../lib/markdown\";\n\nexport function DocSection({ entry }: { entry: ReportDocSection }) {\n const renderers = useBuiltinRenderers();\n if (renderers.section) {\n return <>{renderers.section(entry)}</>;\n }\n const html = safeMarkdownHtml(entry.markdown);\n return (\n <section className=\"my-3 text-sm\" aria-label={entry.title}>\n {entry.title ? <h4 className=\"mb-1 font-semibold text-foreground\">{entry.title}</h4> : null}\n <div\n className=\"es-doc-prose prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n </section>\n );\n}\n","import type { Ref } from \"react\";\nimport type { ReportDocMermaid } from \"executable-stories-core\";\nimport { useBuiltinRenderers } from \"../../hooks/useRenderers\";\n\n/**\n * The raw mermaid source as a semantic `<pre data-mermaid>`. This is the\n * default render and the universal fallback: AI agents, screen readers, and\n * no-JS views all get the readable source. `<MermaidDiagram>` upgrades this to\n * a drawn diagram on the client.\n */\nexport function MermaidSource({ entry, ref }: { entry: ReportDocMermaid; ref?: Ref<HTMLElement> }) {\n return (\n <figure ref={ref} className=\"my-3\" aria-label={entry.title ?? \"Diagram\"}>\n {entry.title ? (\n <figcaption className=\"mb-1.5 text-xs font-medium text-muted-foreground\">{entry.title}</figcaption>\n ) : null}\n <pre\n data-mermaid\n tabIndex={0}\n className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\"\n >\n {entry.code}\n </pre>\n </figure>\n );\n}\n\n/**\n * Renders mermaid source as a semantic `<pre data-mermaid>` by default.\n *\n * To draw the diagram, supply a `renderers.mermaid` prop — e.g. the shipped\n * `MermaidDiagram` (`renderers={{ mermaid: (e) => <MermaidDiagram entry={e} /> }}`).\n */\nexport function DocMermaid({ entry }: { entry: ReportDocMermaid }) {\n const renderers = useBuiltinRenderers();\n if (renderers.mermaid) {\n return <>{renderers.mermaid(entry)}</>;\n }\n return <MermaidSource entry={entry} />;\n}\n","import type { ReportDocScreenshot } from \"executable-stories-core\";\nimport { isLocalFsPath, safeImageUrl } from \"../../lib/url\";\n\n/**\n * A screenshot that's still an absolute local filesystem path by the time it\n * reaches this component means the report's asset bundler couldn't find the\n * file to inline/copy it (deleted, moved, or never captured — see\n * inlineScreenshotIfPossible in executable-stories-playwright). `<img src>`\n * would 404 against a path from the machine that generated the report, so\n * show a placeholder instead of a broken image.\n */\nexport function DocScreenshot({ entry }: { entry: ReportDocScreenshot }) {\n const src = isLocalFsPath(entry.path) ? undefined : safeImageUrl(entry.path);\n\n if (!src) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Screenshot unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs\">{entry.alt}</figcaption> : null}\n </figure>\n );\n }\n\n return (\n <figure className=\"my-3\">\n <img\n src={src}\n alt={entry.alt ?? \"\"}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.alt ? <figcaption className=\"mt-1.5 text-xs text-muted-foreground\">{entry.alt}</figcaption> : null}\n </figure>\n );\n}\n","import type { ReportDocVideo } from \"executable-stories-core\";\nimport { isLocalFsPath, safeUrl } from \"../../lib/url\";\n\n/**\n * Renders a video doc entry. Video bytes are large and never inlined; `path` is\n * a URL or a path that resolves alongside the report. Both `path` and `poster`\n * are adapter-supplied, so they go through the same scheme allow-list as the\n * DocHtml iframe src (no `javascript:`/`data:` URLs reach the DOM).\n *\n * An absolute local filesystem path means the report's asset bundler\n * couldn't find/copy the file — a `<video src>` pointed at a runner-local\n * path would just fail to load, so show a placeholder instead.\n */\nexport function DocVideo({ entry }: { entry: ReportDocVideo }) {\n if (isLocalFsPath(entry.path)) {\n return (\n <figure className=\"my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground\">\n <div className=\"font-medium\">Video unavailable</div>\n <div className=\"mt-1 break-all font-mono text-xs\">{entry.path}</div>\n {entry.caption ? <figcaption className=\"mt-1.5 text-xs\">{entry.caption}</figcaption> : null}\n </figure>\n );\n }\n\n const src = safeUrl(entry.path);\n const poster = safeUrl(entry.poster);\n return (\n <figure className=\"my-3\">\n <video\n controls\n preload=\"metadata\"\n {...(src ? { src } : {})}\n {...(poster ? { poster } : {})}\n className=\"max-w-full rounded-md border border-border\"\n />\n {entry.caption ? (\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{entry.caption}</figcaption>\n ) : null}\n </figure>\n );\n}\n","import type { ReportDocHtml } from \"executable-stories-core\";\nimport { safeUrl } from \"../../lib/url\";\n\n/**\n * Renders an embedded-HTML doc entry inside a SANDBOXED iframe. All embedded\n * HTML is untrusted, so the frame is `sandbox=\"allow-scripts\"` only (no\n * allow-same-origin) — embedded scripts run (charts work) but can't touch the\n * report DOM, cookies, or storage. Inline `content` → srcdoc (keeps the report\n * self-contained); `url`/`path` → src (scheme-validated).\n */\nexport function DocHtml({ entry }: { entry: ReportDocHtml }) {\n const height = typeof entry.height === \"number\" ? `${entry.height}px` : (entry.height ?? \"400px\");\n const title = entry.title ?? \"Embedded HTML\";\n const safeHref = safeUrl(entry.url ?? entry.path);\n\n // Exactly one of content / url / path is set. A url/path with an unsafe\n // scheme yields no src (the figure still renders, just empty).\n const frameProps = entry.content !== undefined ? { srcDoc: entry.content } : { src: safeHref ?? \"\" };\n\n return (\n <figure className=\"my-3 overflow-hidden rounded-md border border-border\">\n <figcaption className=\"flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground\">\n <span>{entry.title ?? \"HTML\"}</span>\n {safeHref ? (\n <a\n href={safeHref}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n className=\"text-primary\"\n >\n ↗\n </a>\n ) : null}\n </figcaption>\n <iframe\n {...frameProps}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n title={title}\n className=\"block w-full border-0\"\n // Embedded HTML is authored standalone, so it assumes a light page. An\n // iframe with no background inherits the host's dark canvas (via the\n // report's `color-scheme`), leaving that authored dark text unreadable.\n style={{ height, colorScheme: \"light\", background: \"#fff\" }}\n />\n </figure>\n );\n}\n","import type { ReportDocState } from \"executable-stories-core\";\nimport { CodeFigure } from \"./DocCode\";\n\n/**\n * A `story.state()` snapshot in the step detail: label + pretty JSON, same\n * chrome as `code(json)`. Frame-to-frame diffs are the storyboard's job —\n * here the entry just shows what was captured at this step.\n */\nexport function DocState({ entry }: { entry: ReportDocState }) {\n let json: string;\n try {\n json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);\n } catch {\n json = String(entry.value);\n }\n return (\n <CodeFigure label={entry.label ?? \"State\"}>\n <code className=\"font-mono text-xs language-json\">{json}</code>\n </CodeFigure>\n );\n}\n","import type { ReportDocCustom } from \"executable-stories-core\";\nimport { useCustomRenderers } from \"../../hooks/useRenderers\";\n\nexport function DocCustom({ entry }: { entry: ReportDocCustom }) {\n const renderers = useCustomRenderers();\n const renderer = renderers[entry.type];\n if (renderer) {\n return <>{renderer(entry)}</>;\n }\n return (\n <div className=\"my-2\" data-type={entry.type}>\n <p className=\"mb-1 text-xs font-medium text-muted-foreground\">{entry.type}</p>\n <pre tabIndex={0} className=\"overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground\">\n {safeStringify(entry.data)}\n </pre>\n </div>\n );\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocNote } from \"./DocNote\";\nimport { DocTag } from \"./DocTag\";\nimport { DocKv } from \"./DocKv\";\nimport { DocCode } from \"./DocCode\";\nimport { DocTable } from \"./DocTable\";\nimport { DocLink } from \"./DocLink\";\nimport { DocSection } from \"./DocSection\";\nimport { DocMermaid } from \"./DocMermaid\";\nimport { DocScreenshot } from \"./DocScreenshot\";\nimport { DocVideo } from \"./DocVideo\";\nimport { DocHtml } from \"./DocHtml\";\nimport { DocState } from \"./DocState\";\nimport { DocCustom } from \"./DocCustom\";\n\nexport function DocEntry({ entry }: { entry: ReportDocEntry }) {\n switch (entry.kind) {\n case \"note\":\n return <DocNote entry={entry} />;\n case \"tag\":\n return <DocTag entry={entry} />;\n case \"kv\":\n return <DocKv entry={entry} />;\n case \"code\":\n return <DocCode entry={entry} />;\n case \"table\":\n return <DocTable entry={entry} />;\n case \"link\":\n return <DocLink entry={entry} />;\n case \"section\":\n return <DocSection entry={entry} />;\n case \"mermaid\":\n return <DocMermaid entry={entry} />;\n case \"screenshot\":\n return <DocScreenshot entry={entry} />;\n case \"video\":\n return <DocVideo entry={entry} />;\n case \"html\":\n return <DocHtml entry={entry} />;\n case \"state\":\n return <DocState entry={entry} />;\n case \"custom\":\n return <DocCustom entry={entry} />;\n }\n}\n","import type { ReportDocEntry } from \"executable-stories-core\";\nimport { DocEntry } from \"./doc/DocEntry\";\n\nexport interface ReportDocEntriesProps {\n entries: readonly ReportDocEntry[];\n}\n\nexport function ReportDocEntries({ entries }: ReportDocEntriesProps) {\n if (entries.length === 0) return null;\n return (\n <>\n {entries.map((entry, i) => (\n <DocEntry key={i} entry={entry} />\n ))}\n </>\n );\n}\n","import type { ReportScenario } from \"executable-stories-core\";\n// Subpath import: the core package root pulls in Node-only converters\n// (node:crypto), which breaks browser bundles — see formatDuration's import.\nimport { extractStoryboardFrames } from \"executable-stories-core/storyboard\";\nimport type { StoryboardFrame, StoryboardStateCard } from \"executable-stories-core/storyboard\";\nimport { summarizeStateChanges } from \"executable-stories-core/state-diff\";\nimport type { StateChangeKind } from \"executable-stories-core/state-diff\";\nimport { isLocalFsPath, safeImageUrl } from \"executable-stories-core/utils/url\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportStoryboardProps {\n scenario: ReportScenario;\n}\n\nconst FRAME_GLYPH: Record<string, string> = {\n passed: \"✓\",\n failed: \"✗\",\n skipped: \"○\",\n pending: \"○\",\n};\n\nconst FRAME_GLYPH_COLOR: Record<string, string> = {\n passed: \"text-pass\",\n failed: \"text-fail\",\n skipped: \"text-skip\",\n pending: \"text-pend\",\n};\n\n/**\n * Storyboard — a horizontal filmstrip of the scenario's step evidence\n * (Given → When → Then), derived from the same step docs the vertical step\n * list renders. A frame is a container: the step's screenshot (when present)\n * plus its `story.state()` snapshot cards, so data-only scenarios get\n * filmstrips too. Each frame links to its step's anchor.\n *\n * Renders nothing below 2 frames: a single capture is evidence, not a\n * walkthrough, and it already shows under its step.\n *\n * Must stay hydration-free: the Astro story pages render this inside a static\n * (no client JS) island, so navigation is plain anchors and snapshot expansion\n * is a native <details> — no lightbox or toggle state.\n */\nexport function ReportStoryboard({ scenario }: ReportStoryboardProps) {\n const frames = extractStoryboardFrames(scenario);\n if (frames.length < 2) return null;\n return (\n <section data-slot=\"storyboard\" aria-label=\"Storyboard\" className=\"mb-3\">\n <h4 className=\"mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase\">\n Storyboard\n </h4>\n <ol className=\"flex items-start gap-3 overflow-x-auto pb-2\">\n {frames.map((frame) => (\n <StoryboardFrameItem key={frame.stepId} frame={frame} />\n ))}\n </ol>\n </section>\n );\n}\n\nfunction StoryboardFrameItem({ frame }: { frame: StoryboardFrame }) {\n const label = `${frame.keyword} ${frame.text}`;\n const hasStates = frame.states.length > 0;\n const caption = (\n <p className=\"mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug\">\n <span aria-hidden className={cn(\"shrink-0\", FRAME_GLYPH_COLOR[frame.status])}>\n {FRAME_GLYPH[frame.status] ?? \"○\"}\n </span>\n <span className=\"min-w-0\">\n <span className=\"font-mono font-semibold text-keyword\">{frame.keyword}</span>{\" \"}\n <span className=\"text-muted-foreground\">{frame.screenshot?.alt ?? frame.text}</span>\n </span>\n </p>\n );\n return (\n // State cards need room for diff rows; screenshot-only frames keep the\n // original narrow film-cell width (and DOM) unchanged.\n <li className={cn(\"shrink-0\", hasStates ? \"w-64\" : \"w-40\")}>\n {frame.screenshot ? (\n <FrameScreenshot frame={frame} label={label} />\n ) : null}\n {hasStates ? (\n <div className={cn(\"flex flex-col gap-1.5\", frame.screenshot && \"mt-1.5\")}>\n {frame.states.map((card, i) => (\n <StateCardView key={card.label ?? i} card={card} />\n ))}\n </div>\n ) : null}\n {frame.screenshot ? (\n caption\n ) : (\n // No screenshot means no image anchor, so the caption carries the\n // jump-to-step link instead.\n <a href={`#${frame.stepId}`} aria-label={`Jump to step: ${label}`} className=\"block hover:underline\">\n {caption}\n </a>\n )}\n </li>\n );\n}\n\nfunction FrameScreenshot({ frame, label }: { frame: StoryboardFrame; label: string }) {\n const path = frame.screenshot?.path ?? \"\";\n const src = isLocalFsPath(path) ? undefined : safeImageUrl(path);\n return (\n <a\n href={`#${frame.stepId}`}\n aria-label={`Jump to step: ${label}`}\n className=\"block overflow-hidden rounded-md border border-border transition-colors hover:border-ring\"\n >\n {src ? (\n <img\n src={src}\n alt={frame.screenshot?.alt ?? label}\n loading=\"lazy\"\n className=\"h-24 w-full bg-muted object-cover object-top\"\n />\n ) : (\n <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\">\n Screenshot unavailable\n </span>\n )}\n </a>\n );\n}\n\n// Same accent scheme as the status badges/KPI cards: green = new, red = gone,\n// amber (skip tokens) = changed. Text + bg pairs are the AA-audited --es-*\n// combinations from tailwind.css.\nconst CHANGE_TONE: Record<StateChangeKind, string> = {\n added: \"bg-pass-bg text-pass\",\n removed: \"bg-fail-bg text-fail\",\n changed: \"bg-skip-bg text-skip\",\n};\n\nfunction prettyJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * One `story.state()` snapshot card: label chip, then what changed since the\n * previous frame's snapshot of the same label (changed fields first, full\n * snapshot behind a disclosure). First appearance shows the snapshot itself\n * with a \"first capture\" hint — there is nothing to diff against yet.\n */\nfunction StateCardView({ card }: { card: StoryboardStateCard }) {\n const json = prettyJson(card.value);\n const firstCapture = card.changes === undefined;\n return (\n <div data-slot=\"state-card\" className=\"rounded-md border border-border bg-card p-2\">\n <p className=\"flex flex-wrap items-baseline gap-1.5\">\n <span className=\"inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground\">\n {card.label ?? \"State\"}\n </span>\n {firstCapture ? (\n <span className=\"text-[0.625rem] text-muted-foreground italic\">first capture</span>\n ) : null}\n </p>\n {!firstCapture &&\n (card.changes && card.changes.length > 0 ? (\n <ul className=\"mt-1.5 flex flex-col gap-0.5\">\n {card.changes.map((change, i) => (\n <li\n key={i}\n className={cn(\n \"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all\",\n CHANGE_TONE[change.kind]\n )}\n >\n {summarizeStateChanges([change])[0]}\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"mt-1.5 text-[0.625rem] text-muted-foreground\">No changes</p>\n ))}\n <details\n // First capture opens short snapshots by default: it IS the card's\n // content. Diff cards keep the snapshot collapsed — the rows above\n // already tell the story.\n open={firstCapture && json.length <= 240}\n className={cn(firstCapture ? \"mt-1.5\" : \"mt-1\")}\n >\n <summary className=\"cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground\">\n Snapshot\n </summary>\n <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\">\n {json}\n </pre>\n </details>\n </div>\n );\n}\n","import type { ReportAttachment } from \"executable-stories-core\";\n\n/**\n * Renders scenario attachments. Base64 images embed inline; everything else\n * becomes a labelled data-URI download link. Mirrors the report's attachments\n * block (which also inlines images and links other media).\n */\nexport function ReportAttachments({ attachments }: { attachments: ReportAttachment[] }) {\n if (attachments.length === 0) return null;\n return (\n // role=\"group\" (not a labelled <section>) so multiple scenarios' attachment\n // blocks don't create duplicate \"Attachments\" region landmarks.\n <div role=\"group\" aria-label=\"Attachments\" className=\"mt-3 flex flex-col gap-2\">\n {attachments.map((att, i) => {\n const dataUri =\n att.contentEncoding === \"BASE64\"\n ? `data:${att.mediaType};base64,${att.body}`\n : `data:${att.mediaType},${encodeURIComponent(att.body)}`;\n const isImage = att.mediaType.startsWith(\"image/\");\n return (\n <figure key={`${att.name}-${i}`} className=\"m-0\">\n {isImage ? (\n <>\n <img\n src={dataUri}\n alt={att.name}\n loading=\"lazy\"\n className=\"max-w-full rounded-md border border-border\"\n />\n <figcaption className=\"mt-1 text-xs text-muted-foreground\">{att.name}</figcaption>\n </>\n ) : (\n <a\n href={dataUri}\n download={att.name}\n className=\"text-xs text-link underline underline-offset-2\"\n >\n {att.name} <span className=\"text-muted-foreground\">({att.mediaType})</span>\n </a>\n )}\n </figure>\n );\n })}\n </div>\n );\n}\n","import type { OtelSpan } from \"executable-stories-core/types/otel\";\nimport { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { toTraceRows, traceWindow } from \"@/lib/trace\";\nimport { cn } from \"@/lib/utils\";\n\nconst BAR_COLOR: Record<string, string> = {\n ok: \"bg-pass\",\n error: \"bg-fail\",\n unset: \"bg-skip\",\n};\n\n/**\n * OTel trace waterfall. Collapsed by default (native <details>, no JS) so it\n * renders in both the static and interactive reports. Each span is a row with a\n * depth-indented name and a bar positioned/sized by its time window.\n */\nexport function ReportTrace({ spans }: { spans: readonly OtelSpan[] | undefined }) {\n if (!spans || spans.length === 0) return null;\n const rows = toTraceRows(spans);\n if (rows.length === 0) return null;\n const { minStartMs, totalMs } = traceWindow(rows);\n\n return (\n <details className=\"mt-3 rounded-md border border-border bg-muted/30\">\n <summary className=\"cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground\">\n Trace ({rows.length} span{rows.length === 1 ? \"\" : \"s\"}, {formatDuration(totalMs)})\n </summary>\n <ul className=\"flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]\">\n {rows.map((row, i) => {\n const leftPct = ((row.startTimeMs - minStartMs) / totalMs) * 100;\n const widthPct = Math.max((row.durationMs / totalMs) * 100, 0.5);\n return (\n <li key={`${row.spanId}-${i}`} className=\"flex items-center gap-2\">\n <span\n className=\"min-w-0 flex-1 truncate text-foreground\"\n style={{ paddingLeft: `${row.depth * 12}px` }}\n title={row.statusMessage ? `${row.name}: ${row.statusMessage}` : row.name}\n >\n {row.name}\n </span>\n <span className=\"relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40\">\n <span\n className={cn(\"absolute top-0 h-full rounded-sm\", BAR_COLOR[row.status])}\n style={{ left: `${leftPct}%`, width: `${widthPct}%` }}\n />\n </span>\n <span className=\"w-16 shrink-0 text-right text-muted-foreground\">\n {formatDuration(row.durationMs)}\n </span>\n </li>\n );\n })}\n </ul>\n </details>\n );\n}\n","/**\n * Pure span normalization + tree building for the OTel trace waterfall.\n * Ported from the formatters trace-view renderer so the React waterfall shows\n * the same structure. Side-effect-free for unit testing.\n */\n\nimport type { OtelSpan } from \"executable-stories-core/types/otel\";\n\nexport interface NormalizedSpan {\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeMs: number;\n durationMs: number;\n status: \"ok\" | \"error\" | \"unset\";\n statusMessage?: string;\n}\n\nexport interface TraceRow extends NormalizedSpan {\n depth: number;\n}\n\nconst VALID = new Set([\"ok\", \"error\", \"unset\"]);\nconst safeStatus = (s: string): NormalizedSpan[\"status\"] => (VALID.has(s) ? (s as NormalizedSpan[\"status\"]) : \"unset\");\n\nexport function normalizeSpans(spans: readonly OtelSpan[]): NormalizedSpan[] {\n const out: NormalizedSpan[] = [];\n for (const span of spans) {\n if (!span || typeof span.spanId !== \"string\" || typeof span.name !== \"string\") continue;\n let startTimeMs: number;\n let durationMs: number;\n if (span.startTimeMs != null && span.durationMs != null) {\n startTimeMs = span.startTimeMs;\n durationMs = span.durationMs;\n } else if (span.startTimeUnixNano != null && span.endTimeUnixNano != null) {\n startTimeMs = span.startTimeUnixNano / 1e6;\n durationMs = (span.endTimeUnixNano - span.startTimeUnixNano) / 1e6;\n } else {\n continue;\n }\n durationMs = Math.max(0, durationMs);\n if (!isFinite(startTimeMs) || !isFinite(durationMs)) continue;\n out.push({\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n startTimeMs,\n durationMs,\n status: safeStatus(span.status),\n statusMessage: span.statusMessage,\n });\n }\n return out;\n}\n\n/** Flatten spans into rows in tree order with a depth, parent before children. */\nexport function toTraceRows(spans: readonly OtelSpan[]): TraceRow[] {\n const normalized = normalizeSpans(spans);\n if (normalized.length === 0) return [];\n\n interface Node {\n span: NormalizedSpan;\n children: Node[];\n depth: number;\n }\n const byId = new Map<string, Node>();\n for (const span of normalized) {\n let key = span.spanId;\n let suffix = 2;\n while (byId.has(key)) key = `${span.spanId}__dup${suffix++}`;\n byId.set(key, { span: { ...span, spanId: key }, children: [], depth: 0 });\n }\n\n const roots: Node[] = [];\n for (const node of byId.values()) {\n const parent = node.span.parentSpanId ? byId.get(node.span.parentSpanId) : undefined;\n if (parent && parent !== node) parent.children.push(node);\n else roots.push(node);\n }\n for (const node of byId.values()) node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n\n const rows: TraceRow[] = [];\n const seen = new Set<string>();\n const walk = (node: Node, depth: number): void => {\n if (seen.has(node.span.spanId)) return;\n seen.add(node.span.spanId);\n rows.push({ ...node.span, depth });\n for (const child of node.children) walk(child, depth + 1);\n };\n for (const root of roots) walk(root, 0);\n // Orphans from cycles: promote to depth 0.\n for (const node of byId.values()) {\n if (!seen.has(node.span.spanId)) walk(node, 0);\n }\n return rows;\n}\n\nexport interface TraceWindow {\n minStartMs: number;\n totalMs: number;\n}\n\nexport function traceWindow(rows: readonly TraceRow[]): TraceWindow {\n let min = Infinity;\n let max = -Infinity;\n for (const r of rows) {\n min = Math.min(min, r.startTimeMs);\n max = Math.max(max, r.startTimeMs + r.durationMs);\n }\n const total = max - min;\n return { minStartMs: isFinite(min) ? min : 0, totalMs: total > 0 ? total : 1 };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ScenarioHistoryMap } from \"../lib/run-history\";\n\n/**\n * Provided only inside <ReportInteractive> when the CLI embedded a run\n * history (--history-file). When null (the static <Report/> render,\n * Storybook, Astro), scenario cards simply omit the history strip.\n */\nconst ScenarioHistoryContext = createContext<ScenarioHistoryMap | null>(null);\n\nexport const ScenarioHistoryProvider = ScenarioHistoryContext.Provider;\n\nexport function useScenarioHistory(): ScenarioHistoryMap | null {\n return useContext(ScenarioHistoryContext);\n}\n","export type ScenarioRunStatus = \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n\n/** One historical run of a scenario, oldest → newest in a history array. */\nexport interface ScenarioRunEvent {\n /** Epoch ms the run started. */\n timestamp: number;\n status: ScenarioRunStatus;\n runId?: string;\n durationMs?: number;\n commitSha?: string;\n branch?: string;\n}\n\n/** Recent run events keyed by ReportScenario.id. */\nexport type ScenarioHistoryMap = Record<string, ScenarioRunEvent[]>;\n\nexport interface RunStreak {\n status: ScenarioRunStatus;\n /** How many consecutive trailing runs share that status (≥1). */\n count: number;\n}\n\n/** The trailing same-status streak — \"passing for 5 runs\", \"failing for 2\". */\nexport function currentStreak(entries: readonly ScenarioRunEvent[]): RunStreak | undefined {\n const last = entries[entries.length - 1];\n if (!last) return undefined;\n let count = 0;\n for (let i = entries.length - 1; i >= 0 && entries[i]!.status === last.status; i--) count++;\n return { status: last.status, count };\n}\n\nconst STREAK_VERB: Record<ScenarioRunStatus, string> = {\n passed: \"Passing\",\n failed: \"Failing\",\n skipped: \"Skipped\",\n pending: \"Pending\",\n};\n\n/** Short human summary of a history window, used for the strip's tooltip. */\nexport function describeRunHistory(entries: readonly ScenarioRunEvent[]): string {\n const passed = entries.filter((e) => e.status === \"passed\").length;\n const base = `${passed}/${entries.length} runs passed`;\n const streak = currentStreak(entries);\n if (!streak || entries.length < 2) return base;\n return `${base} · ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? \"run\" : `${streak.count} runs`}`;\n}\n\nexport type FlakinessLevel = \"stable\" | \"unstable\" | \"flaky\";\n\n/**\n * Below this many pass/fail samples a scenario is always \"stable\" — mirrors\n * MIN_FLAKINESS_SAMPLES in the formatters history module, which owns the\n * canonical thresholds. Keep the two in sync.\n */\nconst MIN_FLAKINESS_SAMPLES = 3;\n\n/**\n * Status-transition flakiness over a scenario's recent runs. Same\n * classification as the CLI history module (`calculateFlakiness`), ported so\n * the island stays self-sufficient on the embedded history JSON.\n */\nexport function flakinessOf(entries: readonly ScenarioRunEvent[]): FlakinessLevel {\n const countable = entries.filter((e) => e.status === \"passed\" || e.status === \"failed\");\n if (countable.length < MIN_FLAKINESS_SAMPLES) return \"stable\";\n\n let transitions = 0;\n for (let i = 1; i < countable.length; i++) {\n if (countable[i]!.status !== countable[i - 1]!.status) transitions++;\n }\n const transitionScore = transitions / (countable.length - 1);\n const failureRate = countable.filter((e) => e.status === \"failed\").length / countable.length;\n\n if (transitionScore > 0.5 || (transitionScore > 0.3 && failureRate > 0.2)) return \"flaky\";\n if (transitionScore > 0.2 || failureRate > 0.3) return \"unstable\";\n return \"stable\";\n}\n\nexport interface ScenarioRef {\n id: string;\n title: string;\n}\n\nexport interface LastRunDelta {\n /** Failed in this run, not failed in the previous one. */\n newlyFailing: ScenarioRef[];\n /** Passed in this run, failed in the previous one. */\n newlyPassing: ScenarioRef[];\n /** First appearance in the history window — no previous run to compare. */\n added: ScenarioRef[];\n}\n\n/**\n * What changed between the previous run and this one, for the report-header\n * strip. The history store appends the current run before the report is\n * generated, so each scenario's last entry IS this run and the entry before\n * it is the previous run. Returns undefined when no scenario has a previous\n * run to compare against (first run with history enabled).\n */\nexport function diffSinceLastRun(\n history: ScenarioHistoryMap,\n scenarios: readonly ScenarioRef[],\n): LastRunDelta | undefined {\n let hasPreviousRun = false;\n const delta: LastRunDelta = { newlyFailing: [], newlyPassing: [], added: [] };\n\n for (const scenario of scenarios) {\n const entries = history[scenario.id];\n if (!entries || entries.length === 0) continue;\n const last = entries[entries.length - 1]!;\n const prev = entries[entries.length - 2];\n if (!prev) {\n delta.added.push(scenario);\n continue;\n }\n hasPreviousRun = true;\n if (last.status === \"failed\" && prev.status !== \"failed\") delta.newlyFailing.push(scenario);\n else if (last.status === \"passed\" && prev.status === \"failed\") delta.newlyPassing.push(scenario);\n }\n\n return hasPreviousRun ? delta : undefined;\n}\n","import { useScenarioHistory } from \"../interactive/scenario-history-context\";\nimport { describeRunHistory, flakinessOf, type ScenarioRunEvent, type ScenarioRunStatus } from \"../lib/run-history\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\n\n/** How many trailing runs the strip shows; older entries stay in the tooltip count. */\nconst MAX_DOTS = 10;\n\nconst DOT_COLOR: Record<ScenarioRunStatus, string> = {\n passed: \"bg-pass\",\n failed: \"bg-fail\",\n skipped: \"bg-skip\",\n pending: \"bg-pend\",\n};\n\nfunction dotTitle(e: ScenarioRunEvent): string {\n const parts = [new Date(e.timestamp).toLocaleString(), e.status];\n if (e.commitSha) parts.push(e.commitSha.slice(0, 8));\n return parts.join(\" · \");\n}\n\n/**\n * Compact run-over-run timeline for one scenario: a dot per recent run,\n * oldest → newest. Renders nothing outside <ReportInteractive> or when the\n * report was generated without --history-file — history is presentation-layer\n * data and never part of the StoryReport contract.\n */\nexport function ScenarioRunHistory({ scenarioId }: { scenarioId: string }) {\n const history = useScenarioHistory();\n const entries = history?.[scenarioId];\n if (!entries || entries.length < 2) return null; // one run = no timeline yet\n\n const recent = entries.slice(-MAX_DOTS);\n // Judge flakiness on the same window the dots show, so the badge never\n // contradicts the strip next to it.\n const flaky = flakinessOf(recent) === \"flaky\";\n const summary = flaky ? `${describeRunHistory(recent)} · Flaky` : describeRunHistory(recent);\n\n return (\n <>\n {flaky ? (\n <Badge variant=\"pending\" aria-label=\"Flaky: status flips between recent runs\" title={summary}>\n Flaky\n </Badge>\n ) : null}\n <span\n role=\"img\"\n aria-label={`Run history: ${summary}`}\n title={summary}\n className=\"flex shrink-0 items-center gap-[3px]\"\n >\n {recent.map((e, i) => (\n <span\n key={`${e.timestamp}-${i}`}\n aria-hidden\n title={dotTitle(e)}\n className={cn(\n \"inline-block size-1.5 rounded-full\",\n DOT_COLOR[e.status],\n // The newest run (rightmost dot) is the one the card's status\n // badge already describes; ring it so the timeline reads as\n // \"…leading up to now\".\n i === recent.length - 1 && \"ring-1 ring-border ring-offset-1 ring-offset-card\",\n )}\n />\n ))}\n </span>\n </>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { formatRelativeAge, isReportStale } from \"../lib/provenance\";\nimport { useScenarioFreshness } from \"../interactive/scenario-freshness-context\";\nimport { Badge } from \"@/components/ui/badge\";\n\n/**\n * Per-scenario age signal.\n *\n * A report assembled from accumulated runs can be freshly rendered while some\n * of its scenarios last ran weeks ago. The report-level banner speaks for the\n * run, not for those scenarios, so without this the carried-over ones borrow a\n * freshness they have not earned.\n *\n * Only scenarios that are actually old say anything: a scenario that ran in\n * this run is the normal case and adds no badge. Age is computed on mount for\n * the same reason the report banner does it — static HTML is generated once and\n * read later, so an age baked in at build time would lie.\n */\nexport function ScenarioStaleness({ scenario }: { scenario: { lastRunAtMs?: number } }) {\n const freshness = useScenarioFreshness();\n const fixedNow = freshness?.nowMs;\n const [now, setNow] = useState<number | undefined>(fixedNow);\n\n useEffect(() => {\n if (fixedNow === undefined) setNow(Date.now());\n }, [fixedNow]);\n\n if (!freshness || now === undefined) return null;\n\n // No stamp means the report predates stamping, or came straight from one run.\n // Either way the report-level signal already speaks for it.\n const lastRunAtMs = scenario.lastRunAtMs;\n if (!lastRunAtMs || lastRunAtMs <= 0) return null;\n if (!isReportStale(lastRunAtMs, freshness.staleAfterDays, now)) return null;\n\n return (\n <Badge variant=\"outline\" aria-label=\"Scenario freshness\">\n Last ran {formatRelativeAge(lastRunAtMs, now)}\n </Badge>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\n\ntype ReportCI = NonNullable<StoryReport[\"ci\"]>;\n\n/**\n * Epoch ms of the run the report documents — the staleness reference.\n * Prefers finishedAtMs; falls back to startedAtMs for reports from adapters\n * that only stamp a start time.\n */\nexport function reportLastRunMs(\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">,\n): number | undefined {\n if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;\n if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;\n return undefined;\n}\n\n/**\n * Epoch ms of the run that produced one scenario.\n *\n * A report assembled from accumulated runs holds scenarios that last ran at\n * different times, so the run-level timestamp overstates how fresh most of them\n * are. Falls back to the report for scenarios recorded before stamping, and for\n * reports rendered straight from a single run.\n */\nexport function scenarioLastRunMs(\n scenario: { lastRunAtMs?: number },\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">,\n): number | undefined {\n if (scenario.lastRunAtMs && scenario.lastRunAtMs > 0) return scenario.lastRunAtMs;\n return reportLastRunMs(report);\n}\n\n/**\n * Human-readable age like \"just now\", \"5 minutes ago\", \"3 hours ago\",\n * \"12 days ago\". Clock skew (thenMs in the future) reads as \"just now\".\n */\nexport function formatRelativeAge(thenMs: number, nowMs: number): string {\n const deltaMs = Math.max(0, nowMs - thenMs);\n const minutes = Math.floor(deltaMs / 60_000);\n if (minutes < 1) return \"just now\";\n if (minutes < 60) return `${minutes} minute${minutes === 1 ? \"\" : \"s\"} ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours} hour${hours === 1 ? \"\" : \"s\"} ago`;\n const days = Math.floor(hours / 24);\n return `${days} day${days === 1 ? \"\" : \"s\"} ago`;\n}\n\n/**\n * A report is stale once its run is `staleAfterDays` or more days old.\n * A threshold of 0 (or negative) disables staleness entirely.\n */\nexport function isReportStale(\n lastRunMs: number | undefined,\n staleAfterDays: number,\n nowMs: number,\n): boolean {\n if (lastRunMs === undefined || staleAfterDays <= 0) return false;\n return nowMs - lastRunMs >= staleAfterDays * 86_400_000;\n}\n\n/**\n * StoryReport.ci.name carries the raw transport name — lowercase provider\n * keys (\"github\") from env detection, or a free-form string from older\n * adapters (\"GitHub Actions\"). Map the known keys to display names and pass\n * everything else through.\n */\nconst CI_DISPLAY_NAMES: Record<string, string> = {\n github: \"GitHub Actions\",\n gitlab: \"GitLab CI\",\n circleci: \"CircleCI\",\n jenkins: \"Jenkins\",\n azure: \"Azure DevOps\",\n buildkite: \"Buildkite\",\n travis: \"Travis CI\",\n ci: \"CI\",\n};\n\nexport function ciDisplayName(name: string): string {\n return CI_DISPLAY_NAMES[name] ?? name;\n}\n\n/**\n * Derive a browsable commit URL from the CI run URL, for the providers whose\n * URL structure makes that safe:\n * GitHub Actions …/owner/repo/actions/runs/123 -> …/owner/repo/commit/<sha>\n * GitLab CI …/group/project/-/pipelines/123 -> …/group/project/-/commit/<sha>\n * Other providers return undefined (a wrong link is worse than none).\n */\nexport function commitUrl(ci: ReportCI | undefined, sha: string | undefined): string | undefined {\n const commitSha = ci?.commitSha ?? sha;\n if (!ci?.url || !commitSha) return undefined;\n\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/commit/${commitSha}`;\n\n const gitlab = ci.url.match(/^(https?:\\/\\/.+)\\/-\\/pipelines\\//);\n if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;\n\n return undefined;\n}\n\n/**\n * Derive a pull-request URL for GitHub-shaped CI run URLs. GitLab and the\n * rest return undefined for the same wrong-link-is-worse-than-none reason.\n */\nexport function prUrl(ci: ReportCI | undefined): string | undefined {\n if (!ci?.url || !ci.prNumber) return undefined;\n const github = ci.url.match(/^(https?:\\/\\/[^/]+\\/[^/]+\\/[^/]+)\\/actions\\/runs\\//);\n if (github) return `${github[1]}/pull/${ci.prNumber}`;\n return undefined;\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { StoryReport } from \"executable-stories-core\";\n\nexport interface ScenarioFreshness {\n /** Days before a scenario counts as stale; 0 disables the signal. */\n staleAfterDays: number;\n /** The run being rendered, used for scenarios carrying no stamp of their own. */\n report: Pick<StoryReport, \"startedAtMs\" | \"finishedAtMs\">;\n /** Test seam: fixed \"now\". Left undefined, the badge reads the clock on mount. */\n nowMs?: number;\n}\n\n/**\n * Provided only where a report knows its staleness threshold. When null (a bare\n * <Report/> render, Storybook), scenario cards simply omit the age signal —\n * same shape as the run-history context.\n */\nconst ScenarioFreshnessContext = createContext<ScenarioFreshness | null>(null);\n\nexport const ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;\n\nexport function useScenarioFreshness(): ScenarioFreshness | null {\n return useContext(ScenarioFreshnessContext);\n}\n","\"use client\";\n\nimport { createContext, useCallback, useContext, useState } from \"react\";\n\nexport interface CollapseApi {\n isCollapsed: (id: string) => boolean;\n toggle: (id: string) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (the static <Report/>\n * render, Storybook, Astro), components render fully expanded with no toggle\n * affordance — so the static path and component-tier tests are unaffected.\n */\nconst CollapseContext = createContext<CollapseApi | null>(null);\n\nexport const CollapseProvider = CollapseContext.Provider;\n\nexport function useCollapse(): CollapseApi | null {\n return useContext(CollapseContext);\n}\n\nconst STORAGE_KEY = \"es-collapsed-ids\";\n\n/** Returns the persisted collapsed set, or null when the user has never set one\n * (so the caller can fall back to a data-driven default like failures-first). */\nfunction readPersisted(): Set<string> | null {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n return raw ? new Set(JSON.parse(raw) as string[]) : null;\n } catch {\n return null;\n }\n}\n\nfunction persist(ids: Set<string>): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...ids]));\n } catch {\n /* quota / disabled — collapse still works for the session */\n }\n}\n\n/**\n * Collapse state for the interactive report: a persisted set of collapsed\n * feature/scenario ids, plus expand-all / collapse-all. `computeDefault` seeds\n * the initial set the FIRST time (nothing persisted yet) — the report uses it\n * to open failures and collapse the rest, so a broken run reveals what failed\n * without a click. Once the user toggles anything, their choice persists and\n * wins over the default.\n */\nexport function useCollapseState(computeDefault?: () => Set<string>) {\n const [collapsed, setCollapsed] = useState<Set<string>>(\n () => readPersisted() ?? computeDefault?.() ?? new Set<string>(),\n );\n\n const isCollapsed = useCallback((id: string) => collapsed.has(id), [collapsed]);\n\n const toggle = useCallback((id: string) => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n persist(next);\n return next;\n });\n }, []);\n\n const collapseAll = useCallback((ids: string[]) => {\n setCollapsed(() => {\n const next = new Set(ids);\n persist(next);\n return next;\n });\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsed(() => {\n const next = new Set<string>();\n persist(next);\n return next;\n });\n }, []);\n\n return { api: { isCollapsed, toggle } as CollapseApi, collapseAll, expandAll };\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { ReportScenario } from \"executable-stories-core\";\n// Deep import, NOT the package barrel: core's index pulls in Node-only modules\n// (attachment resolution reads the filesystem), which a browser bundler cannot\n// resolve. Types erase at compile time, so the type-only import above is safe;\n// this one is a value and must stay on the fs-free subpath.\nimport { scenarioToMarkdown as coreScenarioToMarkdown } from \"executable-stories-core/utils/scenario-markdown\";\n\nexport interface ScenarioActions {\n copyLink: (scenario: ReportScenario) => void;\n copyMarkdown: (scenario: ReportScenario) => void;\n copyPrompt: (scenario: ReportScenario) => void;\n}\n\n/**\n * Provided only inside <ReportInteractive>. When null (static render), scenarios\n * show no per-scenario action buttons.\n */\nconst ScenarioActionsContext = createContext<ScenarioActions | null>(null);\nexport const ScenarioActionsProvider = ScenarioActionsContext.Provider;\nexport function useScenarioActions(): ScenarioActions | null {\n return useContext(ScenarioActionsContext);\n}\n\n/**\n * A scenario rendered as Markdown — for pasting into PRs / issues / docs.\n *\n * Delegates to the shared serializer in core (`variant: \"compact\"`), the same\n * one behind the Astro site's `<slug>.md` twin endpoints, so what you copy here\n * and what an agent fetches there can never drift.\n */\nexport function scenarioToMarkdown(scenario: ReportScenario): string {\n return coreScenarioToMarkdown(scenario, { variant: \"compact\" });\n}\n\n/**\n * A failed scenario rendered as an investigation prompt for an AI agent — the\n * \"cheap to verify\" loop: hand the agent the failing behaviour + error verbatim.\n */\nexport function scenarioToPrompt(scenario: ReportScenario): string {\n const lines: string[] = [\n `A test scenario is ${scenario.status}. Investigate the likely cause and propose a fix.`,\n \"\",\n `Scenario: ${scenario.title}`,\n \"Steps:\",\n ];\n for (const step of scenario.steps) {\n const mark = step.status === \"failed\" ? \" ⟵ failed here\" : \"\";\n lines.push(` ${step.keyword} ${step.text}${mark}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"\", \"Error:\", scenario.errorMessage.trim());\n }\n if (scenario.errorStack) {\n lines.push(\"\", \"Stack:\", scenario.errorStack.trim());\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Every failure in the run as ONE prompt. A red run is rarely one broken thing,\n * and copying scenarios one at a time loses the shape of the breakage — the\n * agent that sees all three at once can spot the shared cause.\n */\nexport function failuresToPrompt(scenarios: readonly ReportScenario[]): string {\n if (scenarios.length === 0) return \"\";\n const noun = scenarios.length === 1 ? \"test scenario is\" : \"test scenarios are\";\n const lines: string[] = [\n `${scenarios.length} ${noun} failing. Investigate the likely cause (they may share one) and propose a fix.`,\n ];\n scenarios.forEach((scenario, i) => {\n lines.push(\"\", `${i + 1}. ${scenario.title}`, \"Steps:\");\n for (const step of scenario.steps) {\n const mark = step.status === \"failed\" ? \" ⟵ failed here\" : \"\";\n lines.push(` ${step.keyword} ${step.text}${mark}`);\n }\n if (scenario.errorMessage) {\n lines.push(\"Error:\", scenario.errorMessage.trim());\n }\n });\n return lines.join(\"\\n\");\n}\n\n/** Absolute permalink to a scenario in the current document. */\nexport function scenarioPermalink(scenario: ReportScenario): string {\n if (typeof location === \"undefined\") return `#${scenario.id}`;\n return `${location.href.split(\"#\")[0]}#${scenario.id}`;\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport { CheckIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst itemClasses =\n \"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\"\n\nfunction DropdownMenu(props: React.ComponentProps<typeof MenuPrimitive.Root>) {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuTrigger(\n props: React.ComponentProps<typeof MenuPrimitive.Trigger>,\n) {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\n\nfunction DropdownMenuContent({\n className,\n align = \"end\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.Popup> & {\n align?: MenuPrimitive.Positioner.Props[\"align\"]\n sideOffset?: MenuPrimitive.Positioner.Props[\"sideOffset\"]\n}) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n data-slot=\"dropdown-menu-positioner\"\n className=\"z-50\"\n align={align}\n sideOffset={sideOffset}\n >\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n className={cn(\n \"z-50 min-w-[11rem] origin-[var(--transform-origin)] overflow-hidden rounded-md border border-border bg-popover p-1 font-sans text-sm text-popover-foreground shadow-md transition-[opacity,transform] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.Item>) {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n className={cn(itemClasses, className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuLabel({\n className,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.GroupLabel>) {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n className={cn(\"px-2 py-1.5 text-xs font-medium text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\n// Base UI's Menu has no Separator part; a plain divider row is equivalent.\nfunction DropdownMenuSeparator({ className }: { className?: string }) {\n return <div role=\"separator\" className={cn(\"-mx-1 my-1 h-px bg-border\", className)} />\n}\n\nfunction DropdownMenuRadioGroup(\n props: React.ComponentProps<typeof MenuPrimitive.RadioGroup>,\n) {\n return <MenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.RadioItem>) {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(itemClasses, \"pl-8\", className)}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.RadioItemIndicator>\n <CheckIcon className=\"size-4 text-foreground\" />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenuPrimitive.CheckboxItem>) {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(itemClasses, \"pl-8\", className)}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon className=\"size-4\" />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuCheckboxItem,\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { ReportScenario } from \"./ReportScenario\";\n\nexport interface ReportScenarioListProps {\n feature: ReportFeature;\n}\n\nexport function ReportScenarioList({ feature }: ReportScenarioListProps) {\n return (\n <>\n {feature.scenarios.map((scenario) => (\n <ReportScenario key={scenario.id} scenario={scenario} />\n ))}\n </>\n );\n}\n","import type { ReportFeature } from \"executable-stories-core\";\nimport { dedent, safeMarkdownHtml } from \"../lib/markdown\";\n\nexport interface ReportFeatureIntroProps {\n feature: ReportFeature;\n}\n\n/**\n * What the feature is for, ahead of the scenarios that prove it.\n *\n * Scenarios answer \"what does it do\". A reader arriving cold needs \"why does\n * this exist and who is it for\" first, which is what `story.feature(...)`\n * records. Renders nothing when a file never declared one, so existing reports\n * look exactly as they did.\n */\nexport function ReportFeatureIntro({ feature }: ReportFeatureIntroProps) {\n const hasNarrative = Boolean(feature.narrative?.trim());\n const hasGlossary = Boolean(feature.glossary?.length);\n if (!hasNarrative && !hasGlossary) return null;\n\n return (\n <div className=\"flex flex-col gap-3 border-l-2 border-border pl-4 text-sm\">\n {hasNarrative ? (\n <div\n className=\"es-doc-prose prose prose-sm max-w-none text-muted-foreground\"\n dangerouslySetInnerHTML={{ __html: safeMarkdownHtml(dedent(feature.narrative!)) }}\n />\n ) : null}\n\n {hasGlossary ? (\n <dl className=\"grid gap-1.5\" aria-label=\"Glossary\">\n {feature.glossary!.map((entry) => (\n <div key={entry.term} className=\"flex flex-wrap gap-x-2 text-xs\">\n <dt className=\"font-medium text-foreground\">{entry.term}</dt>\n <dd className=\"flex-1 text-muted-foreground\">{entry.definition}</dd>\n </div>\n ))}\n </dl>\n ) : null}\n </div>\n );\n}\n\n/**\n * Label the feature the way it was declared.\n *\n * An ability reads as something a person can now do; a business need covers the\n * cross-cutting concerns nobody asks for by name, like security or performance.\n * Naming the kind keeps that distinction visible to a reader who never sees the\n * test code. A derived title gets no badge, since nobody claimed anything.\n */\nexport function featureKindLabel(kind: ReportFeature[\"kind\"]): string | null {\n if (kind === \"ability\") return \"Ability\";\n if (kind === \"business-need\") return \"Business need\";\n if (kind === \"feature\") return \"Feature\";\n return null;\n}\n","import type { ReportFeature as ReportFeatureT } from \"executable-stories-core\";\nimport { ReportScenarioList } from \"./ReportScenarioList\";\nimport { ReportFeatureIntro, featureKindLabel } from \"./ReportFeatureIntro\";\nimport { useCollapse } from \"../interactive/collapse-context\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportFeatureProps {\n feature: ReportFeatureT;\n}\n\n/**\n * Feature group — the report's `.feature` card: a header bar with the feature\n * title + mono source path and ✓/✗/○ status counts on the right, over a stack\n * of scenario cards. Kept a semantic <section> (a region), not a shadcn Card\n * div, so it stays a landmark and doesn't collide with the scenario cards'\n * `[data-slot=\"card\"]`.\n */\nexport function ReportFeature({ feature }: ReportFeatureProps) {\n const titleId = `${feature.id}-title`;\n const bodyId = `${feature.id}-body`;\n const s = feature.summary;\n const skipped = s.skipped + s.pending;\n const collapse = useCollapse();\n const collapsed = collapse?.isCollapsed(feature.id) ?? false;\n const kindLabel = featureKindLabel(feature.kind);\n return (\n // Suite = a section heading + a divider, NOT another bordered card. Drops a\n // layer of nesting so the scenario cards below read as the primary unit.\n <section\n id={feature.id}\n data-slot=\"feature\"\n aria-labelledby={titleId}\n className=\"flex flex-col gap-3\"\n >\n <div className=\"flex items-end justify-between gap-4 border-b border-border pb-2\">\n <div className=\"min-w-0\">\n {/* The heading itself is the toggle — a wide, obvious hit area rather\n than a lone caret. Kept inside <h2> so it stays a landmark. */}\n <h2 id={titleId} className=\"text-base font-semibold tracking-tight text-foreground\">\n {collapse ? (\n <button\n type=\"button\"\n onClick={() => collapse.toggle(feature.id)}\n aria-expanded={!collapsed}\n aria-controls={bodyId}\n className=\"flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80\"\n >\n <span aria-hidden className={cn(\"shrink-0 text-xs text-muted-foreground transition-transform\", !collapsed && \"rotate-90\")}>▸</span>\n <span className=\"truncate\">{feature.title}</span>\n </button>\n ) : (\n feature.title\n )}\n </h2>\n <p className={cn(\"mt-0.5 flex items-center gap-2 text-xs text-muted-foreground\", collapse && \"pl-5\")}>\n {kindLabel ? (\n <span className=\"shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground\">\n {kindLabel}\n </span>\n ) : null}\n <span className=\"truncate font-mono\">{feature.sourceFile}</span>\n </p>\n </div>\n {/* Readable, failure-weighted counts — only the failure count carries\n colour, so a broken suite reads at a glance without a colour salad. */}\n <p\n className=\"flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground\"\n aria-label={`${s.passed} passed, ${s.failed} failed, ${skipped} skipped`}\n >\n <span>{s.passed} passed</span>\n <span aria-hidden>·</span>\n <span className={cn(s.failed > 0 && \"font-medium text-fail\")}>{s.failed} failed</span>\n {skipped > 0 ? (\n <>\n <span aria-hidden>·</span>\n <span>{skipped} skipped</span>\n </>\n ) : null}\n </p>\n </div>\n <div id={bodyId} hidden={collapsed} className=\"flex flex-col gap-3\">\n <ReportFeatureIntro feature={feature} />\n <ReportScenarioList feature={feature} />\n </div>\n </section>\n );\n}\n","import { useReport } from \"../hooks/useReport\";\nimport { ReportFeature } from \"./ReportFeature\";\n\nexport function ReportFeatureList() {\n const report = useReport();\n // Roomy gap between features — they're now divider-led sections rather than\n // self-contained cards, so they need clear air to read as separate suites.\n return (\n <div className=\"flex flex-col gap-8\">\n {report.features.map((feature) => (\n <ReportFeature key={feature.id} feature={feature} />\n ))}\n </div>\n );\n}\n","import { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Empty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst emptyMediaVariants = cva(\n \"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\nfunction EmptyTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n )\n}\n\nfunction EmptyDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction EmptyContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n}\n","import { Empty, EmptyHeader, EmptyTitle } from \"@/components/ui/empty\";\n\nexport interface ReportEmptyProps {\n message?: string;\n}\n\nexport function ReportEmpty({ message }: ReportEmptyProps) {\n return (\n <Empty aria-live=\"polite\" className=\"border\">\n <EmptyHeader>\n <EmptyTitle>{message ?? \"No scenarios in this report.\"}</EmptyTitle>\n </EmptyHeader>\n </Empty>\n );\n}\n","import type { ReportSummary as ReportSummaryT } from \"executable-stories-core\";\nimport { useReport } from \"../hooks/useReport\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReportSummaryProps {\n className?: string;\n}\n\nexport function ReportSummary({ className }: ReportSummaryProps) {\n const report = useReport();\n return (\n <ReportSummaryView\n summary={report.summary}\n {...(className !== undefined && { className })}\n ariaLabel=\"Run summary\"\n />\n );\n}\n\nexport interface ReportSummaryViewProps {\n summary: ReportSummaryT;\n className?: string;\n ariaLabel?: string;\n}\n\n/**\n * A single stat card. All cards share the neutral card surface; the status\n * *number* carries the colour (`--es-pass/fail/skip/pend`, mapped to Tailwind\n * in tailwind.css) and a matching leading dot. This drops the earlier pastel\n * fills for the flatter, dashboard-style KPI treatment — a mono micro-label\n * above an oversized tabular number.\n */\nconst TONE = {\n total: { num: \"text-foreground\", dot: \"bg-muted-foreground/50\" },\n passed: { num: \"text-pass\", dot: \"bg-pass\" },\n failed: { num: \"text-fail\", dot: \"bg-fail\" },\n skipped: { num: \"text-skip\", dot: \"bg-skip\" },\n pending: { num: \"text-pend\", dot: \"bg-pend\" },\n} as const;\n\nexport function ReportSummaryView({ summary, className, ariaLabel }: ReportSummaryViewProps) {\n const cards: Array<{ status: keyof typeof TONE; label: string; value: number }> = [\n { status: \"total\", label: \"Total\", value: summary.total },\n { status: \"passed\", label: \"Passed\", value: summary.passed },\n { status: \"failed\", label: \"Failed\", value: summary.failed },\n { status: \"skipped\", label: \"Skipped\", value: summary.skipped },\n ];\n if (summary.pending > 0) {\n cards.push({ status: \"pending\", label: \"Pending\", value: summary.pending });\n }\n return (\n <dl\n className={cn(\n \"grid grid-cols-2 gap-3\",\n // Columns follow the card count so the row is always full — 5 statuses\n // (pending present) never leave a lone orphan card below a row of four.\n cards.length === 5 ? \"sm:grid-cols-5\" : \"sm:grid-cols-4\",\n className,\n )}\n aria-label={ariaLabel}\n >\n {cards.map((c) => {\n const tone = TONE[c.status];\n return (\n <div\n key={c.status}\n data-status={c.status}\n className=\"rounded-lg border bg-card px-4 py-3\"\n >\n <dt className=\"flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground\">\n <span className={cn(\"size-1.5 shrink-0 rounded-full\", tone.dot)} aria-hidden=\"true\" />\n {c.label}\n </dt>\n <dd className={cn(\"mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums\", tone.num)}>\n {c.value}\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n","import { formatDuration } from \"executable-stories-core/utils/duration\";\nimport { slowestScenarios } from \"executable-stories-core/report-queries\";\nimport { useReport } from \"../hooks/useReport\";\nimport { ciDisplayName, commitUrl, prUrl } from \"../lib/provenance\";\n\n/**\n * Run metadata line (started, duration, version, branch, git SHA, CI, PR) —\n * the React equivalent of the report's `.meta-info` block. Reads the top-level\n * StoryReport fields from context. Commit and PR become links when the CI run\n * URL lets us derive them safely (GitHub/GitLab shapes only).\n */\nexport function ReportMeta() {\n const report = useReport();\n\n const items: Array<{ label: string; value: React.ReactNode }> = [];\n const linkClass = \"text-primary underline underline-offset-2\";\n\n if (report.startedAtMs) {\n items.push({ label: \"Started\", value: new Date(report.startedAtMs).toLocaleString() });\n }\n if (report.durationMs) {\n items.push({ label: \"Duration\", value: formatDuration(report.durationMs) });\n }\n if (report.packageVersion) {\n items.push({ label: \"Version\", value: report.packageVersion });\n }\n if (report.ci?.branch) {\n items.push({ label: \"Branch\", value: report.ci.branch });\n }\n const sha = report.ci?.commitSha ?? report.gitSha;\n if (sha) {\n const url = commitUrl(report.ci, report.gitSha);\n const short = sha.slice(0, 8);\n items.push({\n label: \"Commit\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {short}\n </a>\n ) : (\n short\n ),\n });\n }\n if (report.ci) {\n items.push({\n label: \"CI\",\n value: report.ci.url ? (\n <a href={report.ci.url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {ciDisplayName(report.ci.name)}\n {report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}\n </a>\n ) : (\n `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : \"\"}`\n ),\n });\n }\n if (report.ci?.prNumber) {\n const url = prUrl(report.ci);\n const label = `#${report.ci.prNumber}`;\n items.push({\n label: \"PR\",\n value: url ? (\n <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" className={linkClass}>\n {label}\n </a>\n ) : (\n label\n ),\n });\n }\n\n // A \"slowest\" list needs a field to rank: below a handful of timed scenarios\n // it just repeats the run in a different order.\n const slowest = slowestScenarios(report, 5);\n const showSlowest = slowest.length >= 3;\n\n if (items.length === 0 && !showSlowest) return null;\n\n return (\n // Run metadata is useful but secondary to \"what failed\" — tuck it into a\n // collapsed disclosure so it doesn't push the result down. Native <details>\n // so it works with no JS (the SSR/no-hydration report still toggles).\n <details data-es-meta-card className=\"es-run-details group rounded-lg border border-border bg-card text-xs\">\n <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\">\n <span aria-hidden className=\"text-xs transition-transform group-open:rotate-90\">▸</span>\n Run details\n </summary>\n <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\">\n {items.map((item) => (\n <div key={item.label} className=\"flex items-baseline gap-1.5\">\n <dt className=\"font-medium\">{item.label}</dt>\n <dd className=\"font-mono text-foreground\">{item.value}</dd>\n </div>\n ))}\n </dl>\n {showSlowest ? (\n <div className=\"border-t border-border px-4 py-3\">\n <div className=\"mb-1.5 font-medium text-muted-foreground\">Slowest scenarios</div>\n <ol className=\"flex flex-col gap-1\" aria-label=\"Slowest scenarios\">\n {slowest.map((s) => (\n <li key={s.id} className=\"flex items-baseline justify-between gap-4\">\n <a href={`#${s.id}`} className=\"min-w-0 text-primary underline underline-offset-2\">\n {s.title}\n </a>\n <span className=\"shrink-0 font-mono tabular-nums text-muted-foreground\">\n {formatDuration(s.durationMs)}\n </span>\n </li>\n ))}\n </ol>\n </div>\n ) : null}\n </details>\n );\n}\n","import type { ReportParseError } from \"../result\";\n\nexport interface ReportSchemaErrorProps {\n error: ReportParseError;\n}\n\nexport function ReportSchemaError({ error }: ReportSchemaErrorProps) {\n return (\n <section className=\"es-schema-error\" role=\"alert\" aria-live=\"assertive\">\n <p>\n <strong>Report could not be displayed.</strong>\n </p>\n <p>{error.message}</p>\n {error.code === \"SCHEMA_VERSION_MISMATCH\" ? (\n <p>\n The report bundle is newer than this version of <code>executable-stories-react</code>.\n Upgrade the package, or regenerate the report with an older formatters CLI.\n </p>\n ) : null}\n {error.issues && error.issues.length > 0 ? (\n <details>\n <summary>{error.issues.length} validation issue{error.issues.length === 1 ? \"\" : \"s\"}</summary>\n <pre>\n {error.issues\n .slice(0, 20)\n .map((i) => `${i.path}: ${i.message}`)\n .join(\"\\n\")}\n </pre>\n </details>\n ) : null}\n </section>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { ReportParseError } from \"../result\";\nimport { cn } from \"../lib/utils\";\nimport { ReportSummary } from \"./ReportSummary\";\nimport { ReportMeta } from \"./ReportMeta\";\nimport { ReportSchemaError } from \"./ReportSchemaError\";\n\n/**\n * The report's title block — `<h1>` + summary + meta. Shared by the static\n * `Report` header and the interactive `ReportInteractive` header so the two\n * views can't drift on the no-JS fallback.\n */\nexport function ReportTitleBlock({ title }: { title?: string }) {\n return (\n <>\n <h1>{title ?? \"Story Report\"}</h1>\n <ReportSummary />\n <ReportMeta />\n </>\n );\n}\n\n/**\n * The `<main>` landmark shown when the report failed to parse. Both entrypoints\n * render the identical shell on a `Result` error, so it lives here once.\n */\nexport function ReportErrorShell({\n error,\n className,\n title,\n dataTheme,\n}: {\n error: ReportParseError;\n className?: string;\n title?: string;\n dataTheme?: \"light\" | \"dark\";\n}): ReactNode {\n return (\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <ReportSchemaError error={error} />\n </main>\n );\n}\n","import type { StoryReport } from \"executable-stories-core\";\nimport type { Result } from \"../result\";\nimport { unwrapReport } from \"../result\";\nimport type { BuiltinRenderers, CustomRenderers } from \"../renderers\";\nimport { ReportRoot } from \"../context/ReportRoot\";\nimport { ReportFeatureList } from \"./ReportFeatureList\";\nimport { ReportEmpty } from \"./ReportEmpty\";\nimport { ReportTitleBlock, ReportErrorShell } from \"./ReportShell\";\nimport { cn } from \"../lib/utils\";\n\nexport interface ReportProps {\n /** A StoryReport, or a Result-wrapped one (e.g., from parseStoryReport). */\n report: StoryReport | Result<StoryReport>;\n /** Renderers keyed by `story.custom({ type })` strings. */\n customRenderers?: CustomRenderers;\n /** Optional overrides for the heavy built-ins (mermaid, code, section). */\n renderers?: BuiltinRenderers;\n /** Optional class on the <main> landmark for layout positioning. */\n className?: string;\n /** Optional override title. */\n title?: string;\n /** Optional theme attribute scope. Use to force \"light\" or \"dark\". */\n dataTheme?: \"light\" | \"dark\";\n}\n\nexport function Report(props: ReportProps) {\n const { report, customRenderers, renderers, className, title, dataTheme } = props;\n const result = unwrapReport(report);\n if (!result.ok) {\n return <ReportErrorShell error={result.error} className={className} title={title} dataTheme={dataTheme} />;\n }\n const data = result.data;\n const hasContent = data.features.length > 0;\n return (\n <ReportRoot report={data} customRenderers={customRenderers} renderers={renderers}>\n <main className={cn(\"es-report\", className)} aria-label={title ?? \"Test report\"} data-theme={dataTheme}>\n <header className=\"es-report-header\">\n <ReportTitleBlock title={title} />\n </header>\n {hasContent ? <ReportFeatureList /> : <ReportEmpty />}\n </main>\n </ReportRoot>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_react","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","EMPTY_RENDERERS","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","safeStringify","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_url","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","React","import_jsx_runtime","React","import_jsx_runtime","MenuPrimitive","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_duration","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}