@campfire-interactive/volume-intelligence-ui 0.11.1 → 0.12.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/index.d.ts CHANGED
@@ -418,14 +418,6 @@ interface VolumeSourcesListProps {
418
418
  readOnly?: boolean;
419
419
  className?: string;
420
420
  }
421
- /**
422
- * Volume-source list: cards per source, "add from template", manual create,
423
- * and activate (with the data-wipe confirm). Transport-agnostic and router-free
424
- * — the host supplies `transport` and an `onOpenSource` navigation callback.
425
- *
426
- * The VI-webapp's active-source analytical sub-cards (enrichment toggle,
427
- * backtests) are intentionally NOT here — per ADR §6 they stay VI-webapp-only.
428
- */
429
421
  declare function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras, readOnly, className }: VolumeSourcesListProps): react.JSX.Element;
430
422
 
431
423
  /**
@@ -528,6 +520,62 @@ interface ValueAliasesCardProps {
528
520
  }
529
521
  declare function ValueAliasesCard({ transport, sourceId, locked, isOverlay, targets }: ValueAliasesCardProps): react.JSX.Element;
530
522
 
523
+ /**
524
+ * What each source role looks like, and why it looks like that.
525
+ *
526
+ * The colors are not decorative. Each one is the stroke the forecast chart
527
+ * draws that role's data in, so a source badged teal here is the teal dashed
528
+ * curve there. That is the whole point of coloring this screen: the operator
529
+ * setting a source to `reference` should be able to see, before loading a
530
+ * single row, which line on the chart they are about to create.
531
+ *
532
+ * The chart's table lives in the app (`SERIES_STYLE` in ForecastChart) and this
533
+ * one lives in the package, so they cannot literally be the same constant —
534
+ * the package must not depend on the app. They are duplicated deliberately and
535
+ * this comment is the link. If the chart repaints a series, repaint it here.
536
+ */
537
+ interface RoleStyle {
538
+ /** The chart stroke for the series this role feeds. */
539
+ color: string;
540
+ /** Sentence-case name for a badge. */
541
+ label: string;
542
+ /** One line on what the role does, shown under the selector. */
543
+ blurb: string;
544
+ /** Matches the chart's dashed reference curve. */
545
+ dash?: string;
546
+ }
547
+ declare const ROLE_STYLE: Record<VolumeSourceKind, RoleStyle>;
548
+ declare const ROLE_ORDER: VolumeSourceKind[];
549
+
550
+ /** The chart-legend glyph: a stroke with its marker on it.
551
+ *
552
+ * Same shape the forecast chart's provider row uses, for the same reason —
553
+ * these stand for lines, and the reference role's line is dashed. A plain dot
554
+ * would drop that, and teal-dashed against teal-solid is the difference
555
+ * between "a second vendor" and "the main curve". */
556
+ declare function RoleSwatch(props: {
557
+ color: string;
558
+ dash?: string;
559
+ title?: string;
560
+ }): react.JSX.Element;
561
+ /** One joined control with hairline dividers, not a row of separate pills.
562
+ *
563
+ * Mirrors the forecast chart's "View by" control so the two screens read as
564
+ * one product. `activeColor` fills the selected segment, which is how the
565
+ * role's chart color gets stated before any data exists to draw. */
566
+ declare function Segmented<T extends string>(props: {
567
+ value: T;
568
+ options: {
569
+ value: T;
570
+ label: ReactNode;
571
+ title?: string;
572
+ activeColor?: string;
573
+ }[];
574
+ onChange: (value: T) => void;
575
+ disabled?: boolean;
576
+ ariaLabel: string;
577
+ }): react.JSX.Element;
578
+
531
579
  declare const HIERARCHY_LEVEL_COUNT = 6;
532
580
  /** Display labels for hierarchy levels 1..6 (the mapping of source columns to
533
581
  * levels is per-tenant config; this only controls the label). */
@@ -539,4 +587,4 @@ declare const DEFAULT_LEVEL_NAMES: Record<number, string>;
539
587
  declare const AUTOMOTIVE_SLOTS: AutomotiveSlot[];
540
588
  declare const AUTOMOTIVE_TRANSFORM_LABELS: Record<string, string>;
541
589
 
542
- export { AUTOMOTIVE_SLOTS, AUTOMOTIVE_TRANSFORM_LABELS, type AliasStatus, type AliasTarget, type AutomotiveSlot, type ClearSourceDataResult, type CreateSegmentInput, type CreateSourceInput, DEFAULT_LEVEL_NAMES, type DetectSegmentsResult, HIERARCHY_LEVEL_COUNT, type ListErrorsResult, type MappableDimension, type RelinkResult, type RequiredMappingStatus, type SegmentMappingCategory, type SegmentMappingCategoryKeys, type SegmentMappingEntry, type SegmentMappingKeys, type SegmentMappingRow, type SourceAdminTransport, type SourceLayout, type SourceTemplateSummary, type SourceValueAlias, type SourceWithSegments, TallLayoutMappings, type TallLayoutMappingsProps, type TenantVolumeConfig, UnifiedSegmentMapper, type UnifiedSegmentMapperProps, type UpdateSourceInput, type Upload, type UploadError, type UploadErrorRow, type UploadInput, type UploadListParams, type UploadListResponse, type UploadRecord, type UploadStats, type UploadStatus, type ValueAliasEntry, ValueAliasesCard, type ValueAliasesCardProps, VolumeFiles, type VolumeFilesProps, type VolumeFilesTransport, VolumeImport, type VolumeImportProps, type VolumeSource$1 as VolumeImportSource, type VolumeImportTransport, type UploadStatus$1 as VolumeImportUploadStatus, type VolumeSource, VolumeSourceDetail, type VolumeSourceDetailProps, type VolumeSourceKind, type VolumeSourceLayout, type VolumeSourceSegment, VolumeSourcesList, type VolumeSourcesListProps };
590
+ export { AUTOMOTIVE_SLOTS, AUTOMOTIVE_TRANSFORM_LABELS, type AliasStatus, type AliasTarget, type AutomotiveSlot, type ClearSourceDataResult, type CreateSegmentInput, type CreateSourceInput, DEFAULT_LEVEL_NAMES, type DetectSegmentsResult, HIERARCHY_LEVEL_COUNT, type ListErrorsResult, type MappableDimension, ROLE_ORDER, ROLE_STYLE, type RelinkResult, type RequiredMappingStatus, type RoleStyle, RoleSwatch, type SegmentMappingCategory, type SegmentMappingCategoryKeys, type SegmentMappingEntry, type SegmentMappingKeys, type SegmentMappingRow, Segmented, type SourceAdminTransport, type SourceLayout, type SourceTemplateSummary, type SourceValueAlias, type SourceWithSegments, TallLayoutMappings, type TallLayoutMappingsProps, type TenantVolumeConfig, UnifiedSegmentMapper, type UnifiedSegmentMapperProps, type UpdateSourceInput, type Upload, type UploadError, type UploadErrorRow, type UploadInput, type UploadListParams, type UploadListResponse, type UploadRecord, type UploadStats, type UploadStatus, type ValueAliasEntry, ValueAliasesCard, type ValueAliasesCardProps, VolumeFiles, type VolumeFilesProps, type VolumeFilesTransport, VolumeImport, type VolumeImportProps, type VolumeSource$1 as VolumeImportSource, type VolumeImportTransport, type UploadStatus$1 as VolumeImportUploadStatus, type VolumeSource, VolumeSourceDetail, type VolumeSourceDetailProps, type VolumeSourceKind, type VolumeSourceLayout, type VolumeSourceSegment, VolumeSourcesList, type VolumeSourcesListProps };
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ function styleInject(css, { insertAt } = {}) {
25
25
  }
