@adoptai/genui-components 0.1.56 → 0.1.58

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.
Files changed (52) hide show
  1. package/dist/builders/BuilderForm.d.ts.map +1 -1
  2. package/dist/composites/decision-card/resolver.cjs +634 -0
  3. package/dist/composites/decision-card/resolver.cjs.map +1 -0
  4. package/dist/composites/decision-card/resolver.d.ts +13 -0
  5. package/dist/composites/decision-card/resolver.d.ts.map +1 -0
  6. package/dist/composites/decision-card/resolver.js +627 -0
  7. package/dist/composites/decision-card/resolver.js.map +1 -0
  8. package/dist/composites/document-field-extraction/FieldAuditLog.d.ts +27 -0
  9. package/dist/composites/document-field-extraction/FieldAuditLog.d.ts.map +1 -0
  10. package/dist/composites/document-field-extraction/FieldDetail.d.ts +22 -0
  11. package/dist/composites/document-field-extraction/FieldDetail.d.ts.map +1 -0
  12. package/dist/composites/document-field-extraction/FieldDetails.d.ts +18 -0
  13. package/dist/composites/document-field-extraction/FieldDetails.d.ts.map +1 -0
  14. package/dist/composites/document-field-extraction/bboxTransform.d.ts +25 -0
  15. package/dist/composites/document-field-extraction/bboxTransform.d.ts.map +1 -0
  16. package/dist/composites/document-field-extraction/fieldLabels.d.ts +2 -0
  17. package/dist/composites/document-field-extraction/fieldLabels.d.ts.map +1 -0
  18. package/dist/composites/document-field-extraction/resolver.d.ts +16 -0
  19. package/dist/composites/document-field-extraction/resolver.d.ts.map +1 -0
  20. package/dist/composites/workflow-stepper/resolver.cjs +4 -1
  21. package/dist/composites/workflow-stepper/resolver.cjs.map +1 -1
  22. package/dist/composites/workflow-stepper/resolver.js +4 -1
  23. package/dist/composites/workflow-stepper/resolver.js.map +1 -1
  24. package/dist/index.cjs +2735 -382
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2530 -183
  29. package/dist/index.js.map +1 -1
  30. package/dist/renderer.cjs +2410 -178
  31. package/dist/renderer.cjs.map +1 -1
  32. package/dist/renderer.js +2267 -35
  33. package/dist/renderer.js.map +1 -1
  34. package/dist/resolver.cjs +2409 -177
  35. package/dist/resolver.cjs.map +1 -1
  36. package/dist/resolver.d.ts.map +1 -1
  37. package/dist/resolver.js +2267 -35
  38. package/dist/resolver.js.map +1 -1
  39. package/dist/schemas/decision-card.d.ts +149 -0
  40. package/dist/schemas/decision-card.d.ts.map +1 -0
  41. package/dist/schemas/document-field-extraction.d.ts +258 -0
  42. package/dist/schemas/document-field-extraction.d.ts.map +1 -0
  43. package/dist/schemas/index.cjs +283 -1
  44. package/dist/schemas/index.cjs.map +1 -1
  45. package/dist/schemas/index.d.ts +407 -0
  46. package/dist/schemas/index.d.ts.map +1 -1
  47. package/dist/schemas/index.js +283 -1
  48. package/dist/schemas/index.js.map +1 -1
  49. package/dist/shared/InteractionContext.d.ts +10 -0
  50. package/dist/shared/InteractionContext.d.ts.map +1 -1
  51. package/dist/tool-definitions.json +359 -3
  52. package/package.json +1 -1
package/dist/renderer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import React41, { lazy, createContext, useState, useCallback, useEffect, useRef, Suspense, useMemo, useContext, useLayoutEffect } from 'react';
2
+ import React45, { lazy, createContext, useState, useCallback, useEffect, useRef, Suspense, useMemo, useContext, useLayoutEffect } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import dagre from '@dagrejs/dagre';
5
5
  import { createPortal } from 'react-dom';
@@ -5277,6 +5277,286 @@ var workflowStepperTool = {
5277
5277
  required: ["type", "title", "steps"]
5278
5278
  }
5279
5279
  };
5280
+ var bbox = z.tuple([z.number(), z.number(), z.number(), z.number()]);
5281
+ var fieldSchema = z.object({
5282
+ field_key: z.string(),
5283
+ label: z.string(),
5284
+ value: z.string(),
5285
+ page: z.number(),
5286
+ // 0-indexed, matches PageDimension.page
5287
+ bbox: bbox.nullable().optional(),
5288
+ confidence: z.number().optional(),
5289
+ confidence_tier: z.enum(["green", "amber", "red"]).optional(),
5290
+ badge: z.enum(["SC", "CN", "AB", "SW"]).optional(),
5291
+ state: z.enum(["ok", "corrected", "missing", "warn"]).optional(),
5292
+ entity_type: z.string().optional(),
5293
+ is_primary: z.boolean().optional(),
5294
+ // Set after a human correction (extractor output, or an optimistic in-card
5295
+ // edit) so the editable field card can show old → new and who changed it.
5296
+ previous_value: z.string().nullable().optional(),
5297
+ corrected_by: z.string().nullable().optional()
5298
+ });
5299
+ var pageSchema = z.object({
5300
+ page: z.number(),
5301
+ // 0-indexed
5302
+ imageUrl: z.string().optional(),
5303
+ // host-resolved from the durable image_ref
5304
+ width_pt: z.number(),
5305
+ height_pt: z.number()
5306
+ });
5307
+ var summaryStatSchema = z.object({
5308
+ field_key: z.string(),
5309
+ label: z.string(),
5310
+ value: z.string(),
5311
+ caption: z.string().nullable().optional()
5312
+ });
5313
+ var summaryFactSchema = z.object({
5314
+ field_key: z.string(),
5315
+ label: z.string(),
5316
+ value: z.string(),
5317
+ badge: z.string().nullable().optional()
5318
+ });
5319
+ var summarySchema = z.object({
5320
+ display_name: z.string().nullable().optional(),
5321
+ short_name: z.string().nullable().optional(),
5322
+ organization: z.string().nullable().optional(),
5323
+ domain: z.string().nullable().optional(),
5324
+ domain_group: z.string().nullable().optional(),
5325
+ tax_year: z.union([z.string(), z.number()]).nullable().optional(),
5326
+ crumbs: z.array(z.string()).optional(),
5327
+ tags: z.array(z.string()).optional(),
5328
+ stats: z.array(summaryStatSchema).optional(),
5329
+ facts: z.array(summaryFactSchema).optional()
5330
+ });
5331
+ var documentFieldExtractionSchema = z.object({
5332
+ type: z.literal("document-field-extraction"),
5333
+ doc_type: z.string().optional(),
5334
+ // Original uploaded filename (e.g. "2024_gl.pdf"); preferred over doc_type for
5335
+ // the card title since doc_type is often the "generic_fallback" schema name.
5336
+ file_name: z.string().optional(),
5337
+ // Server-side token; resolved by the host into pages/fields before render.
5338
+ payload_ref: z.string().optional(),
5339
+ // Present for persisted workstream docs; absent for pre-existing cards.
5340
+ store_id: z.string().optional(),
5341
+ doc_id: z.string().optional(),
5342
+ pages: z.array(pageSchema).max(100).optional(),
5343
+ fields: z.array(fieldSchema).max(1e3).optional(),
5344
+ // Page-count metadata for the Details tab ("N of M pages extracted").
5345
+ page_count: z.number().optional(),
5346
+ pages_processed: z.number().optional(),
5347
+ // Deterministic document summary for the Details tab.
5348
+ summary: summarySchema.nullable().optional()
5349
+ });
5350
+ var documentFieldExtractionTool = {
5351
+ name: "render_document_field_extraction",
5352
+ description: "Render extracted document fields as an interactive overlay on the page image(s) \u2014 colored bounding boxes per field plus a synced field-card list. Use after the extract_document tool returns; pass the returned payload_ref (the host expands it). For invoices, statements, tax forms, receipts, KYC/loan docs, POs where the user wants to SEE where each value sits on the page.",
5353
+ input_schema: {
5354
+ type: "object",
5355
+ properties: {
5356
+ type: { type: "string", enum: ["document-field-extraction"] },
5357
+ doc_type: { type: "string" },
5358
+ file_name: {
5359
+ type: "string",
5360
+ description: "Original uploaded filename; shown as the card title."
5361
+ },
5362
+ payload_ref: {
5363
+ type: "string",
5364
+ description: "Durable store key returned by extract_document; the GenUI host expands it into pages/fields at render time. Pass this verbatim \u2014 do NOT hand-build pages/fields."
5365
+ },
5366
+ store_id: {
5367
+ type: "string",
5368
+ description: "Docstore store id; present for persisted workstream docs. The host uses this to open the editable viewer."
5369
+ },
5370
+ doc_id: {
5371
+ type: "string",
5372
+ description: "Docstore document id; present for persisted workstream docs. Required for the editable viewer."
5373
+ },
5374
+ pages: {
5375
+ type: "array",
5376
+ items: {
5377
+ type: "object",
5378
+ properties: {
5379
+ page: { type: "number", description: "0-indexed page number" },
5380
+ imageUrl: { type: "string" },
5381
+ width_pt: { type: "number" },
5382
+ height_pt: { type: "number" }
5383
+ },
5384
+ required: ["page", "width_pt", "height_pt"]
5385
+ }
5386
+ },
5387
+ fields: {
5388
+ type: "array",
5389
+ items: {
5390
+ type: "object",
5391
+ properties: {
5392
+ field_key: { type: "string" },
5393
+ label: { type: "string" },
5394
+ value: { type: "string" },
5395
+ page: { type: "number", description: "0-indexed page number" },
5396
+ bbox: {
5397
+ type: "array",
5398
+ items: { type: "number" },
5399
+ description: "[x0,y0,x1,y1] PDF points, origin bottom-left; null if unlocated"
5400
+ },
5401
+ confidence: { type: "number" },
5402
+ confidence_tier: { type: "string", enum: ["green", "amber", "red"] },
5403
+ badge: { type: "string", enum: ["SC", "CN", "AB", "SW"] },
5404
+ state: { type: "string", enum: ["ok", "corrected", "missing", "warn"] },
5405
+ entity_type: { type: "string" },
5406
+ is_primary: { type: "boolean" }
5407
+ },
5408
+ required: ["field_key", "label", "value", "page"]
5409
+ }
5410
+ },
5411
+ page_count: { type: "number" },
5412
+ pages_processed: { type: "number" },
5413
+ summary: {
5414
+ type: "object",
5415
+ description: "Deterministic document summary for the Details tab (display_name, organization, domain, stats, facts, tags). Produced by the extractor \u2014 pass through verbatim.",
5416
+ properties: {
5417
+ display_name: { type: "string" },
5418
+ short_name: { type: "string" },
5419
+ organization: { type: "string" },
5420
+ domain: { type: "string" },
5421
+ domain_group: { type: "string" },
5422
+ tax_year: { type: "string" },
5423
+ crumbs: { type: "array", items: { type: "string" } },
5424
+ tags: { type: "array", items: { type: "string" } },
5425
+ stats: {
5426
+ type: "array",
5427
+ items: {
5428
+ type: "object",
5429
+ properties: {
5430
+ field_key: { type: "string" },
5431
+ label: { type: "string" },
5432
+ value: { type: "string" },
5433
+ caption: { type: "string" }
5434
+ },
5435
+ required: ["field_key", "label", "value"]
5436
+ }
5437
+ },
5438
+ facts: {
5439
+ type: "array",
5440
+ items: {
5441
+ type: "object",
5442
+ properties: {
5443
+ field_key: { type: "string" },
5444
+ label: { type: "string" },
5445
+ value: { type: "string" },
5446
+ badge: { type: "string" }
5447
+ },
5448
+ required: ["field_key", "label", "value"]
5449
+ }
5450
+ }
5451
+ }
5452
+ }
5453
+ },
5454
+ required: ["type"]
5455
+ }
5456
+ };
5457
+ var decisionCardSchema = z.object({
5458
+ type: z.literal("decision-card"),
5459
+ id: z.string().optional(),
5460
+ decision_type: z.string().optional(),
5461
+ title: z.string(),
5462
+ question: z.string(),
5463
+ amount: z.number().optional(),
5464
+ currency: z.string().optional(),
5465
+ amount_label: z.string().optional(),
5466
+ severity: z.enum(["low", "medium", "high"]).optional(),
5467
+ flags: z.array(
5468
+ z.object({
5469
+ field: z.string().optional(),
5470
+ issue: z.string(),
5471
+ severity: z.enum(["low", "medium", "high"]).optional()
5472
+ })
5473
+ ).max(6).optional(),
5474
+ options: z.array(
5475
+ z.object({
5476
+ id: z.string().optional(),
5477
+ label: z.string(),
5478
+ recommended: z.boolean().optional()
5479
+ })
5480
+ ).min(1).max(5),
5481
+ source: z.object({
5482
+ label: z.string().optional(),
5483
+ url: z.string().optional()
5484
+ }).optional(),
5485
+ resolved: z.object({
5486
+ option: z.string()
5487
+ }).optional()
5488
+ });
5489
+ var decisionCardTool = {
5490
+ name: "render_decision_card",
5491
+ description: "Render an inline human-in-the-loop (HITL) decision card \u2014 a single judgment the agent needs from the user, resolved in-thread. Shows a titled question with an optional dollar amount at stake, optional data-quality flags, and 2-5 mutually-exclusive resolution options (the first or `recommended` one renders as the primary action), plus an optional 'view source' link. Use for inline approve/choose decisions the user resolves directly in the conversation. NOT for handing off to an external review portal (use escalation-card) and NOT for collecting multiple typed fields (use render_builder).",
5492
+ input_schema: {
5493
+ type: "object",
5494
+ properties: {
5495
+ type: { type: "string", enum: ["decision-card"] },
5496
+ id: { type: "string", description: "Stable id for update-in-place rendering" },
5497
+ decision_type: {
5498
+ type: "string",
5499
+ description: "Short category shown in the eyebrow, e.g. 'Cross-check', 'Allocation', 'Reserve'"
5500
+ },
5501
+ title: { type: "string", description: "The decision headline, e.g. 'AR reserve adequacy'" },
5502
+ question: { type: "string", description: "The full question / context the user must judge" },
5503
+ amount: { type: "number", description: "Dollar value at stake, e.g. 27100" },
5504
+ currency: { type: "string", description: "ISO currency code; defaults to USD" },
5505
+ amount_label: { type: "string", description: "Caption above the amount, e.g. 'At stake'" },
5506
+ severity: {
5507
+ type: "string",
5508
+ enum: ["low", "medium", "high"],
5509
+ description: "Severity of the decision; tints the accent rail"
5510
+ },
5511
+ flags: {
5512
+ type: "array",
5513
+ maxItems: 6,
5514
+ description: "Optional data-quality flags surfaced on the card",
5515
+ items: {
5516
+ type: "object",
5517
+ properties: {
5518
+ field: { type: "string" },
5519
+ issue: { type: "string" },
5520
+ severity: { type: "string", enum: ["low", "medium", "high"] }
5521
+ },
5522
+ required: ["issue"]
5523
+ }
5524
+ },
5525
+ options: {
5526
+ type: "array",
5527
+ minItems: 1,
5528
+ maxItems: 5,
5529
+ description: "Mutually-exclusive resolution choices; mark one `recommended` to make it primary",
5530
+ items: {
5531
+ type: "object",
5532
+ properties: {
5533
+ id: { type: "string" },
5534
+ label: { type: "string" },
5535
+ recommended: { type: "boolean" }
5536
+ },
5537
+ required: ["label"]
5538
+ }
5539
+ },
5540
+ source: {
5541
+ type: "object",
5542
+ description: "Optional provenance link for the figure",
5543
+ properties: {
5544
+ label: { type: "string" },
5545
+ url: { type: "string" }
5546
+ }
5547
+ },
5548
+ resolved: {
5549
+ type: "object",
5550
+ description: "Pre-resolved state for transcript replay",
5551
+ properties: {
5552
+ option: { type: "string" }
5553
+ },
5554
+ required: ["option"]
5555
+ }
5556
+ },
5557
+ required: ["type", "title", "question", "options"]
5558
+ }
5559
+ };
5280
5560
 
