@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 +57 -9
- package/dist/index.js +100 -13
- package/package.json +2 -2
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
|
-
|
|
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__ */
|
|
1984
|
-
|
|
2061
|
+
/* @__PURE__ */ jsx8(
|
|
2062
|
+
Segmented,
|
|
1985
2063
|
{
|
|
1986
|
-
|
|
2064
|
+
ariaLabel: "Source role",
|
|
1987
2065
|
value: editKind,
|
|
1988
2066
|
disabled: savingLayout || readOnly,
|
|
1989
|
-
onChange:
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
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.
|
|
4
|
-
"description": "Shared Volume Intelligence UI components (volume import) for the Campfire Suite
|
|
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",
|