26
26
 
27
27
  // src/styles.css
28
- styleInject(".cfi-volume-import {\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-base, 14px);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n max-width: 640px;\n}\n.cfi-volume-import .cfi-vi-field {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-xs, 4px);\n}\n.cfi-volume-import .cfi-vi-row {\n display: flex;\n gap: var(--cfi-spacing-md, 12px);\n flex-wrap: wrap;\n}\n.cfi-volume-import .cfi-vi-row .cfi-vi-field {\n flex: 1 1 8rem;\n}\n.cfi-volume-import .cfi-vi-label {\n font-size: var(--cfi-font-size-sm, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-volume-import .cfi-vi-select,\n.cfi-volume-import .cfi-vi-file {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n color: inherit;\n}\n.cfi-volume-import .cfi-vi-select:focus,\n.cfi-volume-import .cfi-vi-file:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: 1px;\n}\n.cfi-volume-import .cfi-vi-button {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 6px);\n align-self: flex-start;\n padding: 8px 14px;\n border: none;\n border-radius: var(--cfi-radius-md, 6px);\n background: var(--cfi-color-primary-600, #2563eb);\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n.cfi-volume-import .cfi-vi-button:hover:not(:disabled) {\n background: var(--cfi-color-primary-700, #1d4ed8);\n}\n.cfi-volume-import .cfi-vi-button:disabled {\n background: var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-500, #6b7280);\n cursor: not-allowed;\n}\n.cfi-volume-import .cfi-vi-loading,\n.cfi-volume-import .cfi-vi-alert {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 6px);\n padding: 8px 10px;\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-alert--error {\n background: var(--cfi-color-gray-100, #fef2f2);\n color: var(--cfi-color-error, #b91c1c);\n}\n.cfi-volume-import .cfi-vi-alert--warn {\n background: #fffbeb;\n color: #92400e;\n align-items: flex-start;\n}\n.cfi-volume-import .cfi-vi-blockers {\n margin: 0;\n padding-left: 1.1rem;\n}\n.cfi-volume-import .cfi-vi-status {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n padding: var(--cfi-spacing-md, 12px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-volume-import .cfi-vi-status-head {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-volume-import .cfi-vi-filename {\n font-weight: 600;\n}\n.cfi-volume-import .cfi-vi-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n border-radius: 999px;\n font-size: var(--cfi-font-size-xs, 11px);\n text-transform: capitalize;\n background: var(--cfi-color-gray-100, #f3f4f6);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-volume-import .cfi-vi-badge--done {\n background: #dcfce7;\n color: #166534;\n}\n.cfi-volume-import .cfi-vi-badge--done_with_errors {\n background: #fef9c3;\n color: #854d0e;\n}\n.cfi-volume-import .cfi-vi-badge--failed {\n background: #fee2e2;\n color: #991b1b;\n}\n.cfi-volume-import .cfi-vi-badge--processing,\n.cfi-volume-import .cfi-vi-badge--pending,\n.cfi-volume-import .cfi-vi-badge--awaiting_calendar {\n background: #dbeafe;\n color: #1e40af;\n}\n.cfi-volume-import .cfi-vi-link {\n background: none;\n border: none;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--cfi-color-primary-600, #2563eb);\n font: inherit;\n cursor: pointer;\n}\n.cfi-volume-import .cfi-vi-stats {\n display: flex;\n gap: var(--cfi-spacing-md, 12px);\n color: var(--cfi-color-gray-600, #4b5563);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-errors {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-errors th,\n.cfi-volume-import .cfi-vi-errors td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n vertical-align: top;\n}\n.cfi-volume-import .cfi-vi-spin {\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n@keyframes cfi-vi-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.cfi-vi {\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-base, 14px);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n}\n.cfi-vi *,\n.cfi-vi *::before,\n.cfi-vi *::after {\n box-sizing: border-box;\n}\n.cfi-vi .cfi-vi-row {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi .cfi-vi-row--between {\n justify-content: space-between;\n}\n.cfi-vi .cfi-vi-spacer {\n flex: 1;\n}\n.cfi-vi .cfi-vi-muted {\n color: var(--cfi-color-gray-600, #4b5563);\n}\n.cfi-vi .cfi-vi-error {\n color: var(--cfi-color-error, #b91c1c);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-mono {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n font-size: var(--cfi-font-size-xs, 11px);\n}\n.cfi-vi .cfi-vi-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n border-radius: var(--cfi-radius-md, 6px);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n white-space: nowrap;\n}\n.cfi-vi .cfi-vi-btn--sm {\n padding: 4px 10px;\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-btn--md {\n padding: 8px 14px;\n}\n.cfi-vi .cfi-vi-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-vi .cfi-vi-btn--primary {\n background: var(--cfi-color-primary-600, #2563eb);\n color: #fff;\n}\n.cfi-vi .cfi-vi-btn--primary:hover:not(:disabled) {\n background: var(--cfi-color-primary-700, #1d4ed8);\n}\n.cfi-vi .cfi-vi-btn--outline {\n background: #fff;\n border-color: var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-vi .cfi-vi-btn--outline:hover:not(:disabled) {\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-vi .cfi-vi-btn--ghost {\n background: transparent;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-btn--ghost:hover:not(:disabled) {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-vi .cfi-vi-btn--destructive {\n background: var(--cfi-color-error, #dc2626);\n color: #fff;\n}\n.cfi-vi .cfi-vi-btn--destructive:hover:not(:disabled) {\n filter: brightness(0.92);\n}\n.cfi-vi .cfi-vi-icon-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: var(--cfi-color-gray-500, #6b7280);\n border-radius: var(--cfi-radius-sm, 4px);\n display: inline-flex;\n}\n.cfi-vi .cfi-vi-icon-btn:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-vi .cfi-vi-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 600;\n}\n.cfi-vi .cfi-vi-tag--default {\n background: var(--cfi-color-gray-100, #f3f4f6);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--outline {\n background: transparent;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--secondary {\n background: var(--cfi-color-gray-200, #e5e7eb);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--success {\n background: #16a34a;\n color: #fff;\n}\n.cfi-vi .cfi-vi-tag--purple {\n background: var(--cfi-color-violet-600, #7c3aed);\n color: #fff;\n}\n.cfi-vi .cfi-vi-card {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-lg, 8px);\n background: #fff;\n}\n.cfi-vi .cfi-vi-card--active {\n border-color: #86efac;\n background: #f0fdf4;\n}\n.cfi-vi .cfi-vi-card--hover:hover {\n border-color: var(--cfi-color-primary-600, #2563eb);\n}\n.cfi-vi .cfi-vi-card-head {\n padding: var(--cfi-spacing-md, 12px);\n padding-bottom: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi .cfi-vi-card-body {\n padding: 0 var(--cfi-spacing-md, 12px) var(--cfi-spacing-md, 12px);\n}\n.cfi-vi .cfi-vi-card-title {\n font-size: var(--cfi-font-size-base, 15px);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.cfi-vi .cfi-vi-link {\n background: none;\n border: none;\n padding: 0;\n color: inherit;\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n.cfi-vi .cfi-vi-link:hover {\n text-decoration: underline;\n}\n.cfi-vi .cfi-vi-field {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-xs, 4px);\n}\n.cfi-vi .cfi-vi-label {\n font-size: var(--cfi-font-size-sm, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-hint {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-gray-500, #6b7280);\n margin: 2px 0 0;\n}\n.cfi-vi .cfi-vi-input,\n.cfi-vi select.cfi-vi-input {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n color: inherit;\n width: 100%;\n}\n.cfi-vi .cfi-vi-input:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: 1px;\n}\n.cfi-vi-modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n padding: 16px;\n}\n.cfi-vi-modal {\n background: #fff;\n border-radius: var(--cfi-radius-lg, 8px);\n width: 100%;\n max-width: 32rem;\n max-height: 90vh;\n overflow: auto;\n box-shadow: var(--cfi-shadow-lg, 0 10px 30px rgba(0,0,0,0.2));\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n}\n.cfi-vi-modal-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--cfi-spacing-md, 14px);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi-modal-title {\n font-size: var(--cfi-font-size-lg, 16px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi-modal-body {\n padding: var(--cfi-spacing-md, 14px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n}\n.cfi-vi-modal-foot {\n display: flex;\n justify-content: flex-end;\n gap: var(--cfi-spacing-sm, 8px);\n padding: var(--cfi-spacing-md, 14px);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi-icon-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: var(--cfi-color-gray-500, #6b7280);\n border-radius: 4px;\n display: inline-flex;\n}\n.cfi-vi .cfi-vi-spinner {\n display: inline-block;\n border: 2px solid var(--cfi-color-gray-300, #d1d5db);\n border-top-color: var(--cfi-color-primary-600, #2563eb);\n border-radius: 50%;\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n.cfi-vi .cfi-vi-list {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 10px);\n}\n.cfi-vi .cfi-vi-list-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n}\n.cfi-vi .cfi-vi-h1 {\n font-size: var(--cfi-font-size-lg, 18px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-active-line {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--cfi-font-size-sm, 13px);\n color: var(--cfi-color-gray-600, #4b5563);\n margin-top: 2px;\n}\n.cfi-vi .cfi-vi-active-name {\n font-weight: 600;\n color: #15803d;\n}\n.cfi-vi .cfi-vi-active-extras {\n margin-top: var(--cfi-spacing-md, 16px);\n padding-top: var(--cfi-spacing-md, 16px);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 16px);\n}\n.cfi-vi-mapper {\n display: grid;\n grid-template-columns: 1fr;\n gap: var(--cfi-spacing-lg, 24px);\n align-items: start;\n}\n@media (min-width: 1024px) {\n .cfi-vi-mapper {\n grid-template-columns: 1fr 1fr;\n }\n}\n.cfi-vi-mapper .cfi-vi-mapper-col {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 24px);\n min-width: 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-section {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi-mapper .cfi-vi-mapper-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-h3 {\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 700;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--cfi-color-gray-500, #6b7280);\n margin: 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-note {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi-mapper .cfi-vi-mapper-box {\n border: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n border-radius: var(--cfi-radius-lg, 8px);\n background: #fff;\n padding: var(--cfi-spacing-md, 14px);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-err {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-error, #b91c1c);\n margin: 2px 0 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-save {\n display: flex;\n align-items: center;\n gap: 12px;\n padding-top: 4px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-dirty {\n font-size: var(--cfi-font-size-xs, 11px);\n color: #b45309;\n}\n.cfi-vi-mapper .cfi-vi-hier-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-hier-elbow {\n width: 18px;\n align-self: stretch;\n border-left: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n height: 18px;\n margin-bottom: 9px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-hier-dot {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: 2px solid var(--cfi-color-gray-300, #d1d5db);\n background: #fff;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-hier-dot--filled {\n border-color: var(--cfi-color-primary-600, #6366f1);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-hier-name {\n font-size: var(--cfi-font-size-xs, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-600, #4b5563);\n width: 96px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-leaf {\n font-size: 10px;\n font-weight: 600;\n color: #b45309;\n background: #fffbeb;\n border: 1px solid #fde68a;\n padding: 1px 6px;\n border-radius: 999px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-dropzone {\n flex: 1;\n min-height: 36px;\n border-radius: var(--cfi-radius-md, 6px);\n border: 2px solid;\n display: flex;\n align-items: center;\n padding: 0 10px;\n min-width: 0;\n transition: all 0.12s;\n}\n.cfi-vi-mapper .cfi-vi-dropzone--active {\n border-color: var(--cfi-color-primary-600, #6366f1);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-dropzone--filled {\n border-style: solid;\n border-color: var(--cfi-color-gray-200, #e5e7eb);\n background: #fff;\n}\n.cfi-vi-mapper .cfi-vi-dropzone--empty {\n border-style: dashed;\n border-color: var(--cfi-color-gray-200, #e5e7eb);\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-vi-mapper .cfi-vi-dropzone--covered {\n border-style: solid;\n border-color: #a7f3d0;\n background: #ecfdf5;\n}\n.cfi-vi-mapper .cfi-vi-dropzone-ph {\n font-size: var(--cfi-font-size-xs, 12px);\n color: var(--cfi-color-gray-400, #9ca3af);\n user-select: none;\n}\n.cfi-vi-mapper .cfi-vi-base-hint {\n font-size: 10px;\n font-family: ui-monospace, monospace;\n color: #1d4ed8;\n background: #eff6ff;\n border: 1px solid #bfdbfe;\n padding: 1px 6px;\n border-radius: 4px;\n flex-shrink: 0;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-auto-row {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-auto-label {\n width: 160px;\n flex-shrink: 0;\n padding-top: 6px;\n}\n.cfi-vi-mapper .cfi-vi-auto-label-text {\n font-size: var(--cfi-font-size-xs, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi-mapper .cfi-vi-auto-cover {\n font-size: 10px;\n margin: 2px 0 0;\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi-mapper .cfi-vi-auto-cover--on {\n color: #047857;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n color: #047857;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto-label {\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto-tag {\n font-size: 10px;\n font-style: italic;\n color: #059669;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-auto-transform {\n width: 224px;\n flex-shrink: 0;\n padding-top: 6px;\n font-size: 11px;\n color: var(--cfi-color-gray-500, #6b7280);\n line-height: 1.3;\n}\n.cfi-vi-mapper .cfi-vi-auto-transform-label {\n font-weight: 600;\n}\n.cfi-vi-mapper .cfi-vi-pool-col {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n@media (min-width: 1024px) {\n .cfi-vi-mapper .cfi-vi-pool-col {\n position: sticky;\n top: 16px;\n align-self: start;\n }\n}\n.cfi-vi-mapper .cfi-vi-search {\n position: relative;\n}\n.cfi-vi-mapper .cfi-vi-search .cfi-vi-input {\n padding-left: 28px;\n}\n.cfi-vi-mapper .cfi-vi-search-icon {\n position: absolute;\n left: 8px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--cfi-color-gray-400, #9ca3af);\n pointer-events: none;\n}\n.cfi-vi-mapper .cfi-vi-pool {\n border: 2px dashed var(--cfi-color-gray-200, #e5e7eb);\n background: var(--cfi-color-gray-50, #f9fafb);\n border-radius: var(--cfi-radius-lg, 8px);\n padding: 12px;\n min-height: 200px;\n max-height: 600px;\n overflow-y: auto;\n}\n.cfi-vi-mapper .cfi-vi-pool--active {\n border-color: var(--cfi-color-primary-600, #818cf8);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-pool-empty {\n font-size: var(--cfi-font-size-xs, 12px);\n color: var(--cfi-color-gray-400, #9ca3af);\n font-style: italic;\n}\n.cfi-vi-mapper .cfi-vi-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n.cfi-vi-mapper .cfi-vi-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n cursor: grab;\n user-select: none;\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi-mapper .cfi-vi-chip:hover {\n border-color: var(--cfi-color-primary-600, #818cf8);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-chip:active {\n cursor: grabbing;\n}\n.cfi-vi-mapper .cfi-vi-chip--assigned {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n cursor: grab;\n}\n.cfi-vi-mapper .cfi-vi-chip--assigned:active {\n cursor: grabbing;\n}\n.cfi-vi-mapper .cfi-vi-chip-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--cfi-color-gray-400, #9ca3af);\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-chip-dot--on {\n background: var(--cfi-color-primary-600, #6366f1);\n}\n.cfi-vi-mapper .cfi-vi-chip-label {\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n color: #3730a3;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-chip-x {\n margin-left: 4px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--cfi-color-gray-400, #9ca3af);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-chip-x:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n.cfi-vi .cfi-vi-spin {\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n.cfi-vi .cfi-vi-detail {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 20px);\n}\n.cfi-vi .cfi-vi-h2 {\n font-size: var(--cfi-font-size-base, 15px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-panel {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n padding: var(--cfi-spacing-md, 16px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-grid2 {\n display: grid;\n grid-template-columns: 1fr;\n gap: var(--cfi-spacing-md, 16px);\n}\n@media (min-width: 768px) {\n .cfi-vi .cfi-vi-grid2 {\n grid-template-columns: 1fr 1fr;\n }\n}\n.cfi-vi .cfi-vi-lock {\n display: flex;\n align-items: center;\n gap: 8px;\n border: 1px solid #fde68a;\n background: #fffbeb;\n color: #92400e;\n border-radius: var(--cfi-radius-md, 6px);\n padding: 8px 12px;\n font-size: var(--cfi-font-size-xs, 12px);\n}\n.cfi-vi .cfi-vi-table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-table th,\n.cfi-vi .cfi-vi-table td {\n text-align: left;\n padding: 6px 10px;\n border-bottom: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n vertical-align: middle;\n}\n.cfi-vi .cfi-vi-table th {\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 600;\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi .cfi-vi-table tr:last-child td {\n border-bottom: none;\n}\n.cfi-vi .cfi-vi-danger {\n border: 1px solid rgba(220, 38, 38, 0.4);\n background: rgba(220, 38, 38, 0.05);\n border-radius: var(--cfi-radius-md, 6px);\n padding: var(--cfi-spacing-md, 16px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-aliases {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-alias-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.cfi-vi .cfi-vi-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi .cfi-vi-tab {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n margin-bottom: -1px;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n font: inherit;\n font-size: var(--cfi-font-size-sm, 13px);\n cursor: pointer;\n color: var(--cfi-color-gray-600, #4b5563);\n}\n.cfi-vi .cfi-vi-tab:hover {\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-vi .cfi-vi-tab--active {\n color: var(--cfi-color-primary-600, #2563eb);\n border-bottom-color: var(--cfi-color-primary-600, #2563eb);\n font-weight: 600;\n}\n.cfi-vi .cfi-vi-tab--danger:hover {\n color: #dc2626;\n}\n.cfi-vi .cfi-vi-tab--danger.cfi-vi-tab--active {\n color: #dc2626;\n border-bottom-color: #dc2626;\n}\n.cfi-vi .cfi-vi-tabpanel {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 20px);\n}\n.cfi-vi .cfi-vi-tag--warn {\n background: #fffbeb;\n color: #92400e;\n border: 1px solid #fde68a;\n}\n.cfi-vi .cfi-vi-tag--danger {\n background: #fef2f2;\n color: #b91c1c;\n border: 1px solid #fecaca;\n}\n.cfi-vi .cfi-vi-select {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n}\n.cfi-vi .cfi-vi-select:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: -1px;\n}\n.cfi-vi .cfi-vi-file-input {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n}\n.cfi-vi .cfi-vi-filepick {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n min-width: 0;\n}\n.cfi-vi .cfi-vi-filepick-name {\n font-size: var(--cfi-font-size-sm, 13px);\n color: var(--cfi-color-gray-600, #4b5563);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n.cfi-vi .cfi-vi-alert {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n margin: 8px 0;\n}\n.cfi-vi .cfi-vi-alert--error {\n background: #fef2f2;\n color: #b91c1c;\n}\n.cfi-vi .cfi-vi-alert--warn {\n background: #fffbeb;\n color: #92400e;\n}\n.cfi-vi .cfi-vi-alert ul.cfi-vi-blockers {\n margin: 0;\n padding-left: 18px;\n}\n.cfi-vi .cfi-vi-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--cfi-color-gray-500, #6b7280);\n padding: 12px 0;\n}\n.cfi-vi .cfi-vi-files-head {\n align-items: center;\n margin-bottom: 12px;\n}\n.cfi-vi .cfi-vi-files-title {\n font-size: var(--cfi-font-size-lg, 18px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-files-filters {\n gap: 8px;\n align-items: center;\n margin-bottom: 12px;\n}\n.cfi-vi .cfi-vi-files-table th,\n.cfi-vi .cfi-vi-files-table td {\n white-space: nowrap;\n}\n.cfi-vi .cfi-vi-files-file {\n font-family: var(--cfi-font-mono, ui-monospace, monospace);\n max-width: 220px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.cfi-vi .cfi-vi-files-actions {\n display: flex;\n gap: 4px;\n justify-content: flex-end;\n}\n.cfi-vi .cfi-vi-files-detail td {\n background: var(--cfi-color-gray-50, #f9fafb);\n white-space: normal;\n}\n.cfi-vi .cfi-vi-files-pager {\n align-items: center;\n gap: 10px;\n margin-top: 12px;\n}\n.cfi-vi .cfi-vi-ta-right {\n text-align: right;\n}\n.cfi-vi .cfi-vi-danger-text {\n color: #b91c1c;\n}\n");
28
+ styleInject(".cfi-volume-import {\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-base, 14px);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n max-width: 640px;\n}\n.cfi-volume-import .cfi-vi-field {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-xs, 4px);\n}\n.cfi-volume-import .cfi-vi-row {\n display: flex;\n gap: var(--cfi-spacing-md, 12px);\n flex-wrap: wrap;\n}\n.cfi-volume-import .cfi-vi-row .cfi-vi-field {\n flex: 1 1 8rem;\n}\n.cfi-volume-import .cfi-vi-label {\n font-size: var(--cfi-font-size-sm, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-volume-import .cfi-vi-select,\n.cfi-volume-import .cfi-vi-file {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n color: inherit;\n}\n.cfi-volume-import .cfi-vi-select:focus,\n.cfi-volume-import .cfi-vi-file:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: 1px;\n}\n.cfi-volume-import .cfi-vi-button {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 6px);\n align-self: flex-start;\n padding: 8px 14px;\n border: none;\n border-radius: var(--cfi-radius-md, 6px);\n background: var(--cfi-color-primary-600, #2563eb);\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n.cfi-volume-import .cfi-vi-button:hover:not(:disabled) {\n background: var(--cfi-color-primary-700, #1d4ed8);\n}\n.cfi-volume-import .cfi-vi-button:disabled {\n background: var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-500, #6b7280);\n cursor: not-allowed;\n}\n.cfi-volume-import .cfi-vi-loading,\n.cfi-volume-import .cfi-vi-alert {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 6px);\n padding: 8px 10px;\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-alert--error {\n background: var(--cfi-color-gray-100, #fef2f2);\n color: var(--cfi-color-error, #b91c1c);\n}\n.cfi-volume-import .cfi-vi-alert--warn {\n background: #fffbeb;\n color: #92400e;\n align-items: flex-start;\n}\n.cfi-volume-import .cfi-vi-blockers {\n margin: 0;\n padding-left: 1.1rem;\n}\n.cfi-volume-import .cfi-vi-status {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n padding: var(--cfi-spacing-md, 12px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-volume-import .cfi-vi-status-head {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-volume-import .cfi-vi-filename {\n font-weight: 600;\n}\n.cfi-volume-import .cfi-vi-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n border-radius: 999px;\n font-size: var(--cfi-font-size-xs, 11px);\n text-transform: capitalize;\n background: var(--cfi-color-gray-100, #f3f4f6);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-volume-import .cfi-vi-badge--done {\n background: #dcfce7;\n color: #166534;\n}\n.cfi-volume-import .cfi-vi-badge--done_with_errors {\n background: #fef9c3;\n color: #854d0e;\n}\n.cfi-volume-import .cfi-vi-badge--failed {\n background: #fee2e2;\n color: #991b1b;\n}\n.cfi-volume-import .cfi-vi-badge--processing,\n.cfi-volume-import .cfi-vi-badge--pending,\n.cfi-volume-import .cfi-vi-badge--awaiting_calendar {\n background: #dbeafe;\n color: #1e40af;\n}\n.cfi-volume-import .cfi-vi-link {\n background: none;\n border: none;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--cfi-color-primary-600, #2563eb);\n font: inherit;\n cursor: pointer;\n}\n.cfi-volume-import .cfi-vi-stats {\n display: flex;\n gap: var(--cfi-spacing-md, 12px);\n color: var(--cfi-color-gray-600, #4b5563);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-errors {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-volume-import .cfi-vi-errors th,\n.cfi-volume-import .cfi-vi-errors td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n vertical-align: top;\n}\n.cfi-volume-import .cfi-vi-spin {\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n@keyframes cfi-vi-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.cfi-vi {\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-base, 14px);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n}\n.cfi-vi *,\n.cfi-vi *::before,\n.cfi-vi *::after {\n box-sizing: border-box;\n}\n.cfi-vi .cfi-vi-row {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi .cfi-vi-row--between {\n justify-content: space-between;\n}\n.cfi-vi .cfi-vi-spacer {\n flex: 1;\n}\n.cfi-vi .cfi-vi-muted {\n color: var(--cfi-color-gray-600, #4b5563);\n}\n.cfi-vi .cfi-vi-error {\n color: var(--cfi-color-error, #b91c1c);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-mono {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n font-size: var(--cfi-font-size-xs, 11px);\n}\n.cfi-vi .cfi-vi-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n border-radius: var(--cfi-radius-md, 6px);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n white-space: nowrap;\n}\n.cfi-vi .cfi-vi-btn--sm {\n padding: 4px 10px;\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-btn--md {\n padding: 8px 14px;\n}\n.cfi-vi .cfi-vi-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-vi .cfi-vi-btn--primary {\n background: var(--cfi-color-primary-600, #2563eb);\n color: #fff;\n}\n.cfi-vi .cfi-vi-btn--primary:hover:not(:disabled) {\n background: var(--cfi-color-primary-700, #1d4ed8);\n}\n.cfi-vi .cfi-vi-btn--outline {\n background: #fff;\n border-color: var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-vi .cfi-vi-btn--outline:hover:not(:disabled) {\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-vi .cfi-vi-btn--ghost {\n background: transparent;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-btn--ghost:hover:not(:disabled) {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-vi .cfi-vi-btn--destructive {\n background: var(--cfi-color-error, #dc2626);\n color: #fff;\n}\n.cfi-vi .cfi-vi-btn--destructive:hover:not(:disabled) {\n filter: brightness(0.92);\n}\n.cfi-vi .cfi-vi-icon-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: var(--cfi-color-gray-500, #6b7280);\n border-radius: var(--cfi-radius-sm, 4px);\n display: inline-flex;\n}\n.cfi-vi .cfi-vi-icon-btn:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-vi .cfi-vi-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 600;\n}\n.cfi-vi .cfi-vi-tag--default {\n background: var(--cfi-color-gray-100, #f3f4f6);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--outline {\n background: transparent;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--secondary {\n background: var(--cfi-color-gray-200, #e5e7eb);\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-tag--success {\n background: #16a34a;\n color: #fff;\n}\n.cfi-vi .cfi-vi-tag--purple {\n background: var(--cfi-color-violet-600, #7c3aed);\n color: #fff;\n}\n.cfi-vi .cfi-vi-card {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-lg, 8px);\n background: #fff;\n}\n.cfi-vi .cfi-vi-card--active {\n border-color: #86efac;\n background: #f0fdf4;\n}\n.cfi-vi .cfi-vi-card--hover:hover {\n border-color: var(--cfi-color-primary-600, #2563eb);\n}\n.cfi-vi .cfi-vi-card-head {\n padding: var(--cfi-spacing-md, 12px);\n padding-bottom: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi .cfi-vi-card-body {\n padding: 0 var(--cfi-spacing-md, 12px) var(--cfi-spacing-md, 12px);\n}\n.cfi-vi .cfi-vi-card-title {\n font-size: var(--cfi-font-size-base, 15px);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.cfi-vi .cfi-vi-link {\n background: none;\n border: none;\n padding: 0;\n color: inherit;\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n.cfi-vi .cfi-vi-link:hover {\n text-decoration: underline;\n}\n.cfi-vi .cfi-vi-field {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-xs, 4px);\n}\n.cfi-vi .cfi-vi-label {\n font-size: var(--cfi-font-size-sm, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi .cfi-vi-hint {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-gray-500, #6b7280);\n margin: 2px 0 0;\n}\n.cfi-vi .cfi-vi-input,\n.cfi-vi select.cfi-vi-input {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n color: inherit;\n width: 100%;\n}\n.cfi-vi .cfi-vi-input:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: 1px;\n}\n.cfi-vi-modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n padding: 16px;\n}\n.cfi-vi-modal {\n background: #fff;\n border-radius: var(--cfi-radius-lg, 8px);\n width: 100%;\n max-width: 32rem;\n max-height: 90vh;\n overflow: auto;\n box-shadow: var(--cfi-shadow-lg, 0 10px 30px rgba(0,0,0,0.2));\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n}\n.cfi-vi-modal-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--cfi-spacing-md, 14px);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi-modal-title {\n font-size: var(--cfi-font-size-lg, 16px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi-modal-body {\n padding: var(--cfi-spacing-md, 14px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 12px);\n}\n.cfi-vi-modal-foot {\n display: flex;\n justify-content: flex-end;\n gap: var(--cfi-spacing-sm, 8px);\n padding: var(--cfi-spacing-md, 14px);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi-icon-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: var(--cfi-color-gray-500, #6b7280);\n border-radius: 4px;\n display: inline-flex;\n}\n.cfi-vi .cfi-vi-spinner {\n display: inline-block;\n border: 2px solid var(--cfi-color-gray-300, #d1d5db);\n border-top-color: var(--cfi-color-primary-600, #2563eb);\n border-radius: 50%;\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n.cfi-vi .cfi-vi-list {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 10px);\n}\n.cfi-vi .cfi-vi-list-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n}\n.cfi-vi .cfi-vi-h1 {\n font-size: var(--cfi-font-size-lg, 18px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-active-line {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--cfi-font-size-sm, 13px);\n color: var(--cfi-color-gray-600, #4b5563);\n margin-top: 2px;\n}\n.cfi-vi .cfi-vi-active-name {\n font-weight: 600;\n color: #15803d;\n}\n.cfi-vi .cfi-vi-active-extras {\n margin-top: var(--cfi-spacing-md, 16px);\n padding-top: var(--cfi-spacing-md, 16px);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 16px);\n}\n.cfi-vi-mapper {\n display: grid;\n grid-template-columns: 1fr;\n gap: var(--cfi-spacing-lg, 24px);\n align-items: start;\n}\n@media (min-width: 1024px) {\n .cfi-vi-mapper {\n grid-template-columns: 1fr 1fr;\n }\n}\n.cfi-vi-mapper .cfi-vi-mapper-col {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 24px);\n min-width: 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-section {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n.cfi-vi-mapper .cfi-vi-mapper-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-h3 {\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 700;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--cfi-color-gray-500, #6b7280);\n margin: 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-note {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi-mapper .cfi-vi-mapper-box {\n border: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n border-radius: var(--cfi-radius-lg, 8px);\n background: #fff;\n padding: var(--cfi-spacing-md, 14px);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-err {\n font-size: var(--cfi-font-size-xs, 11px);\n color: var(--cfi-color-error, #b91c1c);\n margin: 2px 0 0;\n}\n.cfi-vi-mapper .cfi-vi-mapper-save {\n display: flex;\n align-items: center;\n gap: 12px;\n padding-top: 4px;\n}\n.cfi-vi-mapper .cfi-vi-mapper-dirty {\n font-size: var(--cfi-font-size-xs, 11px);\n color: #b45309;\n}\n.cfi-vi-mapper .cfi-vi-hier-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-hier-elbow {\n width: 18px;\n align-self: stretch;\n border-left: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n height: 18px;\n margin-bottom: 9px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-hier-dot {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: 2px solid var(--cfi-color-gray-300, #d1d5db);\n background: #fff;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-hier-dot--filled {\n border-color: var(--cfi-color-primary-600, #6366f1);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-hier-name {\n font-size: var(--cfi-font-size-xs, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-600, #4b5563);\n width: 96px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-leaf {\n font-size: 10px;\n font-weight: 600;\n color: #b45309;\n background: #fffbeb;\n border: 1px solid #fde68a;\n padding: 1px 6px;\n border-radius: 999px;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-dropzone {\n flex: 1;\n min-height: 36px;\n border-radius: var(--cfi-radius-md, 6px);\n border: 2px solid;\n display: flex;\n align-items: center;\n padding: 0 10px;\n min-width: 0;\n transition: all 0.12s;\n}\n.cfi-vi-mapper .cfi-vi-dropzone--active {\n border-color: var(--cfi-color-primary-600, #6366f1);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-dropzone--filled {\n border-style: solid;\n border-color: var(--cfi-color-gray-200, #e5e7eb);\n background: #fff;\n}\n.cfi-vi-mapper .cfi-vi-dropzone--empty {\n border-style: dashed;\n border-color: var(--cfi-color-gray-200, #e5e7eb);\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-vi-mapper .cfi-vi-dropzone--covered {\n border-style: solid;\n border-color: #a7f3d0;\n background: #ecfdf5;\n}\n.cfi-vi-mapper .cfi-vi-dropzone-ph {\n font-size: var(--cfi-font-size-xs, 12px);\n color: var(--cfi-color-gray-400, #9ca3af);\n user-select: none;\n}\n.cfi-vi-mapper .cfi-vi-base-hint {\n font-size: 10px;\n font-family: ui-monospace, monospace;\n color: #1d4ed8;\n background: #eff6ff;\n border: 1px solid #bfdbfe;\n padding: 1px 6px;\n border-radius: 4px;\n flex-shrink: 0;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-auto-row {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.cfi-vi-mapper .cfi-vi-auto-label {\n width: 160px;\n flex-shrink: 0;\n padding-top: 6px;\n}\n.cfi-vi-mapper .cfi-vi-auto-label-text {\n font-size: var(--cfi-font-size-xs, 12px);\n font-weight: 600;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi-mapper .cfi-vi-auto-cover {\n font-size: 10px;\n margin: 2px 0 0;\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi-mapper .cfi-vi-auto-cover--on {\n color: #047857;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n color: #047857;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto-label {\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-auto-auto-tag {\n font-size: 10px;\n font-style: italic;\n color: #059669;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-auto-transform {\n width: 224px;\n flex-shrink: 0;\n padding-top: 6px;\n font-size: 11px;\n color: var(--cfi-color-gray-500, #6b7280);\n line-height: 1.3;\n}\n.cfi-vi-mapper .cfi-vi-auto-transform-label {\n font-weight: 600;\n}\n.cfi-vi-mapper .cfi-vi-pool-col {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 8px);\n}\n@media (min-width: 1024px) {\n .cfi-vi-mapper .cfi-vi-pool-col {\n position: sticky;\n top: 16px;\n align-self: start;\n }\n}\n.cfi-vi-mapper .cfi-vi-search {\n position: relative;\n}\n.cfi-vi-mapper .cfi-vi-search .cfi-vi-input {\n padding-left: 28px;\n}\n.cfi-vi-mapper .cfi-vi-search-icon {\n position: absolute;\n left: 8px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--cfi-color-gray-400, #9ca3af);\n pointer-events: none;\n}\n.cfi-vi-mapper .cfi-vi-pool {\n border: 2px dashed var(--cfi-color-gray-200, #e5e7eb);\n background: var(--cfi-color-gray-50, #f9fafb);\n border-radius: var(--cfi-radius-lg, 8px);\n padding: 12px;\n min-height: 200px;\n max-height: 600px;\n overflow-y: auto;\n}\n.cfi-vi-mapper .cfi-vi-pool--active {\n border-color: var(--cfi-color-primary-600, #818cf8);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-pool-empty {\n font-size: var(--cfi-font-size-xs, 12px);\n color: var(--cfi-color-gray-400, #9ca3af);\n font-style: italic;\n}\n.cfi-vi-mapper .cfi-vi-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n.cfi-vi-mapper .cfi-vi-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n cursor: grab;\n user-select: none;\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n color: var(--cfi-color-gray-700, #374151);\n}\n.cfi-vi-mapper .cfi-vi-chip:hover {\n border-color: var(--cfi-color-primary-600, #818cf8);\n background: var(--cfi-color-primary-50, #eef2ff);\n}\n.cfi-vi-mapper .cfi-vi-chip:active {\n cursor: grabbing;\n}\n.cfi-vi-mapper .cfi-vi-chip--assigned {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n cursor: grab;\n}\n.cfi-vi-mapper .cfi-vi-chip--assigned:active {\n cursor: grabbing;\n}\n.cfi-vi-mapper .cfi-vi-chip-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--cfi-color-gray-400, #9ca3af);\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-chip-dot--on {\n background: var(--cfi-color-primary-600, #6366f1);\n}\n.cfi-vi-mapper .cfi-vi-chip-label {\n font-size: var(--cfi-font-size-xs, 12px);\n font-family: ui-monospace, monospace;\n color: #3730a3;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-vi-mapper .cfi-vi-chip-x {\n margin-left: 4px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--cfi-color-gray-400, #9ca3af);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.cfi-vi-mapper .cfi-vi-chip-x:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n.cfi-vi .cfi-vi-spin {\n animation: cfi-vi-spin 0.8s linear infinite;\n}\n.cfi-vi .cfi-vi-detail {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 20px);\n}\n.cfi-vi .cfi-vi-h2 {\n font-size: var(--cfi-font-size-base, 15px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-panel {\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n padding: var(--cfi-spacing-md, 16px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-grid2 {\n display: grid;\n grid-template-columns: 1fr;\n gap: var(--cfi-spacing-md, 16px);\n}\n@media (min-width: 768px) {\n .cfi-vi .cfi-vi-grid2 {\n grid-template-columns: 1fr 1fr;\n }\n}\n.cfi-vi .cfi-vi-lock {\n display: flex;\n align-items: center;\n gap: 8px;\n border: 1px solid #fde68a;\n background: #fffbeb;\n color: #92400e;\n border-radius: var(--cfi-radius-md, 6px);\n padding: 8px 12px;\n font-size: var(--cfi-font-size-xs, 12px);\n}\n.cfi-vi .cfi-vi-table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n}\n.cfi-vi .cfi-vi-table th,\n.cfi-vi .cfi-vi-table td {\n text-align: left;\n padding: 6px 10px;\n border-bottom: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n vertical-align: middle;\n}\n.cfi-vi .cfi-vi-table th {\n font-size: var(--cfi-font-size-xs, 11px);\n font-weight: 600;\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-vi .cfi-vi-table tr:last-child td {\n border-bottom: none;\n}\n.cfi-vi .cfi-vi-danger {\n border: 1px solid rgba(220, 38, 38, 0.4);\n background: rgba(220, 38, 38, 0.05);\n border-radius: var(--cfi-radius-md, 6px);\n padding: var(--cfi-spacing-md, 16px);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-aliases {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 12px);\n}\n.cfi-vi .cfi-vi-alias-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.cfi-vi .cfi-vi-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-vi .cfi-vi-tab {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n margin-bottom: -1px;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n font: inherit;\n font-size: var(--cfi-font-size-sm, 13px);\n cursor: pointer;\n color: var(--cfi-color-gray-600, #4b5563);\n}\n.cfi-vi .cfi-vi-tab:hover {\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-vi .cfi-vi-tab--active {\n color: var(--cfi-color-primary-600, #2563eb);\n border-bottom-color: var(--cfi-color-primary-600, #2563eb);\n font-weight: 600;\n}\n.cfi-vi .cfi-vi-tab--danger:hover {\n color: #dc2626;\n}\n.cfi-vi .cfi-vi-tab--danger.cfi-vi-tab--active {\n color: #dc2626;\n border-bottom-color: #dc2626;\n}\n.cfi-vi .cfi-vi-tabpanel {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-lg, 20px);\n}\n.cfi-vi .cfi-vi-tag--warn {\n background: #fffbeb;\n color: #92400e;\n border: 1px solid #fde68a;\n}\n.cfi-vi .cfi-vi-tag--danger {\n background: #fef2f2;\n color: #b91c1c;\n border: 1px solid #fecaca;\n}\n.cfi-vi .cfi-vi-select {\n padding: 6px 8px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n background: #fff;\n font: inherit;\n}\n.cfi-vi .cfi-vi-select:focus {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: -1px;\n}\n.cfi-vi .cfi-vi-file-input {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n}\n.cfi-vi .cfi-vi-filepick {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 8px);\n min-width: 0;\n}\n.cfi-vi .cfi-vi-filepick-name {\n font-size: var(--cfi-font-size-sm, 13px);\n color: var(--cfi-color-gray-600, #4b5563);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n.cfi-vi .cfi-vi-alert {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--cfi-radius-md, 6px);\n font-size: var(--cfi-font-size-sm, 13px);\n margin: 8px 0;\n}\n.cfi-vi .cfi-vi-alert--error {\n background: #fef2f2;\n color: #b91c1c;\n}\n.cfi-vi .cfi-vi-alert--warn {\n background: #fffbeb;\n color: #92400e;\n}\n.cfi-vi .cfi-vi-alert ul.cfi-vi-blockers {\n margin: 0;\n padding-left: 18px;\n}\n.cfi-vi .cfi-vi-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--cfi-color-gray-500, #6b7280);\n padding: 12px 0;\n}\n.cfi-vi .cfi-vi-files-head {\n align-items: center;\n margin-bottom: 12px;\n}\n.cfi-vi .cfi-vi-files-title {\n font-size: var(--cfi-font-size-lg, 18px);\n font-weight: 600;\n margin: 0;\n}\n.cfi-vi .cfi-vi-files-filters {\n gap: 8px;\n align-items: center;\n margin-bottom: 12px;\n}\n.cfi-vi .cfi-vi-files-table th,\n.cfi-vi .cfi-vi-files-table td {\n white-space: nowrap;\n}\n.cfi-vi .cfi-vi-files-file {\n font-family: var(--cfi-font-mono, ui-monospace, monospace);\n max-width: 220px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.cfi-vi .cfi-vi-files-actions {\n display: flex;\n gap: 4px;\n justify-content: flex-end;\n}\n.cfi-vi .cfi-vi-files-detail td {\n background: var(--cfi-color-gray-50, #f9fafb);\n white-space: normal;\n}\n.cfi-vi .cfi-vi-files-pager {\n align-items: center;\n gap: 10px;\n margin-top: 12px;\n}\n.cfi-vi .cfi-vi-ta-right {\n text-align: right;\n}\n.cfi-vi .cfi-vi-danger-text {\n color: #b91c1c;\n}\n.cfi-vi .cfi-vi-swatch {\n flex-shrink: 0;\n vertical-align: middle;\n}\n.cfi-vi .cfi-vi-tag--role {\n background: transparent;\n border: 1px solid currentColor;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n}\n.cfi-vi .cfi-vi-seg {\n display: inline-flex;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 6px);\n overflow: hidden;\n background: #fff;\n}\n.cfi-vi .cfi-vi-seg-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n font: inherit;\n font-size: 13px;\n font-weight: 500;\n background: #fff;\n color: var(--cfi-color-gray-600, #4b5563);\n border: 0;\n border-left: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n cursor: pointer;\n transition: background-color 120ms, color 120ms;\n}\n.cfi-vi .cfi-vi-seg-btn:first-child {\n border-left: 0;\n}\n.cfi-vi .cfi-vi-seg-btn:hover:not(:disabled):not(.cfi-vi-seg-btn--on) {\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-vi .cfi-vi-seg-btn:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n.cfi-vi .cfi-vi-seg-btn:focus-visible {\n outline: 2px solid var(--cfi-color-primary-600, #2563eb);\n outline-offset: -2px;\n}\n.cfi-vi .cfi-vi-seg-btn--on .cfi-vi-swatch circle {\n stroke: currentColor;\n}\n");
29
29
 