5281
5561
  // src/schemas/index.ts
5282
5562
  var schemaRegistry = {
@@ -5336,7 +5616,9 @@ var schemaRegistry = {
5336
5616
  "connect-integration": { schema: connectIntegrationSchema, tool: connectIntegrationTool },
5337
5617
  "integrations-list": { schema: integrationsListSchema, tool: integrationsListTool },
5338
5618
  "pipeline-preview": { schema: pipelinePreviewSchema, tool: pipelinePreviewTool },
5339
- "workflow-stepper": { schema: workflowStepperSchema, tool: workflowStepperTool }
5619
+ "workflow-stepper": { schema: workflowStepperSchema, tool: workflowStepperTool },
5620
+ "document-field-extraction": { schema: documentFieldExtractionSchema, tool: documentFieldExtractionTool },
5621
+ "decision-card": { schema: decisionCardSchema, tool: decisionCardTool }
5340
5622
  };
5341
5623
 
5342
5624
  // src/schemas/coercePayload.ts
@@ -6074,17 +6356,17 @@ function SparklineTableResolver(p) {
6074
6356
  // src/composites/heatmap-table/resolver.tsx
6075
6357
  init_theme();
6076
6358
  init_ThemeContext();
6077
- function heatColor(z58) {
6078
- const clamped = Math.max(-3, Math.min(3, z58));
6359
+ function heatColor(z60) {
6360
+ const clamped = Math.max(-3, Math.min(3, z60));
6079
6361
  const abs = Math.abs(clamped);
6080
6362
  const lightness = 95 - abs * 8;
6081
6363
  const hue = clamped >= 0 ? 142 : 0;
6082
6364
  return `hsl(${hue} 60% ${lightness}%)`;
6083
6365
  }
6084
- function heatTextColor(z58) {
6085
- const abs = Math.abs(z58);
6086
- if (abs > 2) return z58 >= 0 ? "#14532d" : "#7f1d1d";
6087
- if (abs > 1) return z58 >= 0 ? "#166534" : "#991b1b";
6366
+ function heatTextColor(z60) {
6367
+ const abs = Math.abs(z60);
6368
+ if (abs > 2) return z60 >= 0 ? "#14532d" : "#7f1d1d";
6369
+ if (abs > 1) return z60 >= 0 ? "#166534" : "#991b1b";
6088
6370
  return "var(--foreground)";
6089
6371
  }
6090
6372
  var th2 = {
@@ -6718,7 +7000,7 @@ function WaterfallChartResolver(p) {
6718
7000
  ] }) });
6719
7001
  }
6720
7002
  init_ThemeContext();
6721
- var FlowGraph2 = React41.lazy(
7003
+ var FlowGraph2 = React45.lazy(
6722
7004
  () => Promise.resolve().then(() => (init_FlowGraph(), FlowGraph_exports)).then((m) => ({ default: m.FlowGraph }))
6723
7005
  );
6724
7006
  function FlowCanvasRenderer({
@@ -6992,7 +7274,7 @@ function TrialBalanceResolver(p) {
6992
7274
  gDebit += a.debit;
6993
7275
  gCredit += a.credit;
6994
7276
  });
6995
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
7277
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
6996
7278
  /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 4, style: {
6997
7279
  padding: "8px 12px",
6998
7280
  fontSize: "12px",
@@ -8378,10 +8660,10 @@ function useFullscreen(ref) {
8378
8660
  // src/composites/document-preview/resolver.tsx
8379
8661
  init_theme();
8380
8662
  init_ThemeContext();
8381
- var PdfViewer2 = React41.lazy(
8663
+ var PdfViewer2 = React45.lazy(
8382
8664
  () => Promise.resolve().then(() => (init_PdfViewer(), PdfViewer_exports)).then((m) => ({ default: m.PdfViewer }))
8383
8665
  );
8384
- var ExcelViewer2 = React41.lazy(
8666
+ var ExcelViewer2 = React45.lazy(
8385
8667
  () => Promise.resolve().then(() => (init_ExcelViewer(), ExcelViewer_exports)).then((m) => ({ default: m.ExcelViewer }))
8386
8668
  );
8387
8669
  var highlightColors = {
@@ -9337,7 +9619,7 @@ function EngagementPipelineResolver(p) {
9337
9619
  const color = (_a2 = statusColor2[phase.status]) != null ? _a2 : "#d6d3d1";
9338
9620
  const isCurrent = i === activeIdx;
9339
9621
  const size = isCurrent ? 28 : 20;
9340
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
9622
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
9341
9623
  i > 0 && /* @__PURE__ */ jsx(
9342
9624
  "div",
9343
9625
  {
@@ -11500,7 +11782,7 @@ function FileCard({
11500
11782
  whiteSpace: "nowrap"
11501
11783
  },
11502
11784
  children: [
11503
- metaTokens.map((t, i) => /* @__PURE__ */ jsxs(React41.Fragment, { children: [
11785
+ metaTokens.map((t, i) => /* @__PURE__ */ jsxs(React45.Fragment, { children: [
11504
11786
  i > 0 && /* @__PURE__ */ jsx("span", { style: { color: "#c4c4c4" }, children: "\xB7" }),
11505
11787
  /* @__PURE__ */ jsx("span", { children: t })
11506
11788
  ] }, i)),
@@ -12075,7 +12357,7 @@ function KeyValueListResolver(p) {
12075
12357
  var _a3;
12076
12358
  return sum + ((_a3 = g.items) != null ? _a3 : []).length;
12077
12359
  }, 0);
12078
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12360
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12079
12361
  /* @__PURE__ */ jsxs(
12080
12362
  "div",
12081
12363
  {
@@ -12253,7 +12535,7 @@ function BalanceSheetResolver(p) {
12253
12535
  /* @__PURE__ */ jsxs("tbody", { children: [
12254
12536
  ((_p = p.sections) != null ? _p : []).map((section) => {
12255
12537
  var _a2;
12256
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12538
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12257
12539
  /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan, style: {
12258
12540
  padding: "8px 12px",
12259
12541
  fontSize: "12px",
@@ -12266,7 +12548,7 @@ function BalanceSheetResolver(p) {
12266
12548
  }, children: (_a2 = categoryLabels2[section.category]) != null ? _a2 : section.category }) }),
12267
12549
  section.subsections.map((sub, si) => {
12268
12550
  var _a3;
12269
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12551
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12270
12552
  /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan, style: {
12271
12553
  padding: "6px 10px 6px 24px",
12272
12554
  fontSize: "12px",
@@ -12442,7 +12724,7 @@ function IncomeStatementResolver(p) {
12442
12724
  textAlign: "left",
12443
12725
  whiteSpace: "nowrap"
12444
12726
  }, children: "\xA0" }),
12445
- periods.map((period) => /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12727
+ periods.map((period) => /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12446
12728
  /* @__PURE__ */ jsx("th", { style: {
12447
12729
  fontSize: "11px",
12448
12730
  fontWeight: 500,
@@ -12473,7 +12755,7 @@ function IncomeStatementResolver(p) {
12473
12755
  sections.map((section, si) => {
12474
12756
  var _a2;
12475
12757
  const isSubtotal = section.sectionType === "subtotal";
12476
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12758
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12477
12759
  /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: {
12478
12760
  padding: "8px 12px",
12479
12761
  fontSize: "12px",
@@ -12504,7 +12786,7 @@ function IncomeStatementResolver(p) {
12504
12786
  var _a4;
12505
12787
  const val = (_a4 = amounts[pi]) != null ? _a4 : 0;
12506
12788
  const isNeg = val < 0;
12507
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12789
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12508
12790
  /* @__PURE__ */ jsx("td", { style: {
12509
12791
  padding: "6px 10px",
12510
12792
  fontSize: "13px",
@@ -12539,7 +12821,7 @@ function IncomeStatementResolver(p) {
12539
12821
  var _a2;
12540
12822
  const val = (_a2 = grossProfit[pi]) != null ? _a2 : 0;
12541
12823
  const isNeg = val < 0;
12542
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12824
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12543
12825
  /* @__PURE__ */ jsx("td", { style: {
12544
12826
  padding: "8px 10px",
12545
12827
  fontSize: "12px",
@@ -12574,7 +12856,7 @@ function IncomeStatementResolver(p) {
12574
12856
  var _a2;
12575
12857
  const val = (_a2 = operatingIncome[pi]) != null ? _a2 : 0;
12576
12858
  const isNeg = val < 0;
12577
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12859
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12578
12860
  /* @__PURE__ */ jsx("td", { style: {
12579
12861
  padding: "8px 10px",
12580
12862
  fontSize: "12px",
@@ -12608,7 +12890,7 @@ function IncomeStatementResolver(p) {
12608
12890
  var _a2;
12609
12891
  const val = (_a2 = netIncome[pi]) != null ? _a2 : 0;
12610
12892
  const isNeg = val < 0;
12611
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
12893
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12612
12894
  /* @__PURE__ */ jsx("td", { style: {
12613
12895
  padding: "10px 10px",
12614
12896
  fontSize: "13px",
@@ -12828,7 +13110,7 @@ function CashFlowStatementResolver(p) {
12828
13110
  /* @__PURE__ */ jsxs("tbody", { children: [
12829
13111
  activities.map((activity, ai) => {
12830
13112
  var _a2, _b2, _c2;
12831
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
13113
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
12832
13114
  ai > 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
12833
13115
  "td",
12834
13116
  {
@@ -17129,7 +17411,10 @@ function PipelinePreviewResolver(p) {
17129
17411
  init_ThemeContext();
17130
17412
  var DEFAULT_INTERACTION = {
17131
17413
  selectedStepId: null,
17132
- onStepSelect: void 0
17414
+ onStepSelect: void 0,
17415
+ resolvedDecisions: void 0,
17416
+ onDecisionResolve: void 0,
17417
+ onDecisionSource: void 0
17133
17418
  };
17134
17419
  var GenUIInteractionContext = createContext(DEFAULT_INTERACTION);
17135
17420
  function useGenUIInteraction() {
@@ -17262,8 +17547,8 @@ var CARD_MIN = 132;
17262
17547
  var CARD_GAP = 16;
17263
17548
  var AUTO_COMPACT_BELOW = 360;
17264
17549
  function useContainerWidth(ref) {
17265
- const [w, setW] = React41.useState(0);
17266
- React41.useLayoutEffect(() => {
17550
+ const [w, setW] = React45.useState(0);
17551
+ React45.useLayoutEffect(() => {
17267
17552
  const el = ref.current;
17268
17553
  if (!el || typeof ResizeObserver === "undefined") return;
17269
17554
  const ro = new ResizeObserver((entries) => {
@@ -17364,15 +17649,15 @@ function WorkflowStepperRenderer({
17364
17649
  const interactive = typeof onSelectStep === "function";
17365
17650
  const statusColor3 = (s) => s === "active" ? ACCENT2 : STATUS_COLORS3[s];
17366
17651
  const doneCount = steps.filter((s) => s.status === "done").length;
17367
- const rootRef = React41.useRef(null);
17652
+ const rootRef = React45.useRef(null);
17368
17653
  const containerW = useContainerWidth(rootRef);
17369
17654
  let resolved = density === "auto" ? "full" : density;
17370
17655
  if (density === "auto" && containerW > 0) {
17371
17656
  const needed = steps.length * CARD_MIN + Math.max(0, steps.length - 1) * CARD_GAP;
17372
17657
  resolved = containerW < AUTO_COMPACT_BELOW || needed > containerW * 1.6 ? "compact" : "full";
17373
17658
  }
17374
- const scrollerRef = React41.useRef(null);
17375
- React41.useEffect(() => {
17659
+ const scrollerRef = React45.useRef(null);
17660
+ React45.useEffect(() => {
17376
17661
  if (resolved !== "full" || loading) return;
17377
17662
  const sc = scrollerRef.current;
17378
17663
  if (!sc) return;
@@ -17383,11 +17668,11 @@ function WorkflowStepperRenderer({
17383
17668
  el.scrollIntoView({ inline: "center", block: "nearest", behavior: "smooth" });
17384
17669
  }
17385
17670
  }, [resolved, loading, selectedStep, activeStepId]);
17386
- const [edges, setEdges] = React41.useState({
17671
+ const [edges, setEdges] = React45.useState({
17387
17672
  left: false,
17388
17673
  right: false
17389
17674
  });
17390
- const updateEdges = React41.useCallback(() => {
17675
+ const updateEdges = React45.useCallback(() => {
17391
17676
  const sc = scrollerRef.current;
17392
17677
  if (!sc) return;
17393
17678
  const max = sc.scrollWidth - sc.clientWidth;
@@ -17396,7 +17681,7 @@ function WorkflowStepperRenderer({
17396
17681
  const right = sl < max - 1;
17397
17682
  setEdges((prev) => prev.left === left && prev.right === right ? prev : { left, right });
17398
17683
  }, []);
17399
- React41.useLayoutEffect(() => {
17684
+ React45.useLayoutEffect(() => {
17400
17685
  if (resolved !== "full" || loading) return;
17401
17686
  updateEdges();
17402
17687
  const sc = scrollerRef.current;
@@ -17452,7 +17737,7 @@ function WorkflowStepperRenderer({
17452
17737
  const reached = s.status !== "pending";
17453
17738
  const clickable = interactive && reached;
17454
17739
  const size = act ? 11 : done ? 9 : 8;
17455
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
17740
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
17456
17741
  i > 0 && /* @__PURE__ */ jsx(
17457
17742
  "span",
17458
17743
  {
@@ -17595,7 +17880,7 @@ function WorkflowStepperRenderer({
17595
17880
  const color = statusColor3(step.status);
17596
17881
  const humans = ((_a2 = step.assignees) != null ? _a2 : []).filter((a) => a.kind === "human");
17597
17882
  const roleCaption = humans.map((h) => h.role).filter(Boolean).slice(0, 2).join(" \xB7 ");
17598
- return /* @__PURE__ */ jsxs(React41.Fragment, { children: [
17883
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
17599
17884
  i > 0 && /* @__PURE__ */ jsx(
17600
17885
  "div",
17601
17886
  {
@@ -17848,6 +18133,1949 @@ function WorkflowStepperResolver(p) {
17848
18133
  )
17849
18134
  ] }) });
17850
18135
  }
18136
+ init_ThemeContext();
18137
+
18138
+ // src/composites/document-field-extraction/bboxTransform.ts
18139
+ function bboxToRect(bbox2, page, px) {
18140
+ if (!bbox2 || bbox2.length !== 4) return null;
18141
+ const { wPts, hPts } = page;
18142
+ const { wPx, hPx } = px;
18143
+ if (!wPts || !hPts || !wPx || !hPx) return null;
18144
+ const [x0, y0, x1, y1] = bbox2;
18145
+ const sx = wPx / wPts;
18146
+ const sy = hPx / hPts;
18147
+ return {
18148
+ left: x0 * sx,
18149
+ width: (x1 - x0) * sx,
18150
+ // Flip Y: the box's TOP in screen space is the page height minus its upper
18151
+ // PDF-point edge (y1), because PDF y grows upward from the bottom.
18152
+ top: (hPts - y1) * sy,
18153
+ height: (y1 - y0) * sy
18154
+ };
18155
+ }
18156
+
18157
+ // src/composites/document-field-extraction/FieldDetail.tsx
18158
+ init_ThemeContext();
18159
+
18160
+ // src/composites/document-field-extraction/fieldLabels.ts
18161
+ var LABEL_DISPLAY = {
18162
+ "employer identification number": "Employer ID (EIN)",
18163
+ "company or business name": "Company Name",
18164
+ "total revenue": "Total Revenue",
18165
+ "net income": "Net Income",
18166
+ "tax year": "Tax Year",
18167
+ "invoice number": "Invoice Number",
18168
+ "invoice date": "Invoice Date",
18169
+ "total amount due": "Total Amount Due",
18170
+ "vendor name": "Vendor Name",
18171
+ "receipt total": "Receipt Total",
18172
+ "transaction date": "Transaction Date",
18173
+ "merchant name": "Merchant Name"
18174
+ };
18175
+ function prettyLabel(label) {
18176
+ var _a;
18177
+ return (_a = LABEL_DISPLAY[label]) != null ? _a : label.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
18178
+ }
18179
+ var TIER_COLORS = {
18180
+ green: "#15803d",
18181
+ amber: "#f59e0b",
18182
+ red: "#dc2626"
18183
+ };
18184
+ var BADGE_TITLE = {
18185
+ SC: "High confidence",
18186
+ CN: "Medium confidence",
18187
+ AB: "Low confidence",
18188
+ SW: "Very low confidence"
18189
+ };
18190
+ var BADGE_STYLE = {
18191
+ SC: { bg: "#dcfce7", fg: "#15803d" },
18192
+ CN: { bg: "#eff6ff", fg: "#0364ff" },
18193
+ AB: { bg: "#fff7ed", fg: "#92400e" },
18194
+ SW: { bg: "#fef2f2", fg: "#dc2626" }
18195
+ };
18196
+ var STATE_DOT = {
18197
+ ok: "#15803d",
18198
+ corrected: "#0364ff",
18199
+ missing: "#dc2626",
18200
+ warn: "#f59e0b"
18201
+ };
18202
+ function hexToRgba(hex, alpha) {
18203
+ const h = hex.replace("#", "");
18204
+ const r = parseInt(h.slice(0, 2), 16);
18205
+ const g = parseInt(h.slice(2, 4), 16);
18206
+ const b = parseInt(h.slice(4, 6), 16);
18207
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
18208
+ }
18209
+ function badgeStyle(f) {
18210
+ var _a, _b;
18211
+ return (_b = BADGE_STYLE[(_a = f.badge) != null ? _a : ""]) != null ? _b : { bg: "#f6f6f6", fg: "#777777" };
18212
+ }
18213
+ function dotColor2(f) {
18214
+ var _a, _b;
18215
+ return (_b = STATE_DOT[(_a = f.state) != null ? _a : "ok"]) != null ? _b : "#15803d";
18216
+ }
18217
+ function fieldColor(f, secondary) {
18218
+ var _a, _b;
18219
+ if (f.state === "corrected") return secondary;
18220
+ return (_b = TIER_COLORS[(_a = f.confidence_tier) != null ? _a : "amber"]) != null ? _b : TIER_COLORS.amber;
18221
+ }
18222
+ function confidenceLabel(f) {
18223
+ var _a;
18224
+ if (typeof f.confidence === "number" && !Number.isNaN(f.confidence)) {
18225
+ return `${Math.round(f.confidence * 100)}%`;
18226
+ }
18227
+ return (_a = f.badge) != null ? _a : "\u2014";
18228
+ }
18229
+ function FieldDetail({
18230
+ field,
18231
+ selected,
18232
+ onSelect,
18233
+ onSave,
18234
+ correctionCount = 0,
18235
+ cardRef
18236
+ }) {
18237
+ var _a, _b, _c, _d;
18238
+ const { BORDER: BORDER4, MUTED: MUTED2, PAPER: PAPER2, SECONDARY: SECONDARY2 } = useTheme();
18239
+ const [editing, setEditing] = React45.useState(false);
18240
+ const [draft, setDraft] = React45.useState("");
18241
+ const [saving, setSaving] = React45.useState(false);
18242
+ const [saveError, setSaveError] = React45.useState(null);
18243
+ const textareaRef = React45.useRef(null);
18244
+ const color = fieldColor(field, SECONDARY2);
18245
+ const corrected = field.state === "corrected";
18246
+ const startEdit = (e) => {
18247
+ e.stopPropagation();
18248
+ setDraft(field.value || "");
18249
+ setSaveError(null);
18250
+ setEditing(true);
18251
+ setTimeout(() => {
18252
+ var _a2, _b2;
18253
+ (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
18254
+ (_b2 = textareaRef.current) == null ? void 0 : _b2.select();
18255
+ }, 0);
18256
+ };
18257
+ const cancelEdit = (e) => {
18258
+ e.stopPropagation();
18259
+ setEditing(false);
18260
+ setSaveError(null);
18261
+ };
18262
+ const save = async (e) => {
18263
+ var _a2, _b2;
18264
+ e.stopPropagation();
18265
+ if (!onSave || draft === field.value) {
18266
+ setEditing(false);
18267
+ return;
18268
+ }
18269
+ setSaving(true);
18270
+ setSaveError(null);
18271
+ try {
18272
+ await onSave(field.field_key, draft);
18273
+ setEditing(false);
18274
+ } catch (err) {
18275
+ const msg = ((_b2 = (_a2 = err == null ? void 0 : err.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.detail) || "Save failed. Try again.";
18276
+ setSaveError(msg);
18277
+ } finally {
18278
+ setSaving(false);
18279
+ }
18280
+ };
18281
+ const handleKeyDown = (e) => {
18282
+ if (e.key === "Escape") cancelEdit(e);
18283
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) void save(e);
18284
+ };
18285
+ return /* @__PURE__ */ jsxs(
18286
+ "div",
18287
+ {
18288
+ ref: cardRef,
18289
+ "data-testid": "field-card",
18290
+ "data-field-key": field.field_key,
18291
+ "data-selected": selected ? "true" : "false",
18292
+ role: "button",
18293
+ tabIndex: 0,
18294
+ onClick: () => !editing && onSelect(selected ? null : field.field_key),
18295
+ onKeyDown: (e) => {
18296
+ if (!editing && e.key === "Enter") onSelect(selected ? null : field.field_key);
18297
+ },
18298
+ style: {
18299
+ display: "flex",
18300
+ flexDirection: "column",
18301
+ gap: "4px",
18302
+ padding: "8px 10px",
18303
+ borderRadius: "0.5rem",
18304
+ border: `1px solid ${selected ? color : BORDER4}`,
18305
+ background: selected ? hexToRgba(color, 0.06) : "white",
18306
+ cursor: editing ? "default" : "pointer",
18307
+ transition: "background 0.15s, border-color 0.15s"
18308
+ },
18309
+ children: [
18310
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", minWidth: 0 }, children: [
18311
+ /* @__PURE__ */ jsx(
18312
+ "span",
18313
+ {
18314
+ title: (_c = (_b = BADGE_TITLE[(_a = field.badge) != null ? _a : ""]) != null ? _b : field.badge) != null ? _c : "",
18315
+ style: {
18316
+ fontSize: "10px",
18317
+ fontWeight: 700,
18318
+ padding: "2px 6px",
18319
+ borderRadius: "4px",
18320
+ flexShrink: 0,
18321
+ letterSpacing: "0.02em",
18322
+ minWidth: "34px",
18323
+ textAlign: "center",
18324
+ fontVariantNumeric: "tabular-nums",
18325
+ background: badgeStyle(field).bg,
18326
+ color: badgeStyle(field).fg
18327
+ },
18328
+ children: confidenceLabel(field)
18329
+ }
18330
+ ),
18331
+ /* @__PURE__ */ jsx(
18332
+ "span",
18333
+ {
18334
+ title: prettyLabel(field.label),
18335
+ style: {
18336
+ fontSize: "12.5px",
18337
+ fontWeight: 600,
18338
+ color: "var(--foreground)",
18339
+ flex: 1,
18340
+ minWidth: 0,
18341
+ whiteSpace: "nowrap",
18342
+ overflow: "hidden",
18343
+ textOverflow: "ellipsis"
18344
+ },
18345
+ children: prettyLabel(field.label)
18346
+ }
18347
+ ),
18348
+ field.is_primary && /* @__PURE__ */ jsx(
18349
+ "span",
18350
+ {
18351
+ style: {
18352
+ fontSize: "9px",
18353
+ fontWeight: 600,
18354
+ textTransform: "uppercase",
18355
+ letterSpacing: "0.04em",
18356
+ color: MUTED2,
18357
+ flexShrink: 0
18358
+ },
18359
+ children: "Primary"
18360
+ }
18361
+ ),
18362
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "11px", color: MUTED2, flexShrink: 0 }, children: [
18363
+ "p.",
18364
+ field.page + 1
18365
+ ] }),
18366
+ !editing && onSave && /* @__PURE__ */ jsx(
18367
+ "button",
18368
+ {
18369
+ type: "button",
18370
+ onClick: startEdit,
18371
+ title: "Edit value",
18372
+ "aria-label": "Edit value",
18373
+ style: {
18374
+ border: `1px solid ${BORDER4}`,
18375
+ borderRadius: "6px",
18376
+ background: "white",
18377
+ cursor: "pointer",
18378
+ padding: "3px 5px",
18379
+ lineHeight: 1,
18380
+ flexShrink: 0,
18381
+ display: "inline-flex",
18382
+ alignItems: "center",
18383
+ justifyContent: "center"
18384
+ },
18385
+ children: /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: MUTED2, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
18386
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
18387
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
18388
+ ] })
18389
+ }
18390
+ )
18391
+ ] }),
18392
+ editing ? /* @__PURE__ */ jsxs("div", { onClick: (e) => e.stopPropagation(), style: { display: "flex", flexDirection: "column", gap: "5px" }, children: [
18393
+ /* @__PURE__ */ jsx(
18394
+ "textarea",
18395
+ {
18396
+ ref: textareaRef,
18397
+ value: draft,
18398
+ onChange: (e) => setDraft(e.target.value),
18399
+ onKeyDown: handleKeyDown,
18400
+ rows: 3,
18401
+ placeholder: "Enter value\u2026",
18402
+ style: {
18403
+ width: "100%",
18404
+ boxSizing: "border-box",
18405
+ resize: "vertical",
18406
+ fontSize: "13px",
18407
+ fontFamily: "var(--font-sans)",
18408
+ color: "var(--foreground)",
18409
+ padding: "6px 8px",
18410
+ borderRadius: "0.4rem",
18411
+ border: `1px solid ${BORDER4}`
18412
+ }
18413
+ }
18414
+ ),
18415
+ saveError && /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: TIER_COLORS.red }, children: saveError }),
18416
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
18417
+ /* @__PURE__ */ jsx(
18418
+ "button",
18419
+ {
18420
+ type: "button",
18421
+ onClick: save,
18422
+ disabled: saving,
18423
+ title: "Save (\u2318\u21B5)",
18424
+ style: {
18425
+ display: "inline-flex",
18426
+ alignItems: "center",
18427
+ gap: "4px",
18428
+ fontSize: "11px",
18429
+ fontWeight: 600,
18430
+ padding: "4px 10px",
18431
+ borderRadius: "0.4rem",
18432
+ border: "none",
18433
+ background: "var(--foreground)",
18434
+ color: "white",
18435
+ cursor: saving ? "default" : "pointer",
18436
+ opacity: saving ? 0.7 : 1
18437
+ },
18438
+ children: saving ? "Saving\u2026" : "Save"
18439
+ }
18440
+ ),
18441
+ /* @__PURE__ */ jsx(
18442
+ "button",
18443
+ {
18444
+ type: "button",
18445
+ onClick: cancelEdit,
18446
+ disabled: saving,
18447
+ title: "Cancel (Esc)",
18448
+ style: {
18449
+ fontSize: "11px",
18450
+ fontWeight: 600,
18451
+ padding: "4px 10px",
18452
+ borderRadius: "0.4rem",
18453
+ border: `1px solid ${BORDER4}`,
18454
+ background: "white",
18455
+ color: MUTED2,
18456
+ cursor: saving ? "default" : "pointer"
18457
+ },
18458
+ children: "Cancel"
18459
+ }
18460
+ )
18461
+ ] })
18462
+ ] }) : corrected ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px", paddingLeft: "2px" }, children: [
18463
+ field.previous_value != null && field.previous_value !== "" && /* @__PURE__ */ jsx(
18464
+ "span",
18465
+ {
18466
+ style: {
18467
+ fontSize: "11.5px",
18468
+ color: MUTED2,
18469
+ textDecoration: "line-through",
18470
+ fontFamily: "ui-monospace, 'Cascadia Code', monospace",
18471
+ wordBreak: "break-word"
18472
+ },
18473
+ children: field.previous_value
18474
+ }
18475
+ ),
18476
+ /* @__PURE__ */ jsx(
18477
+ "span",
18478
+ {
18479
+ style: {
18480
+ fontSize: "12.5px",
18481
+ fontWeight: 600,
18482
+ color: "var(--foreground)",
18483
+ fontFamily: "ui-monospace, 'Cascadia Code', monospace",
18484
+ wordBreak: "break-word"
18485
+ },
18486
+ children: field.value || "\u2014"
18487
+ }
18488
+ ),
18489
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }, children: [
18490
+ field.corrected_by && /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: SECONDARY2 }, title: `Corrected by ${field.corrected_by}`, children: field.corrected_by }),
18491
+ correctionCount > 0 && /* @__PURE__ */ jsxs(
18492
+ "span",
18493
+ {
18494
+ style: {
18495
+ fontSize: "10.5px",
18496
+ fontWeight: 600,
18497
+ color: MUTED2,
18498
+ background: PAPER2,
18499
+ borderRadius: "9999px",
18500
+ padding: "1px 7px"
18501
+ },
18502
+ children: [
18503
+ correctionCount,
18504
+ " ",
18505
+ correctionCount === 1 ? "event" : "events"
18506
+ ]
18507
+ }
18508
+ )
18509
+ ] })
18510
+ ] }) : (
18511
+ // Bottom row: monospace value + right-edge validation dot (file explorer).
18512
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", paddingLeft: "2px" }, children: [
18513
+ /* @__PURE__ */ jsx(
18514
+ "span",
18515
+ {
18516
+ style: {
18517
+ fontSize: "12.5px",
18518
+ color: MUTED2,
18519
+ fontFamily: "ui-monospace, 'Cascadia Code', monospace",
18520
+ flex: 1,
18521
+ minWidth: 0,
18522
+ whiteSpace: "nowrap",
18523
+ overflow: "hidden",
18524
+ textOverflow: "ellipsis"
18525
+ },
18526
+ title: field.value || "\u2014",
18527
+ children: field.value || "\u2014"
18528
+ }
18529
+ ),
18530
+ /* @__PURE__ */ jsx(
18531
+ "span",
18532
+ {
18533
+ title: (_d = field.state) != null ? _d : "ok",
18534
+ style: {
18535
+ width: "8px",
18536
+ height: "8px",
18537
+ borderRadius: "9999px",
18538
+ flexShrink: 0,
18539
+ background: dotColor2(field)
18540
+ }
18541
+ }
18542
+ )
18543
+ ] })
18544
+ )
18545
+ ]
18546
+ }
18547
+ );
18548
+ }
18549
+
18550
+ // src/composites/document-field-extraction/FieldDetails.tsx
18551
+ init_ThemeContext();
18552
+ var BADGE_DOT = {
18553
+ // gen-ui semantic dot colors
18554
+ ok: "#15803d",
18555
+ green: "#15803d",
18556
+ warn: "#f59e0b",
18557
+ amber: "#f59e0b",
18558
+ missing: "#dc2626",
18559
+ red: "#dc2626",
18560
+ corrected: "#0364ff"
18561
+ };
18562
+ function FieldDetails({
18563
+ summary,
18564
+ fileName,
18565
+ pageCount,
18566
+ pagesProcessed
18567
+ }) {
18568
+ var _a, _b, _c, _d, _e, _f;
18569
+ const { BORDER: BORDER4, MUTED: MUTED2, PAPER: PAPER2, SECONDARY: SECONDARY2 } = useTheme();
18570
+ if (!summary) {
18571
+ return /* @__PURE__ */ jsxs(
18572
+ "div",
18573
+ {
18574
+ style: {
18575
+ height: "100%",
18576
+ display: "flex",
18577
+ flexDirection: "column",
18578
+ alignItems: "center",
18579
+ justifyContent: "center",
18580
+ gap: "6px",
18581
+ color: MUTED2,
18582
+ textAlign: "center",
18583
+ padding: "24px"
18584
+ },
18585
+ children: [
18586
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "26px", lineHeight: 1 }, children: "\u{1F4C4}" }),
18587
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "14px", fontWeight: 600, color: "var(--foreground)" }, children: "No summary yet" }),
18588
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "12px", maxWidth: "280px" }, children: "This document has no extracted summary." })
18589
+ ]
18590
+ }
18591
+ );
18592
+ }
18593
+ const header = buildHeader(summary);
18594
+ const crumb = buildCrumbLine(summary);
18595
+ const facts = buildFacts(summary, fileName, pageCount, pagesProcessed);
18596
+ return /* @__PURE__ */ jsx("div", { style: { height: "100%", overflowY: "auto", paddingRight: "4px" }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "14px" }, children: [
18597
+ /* @__PURE__ */ jsxs("header", { style: { display: "flex", flexDirection: "column", gap: "3px" }, children: [
18598
+ /* @__PURE__ */ jsx(
18599
+ "h2",
18600
+ {
18601
+ title: header.title,
18602
+ style: {
18603
+ margin: 0,
18604
+ fontFamily: "var(--font-serif)",
18605
+ fontSize: "20px",
18606
+ fontWeight: 400,
18607
+ letterSpacing: "-0.01em",
18608
+ color: "var(--foreground)",
18609
+ overflow: "hidden",
18610
+ textOverflow: "ellipsis",
18611
+ whiteSpace: "nowrap"
18612
+ },
18613
+ children: header.title
18614
+ }
18615
+ ),
18616
+ header.subtitle && /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "12px", color: MUTED2 }, children: header.subtitle })
18617
+ ] }),
18618
+ (summary.domain || summary.display_name || summary.domain_group || ((_b = (_a = summary.tags) == null ? void 0 : _a.length) != null ? _b : 0) > 0) && /* @__PURE__ */ jsxs(
18619
+ "section",
18620
+ {
18621
+ style: {
18622
+ display: "flex",
18623
+ flexDirection: "column",
18624
+ gap: "6px",
18625
+ padding: "12px 14px",
18626
+ borderRadius: "0.75rem",
18627
+ border: `1px solid ${BORDER4}`,
18628
+ background: PAPER2
18629
+ },
18630
+ children: [
18631
+ summary.domain_group && /* @__PURE__ */ jsx(
18632
+ "span",
18633
+ {
18634
+ style: {
18635
+ fontSize: "10px",
18636
+ fontWeight: 600,
18637
+ textTransform: "uppercase",
18638
+ letterSpacing: "0.06em",
18639
+ color: MUTED2
18640
+ },
18641
+ children: summary.domain_group
18642
+ }
18643
+ ),
18644
+ /* @__PURE__ */ jsx(
18645
+ "h3",
18646
+ {
18647
+ style: {
18648
+ margin: 0,
18649
+ fontSize: "14px",
18650
+ fontWeight: 600,
18651
+ color: "var(--foreground)"
18652
+ },
18653
+ children: summary.domain || summary.display_name
18654
+ }
18655
+ ),
18656
+ crumb && /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "12px", color: MUTED2 }, children: crumb }),
18657
+ ((_d = (_c = summary.tags) == null ? void 0 : _c.length) != null ? _d : 0) > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "5px", marginTop: "2px" }, children: summary.tags.map((t) => /* @__PURE__ */ jsx(
18658
+ "span",
18659
+ {
18660
+ style: {
18661
+ fontSize: "10px",
18662
+ fontWeight: 600,
18663
+ padding: "2px 8px",
18664
+ borderRadius: "9999px",
18665
+ background: "white",
18666
+ border: `1px solid ${BORDER4}`,
18667
+ color: MUTED2
18668
+ },
18669
+ children: t
18670
+ },
18671
+ t
18672
+ )) })
18673
+ ]
18674
+ }
18675
+ ),
18676
+ ((_f = (_e = summary.stats) == null ? void 0 : _e.length) != null ? _f : 0) > 0 && /* @__PURE__ */ jsx(
18677
+ "div",
18678
+ {
18679
+ style: {
18680
+ display: "grid",
18681
+ gridTemplateColumns: "repeat(auto-fit, minmax(130px, 1fr))",
18682
+ gap: "8px"
18683
+ },
18684
+ children: summary.stats.map((s) => /* @__PURE__ */ jsxs(
18685
+ "div",
18686
+ {
18687
+ style: {
18688
+ display: "flex",
18689
+ flexDirection: "column",
18690
+ gap: "2px",
18691
+ padding: "10px 12px",
18692
+ borderRadius: "0.6rem",
18693
+ border: `1px solid ${BORDER4}`,
18694
+ background: "white"
18695
+ },
18696
+ children: [
18697
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: MUTED2 }, children: s.label }),
18698
+ /* @__PURE__ */ jsx(
18699
+ "span",
18700
+ {
18701
+ title: s.value,
18702
+ style: {
18703
+ fontSize: "15px",
18704
+ fontWeight: 600,
18705
+ color: "var(--foreground)",
18706
+ overflow: "hidden",
18707
+ textOverflow: "ellipsis",
18708
+ whiteSpace: "nowrap"
18709
+ },
18710
+ children: s.value
18711
+ }
18712
+ ),
18713
+ s.caption && /* @__PURE__ */ jsx("span", { style: { fontSize: "10px", color: MUTED2 }, children: s.caption })
18714
+ ]
18715
+ },
18716
+ s.field_key
18717
+ ))
18718
+ }
18719
+ ),
18720
+ facts.length > 0 && /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
18721
+ /* @__PURE__ */ jsxs(
18722
+ "div",
18723
+ {
18724
+ style: {
18725
+ display: "flex",
18726
+ alignItems: "center",
18727
+ gap: "6px",
18728
+ fontSize: "11px",
18729
+ fontWeight: 600,
18730
+ textTransform: "uppercase",
18731
+ letterSpacing: "0.04em",
18732
+ color: MUTED2
18733
+ },
18734
+ children: [
18735
+ /* @__PURE__ */ jsx("span", { children: "\u25A4" }),
18736
+ /* @__PURE__ */ jsx("span", { children: "Document details" })
18737
+ ]
18738
+ }
18739
+ ),
18740
+ /* @__PURE__ */ jsx(
18741
+ "dl",
18742
+ {
18743
+ style: {
18744
+ margin: 0,
18745
+ display: "grid",
18746
+ gridTemplateColumns: "minmax(110px, auto) 1fr",
18747
+ rowGap: "6px",
18748
+ columnGap: "14px"
18749
+ },
18750
+ children: facts.map((f) => {
18751
+ var _a2;
18752
+ return /* @__PURE__ */ jsxs(React45.Fragment, { children: [
18753
+ /* @__PURE__ */ jsx("dt", { style: { fontSize: "12px", color: MUTED2 }, children: f.label }),
18754
+ /* @__PURE__ */ jsxs(
18755
+ "dd",
18756
+ {
18757
+ title: typeof f.value === "string" ? f.value : void 0,
18758
+ style: {
18759
+ margin: 0,
18760
+ fontSize: "12px",
18761
+ color: "var(--foreground)",
18762
+ display: "flex",
18763
+ alignItems: "center",
18764
+ gap: "6px",
18765
+ wordBreak: "break-word"
18766
+ },
18767
+ children: [
18768
+ f.badge && /* @__PURE__ */ jsx(
18769
+ "span",
18770
+ {
18771
+ style: {
18772
+ width: "7px",
18773
+ height: "7px",
18774
+ borderRadius: "9999px",
18775
+ flexShrink: 0,
18776
+ background: (_a2 = BADGE_DOT[f.badge]) != null ? _a2 : SECONDARY2
18777
+ }
18778
+ }
18779
+ ),
18780
+ f.value
18781
+ ]
18782
+ }
18783
+ )
18784
+ ] }, f.key);
18785
+ })
18786
+ }
18787
+ )
18788
+ ] })
18789
+ ] }) });
18790
+ }
18791
+ function buildHeader(summary) {
18792
+ const form = [summary.short_name, summary.display_name].filter(Boolean);
18793
+ const title = summary.organization || form.shift() || summary.domain || "Document";
18794
+ const parts = summary.organization ? [...form] : form;
18795
+ if (summary.tax_year) parts.push(`TY ${summary.tax_year}`);
18796
+ return { title, subtitle: parts.join(" \xB7 ") };
18797
+ }
18798
+ function buildCrumbLine(summary) {
18799
+ const parts = [...summary.crumbs || [], summary.short_name].filter(Boolean);
18800
+ if (parts.length > 0) return parts.join(" \xB7 ");
18801
+ return summary.domain && summary.display_name ? summary.display_name : "";
18802
+ }
18803
+ function buildFacts(summary, fileName, pageCount, pagesProcessed) {
18804
+ const rows = [];
18805
+ if (fileName) rows.push({ key: "file", label: "File", value: fileName });
18806
+ if (summary.display_name) {
18807
+ rows.push({ key: "doctype", label: "Document type", value: summary.display_name });
18808
+ }
18809
+ if (summary.tax_year != null && summary.tax_year !== "") {
18810
+ rows.push({ key: "year", label: "Tax year", value: String(summary.tax_year) });
18811
+ }
18812
+ for (const f of summary.facts || []) {
18813
+ rows.push({ key: f.field_key, label: f.label, value: f.value, badge: f.badge });
18814
+ }
18815
+ if (pageCount) {
18816
+ rows.push({
18817
+ key: "pages",
18818
+ label: "Pages processed",
18819
+ value: `${pagesProcessed != null ? pagesProcessed : pageCount} / ${pageCount}`
18820
+ });
18821
+ }
18822
+ return rows;
18823
+ }
18824
+
18825
+ // src/composites/document-field-extraction/FieldAuditLog.tsx
18826
+ init_ThemeContext();
18827
+ function initials(name) {
18828
+ return name.trim().split(/\s+/).slice(0, 2).map((w) => {
18829
+ var _a;
18830
+ return ((_a = w[0]) != null ? _a : "").toUpperCase();
18831
+ }).join("");
18832
+ }
18833
+ function formatTs(ts) {
18834
+ if (!ts) return "\u2014";
18835
+ const d = new Date(ts);
18836
+ if (Number.isNaN(d.getTime())) return ts;
18837
+ return d.toLocaleString(void 0, {
18838
+ month: "short",
18839
+ day: "numeric",
18840
+ hour: "2-digit",
18841
+ minute: "2-digit"
18842
+ });
18843
+ }
18844
+ function FieldAuditLog({
18845
+ events = [],
18846
+ loading = false,
18847
+ fields = []
18848
+ }) {
18849
+ const { BORDER: BORDER4, MUTED: MUTED2, PAPER: PAPER2, SECONDARY: SECONDARY2 } = useTheme();
18850
+ const fieldLabelMap = React45.useMemo(() => {
18851
+ var _a;
18852
+ const map = {};
18853
+ for (const f of fields) map[f.field_key] = (_a = f.label) != null ? _a : f.field_key;
18854
+ return map;
18855
+ }, [fields]);
18856
+ if (loading) {
18857
+ return /* @__PURE__ */ jsx(
18858
+ "div",
18859
+ {
18860
+ style: {
18861
+ flex: 1,
18862
+ display: "flex",
18863
+ alignItems: "center",
18864
+ justifyContent: "center",
18865
+ padding: "32px 20px",
18866
+ fontSize: "13px",
18867
+ color: MUTED2
18868
+ },
18869
+ children: "Loading audit trail\u2026"
18870
+ }
18871
+ );
18872
+ }
18873
+ if (events.length === 0) {
18874
+ return /* @__PURE__ */ jsxs(
18875
+ "div",
18876
+ {
18877
+ style: {
18878
+ flex: 1,
18879
+ display: "flex",
18880
+ flexDirection: "column",
18881
+ alignItems: "center",
18882
+ justifyContent: "center",
18883
+ gap: "6px",
18884
+ padding: "32px 20px",
18885
+ textAlign: "center"
18886
+ },
18887
+ children: [
18888
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "13.5px", fontWeight: 600, color: "var(--foreground)" }, children: "No changes yet" }),
18889
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "12px", color: MUTED2, maxWidth: "240px", lineHeight: 1.5 }, children: "Field corrections will appear here." })
18890
+ ]
18891
+ }
18892
+ );
18893
+ }
18894
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0, overflow: "hidden" }, children: [
18895
+ /* @__PURE__ */ jsx("div", { style: { padding: "8px 14px 6px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs(
18896
+ "span",
18897
+ {
18898
+ style: {
18899
+ fontSize: "11.5px",
18900
+ fontWeight: 600,
18901
+ color: MUTED2,
18902
+ textTransform: "uppercase",
18903
+ letterSpacing: "0.04em"
18904
+ },
18905
+ children: [
18906
+ events.length,
18907
+ " ",
18908
+ events.length === 1 ? "change" : "changes"
18909
+ ]
18910
+ }
18911
+ ) }),
18912
+ /* @__PURE__ */ jsx("ol", { style: { listStyle: "none", margin: 0, padding: "0 0 16px", overflowY: "auto", flex: 1, minHeight: 0 }, children: events.map((ev) => {
18913
+ var _a, _b;
18914
+ const rawLabel = (_a = fieldLabelMap[ev.field_key]) != null ? _a : ev.field_key;
18915
+ const label = prettyLabel(rawLabel);
18916
+ const isAI = ev.actor_type === "system" || ev.event_type === "ai_corrected" || ev.event_type === "ai_extracted";
18917
+ const actor = isAI ? "AI" : ev.actor_name || "Unknown";
18918
+ const eventLabel = isAI ? "Re-extracted" : "Corrected";
18919
+ return /* @__PURE__ */ jsxs(
18920
+ "li",
18921
+ {
18922
+ "data-testid": "audit-row",
18923
+ style: { display: "flex", gap: "10px", padding: "10px 14px", borderBottom: `1px solid ${BORDER4}` },
18924
+ children: [
18925
+ /* @__PURE__ */ jsx(
18926
+ "div",
18927
+ {
18928
+ title: isAI ? "AI extraction" : actor,
18929
+ style: {
18930
+ flexShrink: 0,
18931
+ width: "28px",
18932
+ height: "28px",
18933
+ borderRadius: "50%",
18934
+ background: isAI ? "#dcfce7" : "#eff6ff",
18935
+ color: isAI ? "#15803d" : SECONDARY2,
18936
+ fontSize: "10.5px",
18937
+ fontWeight: 700,
18938
+ display: "flex",
18939
+ alignItems: "center",
18940
+ justifyContent: "center",
18941
+ marginTop: "1px"
18942
+ },
18943
+ children: isAI ? "\u2728" : initials(actor)
18944
+ }
18945
+ ),
18946
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "3px", flex: 1, minWidth: 0 }, children: [
18947
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: "6px", flexWrap: "wrap" }, children: [
18948
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12.5px", fontWeight: 600, color: isAI ? "#15803d" : "var(--foreground)" }, children: actor }),
18949
+ /* @__PURE__ */ jsx(
18950
+ "span",
18951
+ {
18952
+ style: {
18953
+ fontSize: "10.5px",
18954
+ fontWeight: 600,
18955
+ color: MUTED2,
18956
+ background: PAPER2,
18957
+ borderRadius: "4px",
18958
+ padding: "1px 6px",
18959
+ whiteSpace: "nowrap",
18960
+ flexShrink: 0
18961
+ },
18962
+ children: eventLabel
18963
+ }
18964
+ ),
18965
+ /* @__PURE__ */ jsx(
18966
+ "span",
18967
+ {
18968
+ style: {
18969
+ fontSize: "12px",
18970
+ color: MUTED2,
18971
+ flex: 1,
18972
+ minWidth: 0,
18973
+ whiteSpace: "nowrap",
18974
+ overflow: "hidden",
18975
+ textOverflow: "ellipsis"
18976
+ },
18977
+ children: label
18978
+ }
18979
+ ),
18980
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: MUTED2, flexShrink: 0 }, children: formatTs(ev.created_at) })
18981
+ ] }),
18982
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }, children: [
18983
+ ev.previous_value != null && /* @__PURE__ */ jsxs(Fragment, { children: [
18984
+ /* @__PURE__ */ jsx(
18985
+ "span",
18986
+ {
18987
+ style: {
18988
+ fontSize: "12px",
18989
+ fontFamily: "ui-monospace, monospace",
18990
+ color: MUTED2,
18991
+ textDecoration: "line-through"
18992
+ },
18993
+ children: ev.previous_value
18994
+ }
18995
+ ),
18996
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: BORDER4 }, children: "\u2192" })
18997
+ ] }),
18998
+ /* @__PURE__ */ jsx(
18999
+ "span",
19000
+ {
19001
+ style: {
19002
+ fontSize: "12px",
19003
+ fontFamily: "ui-monospace, monospace",
19004
+ fontWeight: 600,
19005
+ color: "var(--foreground)"
19006
+ },
19007
+ children: (_b = ev.new_value) != null ? _b : "\u2014"
19008
+ }
19009
+ )
19010
+ ] }),
19011
+ ev.reason && /* @__PURE__ */ jsxs("p", { style: { margin: "2px 0 0", fontSize: "11.5px", color: MUTED2, fontStyle: "italic" }, children: [
19012
+ "\u201C",
19013
+ ev.reason,
19014
+ "\u201D"
19015
+ ] })
19016
+ ] })
19017
+ ]
19018
+ },
19019
+ ev.id
19020
+ );
19021
+ }) })
19022
+ ] });
19023
+ }
19024
+ var TIER_COLORS2 = {
19025
+ green: "#15803d",
19026
+ amber: "#f59e0b",
19027
+ red: "#dc2626"
19028
+ };
19029
+ function fieldColor2(f, secondary) {
19030
+ var _a, _b;
19031
+ if (f.state === "corrected") return secondary;
19032
+ return (_b = TIER_COLORS2[(_a = f.confidence_tier) != null ? _a : "amber"]) != null ? _b : TIER_COLORS2.amber;
19033
+ }
19034
+ function hexToRgba2(hex, alpha) {
19035
+ const h = hex.replace("#", "");
19036
+ const r = parseInt(h.slice(0, 2), 16);
19037
+ const g = parseInt(h.slice(2, 4), 16);
19038
+ const b = parseInt(h.slice(4, 6), 16);
19039
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
19040
+ }
19041
+ function PageOverlay({
19042
+ page,
19043
+ fields,
19044
+ selectedKey,
19045
+ onSelect,
19046
+ secondary
19047
+ }) {
19048
+ const { PAPER: PAPER2, MUTED: MUTED2 } = useTheme();
19049
+ const imgRef = React45.useRef(null);
19050
+ const selectedBoxRef = React45.useRef(null);
19051
+ const [px, setPx] = React45.useState(null);
19052
+ React45.useEffect(() => {
19053
+ const el = imgRef.current;
19054
+ if (!el) return;
19055
+ const measure = () => {
19056
+ if (el.clientWidth && el.clientHeight) {
19057
+ setPx({ wPx: el.clientWidth, hPx: el.clientHeight });
19058
+ }
19059
+ };
19060
+ measure();
19061
+ if (typeof ResizeObserver === "undefined") return;
19062
+ const ro = new ResizeObserver(measure);
19063
+ ro.observe(el);
19064
+ return () => ro.disconnect();
19065
+ }, [page.imageUrl]);
19066
+ React45.useEffect(() => {
19067
+ if (!selectedKey) return;
19068
+ if (!fields.some((f) => f.field_key === selectedKey && f.bbox)) return;
19069
+ const el = selectedBoxRef.current;
19070
+ if (el && typeof el.scrollIntoView === "function") {
19071
+ el.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" });
19072
+ }
19073
+ }, [selectedKey, fields, px]);
19074
+ const pagePts = { wPts: page.width_pt, hPts: page.height_pt };
19075
+ return /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: "100%", lineHeight: 0 }, children: [
19076
+ page.imageUrl ? /* @__PURE__ */ jsx(
19077
+ "img",
19078
+ {
19079
+ ref: imgRef,
19080
+ src: page.imageUrl,
19081
+ alt: `Page ${page.page + 1}`,
19082
+ onLoad: () => {
19083
+ const el = imgRef.current;
19084
+ if (el && el.clientWidth && el.clientHeight) {
19085
+ setPx({ wPx: el.clientWidth, hPx: el.clientHeight });
19086
+ }
19087
+ },
19088
+ style: { display: "block", width: "100%", height: "auto" }
19089
+ }
19090
+ ) : (
19091
+ // No resolved image (host couldn't resolve the raster) — keep the
19092
+ // aspect box so cards still make sense, but show nothing to overlay on.
19093
+ /* @__PURE__ */ jsxs(
19094
+ "div",
19095
+ {
19096
+ style: {
19097
+ width: "100%",
19098
+ aspectRatio: `${page.width_pt} / ${page.height_pt}`,
19099
+ background: PAPER2,
19100
+ display: "flex",
19101
+ alignItems: "center",
19102
+ justifyContent: "center",
19103
+ fontSize: "12px",
19104
+ color: MUTED2,
19105
+ lineHeight: 1.4
19106
+ },
19107
+ children: [
19108
+ "Page ",
19109
+ page.page + 1,
19110
+ " image unavailable"
19111
+ ]
19112
+ }
19113
+ )
19114
+ ),
19115
+ px && page.imageUrl && fields.map((f) => {
19116
+ var _a;
19117
+ const rect = bboxToRect((_a = f.bbox) != null ? _a : null, pagePts, px);
19118
+ if (!rect) return null;
19119
+ const color = fieldColor2(f, secondary);
19120
+ const selected = selectedKey === f.field_key;
19121
+ return /* @__PURE__ */ jsx(
19122
+ "div",
19123
+ {
19124
+ ref: selected ? selectedBoxRef : null,
19125
+ "data-testid": "bbox-rect",
19126
+ "data-field-key": f.field_key,
19127
+ "data-selected": selected ? "true" : "false",
19128
+ onClick: () => onSelect(selected ? null : f.field_key),
19129
+ title: `${f.label}: ${f.value}`,
19130
+ style: {
19131
+ position: "absolute",
19132
+ left: `${rect.left}px`,
19133
+ top: `${rect.top}px`,
19134
+ width: `${rect.width}px`,
19135
+ height: `${rect.height}px`,
19136
+ border: `1px solid ${color}`,
19137
+ background: hexToRgba2(color, selected ? 0.28 : 0.12),
19138
+ boxShadow: selected ? `0 0 0 2px ${hexToRgba2(color, 0.5)}` : "none",
19139
+ borderRadius: "2px",
19140
+ cursor: "pointer",
19141
+ transition: "background 0.15s, box-shadow 0.15s"
19142
+ }
19143
+ },
19144
+ f.field_key
19145
+ );
19146
+ })
19147
+ ] });
19148
+ }
19149
+ function ExtractionDetail({
19150
+ pages,
19151
+ orderedFields,
19152
+ fieldsByPage,
19153
+ selectedKey,
19154
+ setSelectedKey,
19155
+ onFieldSave,
19156
+ correctionCounts,
19157
+ tab,
19158
+ setTab,
19159
+ editable,
19160
+ summary,
19161
+ fileName,
19162
+ pageCount,
19163
+ pagesProcessed,
19164
+ auditEvents,
19165
+ auditLoading
19166
+ }) {
19167
+ const { BORDER: BORDER4, MUTED: MUTED2, PAPER: PAPER2, SECONDARY: SECONDARY2 } = useTheme();
19168
+ const selectedCardRef = React45.useRef(null);
19169
+ React45.useEffect(() => {
19170
+ if (!selectedKey || tab !== "fields") return;
19171
+ const el = selectedCardRef.current;
19172
+ if (el && typeof el.scrollIntoView === "function") {
19173
+ el.scrollIntoView({ behavior: "smooth", block: "nearest" });
19174
+ }
19175
+ }, [selectedKey, tab]);
19176
+ const tabs = [
19177
+ { key: "details", label: "Details" },
19178
+ { key: "fields", label: "Fields", count: orderedFields.length }
19179
+ ];
19180
+ if (editable) tabs.push({ key: "audit", label: "Audit Trails", count: (auditEvents == null ? void 0 : auditEvents.length) || void 0 });
19181
+ return /* @__PURE__ */ jsxs(
19182
+ "div",
19183
+ {
19184
+ style: {
19185
+ display: "grid",
19186
+ gridTemplateColumns: "minmax(0, 3fr) minmax(260px, 1fr)",
19187
+ gap: "12px",
19188
+ height: "100%",
19189
+ minHeight: 0
19190
+ },
19191
+ children: [
19192
+ /* @__PURE__ */ jsx(
19193
+ "div",
19194
+ {
19195
+ style: {
19196
+ display: "flex",
19197
+ flexDirection: "column",
19198
+ gap: "10px",
19199
+ borderRadius: "0.75rem",
19200
+ border: `1px solid ${BORDER4}`,
19201
+ overflowY: "auto",
19202
+ minHeight: 0
19203
+ },
19204
+ children: pages.map((pg) => /* @__PURE__ */ jsx(
19205
+ PageOverlay,
19206
+ {
19207
+ page: pg,
19208
+ fields: fieldsByPage(pg.page),
19209
+ selectedKey,
19210
+ onSelect: (key) => {
19211
+ setSelectedKey(key);
19212
+ if (key) setTab("fields");
19213
+ },
19214
+ secondary: SECONDARY2
19215
+ },
19216
+ pg.page
19217
+ ))
19218
+ }
19219
+ ),
19220
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", minWidth: 0, minHeight: 0 }, children: [
19221
+ /* @__PURE__ */ jsx(
19222
+ "div",
19223
+ {
19224
+ style: {
19225
+ display: "flex",
19226
+ gap: "16px",
19227
+ borderBottom: `1px solid ${BORDER4}`,
19228
+ flexShrink: 0,
19229
+ marginBottom: "10px"
19230
+ },
19231
+ children: tabs.map((t) => {
19232
+ const active = tab === t.key;
19233
+ return /* @__PURE__ */ jsxs(
19234
+ "button",
19235
+ {
19236
+ type: "button",
19237
+ onClick: () => setTab(t.key),
19238
+ "data-testid": `tab-${t.key}`,
19239
+ style: {
19240
+ appearance: "none",
19241
+ background: "transparent",
19242
+ borderTop: "none",
19243
+ borderLeft: "none",
19244
+ borderRight: "none",
19245
+ borderBottom: `2px solid ${active ? SECONDARY2 : "transparent"}`,
19246
+ padding: "6px 2px",
19247
+ marginBottom: "-1px",
19248
+ cursor: "pointer",
19249
+ fontSize: "13px",
19250
+ fontWeight: 600,
19251
+ color: active ? SECONDARY2 : MUTED2,
19252
+ display: "inline-flex",
19253
+ alignItems: "center",
19254
+ gap: "6px"
19255
+ },
19256
+ children: [
19257
+ t.label,
19258
+ typeof t.count === "number" && /* @__PURE__ */ jsx(
19259
+ "span",
19260
+ {
19261
+ style: {
19262
+ fontSize: "11px",
19263
+ fontWeight: 600,
19264
+ padding: "1px 7px",
19265
+ borderRadius: "9999px",
19266
+ background: active ? "#eff6ff" : PAPER2,
19267
+ color: active ? SECONDARY2 : MUTED2
19268
+ },
19269
+ children: t.count
19270
+ }
19271
+ )
19272
+ ]
19273
+ },
19274
+ t.key
19275
+ );
19276
+ })
19277
+ }
19278
+ ),
19279
+ tab === "details" ? /* @__PURE__ */ jsx(
19280
+ FieldDetails,
19281
+ {
19282
+ summary,
19283
+ fileName,
19284
+ pageCount,
19285
+ pagesProcessed
19286
+ }
19287
+ ) : tab === "audit" ? /* @__PURE__ */ jsx("div", { style: { minHeight: 0, overflowY: "auto" }, children: /* @__PURE__ */ jsx(
19288
+ FieldAuditLog,
19289
+ {
19290
+ events: auditEvents != null ? auditEvents : [],
19291
+ loading: auditLoading != null ? auditLoading : false,
19292
+ fields: orderedFields.map((f) => ({ field_key: f.field_key, label: f.label }))
19293
+ }
19294
+ ) }) : /* @__PURE__ */ jsxs(
19295
+ "div",
19296
+ {
19297
+ style: {
19298
+ display: "flex",
19299
+ flexDirection: "column",
19300
+ minHeight: 0,
19301
+ overflowY: "auto",
19302
+ paddingRight: "4px"
19303
+ },
19304
+ children: [
19305
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: MUTED2, padding: "0 0 8px 2px", flexShrink: 0 }, children: [
19306
+ orderedFields.length,
19307
+ " extracted"
19308
+ ] }),
19309
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: orderedFields.map((f) => {
19310
+ var _a;
19311
+ const selected = selectedKey === f.field_key;
19312
+ return /* @__PURE__ */ jsx(
19313
+ FieldDetail,
19314
+ {
19315
+ field: f,
19316
+ selected,
19317
+ onSelect: setSelectedKey,
19318
+ onSave: onFieldSave,
19319
+ correctionCount: (_a = correctionCounts == null ? void 0 : correctionCounts[f.field_key]) != null ? _a : 0,
19320
+ cardRef: selected ? selectedCardRef : void 0
19321
+ },
19322
+ f.field_key
19323
+ );
19324
+ }) })
19325
+ ]
19326
+ }
19327
+ )
19328
+ ] })
19329
+ ]
19330
+ }
19331
+ );
19332
+ }
19333
+ function ExtractionModal({
19334
+ open,
19335
+ onClose,
19336
+ title,
19337
+ children
19338
+ }) {
19339
+ const { BORDER: BORDER4, MUTED: MUTED2 } = useTheme();
19340
+ React45.useEffect(() => {
19341
+ if (!open) return;
19342
+ const onKey = (e) => {
19343
+ if (e.key === "Escape") onClose();
19344
+ };
19345
+ window.addEventListener("keydown", onKey);
19346
+ const prev = document.body.style.overflow;
19347
+ document.body.style.overflow = "hidden";
19348
+ return () => {
19349
+ window.removeEventListener("keydown", onKey);
19350
+ document.body.style.overflow = prev;
19351
+ };
19352
+ }, [open, onClose]);
19353
+ if (!open || typeof document === "undefined") return null;
19354
+ return createPortal(
19355
+ /* @__PURE__ */ jsx(
19356
+ "div",
19357
+ {
19358
+ role: "dialog",
19359
+ "aria-modal": "true",
19360
+ "aria-label": title,
19361
+ onClick: onClose,
19362
+ style: {
19363
+ position: "fixed",
19364
+ inset: 0,
19365
+ zIndex: 2147483e3,
19366
+ background: "rgba(0,0,0,0.5)",
19367
+ display: "flex",
19368
+ alignItems: "center",
19369
+ justifyContent: "center",
19370
+ padding: "4vh 4vw",
19371
+ backdropFilter: "blur(2px)"
19372
+ },
19373
+ children: /* @__PURE__ */ jsxs(
19374
+ "div",
19375
+ {
19376
+ onClick: (e) => e.stopPropagation(),
19377
+ style: {
19378
+ width: "90vw",
19379
+ height: "90vh",
19380
+ background: "white",
19381
+ borderRadius: "0.875rem",
19382
+ border: `1px solid ${BORDER4}`,
19383
+ boxShadow: "0 20px 60px rgba(0,0,0,0.30)",
19384
+ display: "flex",
19385
+ flexDirection: "column",
19386
+ overflow: "hidden"
19387
+ },
19388
+ children: [
19389
+ /* @__PURE__ */ jsxs(
19390
+ "div",
19391
+ {
19392
+ style: {
19393
+ display: "flex",
19394
+ alignItems: "center",
19395
+ gap: "10px",
19396
+ padding: "11px 16px",
19397
+ borderBottom: `1px solid ${BORDER4}`,
19398
+ flexShrink: 0
19399
+ },
19400
+ children: [
19401
+ /* @__PURE__ */ jsx(
19402
+ "span",
19403
+ {
19404
+ style: {
19405
+ flex: 1,
19406
+ minWidth: 0,
19407
+ fontFamily: "var(--font-serif)",
19408
+ fontSize: "16px",
19409
+ fontWeight: 400,
19410
+ letterSpacing: "-0.01em",
19411
+ color: "var(--foreground)",
19412
+ overflow: "hidden",
19413
+ textOverflow: "ellipsis",
19414
+ whiteSpace: "nowrap"
19415
+ },
19416
+ children: title
19417
+ }
19418
+ ),
19419
+ /* @__PURE__ */ jsx(
19420
+ "button",
19421
+ {
19422
+ type: "button",
19423
+ "aria-label": "Close",
19424
+ onClick: onClose,
19425
+ style: {
19426
+ border: `1px solid ${BORDER4}`,
19427
+ borderRadius: "8px",
19428
+ background: "white",
19429
+ cursor: "pointer",
19430
+ padding: "5px 9px",
19431
+ fontSize: "13px",
19432
+ color: MUTED2,
19433
+ lineHeight: 1
19434
+ },
19435
+ children: "\u2715"
19436
+ }
19437
+ )
19438
+ ]
19439
+ }
19440
+ ),
19441
+ /* @__PURE__ */ jsx(
19442
+ "div",
19443
+ {
19444
+ style: {
19445
+ flex: 1,
19446
+ minHeight: 0,
19447
+ overflow: "hidden",
19448
+ display: "flex",
19449
+ flexDirection: "column",
19450
+ padding: "14px 16px"
19451
+ },
19452
+ children
19453
+ }
19454
+ )
19455
+ ]
19456
+ }
19457
+ )
19458
+ }
19459
+ ),
19460
+ document.body
19461
+ );
19462
+ }
19463
+ function DocumentFieldExtractionResolver(p) {
19464
+ var _a, _b;
19465
+ const { BORDER: BORDER4, MUTED: MUTED2, PAPER: PAPER2 } = useTheme();
19466
+ const [selectedKey, setSelectedKey] = React45.useState(null);
19467
+ const [open, setOpen] = React45.useState(false);
19468
+ const [tab, setTab] = React45.useState("fields");
19469
+ const pages = (_a = p.pages) != null ? _a : [];
19470
+ const fields = (_b = p.fields) != null ? _b : [];
19471
+ const editable = typeof p.onFieldSave === "function";
19472
+ const onLoadAudit = p.onLoadAudit;
19473
+ React45.useEffect(() => {
19474
+ if (tab === "audit" && onLoadAudit) {
19475
+ onLoadAudit();
19476
+ }
19477
+ }, [tab, onLoadAudit]);
19478
+ const correctionCounts = React45.useMemo(() => {
19479
+ var _a2, _b2;
19480
+ const counts = {};
19481
+ for (const ev of (_a2 = p.auditEvents) != null ? _a2 : []) {
19482
+ const human = ev.actor_type !== "system" && ev.event_type !== "ai_extracted";
19483
+ if (human) counts[ev.field_key] = ((_b2 = counts[ev.field_key]) != null ? _b2 : 0) + 1;
19484
+ }
19485
+ return counts;
19486
+ }, [p.auditEvents]);
19487
+ const orderedFields = [...fields].sort((a, b) => {
19488
+ var _a2, _b2;
19489
+ if (!!a.is_primary !== !!b.is_primary) return a.is_primary ? -1 : 1;
19490
+ return ((_a2 = b.confidence) != null ? _a2 : 0) - ((_b2 = a.confidence) != null ? _b2 : 0);
19491
+ });
19492
+ const fieldsByPage = (pageNo) => fields.filter((f) => f.page === pageNo);
19493
+ const csvCols = [
19494
+ { key: "label", label: "Field" },
19495
+ { key: "value", label: "Value" },
19496
+ { key: "page", label: "Page" },
19497
+ { key: "confidence", label: "Confidence" },
19498
+ { key: "badge", label: "Badge" },
19499
+ { key: "state", label: "State" }
19500
+ ];
19501
+ const csvRows = orderedFields.map((f) => {
19502
+ var _a2, _b2, _c;
19503
+ return {
19504
+ label: f.label,
19505
+ value: f.value,
19506
+ page: f.page + 1,
19507
+ confidence: (_a2 = f.confidence) != null ? _a2 : "",
19508
+ badge: (_b2 = f.badge) != null ? _b2 : "",
19509
+ state: (_c = f.state) != null ? _c : ""
19510
+ };
19511
+ });
19512
+ const title = p.file_name || (p.doc_type ? `${p.doc_type} \u2014 extracted fields` : "Extracted fields");
19513
+ const tierCounts = fields.reduce(
19514
+ (acc, f) => {
19515
+ var _a2;
19516
+ const t = (_a2 = f.confidence_tier) != null ? _a2 : "amber";
19517
+ if (t === "green") acc.high += 1;
19518
+ else if (t === "red") acc.low += 1;
19519
+ else acc.med += 1;
19520
+ return acc;
19521
+ },
19522
+ { high: 0, med: 0, low: 0 }
19523
+ );
19524
+ const chips = [
19525
+ { n: tierCounts.high, label: "high", color: TIER_COLORS2.green },
19526
+ { n: tierCounts.med, label: "medium", color: TIER_COLORS2.amber },
19527
+ { n: tierCounts.low, label: "low", color: TIER_COLORS2.red }
19528
+ ].filter((c) => c.n > 0);
19529
+ const thumb = pages.find((pg) => pg.imageUrl);
19530
+ return /* @__PURE__ */ jsxs(
19531
+ ComponentActions,
19532
+ {
19533
+ filename: "document-fields",
19534
+ onDownloadCSV: () => downloadCSV(csvCols, csvRows, "document-fields"),
19535
+ children: [
19536
+ /* @__PURE__ */ jsxs(
19537
+ "div",
19538
+ {
19539
+ role: "button",
19540
+ tabIndex: 0,
19541
+ onClick: () => setOpen(true),
19542
+ onKeyDown: (e) => {
19543
+ if (e.key === "Enter" || e.key === " ") {
19544
+ e.preventDefault();
19545
+ setOpen(true);
19546
+ }
19547
+ },
19548
+ style: {
19549
+ display: "flex",
19550
+ alignItems: "stretch",
19551
+ gap: "12px",
19552
+ padding: "12px",
19553
+ width: "100%",
19554
+ maxWidth: "440px",
19555
+ borderRadius: "0.75rem",
19556
+ border: `1px solid ${BORDER4}`,
19557
+ background: "white",
19558
+ cursor: "pointer",
19559
+ textAlign: "left",
19560
+ boxShadow: "0 1px 2px rgba(0,0,0,0.03), 0 4px 12px rgba(0,0,0,0.05)"
19561
+ },
19562
+ children: [
19563
+ /* @__PURE__ */ jsx(
19564
+ "div",
19565
+ {
19566
+ style: {
19567
+ width: "64px",
19568
+ flexShrink: 0,
19569
+ borderRadius: "0.5rem",
19570
+ border: `1px solid ${BORDER4}`,
19571
+ background: PAPER2,
19572
+ overflow: "hidden",
19573
+ display: "flex",
19574
+ alignItems: "center",
19575
+ justifyContent: "center"
19576
+ },
19577
+ children: (thumb == null ? void 0 : thumb.imageUrl) ? /* @__PURE__ */ jsx(
19578
+ "img",
19579
+ {
19580
+ src: thumb.imageUrl,
19581
+ alt: "Document preview",
19582
+ style: { width: "100%", height: "auto", display: "block" }
19583
+ }
19584
+ ) : /* @__PURE__ */ jsx("span", { style: { fontSize: "22px", lineHeight: 1, padding: "16px 0" }, children: "\u{1F4C4}" })
19585
+ }
19586
+ ),
19587
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "6px" }, children: [
19588
+ /* @__PURE__ */ jsx(
19589
+ "p",
19590
+ {
19591
+ style: {
19592
+ fontFamily: "var(--font-serif)",
19593
+ fontSize: "15px",
19594
+ fontWeight: 400,
19595
+ color: "var(--foreground)",
19596
+ letterSpacing: "-0.01em",
19597
+ margin: 0,
19598
+ overflow: "hidden",
19599
+ textOverflow: "ellipsis",
19600
+ whiteSpace: "nowrap"
19601
+ },
19602
+ children: p.file_name || p.doc_type || "Document"
19603
+ }
19604
+ ),
19605
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: MUTED2 }, children: [
19606
+ fields.length,
19607
+ " field",
19608
+ fields.length === 1 ? "" : "s",
19609
+ " extracted \xB7 ",
19610
+ pages.length,
19611
+ " page",
19612
+ pages.length === 1 ? "" : "s"
19613
+ ] }),
19614
+ chips.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "5px" }, children: chips.map((c) => /* @__PURE__ */ jsxs(
19615
+ "span",
19616
+ {
19617
+ style: {
19618
+ display: "inline-flex",
19619
+ alignItems: "center",
19620
+ gap: "4px",
19621
+ fontSize: "10px",
19622
+ fontWeight: 600,
19623
+ padding: "2px 7px",
19624
+ borderRadius: "9999px",
19625
+ background: hexToRgba2(c.color, 0.12),
19626
+ color: c.color
19627
+ },
19628
+ children: [
19629
+ /* @__PURE__ */ jsx(
19630
+ "span",
19631
+ {
19632
+ style: {
19633
+ width: "6px",
19634
+ height: "6px",
19635
+ borderRadius: "9999px",
19636
+ background: c.color
19637
+ }
19638
+ }
19639
+ ),
19640
+ c.n,
19641
+ " ",
19642
+ c.label
19643
+ ]
19644
+ },
19645
+ c.label
19646
+ )) }),
19647
+ /* @__PURE__ */ jsx(
19648
+ "span",
19649
+ {
19650
+ style: {
19651
+ marginTop: "2px",
19652
+ alignSelf: "flex-start",
19653
+ fontSize: "12px",
19654
+ fontWeight: 600,
19655
+ padding: "6px 12px",
19656
+ borderRadius: "0.5rem",
19657
+ background: "var(--foreground)",
19658
+ color: "white"
19659
+ },
19660
+ children: "View & edit fields"
19661
+ }
19662
+ )
19663
+ ] })
19664
+ ]
19665
+ }
19666
+ ),
19667
+ /* @__PURE__ */ jsx(ExtractionModal, { open, onClose: () => setOpen(false), title, children: /* @__PURE__ */ jsx(
19668
+ ExtractionDetail,
19669
+ {
19670
+ pages,
19671
+ orderedFields,
19672
+ fieldsByPage,
19673
+ selectedKey,
19674
+ setSelectedKey,
19675
+ onFieldSave: p.onFieldSave,
19676
+ correctionCounts,
19677
+ tab,
19678
+ setTab,
19679
+ editable,
19680
+ summary: p.summary,
19681
+ fileName: p.file_name,
19682
+ pageCount: p.page_count,
19683
+ pagesProcessed: p.pages_processed,
19684
+ auditEvents: p.auditEvents,
19685
+ auditLoading: p.auditLoading
19686
+ }
19687
+ ) })
19688
+ ]
19689
+ }
19690
+ );
19691
+ }
19692
+ init_ThemeContext();
19693
+ var SEVERITY_COLORS = {
19694
+ high: { color: "#dc2626", bg: "#fef2f2" },
19695
+ medium: { color: "#f59e0b", bg: "#fff7ed" },
19696
+ low: { color: "#777777", bg: "#f2f2f2" }
19697
+ };
19698
+ var GREEN3 = "#15803d";
19699
+ var GREEN_SOFT = "#dcfce7";
19700
+ var STACK_BELOW = 380;
19701
+ function formatAmount2(amount, currency = "USD") {
19702
+ var _a, _b;
19703
+ const abs = Math.abs(amount);
19704
+ const sign = amount < 0 ? "-" : "";
19705
+ let body;
19706
+ if (abs >= 1e6) body = `${(abs / 1e6).toFixed(abs >= 1e7 ? 0 : 1)}M`;
19707
+ else if (abs >= 1e3) body = `${(abs / 1e3).toFixed(abs >= 1e4 ? 0 : 1)}K`;
19708
+ else body = `${abs}`;
19709
+ let symbol = "$";
19710
+ try {
19711
+ const parts = new Intl.NumberFormat("en-US", {
19712
+ style: "currency",
19713
+ currency,
19714
+ maximumFractionDigits: 0
19715
+ }).formatToParts(0);
19716
+ symbol = (_b = (_a = parts.find((p) => p.type === "currency")) == null ? void 0 : _a.value) != null ? _b : "$";
19717
+ } catch (e) {
19718
+ symbol = "$";
19719
+ }
19720
+ return `${sign}${symbol}${body}`;
19721
+ }
19722
+ function useContainerWidth2(ref) {
19723
+ const [w, setW] = React45.useState(0);
19724
+ React45.useLayoutEffect(() => {
19725
+ const el = ref.current;
19726
+ if (!el || typeof ResizeObserver === "undefined") return;
19727
+ const ro = new ResizeObserver((entries) => {
19728
+ var _a;
19729
+ const cr = (_a = entries[0]) == null ? void 0 : _a.contentRect;
19730
+ if (cr) setW(cr.width);
19731
+ });
19732
+ ro.observe(el);
19733
+ setW(el.getBoundingClientRect().width);
19734
+ return () => ro.disconnect();
19735
+ }, [ref]);
19736
+ return w;
19737
+ }
19738
+ var KEYFRAMES2 = `
19739
+ @keyframes dcRise{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
19740
+ .dc-rise{animation:dcRise 0.28s cubic-bezier(0.22,1,0.36,1) both}
19741
+ @media (prefers-reduced-motion: reduce){
19742
+ .dc-rise{animation:none !important;opacity:1 !important;transform:none !important}
19743
+ }`;
19744
+ function SparkCheck({ size, color }) {
19745
+ return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
19746
+ "path",
19747
+ {
19748
+ d: "M5 13l4 4L19 7",
19749
+ stroke: color,
19750
+ strokeWidth: 2.5,
19751
+ strokeLinecap: "round",
19752
+ strokeLinejoin: "round"
19753
+ }
19754
+ ) });
19755
+ }
19756
+ function FlagPill({ flag }) {
19757
+ var _a;
19758
+ const sev = (_a = flag.severity) != null ? _a : "medium";
19759
+ const { color, bg } = SEVERITY_COLORS[sev];
19760
+ return /* @__PURE__ */ jsxs(
19761
+ "span",
19762
+ {
19763
+ style: {
19764
+ display: "inline-flex",
19765
+ alignItems: "center",
19766
+ gap: 5,
19767
+ fontSize: 11,
19768
+ fontWeight: 600,
19769
+ padding: "3px 9px",
19770
+ borderRadius: 9999,
19771
+ background: bg,
19772
+ color,
19773
+ lineHeight: 1.2
19774
+ },
19775
+ children: [
19776
+ /* @__PURE__ */ jsx(
19777
+ "span",
19778
+ {
19779
+ "aria-hidden": "true",
19780
+ style: { width: 6, height: 6, borderRadius: "50%", background: color, flexShrink: 0 }
19781
+ }
19782
+ ),
19783
+ flag.field ? `${flag.field}: ${flag.issue}` : flag.issue
19784
+ ]
19785
+ }
19786
+ );
19787
+ }
19788
+ function DecisionCardRenderer({
19789
+ data,
19790
+ resolved = null,
19791
+ onResolve,
19792
+ onOpenSource
19793
+ }) {
19794
+ var _a, _b;
19795
+ const { BORDER: BORDER4, MUTED: MUTED2, ACCENT: ACCENT2, ACCENT_SOFT: ACCENT_SOFT2 } = useTheme();
19796
+ const rootRef = React45.useRef(null);
19797
+ const width = useContainerWidth2(rootRef);
19798
+ const stacked = width > 0 && width < STACK_BELOW;
19799
+ const options = (_a = data.options) != null ? _a : [];
19800
+ const recommendedIdx = Math.max(
19801
+ 0,
19802
+ options.findIndex((o) => o.recommended)
19803
+ );
19804
+ const railColor = data.severity ? SEVERITY_COLORS[data.severity].color : ACCENT2;
19805
+ const isResolved = Boolean(resolved);
19806
+ const amountNode = typeof data.amount === "number" ? /* @__PURE__ */ jsxs(
19807
+ "div",
19808
+ {
19809
+ style: {
19810
+ display: "flex",
19811
+ flexDirection: "column",
19812
+ alignItems: stacked ? "flex-start" : "flex-end",
19813
+ gap: 1,
19814
+ flexShrink: 0
19815
+ },
19816
+ children: [
19817
+ data.amount_label && /* @__PURE__ */ jsx(
19818
+ "span",
19819
+ {
19820
+ style: {
19821
+ fontSize: 10,
19822
+ textTransform: "uppercase",
19823
+ letterSpacing: "0.07em",
19824
+ fontWeight: 700,
19825
+ color: MUTED2
19826
+ },
19827
+ children: data.amount_label
19828
+ }
19829
+ ),
19830
+ /* @__PURE__ */ jsx(
19831
+ "span",
19832
+ {
19833
+ style: {
19834
+ fontSize: 18,
19835
+ fontWeight: 700,
19836
+ color: "var(--foreground)",
19837
+ fontVariantNumeric: "tabular-nums",
19838
+ letterSpacing: "-0.01em",
19839
+ lineHeight: 1.1
19840
+ },
19841
+ children: formatAmount2(data.amount, data.currency)
19842
+ }
19843
+ )
19844
+ ]
19845
+ }
19846
+ ) : null;
19847
+ return /* @__PURE__ */ jsxs(
19848
+ "div",
19849
+ {
19850
+ ref: rootRef,
19851
+ className: "dc-rise",
19852
+ "data-testid": "decision-card",
19853
+ "data-resolved": isResolved || void 0,
19854
+ style: {
19855
+ position: "relative",
19856
+ width: "100%",
19857
+ minWidth: 0,
19858
+ boxSizing: "border-box",
19859
+ borderRadius: "0.75rem",
19860
+ border: `1px solid ${isResolved ? GREEN_SOFT : BORDER4}`,
19861
+ background: isResolved ? "#f6fef9" : "white",
19862
+ boxShadow: "0 1px 2px rgba(0,0,0,0.03), 0 4px 12px rgba(0,0,0,0.04)",
19863
+ padding: "16px 18px 16px 20px",
19864
+ display: "flex",
19865
+ flexDirection: "column",
19866
+ gap: 12,
19867
+ overflow: "hidden"
19868
+ },
19869
+ children: [
19870
+ /* @__PURE__ */ jsx("style", { children: KEYFRAMES2 }),
19871
+ /* @__PURE__ */ jsx(
19872
+ "div",
19873
+ {
19874
+ "aria-hidden": "true",
19875
+ style: {
19876
+ position: "absolute",
19877
+ top: 0,
19878
+ left: 0,
19879
+ bottom: 0,
19880
+ width: 4,
19881
+ background: isResolved ? GREEN3 : railColor
19882
+ }
19883
+ }
19884
+ ),
19885
+ /* @__PURE__ */ jsxs(
19886
+ "div",
19887
+ {
19888
+ style: {
19889
+ display: "flex",
19890
+ flexDirection: stacked ? "column" : "row",
19891
+ alignItems: stacked ? "flex-start" : "flex-start",
19892
+ justifyContent: "space-between",
19893
+ gap: stacked ? 6 : 12
19894
+ },
19895
+ children: [
19896
+ /* @__PURE__ */ jsxs("div", { style: { minWidth: 0, display: "flex", flexDirection: "column", gap: 4 }, children: [
19897
+ /* @__PURE__ */ jsx(
19898
+ "span",
19899
+ {
19900
+ style: {
19901
+ fontSize: 10.5,
19902
+ textTransform: "uppercase",
19903
+ letterSpacing: "0.07em",
19904
+ fontWeight: 700,
19905
+ color: ACCENT2
19906
+ },
19907
+ children: data.decision_type ? `Decision needs you \xB7 ${data.decision_type}` : "Decision needs you"
19908
+ }
19909
+ ),
19910
+ /* @__PURE__ */ jsx(
19911
+ "p",
19912
+ {
19913
+ style: {
19914
+ fontFamily: "var(--font-serif)",
19915
+ fontSize: 17,
19916
+ fontWeight: 400,
19917
+ color: "var(--foreground)",
19918
+ letterSpacing: "-0.01em",
19919
+ margin: 0,
19920
+ lineHeight: 1.2
19921
+ },
19922
+ children: data.title
19923
+ }
19924
+ )
19925
+ ] }),
19926
+ amountNode
19927
+ ]
19928
+ }
19929
+ ),
19930
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 13, lineHeight: 1.5, color: MUTED2, margin: 0 }, children: data.question }),
19931
+ data.flags && data.flags.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: data.flags.map((flag, i) => {
19932
+ var _a2;
19933
+ return /* @__PURE__ */ jsx(FlagPill, { flag }, `${(_a2 = flag.field) != null ? _a2 : "flag"}-${i}`);
19934
+ }) }),
19935
+ isResolved ? /* @__PURE__ */ jsxs(
19936
+ "div",
19937
+ {
19938
+ style: {
19939
+ display: "inline-flex",
19940
+ alignItems: "center",
19941
+ gap: 7,
19942
+ fontSize: 13,
19943
+ fontWeight: 600,
19944
+ color: GREEN3
19945
+ },
19946
+ children: [
19947
+ /* @__PURE__ */ jsx(SparkCheck, { size: 16, color: GREEN3 }),
19948
+ "Resolved \xB7 ",
19949
+ resolved
19950
+ ]
19951
+ }
19952
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
19953
+ /* @__PURE__ */ jsx(
19954
+ "div",
19955
+ {
19956
+ style: {
19957
+ display: "flex",
19958
+ flexDirection: stacked ? "column" : "row",
19959
+ flexWrap: stacked ? "nowrap" : "wrap",
19960
+ gap: 8
19961
+ },
19962
+ children: options.map((opt, idx) => {
19963
+ var _a2;
19964
+ const primary = idx === recommendedIdx;
19965
+ return /* @__PURE__ */ jsx(
19966
+ "button",
19967
+ {
19968
+ type: "button",
19969
+ onClick: () => onResolve == null ? void 0 : onResolve(opt.label),
19970
+ style: {
19971
+ width: stacked ? "100%" : "auto",
19972
+ textAlign: stacked ? "left" : "center",
19973
+ border: `1px solid ${primary ? ACCENT2 : BORDER4}`,
19974
+ background: primary ? ACCENT2 : "white",
19975
+ color: primary ? "white" : "var(--foreground)",
19976
+ borderRadius: 8,
19977
+ fontSize: 13,
19978
+ fontWeight: 600,
19979
+ padding: "9px 14px",
19980
+ cursor: "pointer",
19981
+ transition: "background 0.15s, border-color 0.15s, color 0.15s"
19982
+ },
19983
+ onMouseEnter: (e) => {
19984
+ if (primary) {
19985
+ e.currentTarget.style.background = ACCENT_SOFT2;
19986
+ } else {
19987
+ e.currentTarget.style.borderColor = ACCENT2;
19988
+ e.currentTarget.style.background = "#fafafa";
19989
+ }
19990
+ },
19991
+ onMouseLeave: (e) => {
19992
+ if (primary) {
19993
+ e.currentTarget.style.background = ACCENT2;
19994
+ } else {
19995
+ e.currentTarget.style.borderColor = BORDER4;
19996
+ e.currentTarget.style.background = "white";
19997
+ }
19998
+ },
19999
+ children: opt.label
20000
+ },
20001
+ (_a2 = opt.id) != null ? _a2 : opt.label
20002
+ );
20003
+ })
20004
+ }
20005
+ ),
20006
+ data.source && /* @__PURE__ */ jsxs(
20007
+ "button",
20008
+ {
20009
+ type: "button",
20010
+ onClick: onOpenSource,
20011
+ style: {
20012
+ alignSelf: "flex-start",
20013
+ display: "inline-flex",
20014
+ alignItems: "center",
20015
+ gap: 5,
20016
+ border: "none",
20017
+ background: "none",
20018
+ padding: 0,
20019
+ cursor: "pointer",
20020
+ fontSize: 12,
20021
+ fontWeight: 600,
20022
+ color: MUTED2,
20023
+ transition: "color 0.15s"
20024
+ },
20025
+ onMouseEnter: (e) => e.currentTarget.style.color = ACCENT2,
20026
+ onMouseLeave: (e) => e.currentTarget.style.color = MUTED2,
20027
+ children: [
20028
+ /* @__PURE__ */ jsx("svg", { width: 13, height: 13, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
20029
+ "path",
20030
+ {
20031
+ d: "M14 3v4a1 1 0 001 1h4M5 4a1 1 0 011-1h8l5 5v11a1 1 0 01-1 1H6a1 1 0 01-1-1V4z",
20032
+ stroke: "currentColor",
20033
+ strokeWidth: 1.8,
20034
+ strokeLinecap: "round",
20035
+ strokeLinejoin: "round"
20036
+ }
20037
+ ) }),
20038
+ (_b = data.source.label) != null ? _b : "View source for this figure"
20039
+ ]
20040
+ }
20041
+ )
20042
+ ] })
20043
+ ]
20044
+ }
20045
+ );
20046
+ }
20047
+ function DecisionCardResolver(p) {
20048
+ var _a, _b, _c, _d;
20049
+ const { resolvedDecisions, onDecisionResolve, onDecisionSource } = useGenUIInteraction();
20050
+ const decisionId = (_a = p.id) != null ? _a : p.title;
20051
+ const hostResolved = resolvedDecisions == null ? void 0 : resolvedDecisions[decisionId];
20052
+ const initial = (_c = hostResolved != null ? hostResolved : (_b = p.resolved) == null ? void 0 : _b.option) != null ? _c : null;
20053
+ const [localResolved, setLocalResolved] = React45.useState(initial);
20054
+ React45.useEffect(() => {
20055
+ if (hostResolved !== void 0) setLocalResolved(hostResolved);
20056
+ }, [hostResolved]);
20057
+ const resolved = hostResolved != null ? hostResolved : localResolved;
20058
+ const handleResolve = (option) => {
20059
+ setLocalResolved(option);
20060
+ onDecisionResolve == null ? void 0 : onDecisionResolve(decisionId, option);
20061
+ };
20062
+ const handleSource = () => {
20063
+ var _a2;
20064
+ onDecisionSource == null ? void 0 : onDecisionSource(decisionId, p.source);
20065
+ if (!onDecisionSource && ((_a2 = p.source) == null ? void 0 : _a2.url) && typeof window !== "undefined") {
20066
+ window.open(p.source.url, "_blank", "noopener,noreferrer");
20067
+ }
20068
+ };
20069
+ return /* @__PURE__ */ jsx(ComponentActions, { filename: (_d = p.title) != null ? _d : "decision-card", children: /* @__PURE__ */ jsx(
20070
+ DecisionCardRenderer,
20071
+ {
20072
+ data: p,
20073
+ resolved,
20074
+ onResolve: handleResolve,
20075
+ onOpenSource: handleSource
20076
+ }
20077
+ ) });
20078
+ }
17851
20079
  function resolveUI(rawPayload) {
17852
20080
  const payload = coercePayload(rawPayload);
17853
20081
  switch (payload.type) {
@@ -17965,6 +20193,10 @@ function resolveUI(rawPayload) {
17965
20193
  return /* @__PURE__ */ jsx(PipelinePreviewResolver, __spreadValues({}, payload));
17966
20194
  case "workflow-stepper":
17967
20195
  return /* @__PURE__ */ jsx(WorkflowStepperResolver, __spreadValues({}, payload));
20196
+ case "document-field-extraction":
20197
+ return /* @__PURE__ */ jsx(DocumentFieldExtractionResolver, __spreadValues({}, payload));
20198
+ case "decision-card":
20199
+ return /* @__PURE__ */ jsx(DecisionCardResolver, __spreadValues({}, payload));
17968
20200
  default: {
17969
20201
  return /* @__PURE__ */ jsx(
17970
20202
  "div",