30
30
  // src/VolumeImport.tsx
31
31
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -290,6 +290,55 @@ function Btn(props) {
290
290
  function Badge(props) {
291
291
  return /* @__PURE__ */ jsx2("span", { className: `cfi-vi-tag cfi-vi-tag--${props.variant ?? "default"}`, title: props.title, children: props.children });
292
292
  }
293
+ function RoleSwatch(props) {
294
+ return /* @__PURE__ */ jsxs2(
295
+ "svg",
296
+ {
297
+ className: "cfi-vi-swatch",
298
+ width: "22",
299
+ height: "10",
300
+ viewBox: "0 0 22 10",
301
+ role: "img",
302
+ "aria-label": props.title,
303
+ children: [
304
+ props.title ? /* @__PURE__ */ jsx2("title", { children: props.title }) : null,
305
+ /* @__PURE__ */ jsx2(
306
+ "line",
307
+ {
308
+ x1: "0",
309
+ y1: "5",
310
+ x2: "22",
311
+ y2: "5",
312
+ stroke: props.color,
313
+ strokeWidth: "2.5",
314
+ strokeDasharray: props.dash,
315
+ strokeLinecap: "round"
316
+ }
317
+ ),
318
+ /* @__PURE__ */ jsx2("circle", { cx: "11", cy: "5", r: "3.5", fill: props.color, stroke: "#fff", strokeWidth: "1.5" })
319
+ ]
320
+ }
321
+ );
322
+ }
323
+ function Segmented(props) {
324
+ return /* @__PURE__ */ jsx2("div", { className: "cfi-vi-seg", role: "group", "aria-label": props.ariaLabel, children: props.options.map((o) => {
325
+ const on = o.value === props.value;
326
+ return /* @__PURE__ */ jsx2(
327
+ "button",
328
+ {
329
+ type: "button",
330
+ "aria-pressed": on,
331
+ title: o.title,
332
+ disabled: props.disabled,
333
+ onClick: () => props.onChange(o.value),
334
+ className: `cfi-vi-seg-btn${on ? " cfi-vi-seg-btn--on" : ""}`,
335
+ style: on && o.activeColor ? { background: o.activeColor, borderColor: o.activeColor, color: "#fff" } : void 0,
336
+ children: o.label
337
+ },
338
+ o.value
339
+ );
340
+ }) });
341
+ }
293
342
  function Card(props) {
294
343
  return /* @__PURE__ */ jsx2("div", { className: props.className ? `cfi-vi-card ${props.className}` : "cfi-vi-card", children: props.children });
295
344
  }
@@ -784,8 +833,38 @@ function VolumeFiles({ transport, className }) {
784
833
  // src/VolumeSourcesList.tsx
785
834
  import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
786
835
  import { CheckCircle2, Sparkles } from "lucide-react";
836
+
837
+ // src/roleStyle.ts
838
+ var ROLE_STYLE = {
839
+ base: {
840
+ color: "#f59e0b",
841
+ label: "Base",
842
+ blurb: "The tenant's own volume. The active base source is what prediction runs on."
843
+ },
844
+ overlay: {
845
+ color: "#a855f7",
846
+ label: "Overlay",
847
+ blurb: "Customer-stated demand. Active whenever data is uploaded \u2014 no Set Active step."
848
+ },
849
+ reference: {
850
+ color: "#06b6d4",
851
+ dash: "6 3",
852
+ blurb: "Another vendor's curve, drawn beside the active base rather than summed into it. Never drives prediction.",
853
+ label: "Reference"
854
+ }
855
+ };
856
+ var ROLE_ORDER = ["base", "overlay", "reference"];
857
+
858
+ // src/VolumeSourcesList.tsx
787
859
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
788
860
  var EMPTY_FORM = { code: "", name: "", description: "", headerRowIndex: 0, volumeHeaderFormat: "MMM yyyy" };
861
+ function RoleBadge({ kind }) {
862
+ const style = ROLE_STYLE[kind];
863
+ return /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-tag cfi-vi-tag--role", style: { color: style.color }, title: style.blurb, children: [
864
+ /* @__PURE__ */ jsx4(RoleSwatch, { color: style.color, dash: style.dash }),
865
+ style.label
866
+ ] });
867
+ }
789
868
  function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras, readOnly = false, className }) {
790
869
  const [sources, setSources] = useState3([]);
791
870
  const [activeSourceId, setActiveSourceId] = useState3(null);
@@ -901,8 +980,7 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
901
980
  /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-card-title", children: [
902
981
  /* @__PURE__ */ jsx4("button", { type: "button", className: "cfi-vi-link", onClick: () => onOpenSource(src.id), children: src.name }),
903
982
  isActive && /* @__PURE__ */ jsx4(Badge, { variant: "success", children: "Active" }),
904
- src.kind === "overlay" && /* @__PURE__ */ jsx4(Badge, { variant: "purple", title: "Overlay sources are active whenever data is uploaded \u2014 no Set Active step.", children: "Overlay" }),
905
- src.kind === "reference" && /* @__PURE__ */ jsx4(Badge, { variant: "outline", title: "A second vendor's curve, drawn beside the active base rather than summed into it. Never drives prediction and has no Set Active step.", children: "Reference" })
983
+ /* @__PURE__ */ jsx4(RoleBadge, { kind: src.kind })
906
984
  ] }),
907
985
  /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-row", children: [
908
986
  /* @__PURE__ */ jsx4(Badge, { variant: "outline", children: src.code }),
@@ -1980,20 +2058,25 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, readOnl
1980
2058
  ] }),
1981
2059
  /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1982
2060
  /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Role" }),
1983
- /* @__PURE__ */ jsxs8(
1984
- "select",
2061
+ /* @__PURE__ */ jsx8(
2062
+ Segmented,
1985
2063
  {
1986
- className: "cfi-vi-input",
2064
+ ariaLabel: "Source role",
1987
2065
  value: editKind,
1988
2066
  disabled: savingLayout || readOnly,
1989
- onChange: (e) => setEditKind(e.target.value),
1990
- children: [
1991
- /* @__PURE__ */ jsx8("option", { value: "base", children: "base \u2014 the tenant's own volume" }),
1992
- /* @__PURE__ */ jsx8("option", { value: "overlay", children: "overlay \u2014 customer-stated demand" }),
1993
- /* @__PURE__ */ jsx8("option", { value: "reference", children: "reference \u2014 another vendor's curve" })
1994
- ]
2067
+ onChange: setEditKind,
2068
+ options: ROLE_ORDER.map((k) => ({
2069
+ value: k,
2070
+ title: ROLE_STYLE[k].blurb,
2071
+ activeColor: ROLE_STYLE[k].color,
2072
+ label: /* @__PURE__ */ jsxs8(Fragment3, { children: [
2073
+ /* @__PURE__ */ jsx8(RoleSwatch, { color: ROLE_STYLE[k].color, dash: ROLE_STYLE[k].dash }),
2074
+ ROLE_STYLE[k].label
2075
+ ] })
2076
+ }))
1995
2077
  }
1996
- )
2078
+ ),
2079
+ /* @__PURE__ */ jsx8("p", { className: "cfi-vi-hint", children: ROLE_STYLE[editKind].blurb })
1997
2080
  ] })
1998
2081
  ] }),
1999
2082
  hasData && crossesMeasure && /* @__PURE__ */ jsxs8("p", { className: "cfi-vi-hint", style: { color: "#b45309" }, children: [
@@ -2226,6 +2309,10 @@ export {
2226
2309
  AUTOMOTIVE_TRANSFORM_LABELS,
2227
2310
  DEFAULT_LEVEL_NAMES,
2228
2311
  HIERARCHY_LEVEL_COUNT,
2312
+ ROLE_ORDER,
2313
+ ROLE_STYLE,
2314
+ RoleSwatch,
2315
+ Segmented,
2229
2316
  TallLayoutMappings,
2230
2317
  UnifiedSegmentMapper,
2231
2318
  ValueAliasesCard,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@campfire-interactive/volume-intelligence-ui",
3
- "version": "0.11.1",
4
- "description": "Shared Volume Intelligence UI components (volume import) for the Campfire Suite embedded by the VI webapp and by consuming apps (OMSF) so there is one import surface, not two that drift.",
3
+ "version": "0.12.0",
4
+ "description": "Shared Volume Intelligence UI components (volume import) for the Campfire Suite \u2014 embedded by the VI webapp and by consuming apps (OMSF) so there is one import surface, not two that drift.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",