@campfire-interactive/volume-intelligence-ui 0.1.0 → 0.2.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.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");
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-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 {\n font: inherit;\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");
29
29
 
30
30
  // src/VolumeImport.tsx
31
31
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -271,9 +271,9 @@ function UploadStatusPanel(props) {
271
271
  ] });
272
272
  }
273
273
 
274
- // src/VolumeSourcesList.tsx
275
- import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
276
- import { CheckCircle2, Sparkles } from "lucide-react";
274
+ // src/VolumeFiles.tsx
275
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
276
+ import { AlertTriangle as AlertTriangle2, Download, RotateCcw as RotateCcw2, FileUp as FileUp2, ChevronRight, ChevronDown } from "lucide-react";
277
277
 
278
278
  // src/ui.tsx
279
279
  import { X } from "lucide-react";
@@ -310,6 +310,9 @@ function TextInput(props) {
310
310
  const { className, ...rest } = props;
311
311
  return /* @__PURE__ */ jsx2("input", { className: className ? `cfi-vi-input ${className}` : "cfi-vi-input", ...rest });
312
312
  }
313
+ function Spinner(props) {
314
+ return /* @__PURE__ */ jsx2("span", { className: "cfi-vi-spinner", style: { width: props.size ?? 14, height: props.size ?? 14 }, "aria-hidden": true });
315
+ }
313
316
  function Modal(props) {
314
317
  if (!props.open) return null;
315
318
  return /* @__PURE__ */ jsx2("div", { className: "cfi-vi-modal-overlay", role: "dialog", "aria-modal": "true", onClick: props.onClose, children: /* @__PURE__ */ jsxs2("div", { className: "cfi-vi-modal", onClick: (e) => e.stopPropagation(), children: [
@@ -322,23 +325,469 @@ function Modal(props) {
322
325
  ] }) });
323
326
  }
324
327
 
325
- // src/VolumeSourcesList.tsx
328
+ // src/VolumeFiles.tsx
326
329
  import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
327
- var EMPTY_FORM = { code: "", name: "", description: "", headerRowIndex: 0, volumeHeaderFormat: "MMM yyyy" };
328
- function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras, className }) {
330
+ var MONTH_NAMES2 = [
331
+ "January",
332
+ "February",
333
+ "March",
334
+ "April",
335
+ "May",
336
+ "June",
337
+ "July",
338
+ "August",
339
+ "September",
340
+ "October",
341
+ "November",
342
+ "December"
343
+ ];
344
+ var MONTH_ABBR = MONTH_NAMES2.map((m) => m.slice(0, 3));
345
+ var CURRENT_YEAR = (/* @__PURE__ */ new Date()).getFullYear();
346
+ var CURRENT_MONTH = (/* @__PURE__ */ new Date()).getMonth() + 1;
347
+ var YEAR_OPTIONS = [CURRENT_YEAR - 2, CURRENT_YEAR - 1, CURRENT_YEAR, CURRENT_YEAR + 1, CURRENT_YEAR + 2];
348
+ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "processing", "awaiting_calendar"]);
349
+ var POLL_INTERVAL_MS = 3e3;
350
+ var PAGE_SIZE = 20;
351
+ var STATUS_LABELS2 = {
352
+ awaiting_calendar: "awaiting calendar",
353
+ done_with_errors: "done with errors"
354
+ };
355
+ function statusTagClass(status) {
356
+ switch (status) {
357
+ case "done":
358
+ return "cfi-vi-tag--success";
359
+ case "done_with_errors":
360
+ return "cfi-vi-tag--warn";
361
+ case "awaiting_calendar":
362
+ return "cfi-vi-tag--warn";
363
+ case "failed":
364
+ return "cfi-vi-tag--danger";
365
+ case "processing":
366
+ return "cfi-vi-tag--secondary";
367
+ default:
368
+ return "cfi-vi-tag--default";
369
+ }
370
+ }
371
+ function computeCutoffLabel(uploadYear, uploadMonth, lag) {
372
+ let cutoffMonth = uploadMonth - lag;
373
+ let cutoffYear = uploadYear;
374
+ while (cutoffMonth <= 0) {
375
+ cutoffMonth += 12;
376
+ cutoffYear--;
377
+ }
378
+ let predMonth = cutoffMonth + 1;
379
+ let predYear = cutoffYear;
380
+ if (predMonth > 12) {
381
+ predMonth -= 12;
382
+ predYear++;
383
+ }
384
+ return {
385
+ cutoffLabel: `${MONTH_NAMES2[cutoffMonth - 1]} ${cutoffYear}`,
386
+ predictionsLabel: `${MONTH_NAMES2[predMonth - 1]} ${predYear}`
387
+ };
388
+ }
389
+ function formatDuration(startedAt, completedAt) {
390
+ if (!startedAt || !completedAt) return "\u2014";
391
+ const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime();
392
+ const totalSec = Math.max(0, Math.floor(ms / 1e3));
393
+ const m = Math.floor(totalSec / 60);
394
+ const s = totalSec % 60;
395
+ return m > 0 ? `${m}m ${s}s` : `${s}s`;
396
+ }
397
+ function UploadDialog(props) {
398
+ const { transport, sources, activeSourceId, calendarSeeded, onClose, onCreated } = props;
399
+ const [selectedSourceId, setSelectedSourceId] = useState2(activeSourceId ?? sources[0]?.id ?? "");
400
+ const [year, setYear] = useState2(CURRENT_YEAR);
401
+ const [month, setMonth] = useState2(CURRENT_MONTH);
402
+ const [lag, setLag] = useState2(1);
403
+ const [file, setFile] = useState2(null);
404
+ const [submitting, setSubmitting] = useState2(false);
405
+ const [error, setError] = useState2(null);
406
+ const [hierarchyMapped, setHierarchyMapped] = useState2(null);
407
+ const selected = sources.find((s) => s.id === selectedSourceId) ?? null;
408
+ const isTall = selected?.layout === "tall";
409
+ useEffect2(() => {
410
+ if (!selectedSourceId) {
411
+ setHierarchyMapped(null);
412
+ return;
413
+ }
414
+ let cancelled = false;
415
+ setHierarchyMapped(null);
416
+ transport.isHierarchyMapped(selectedSourceId).then((m) => {
417
+ if (!cancelled) setHierarchyMapped(m);
418
+ }).catch(() => {
419
+ if (!cancelled) setHierarchyMapped(false);
420
+ });
421
+ return () => {
422
+ cancelled = true;
423
+ };
424
+ }, [selectedSourceId, transport]);
425
+ const blockers = [];
426
+ if (!selected) blockers.push("Pick a source to upload to");
427
+ else {
428
+ if (!isTall && !selected.uniqueKeySegmentId) blockers.push("Source has no unique-key column set");
429
+ if (hierarchyMapped === false) blockers.push("Hierarchy levels not mapped");
430
+ }
431
+ if (calendarSeeded === false) blockers.push("Calendar not seeded");
432
+ const blocked = blockers.length > 0;
433
+ const { cutoffLabel, predictionsLabel } = computeCutoffLabel(year, month, lag);
434
+ const handleSubmit = useCallback2(async () => {
435
+ if (!selected || !file) {
436
+ setError("Pick a source and file first");
437
+ return;
438
+ }
439
+ setSubmitting(true);
440
+ setError(null);
441
+ try {
442
+ const input = {
443
+ sourceId: selected.id,
444
+ file,
445
+ ...isTall ? {} : { uploadYear: year, uploadMonth: month, actualsLagMonths: lag }
446
+ };
447
+ const created = await transport.createUpload(input);
448
+ onCreated(created);
449
+ } catch (e) {
450
+ setError(e instanceof Error ? e.message : "Upload failed");
451
+ } finally {
452
+ setSubmitting(false);
453
+ }
454
+ }, [selected, file, isTall, year, month, lag, transport, onCreated]);
455
+ return /* @__PURE__ */ jsx3("div", { className: "cfi-vi-modal-overlay", role: "dialog", "aria-modal": "true", onClick: onClose, children: /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-modal", onClick: (e) => e.stopPropagation(), children: [
456
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-modal-head", children: [
457
+ /* @__PURE__ */ jsx3("h2", { className: "cfi-vi-modal-title", children: "Upload volume file" }),
458
+ /* @__PURE__ */ jsx3("button", { type: "button", className: "cfi-vi-icon-btn", "aria-label": "Close", onClick: onClose, children: "\u2715" })
459
+ ] }),
460
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-modal-body", children: [
461
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-field", children: [
462
+ /* @__PURE__ */ jsx3("label", { className: "cfi-vi-label", htmlFor: "cfi-vf-source", children: "Source" }),
463
+ /* @__PURE__ */ jsxs3(
464
+ "select",
465
+ {
466
+ id: "cfi-vf-source",
467
+ className: "cfi-vi-select",
468
+ value: selectedSourceId,
469
+ onChange: (e) => setSelectedSourceId(e.target.value),
470
+ children: [
471
+ sources.length === 0 && /* @__PURE__ */ jsx3("option", { value: "", children: "No sources defined" }),
472
+ sources.slice().sort((a, b) => a.name.localeCompare(b.name)).map((s) => /* @__PURE__ */ jsxs3("option", { value: s.id, children: [
473
+ s.name,
474
+ " (",
475
+ s.code,
476
+ ") \xB7 ",
477
+ s.layout,
478
+ s.kind === "overlay" ? " \xB7 overlay" : ""
479
+ ] }, s.id))
480
+ ]
481
+ }
482
+ )
483
+ ] }),
484
+ blockers.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-alert cfi-vi-alert--warn", children: [
485
+ /* @__PURE__ */ jsx3(AlertTriangle2, { size: 16, "aria-hidden": true }),
486
+ /* @__PURE__ */ jsx3("ul", { className: "cfi-vi-blockers", children: blockers.map((b, i) => /* @__PURE__ */ jsx3("li", { children: b }, i)) })
487
+ ] }),
488
+ selected && !isTall && /* @__PURE__ */ jsxs3(Fragment, { children: [
489
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row", children: [
490
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-field", children: [
491
+ /* @__PURE__ */ jsx3("label", { className: "cfi-vi-label", htmlFor: "cfi-vf-year", children: "Year" }),
492
+ /* @__PURE__ */ jsx3("select", { id: "cfi-vf-year", className: "cfi-vi-select", value: year, onChange: (e) => setYear(Number(e.target.value)), children: YEAR_OPTIONS.map((y) => /* @__PURE__ */ jsx3("option", { value: y, children: y }, y)) })
493
+ ] }),
494
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-field", children: [
495
+ /* @__PURE__ */ jsx3("label", { className: "cfi-vi-label", htmlFor: "cfi-vf-month", children: "Month" }),
496
+ /* @__PURE__ */ jsx3("select", { id: "cfi-vf-month", className: "cfi-vi-select", value: month, onChange: (e) => setMonth(Number(e.target.value)), children: MONTH_NAMES2.map((name, i) => /* @__PURE__ */ jsx3("option", { value: i + 1, children: name }, name)) })
497
+ ] }),
498
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-field", children: [
499
+ /* @__PURE__ */ jsx3("label", { className: "cfi-vi-label", htmlFor: "cfi-vf-lag", children: "Actuals lag (months)" }),
500
+ /* @__PURE__ */ jsx3("select", { id: "cfi-vf-lag", className: "cfi-vi-select", value: lag, onChange: (e) => setLag(Number(e.target.value)), children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxs3("option", { value: n, children: [
501
+ n,
502
+ " month",
503
+ n !== 1 ? "s" : ""
504
+ ] }, n)) })
505
+ ] })
506
+ ] }),
507
+ /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-hint", children: [
508
+ "\u2190 Actuals up to ",
509
+ cutoffLabel,
510
+ " \xB7 Predictions \u2192 from ",
511
+ predictionsLabel
512
+ ] })
513
+ ] }),
514
+ selected && isTall && /* @__PURE__ */ jsx3("p", { className: "cfi-vi-hint", children: "Tall-format upload \u2014 each row carries its own Week Ending date; cutoff fields aren\u2019t needed." }),
515
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-field", children: [
516
+ /* @__PURE__ */ jsx3("label", { className: "cfi-vi-label", htmlFor: "cfi-vf-file", children: "File (.xlsx / .xls)" }),
517
+ /* @__PURE__ */ jsx3(
518
+ "input",
519
+ {
520
+ id: "cfi-vf-file",
521
+ type: "file",
522
+ accept: ".xlsx,.xls",
523
+ className: "cfi-vi-file",
524
+ onChange: (e) => setFile(e.target.files?.[0] ?? null)
525
+ }
526
+ )
527
+ ] }),
528
+ error && /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-alert cfi-vi-alert--error", children: [
529
+ /* @__PURE__ */ jsx3(AlertTriangle2, { size: 16, "aria-hidden": true }),
530
+ " ",
531
+ /* @__PURE__ */ jsx3("span", { children: error })
532
+ ] })
533
+ ] }),
534
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-modal-foot", children: [
535
+ /* @__PURE__ */ jsx3(Btn, { variant: "outline", size: "sm", onClick: onClose, children: "Cancel" }),
536
+ /* @__PURE__ */ jsxs3(Btn, { size: "sm", disabled: submitting || blocked || !file, onClick: handleSubmit, children: [
537
+ submitting ? /* @__PURE__ */ jsx3(Spinner, {}) : /* @__PURE__ */ jsx3(FileUp2, { size: 14, "aria-hidden": true }),
538
+ " ",
539
+ submitting ? "Uploading\u2026" : "Upload"
540
+ ] })
541
+ ] })
542
+ ] }) });
543
+ }
544
+ function VolumeFiles({ transport, className }) {
329
545
  const [sources, setSources] = useState2([]);
330
546
  const [activeSourceId, setActiveSourceId] = useState2(null);
331
- const [templates, setTemplates] = useState2([]);
547
+ const [calendarSeeded, setCalendarSeeded] = useState2(null);
548
+ const [uploads, setUploads] = useState2([]);
549
+ const [total, setTotal] = useState2(0);
332
550
  const [loading, setLoading] = useState2(true);
333
551
  const [error, setError] = useState2(null);
334
- const [showCreate, setShowCreate] = useState2(false);
335
- const [showTemplates, setShowTemplates] = useState2(false);
336
- const [form, setForm] = useState2(EMPTY_FORM);
337
- const [saving, setSaving] = useState2(false);
338
- const [activating, setActivating] = useState2(null);
339
- const [addingTemplate, setAddingTemplate] = useState2(null);
340
- const [confirmActivate, setConfirmActivate] = useState2(null);
341
- const load = useCallback2(async () => {
552
+ const [dialogOpen, setDialogOpen] = useState2(false);
553
+ const [filterStatus, setFilterStatus] = useState2("");
554
+ const [filterSourceId, setFilterSourceId] = useState2("");
555
+ const [offset, setOffset] = useState2(0);
556
+ const [expandedId, setExpandedId] = useState2(null);
557
+ const [errorsById, setErrorsById] = useState2({});
558
+ const load = useCallback2(async (opts) => {
559
+ if (!opts?.silent) setLoading(true);
560
+ try {
561
+ const [srcs, activeId, result, calSeeded] = await Promise.all([
562
+ transport.listSources(),
563
+ transport.getActiveSourceId().catch(() => null),
564
+ transport.listUploads({
565
+ limit: PAGE_SIZE,
566
+ offset,
567
+ ...filterStatus ? { status: filterStatus } : {},
568
+ ...filterSourceId ? { sourceId: filterSourceId } : {}
569
+ }),
570
+ transport.isCalendarSeeded ? transport.isCalendarSeeded().catch(() => null) : Promise.resolve(null)
571
+ ]);
572
+ setSources(srcs);
573
+ setActiveSourceId(activeId);
574
+ setUploads(result.items);
575
+ setTotal(result.total);
576
+ setCalendarSeeded(calSeeded);
577
+ setError(null);
578
+ } catch (e) {
579
+ setError(e instanceof Error ? e.message : "Failed to load uploads");
580
+ } finally {
581
+ setLoading(false);
582
+ }
583
+ }, [transport, offset, filterStatus, filterSourceId]);
584
+ useEffect2(() => {
585
+ void load();
586
+ }, [load]);
587
+ useEffect2(() => {
588
+ const activeIds = uploads.filter((u) => ACTIVE_STATUSES.has(u.status)).map((u) => u.id);
589
+ if (activeIds.length === 0) return;
590
+ const timer = setInterval(async () => {
591
+ const updated = await Promise.allSettled(activeIds.map((id) => transport.getUpload(id)));
592
+ setUploads((prev) => prev.map((u) => {
593
+ const idx = activeIds.indexOf(u.id);
594
+ if (idx < 0) return u;
595
+ const res = updated[idx];
596
+ return res.status === "fulfilled" ? res.value : u;
597
+ }));
598
+ }, POLL_INTERVAL_MS);
599
+ return () => clearInterval(timer);
600
+ }, [uploads, transport]);
601
+ const handleCreated = useCallback2((u) => {
602
+ setDialogOpen(false);
603
+ setUploads((prev) => [u, ...prev.filter((x) => x.id !== u.id)]);
604
+ setTotal((n) => n + 1);
605
+ }, []);
606
+ const handleReprocess = useCallback2(async (id) => {
607
+ try {
608
+ await transport.reprocessUpload(id);
609
+ await load({ silent: true });
610
+ } catch (e) {
611
+ setError(e instanceof Error ? e.message : "Reprocess failed");
612
+ }
613
+ }, [transport, load]);
614
+ const handleDownload = useCallback2(async (id) => {
615
+ try {
616
+ const url = await transport.getUploadDownloadUrl(id);
617
+ window.open(url, "_blank", "noopener");
618
+ } catch (e) {
619
+ setError(e instanceof Error ? e.message : "Download failed");
620
+ }
621
+ }, [transport]);
622
+ const toggleExpand = useCallback2(async (u) => {
623
+ if (expandedId === u.id) {
624
+ setExpandedId(null);
625
+ return;
626
+ }
627
+ setExpandedId(u.id);
628
+ if (!errorsById[u.id] && u.rowsFailed > 0) {
629
+ try {
630
+ const res = await transport.getUploadErrors(u.id, { limit: 100 });
631
+ setErrorsById((prev) => ({ ...prev, [u.id]: res.items }));
632
+ } catch {
633
+ }
634
+ }
635
+ }, [expandedId, errorsById, transport]);
636
+ const totalPages = Math.ceil(total / PAGE_SIZE);
637
+ const currentPage = Math.floor(offset / PAGE_SIZE) + 1;
638
+ const dialogSources = useMemo2(() => sources, [sources]);
639
+ return /* @__PURE__ */ jsxs3(Root, { className, children: [
640
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row cfi-vi-row--between cfi-vi-files-head", children: [
641
+ /* @__PURE__ */ jsx3("h2", { className: "cfi-vi-files-title", children: "Volume uploads" }),
642
+ /* @__PURE__ */ jsxs3(Btn, { size: "sm", onClick: () => setDialogOpen(true), children: [
643
+ /* @__PURE__ */ jsx3(FileUp2, { size: 14, "aria-hidden": true }),
644
+ " Upload file"
645
+ ] })
646
+ ] }),
647
+ error && /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-alert cfi-vi-alert--error", children: [
648
+ /* @__PURE__ */ jsx3(AlertTriangle2, { size: 16, "aria-hidden": true }),
649
+ " ",
650
+ /* @__PURE__ */ jsx3("span", { children: error })
651
+ ] }),
652
+ /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row cfi-vi-files-filters", children: [
653
+ /* @__PURE__ */ jsxs3("select", { className: "cfi-vi-select", value: filterSourceId, onChange: (e) => {
654
+ setFilterSourceId(e.target.value);
655
+ setOffset(0);
656
+ }, children: [
657
+ /* @__PURE__ */ jsx3("option", { value: "", children: "All sources" }),
658
+ sources.map((s) => /* @__PURE__ */ jsx3("option", { value: s.id, children: s.code }, s.id))
659
+ ] }),
660
+ /* @__PURE__ */ jsxs3("select", { className: "cfi-vi-select", value: filterStatus, onChange: (e) => {
661
+ setFilterStatus(e.target.value);
662
+ setOffset(0);
663
+ }, children: [
664
+ /* @__PURE__ */ jsx3("option", { value: "", children: "All statuses" }),
665
+ /* @__PURE__ */ jsx3("option", { value: "pending", children: "Pending" }),
666
+ /* @__PURE__ */ jsx3("option", { value: "processing", children: "Processing" }),
667
+ /* @__PURE__ */ jsx3("option", { value: "done", children: "Done" }),
668
+ /* @__PURE__ */ jsx3("option", { value: "done_with_errors", children: "Done with errors" }),
669
+ /* @__PURE__ */ jsx3("option", { value: "failed", children: "Failed" })
670
+ ] }),
671
+ /* @__PURE__ */ jsx3(Btn, { variant: "ghost", size: "sm", onClick: () => void load(), children: "Refresh" })
672
+ ] }),
673
+ loading ? /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-loading", children: [
674
+ /* @__PURE__ */ jsx3(Spinner, {}),
675
+ " Loading\u2026"
676
+ ] }) : uploads.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", children: "No uploads yet." }) : /* @__PURE__ */ jsxs3("table", { className: "cfi-vi-table cfi-vi-files-table", children: [
677
+ /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
678
+ /* @__PURE__ */ jsx3("th", {}),
679
+ /* @__PURE__ */ jsx3("th", { children: "File" }),
680
+ /* @__PURE__ */ jsx3("th", { children: "Period" }),
681
+ /* @__PURE__ */ jsx3("th", { children: "Source" }),
682
+ /* @__PURE__ */ jsx3("th", { children: "Progress" }),
683
+ /* @__PURE__ */ jsx3("th", { children: "Catalogue" }),
684
+ /* @__PURE__ */ jsx3("th", { children: "Status" }),
685
+ /* @__PURE__ */ jsx3("th", { children: "Duration" }),
686
+ /* @__PURE__ */ jsx3("th", { className: "cfi-vi-ta-right", children: "Actions" })
687
+ ] }) }),
688
+ /* @__PURE__ */ jsx3("tbody", { children: uploads.map((u) => {
689
+ const active = ACTIVE_STATUSES.has(u.status);
690
+ const expanded = expandedId === u.id;
691
+ const catalogue = u.rowsCanonicalised + u.rowsQueued + u.rowsBound;
692
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
693
+ /* @__PURE__ */ jsxs3("tr", { children: [
694
+ /* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsx3("button", { type: "button", className: "cfi-vi-icon-btn", "aria-label": "Toggle details", onClick: () => void toggleExpand(u), children: expanded ? /* @__PURE__ */ jsx3(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsx3(ChevronRight, { size: 14 }) }) }),
695
+ /* @__PURE__ */ jsx3("td", { className: "cfi-vi-files-file", title: u.fileName, children: u.fileName }),
696
+ /* @__PURE__ */ jsxs3("td", { className: "cfi-vi-muted", children: [
697
+ u.uploadYear,
698
+ " / ",
699
+ MONTH_ABBR[u.uploadMonth - 1]
700
+ ] }),
701
+ /* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsx3("span", { className: "cfi-vi-tag cfi-vi-tag--outline", children: u.source.code }) }),
702
+ /* @__PURE__ */ jsx3("td", { children: active ? /* @__PURE__ */ jsx3("span", { className: "cfi-vi-muted", children: "processing\u2026" }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
703
+ u.rowsProcessed.toLocaleString(),
704
+ " / ",
705
+ u.rowsTotal.toLocaleString(),
706
+ u.rowsFailed > 0 && /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-danger-text", children: [
707
+ " (",
708
+ u.rowsFailed,
709
+ " failed)"
710
+ ] })
711
+ ] }) }),
712
+ /* @__PURE__ */ jsx3("td", { className: "cfi-vi-muted", children: catalogue === 0 ? "\u2014" : `${u.rowsCanonicalised}\u2713 \xB7 ${u.rowsQueued}\u23F3 \xB7 ${u.rowsBound}\u{1F517}` }),
713
+ /* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsxs3("span", { className: `cfi-vi-tag ${statusTagClass(u.status)}`, children: [
714
+ active && /* @__PURE__ */ jsx3(Spinner, { size: 10 }),
715
+ " ",
716
+ STATUS_LABELS2[u.status] ?? u.status.replace(/_/g, " ")
717
+ ] }) }),
718
+ /* @__PURE__ */ jsx3("td", { className: "cfi-vi-muted", children: formatDuration(u.startedAt, u.completedAt) }),
719
+ /* @__PURE__ */ jsx3("td", { className: "cfi-vi-ta-right", children: /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-files-actions", children: [
720
+ /* @__PURE__ */ jsx3("button", { type: "button", className: "cfi-vi-icon-btn", title: "Download original", onClick: () => void handleDownload(u.id), children: /* @__PURE__ */ jsx3(Download, { size: 14 }) }),
721
+ u.status === "failed" && /* @__PURE__ */ jsx3("button", { type: "button", className: "cfi-vi-icon-btn", title: "Reprocess", onClick: () => void handleReprocess(u.id), children: /* @__PURE__ */ jsx3(RotateCcw2, { size: 14 }) })
722
+ ] }) })
723
+ ] }, u.id),
724
+ expanded && /* @__PURE__ */ jsxs3("tr", { className: "cfi-vi-files-detail", children: [
725
+ /* @__PURE__ */ jsx3("td", {}),
726
+ /* @__PURE__ */ jsxs3("td", { colSpan: 8, children: [
727
+ u.errorSummary && /* @__PURE__ */ jsx3("p", { className: "cfi-vi-danger-text", children: u.errorSummary }),
728
+ u.rowsFailed === 0 ? /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", children: "No row errors." }) : errorsById[u.id]?.length ? /* @__PURE__ */ jsxs3("table", { className: "cfi-vi-errors", children: [
729
+ /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
730
+ /* @__PURE__ */ jsx3("th", { children: "Row" }),
731
+ /* @__PURE__ */ jsx3("th", { children: "Type" }),
732
+ /* @__PURE__ */ jsx3("th", { children: "Message" })
733
+ ] }) }),
734
+ /* @__PURE__ */ jsx3("tbody", { children: errorsById[u.id].map((e, i) => /* @__PURE__ */ jsxs3("tr", { children: [
735
+ /* @__PURE__ */ jsx3("td", { children: e.rowNumber ?? "\u2014" }),
736
+ /* @__PURE__ */ jsx3("td", { children: e.errorType }),
737
+ /* @__PURE__ */ jsx3("td", { children: e.errorDetail })
738
+ ] }, e.id ?? i)) })
739
+ ] }) : /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-muted", children: [
740
+ u.rowsFailed,
741
+ " error(s) \u2014 loading\u2026"
742
+ ] })
743
+ ] })
744
+ ] }, `${u.id}-detail`)
745
+ ] });
746
+ }) })
747
+ ] }),
748
+ totalPages > 1 && /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row cfi-vi-files-pager", children: [
749
+ /* @__PURE__ */ jsx3(Btn, { variant: "outline", size: "sm", disabled: offset === 0, onClick: () => setOffset((o) => Math.max(0, o - PAGE_SIZE)), children: "\u2190 Prev" }),
750
+ /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-muted", children: [
751
+ "Page ",
752
+ currentPage,
753
+ " of ",
754
+ totalPages
755
+ ] }),
756
+ /* @__PURE__ */ jsx3(Btn, { variant: "outline", size: "sm", disabled: offset + PAGE_SIZE >= total, onClick: () => setOffset((o) => o + PAGE_SIZE), children: "Next \u2192" })
757
+ ] }),
758
+ dialogOpen && /* @__PURE__ */ jsx3(
759
+ UploadDialog,
760
+ {
761
+ transport,
762
+ sources: dialogSources,
763
+ activeSourceId,
764
+ calendarSeeded,
765
+ onClose: () => setDialogOpen(false),
766
+ onCreated: handleCreated
767
+ }
768
+ )
769
+ ] });
770
+ }
771
+
772
+ // src/VolumeSourcesList.tsx
773
+ import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
774
+ import { CheckCircle2, Sparkles } from "lucide-react";
775
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
776
+ var EMPTY_FORM = { code: "", name: "", description: "", headerRowIndex: 0, volumeHeaderFormat: "MMM yyyy" };
777
+ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras, className }) {
778
+ const [sources, setSources] = useState3([]);
779
+ const [activeSourceId, setActiveSourceId] = useState3(null);
780
+ const [templates, setTemplates] = useState3([]);
781
+ const [loading, setLoading] = useState3(true);
782
+ const [error, setError] = useState3(null);
783
+ const [showCreate, setShowCreate] = useState3(false);
784
+ const [showTemplates, setShowTemplates] = useState3(false);
785
+ const [form, setForm] = useState3(EMPTY_FORM);
786
+ const [saving, setSaving] = useState3(false);
787
+ const [activating, setActivating] = useState3(null);
788
+ const [addingTemplate, setAddingTemplate] = useState3(null);
789
+ const [confirmActivate, setConfirmActivate] = useState3(null);
790
+ const load = useCallback3(async () => {
342
791
  try {
343
792
  setLoading(true);
344
793
  const [allSources, config, allTemplates] = await Promise.all([
@@ -355,11 +804,11 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
355
804
  setLoading(false);
356
805
  }
357
806
  }, [transport]);
358
- useEffect2(() => {
807
+ useEffect3(() => {
359
808
  void load();
360
809
  }, [load]);
361
810
  const availableTemplates = templates.filter((t) => !sources.some((s) => s.code === t.code));
362
- const handleAddFromTemplate = useCallback2(async (code) => {
811
+ const handleAddFromTemplate = useCallback3(async (code) => {
363
812
  setAddingTemplate(code);
364
813
  setError(null);
365
814
  try {
@@ -372,7 +821,7 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
372
821
  setAddingTemplate(null);
373
822
  }
374
823
  }, [transport, onOpenSource]);
375
- const handleCreate = useCallback2(async () => {
824
+ const handleCreate = useCallback3(async () => {
376
825
  if (!form.code || !form.name) return;
377
826
  setSaving(true);
378
827
  try {
@@ -386,7 +835,7 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
386
835
  setSaving(false);
387
836
  }
388
837
  }, [form, transport, load]);
389
- const doActivate = useCallback2(async (sourceId) => {
838
+ const doActivate = useCallback3(async (sourceId) => {
390
839
  setActivating(sourceId);
391
840
  setConfirmActivate(null);
392
841
  try {
@@ -398,7 +847,7 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
398
847
  setActivating(null);
399
848
  }
400
849
  }, [transport, load]);
401
- const handleActivate = useCallback2((src) => {
850
+ const handleActivate = useCallback3((src) => {
402
851
  if (activeSourceId && activeSourceId !== src.id) {
403
852
  setConfirmActivate(src);
404
853
  return;
@@ -406,127 +855,127 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
406
855
  void doActivate(src.id);
407
856
  }, [activeSourceId, doActivate]);
408
857
  const currentActive = sources.find((s) => s.id === activeSourceId);
409
- if (loading) return /* @__PURE__ */ jsx3(Root, { className, children: /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", children: "Loading\u2026" }) });
410
- return /* @__PURE__ */ jsxs3(Root, { className, children: [
411
- /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-list-head", children: [
412
- /* @__PURE__ */ jsxs3("div", { children: [
413
- /* @__PURE__ */ jsx3("h1", { className: "cfi-vi-h1", children: "Volume Sources" }),
414
- currentActive && /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-active-line", children: [
415
- /* @__PURE__ */ jsx3(CheckCircle2, { size: 14, color: "#16a34a", "aria-hidden": true }),
858
+ if (loading) return /* @__PURE__ */ jsx4(Root, { className, children: /* @__PURE__ */ jsx4("p", { className: "cfi-vi-muted", children: "Loading\u2026" }) });
859
+ return /* @__PURE__ */ jsxs4(Root, { className, children: [
860
+ /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-list-head", children: [
861
+ /* @__PURE__ */ jsxs4("div", { children: [
862
+ /* @__PURE__ */ jsx4("h1", { className: "cfi-vi-h1", children: "Volume Sources" }),
863
+ currentActive && /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-active-line", children: [
864
+ /* @__PURE__ */ jsx4(CheckCircle2, { size: 14, color: "#16a34a", "aria-hidden": true }),
416
865
  "Active: ",
417
- /* @__PURE__ */ jsx3("span", { className: "cfi-vi-active-name", children: currentActive.name }),
418
- /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-muted", children: [
866
+ /* @__PURE__ */ jsx4("span", { className: "cfi-vi-active-name", children: currentActive.name }),
867
+ /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-muted", children: [
419
868
  "(",
420
869
  currentActive.code,
421
870
  ")"
422
871
  ] })
423
872
  ] })
424
873
  ] }),
425
- /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row", children: [
426
- availableTemplates.length > 0 && /* @__PURE__ */ jsxs3(Btn, { variant: "outline", size: "sm", onClick: () => setShowTemplates(true), children: [
427
- /* @__PURE__ */ jsx3(Sparkles, { size: 14, "aria-hidden": true }),
874
+ /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-row", children: [
875
+ availableTemplates.length > 0 && /* @__PURE__ */ jsxs4(Btn, { variant: "outline", size: "sm", onClick: () => setShowTemplates(true), children: [
876
+ /* @__PURE__ */ jsx4(Sparkles, { size: 14, "aria-hidden": true }),
428
877
  " Add from template"
429
878
  ] }),
430
- /* @__PURE__ */ jsx3(Btn, { size: "sm", onClick: () => setShowCreate(true), children: "Add Source" })
879
+ /* @__PURE__ */ jsx4(Btn, { size: "sm", onClick: () => setShowCreate(true), children: "Add Source" })
431
880
  ] })
432
881
  ] }),
433
- error && /* @__PURE__ */ jsx3("p", { className: "cfi-vi-error", children: error }),
434
- /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-list", children: [
435
- sources.length === 0 && /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", children: "No sources defined yet." }),
882
+ error && /* @__PURE__ */ jsx4("p", { className: "cfi-vi-error", children: error }),
883
+ /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-list", children: [
884
+ sources.length === 0 && /* @__PURE__ */ jsx4("p", { className: "cfi-vi-muted", children: "No sources defined yet." }),
436
885
  sources.map((src) => {
437
886
  const isActive = src.id === activeSourceId;
438
- return /* @__PURE__ */ jsxs3(Card, { className: isActive ? "cfi-vi-card--active" : "cfi-vi-card--hover", children: [
439
- /* @__PURE__ */ jsx3(CardHeader, { children: /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
440
- /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-card-title", children: [
441
- /* @__PURE__ */ jsx3("button", { type: "button", className: "cfi-vi-link", onClick: () => onOpenSource(src.id), children: src.name }),
442
- isActive && /* @__PURE__ */ jsx3(Badge, { variant: "success", children: "Active" }),
443
- src.kind === "overlay" && /* @__PURE__ */ jsx3(Badge, { variant: "purple", title: "Overlay sources are active whenever data is uploaded \u2014 no Set Active step.", children: "Overlay" })
887
+ return /* @__PURE__ */ jsxs4(Card, { className: isActive ? "cfi-vi-card--active" : "cfi-vi-card--hover", children: [
888
+ /* @__PURE__ */ jsx4(CardHeader, { children: /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
889
+ /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-card-title", children: [
890
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "cfi-vi-link", onClick: () => onOpenSource(src.id), children: src.name }),
891
+ isActive && /* @__PURE__ */ jsx4(Badge, { variant: "success", children: "Active" }),
892
+ src.kind === "overlay" && /* @__PURE__ */ jsx4(Badge, { variant: "purple", title: "Overlay sources are active whenever data is uploaded \u2014 no Set Active step.", children: "Overlay" })
444
893
  ] }),
445
- /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-row", children: [
446
- /* @__PURE__ */ jsx3(Badge, { variant: "outline", children: src.code }),
447
- !src.isActive && /* @__PURE__ */ jsx3(Badge, { variant: "secondary", children: "Disabled" }),
448
- !isActive && src.kind === "base" && /* @__PURE__ */ jsx3(Btn, { variant: "outline", size: "sm", disabled: activating === src.id, onClick: () => handleActivate(src), children: activating === src.id ? "Activating\u2026" : "Set Active" })
894
+ /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-row", children: [
895
+ /* @__PURE__ */ jsx4(Badge, { variant: "outline", children: src.code }),
896
+ !src.isActive && /* @__PURE__ */ jsx4(Badge, { variant: "secondary", children: "Disabled" }),
897
+ !isActive && src.kind === "base" && /* @__PURE__ */ jsx4(Btn, { variant: "outline", size: "sm", disabled: activating === src.id, onClick: () => handleActivate(src), children: activating === src.id ? "Activating\u2026" : "Set Active" })
449
898
  ] })
450
899
  ] }) }),
451
- /* @__PURE__ */ jsxs3(CardBody, { children: [
452
- /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
900
+ /* @__PURE__ */ jsxs4(CardBody, { children: [
901
+ /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
453
902
  src.description || "No description",
454
903
  " \xB7 ",
455
- /* @__PURE__ */ jsx3("span", { className: "cfi-vi-mono", children: src.volumeHeaderFormat })
904
+ /* @__PURE__ */ jsx4("span", { className: "cfi-vi-mono", children: src.volumeHeaderFormat })
456
905
  ] }),
457
- src._count && /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)", marginTop: 4 }, children: [
906
+ src._count && /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)", marginTop: 4 }, children: [
458
907
  src._count.segments,
459
908
  " segments detected"
460
909
  ] }),
461
- isActive && renderActiveSourceExtras && /* @__PURE__ */ jsx3("div", { className: "cfi-vi-active-extras", children: renderActiveSourceExtras(src) })
910
+ isActive && renderActiveSourceExtras && /* @__PURE__ */ jsx4("div", { className: "cfi-vi-active-extras", children: renderActiveSourceExtras(src) })
462
911
  ] })
463
912
  ] }, src.id);
464
913
  })
465
914
  ] }),
466
- /* @__PURE__ */ jsxs3(
915
+ /* @__PURE__ */ jsxs4(
467
916
  Modal,
468
917
  {
469
918
  open: !!confirmActivate,
470
919
  onClose: () => setConfirmActivate(null),
471
920
  title: "Switch active source?",
472
- footer: /* @__PURE__ */ jsxs3(Fragment, { children: [
473
- /* @__PURE__ */ jsx3(Btn, { variant: "outline", onClick: () => setConfirmActivate(null), children: "Cancel" }),
474
- /* @__PURE__ */ jsx3(Btn, { variant: "destructive", onClick: () => confirmActivate && void doActivate(confirmActivate.id), children: "Switch and wipe data" })
921
+ footer: /* @__PURE__ */ jsxs4(Fragment2, { children: [
922
+ /* @__PURE__ */ jsx4(Btn, { variant: "outline", onClick: () => setConfirmActivate(null), children: "Cancel" }),
923
+ /* @__PURE__ */ jsx4(Btn, { variant: "destructive", onClick: () => confirmActivate && void doActivate(confirmActivate.id), children: "Switch and wipe data" })
475
924
  ] }),
476
925
  children: [
477
- /* @__PURE__ */ jsxs3("p", { children: [
926
+ /* @__PURE__ */ jsxs4("p", { children: [
478
927
  "Switching the active source to ",
479
- /* @__PURE__ */ jsx3("strong", { children: confirmActivate?.name }),
928
+ /* @__PURE__ */ jsx4("strong", { children: confirmActivate?.name }),
480
929
  " (",
481
930
  confirmActivate?.code,
482
931
  ")."
483
932
  ] }),
484
- /* @__PURE__ */ jsx3("p", { className: "cfi-vi-error", children: "This permanently wipes all ingested data for this tenant \u2014 volume hierarchy, forecast data, edits, scenarios, uploads, and audit log. Your level 1\u20133 mapping and segment configuration are preserved. This cannot be undone." })
933
+ /* @__PURE__ */ jsx4("p", { className: "cfi-vi-error", children: "This permanently wipes all ingested data for this tenant \u2014 volume hierarchy, forecast data, edits, scenarios, uploads, and audit log. Your level 1\u20133 mapping and segment configuration are preserved. This cannot be undone." })
485
934
  ]
486
935
  }
487
936
  ),
488
- /* @__PURE__ */ jsxs3(
937
+ /* @__PURE__ */ jsxs4(
489
938
  Modal,
490
939
  {
491
940
  open: showCreate,
492
941
  onClose: () => setShowCreate(false),
493
942
  title: "Add volume source",
494
- footer: /* @__PURE__ */ jsxs3(Fragment, { children: [
495
- /* @__PURE__ */ jsx3(Btn, { variant: "outline", onClick: () => setShowCreate(false), children: "Cancel" }),
496
- /* @__PURE__ */ jsx3(Btn, { onClick: handleCreate, disabled: saving || !form.code || !form.name, children: saving ? "Creating\u2026" : "Create" })
943
+ footer: /* @__PURE__ */ jsxs4(Fragment2, { children: [
944
+ /* @__PURE__ */ jsx4(Btn, { variant: "outline", onClick: () => setShowCreate(false), children: "Cancel" }),
945
+ /* @__PURE__ */ jsx4(Btn, { onClick: handleCreate, disabled: saving || !form.code || !form.name, children: saving ? "Creating\u2026" : "Create" })
497
946
  ] }),
498
947
  children: [
499
- /* @__PURE__ */ jsx3(Field, { label: "Code", children: /* @__PURE__ */ jsx3(TextInput, { placeholder: "e.g. IHS", value: form.code, onChange: (e) => setForm((f) => ({ ...f, code: e.target.value.toUpperCase() })) }) }),
500
- /* @__PURE__ */ jsx3(Field, { label: "Name", children: /* @__PURE__ */ jsx3(TextInput, { placeholder: "e.g. IHS Market Production Forecast", value: form.name, onChange: (e) => setForm((f) => ({ ...f, name: e.target.value })) }) }),
501
- /* @__PURE__ */ jsx3(Field, { label: "Description", children: /* @__PURE__ */ jsx3(TextInput, { value: form.description, onChange: (e) => setForm((f) => ({ ...f, description: e.target.value })) }) }),
502
- /* @__PURE__ */ jsx3(Field, { label: "Volume header format", hint: 'e.g. "MMM yyyy" for "Jan 2025", or "MMM_yyyy VehicleVolume" for AFS', children: /* @__PURE__ */ jsx3(TextInput, { placeholder: "MMM yyyy", value: form.volumeHeaderFormat, onChange: (e) => setForm((f) => ({ ...f, volumeHeaderFormat: e.target.value })) }) }),
503
- /* @__PURE__ */ jsx3(Field, { label: "Header row index (0-based)", children: /* @__PURE__ */ jsx3(TextInput, { type: "number", value: form.headerRowIndex, onChange: (e) => setForm((f) => ({ ...f, headerRowIndex: parseInt(e.target.value, 10) || 0 })) }) })
948
+ /* @__PURE__ */ jsx4(Field, { label: "Code", children: /* @__PURE__ */ jsx4(TextInput, { placeholder: "e.g. IHS", value: form.code, onChange: (e) => setForm((f) => ({ ...f, code: e.target.value.toUpperCase() })) }) }),
949
+ /* @__PURE__ */ jsx4(Field, { label: "Name", children: /* @__PURE__ */ jsx4(TextInput, { placeholder: "e.g. IHS Market Production Forecast", value: form.name, onChange: (e) => setForm((f) => ({ ...f, name: e.target.value })) }) }),
950
+ /* @__PURE__ */ jsx4(Field, { label: "Description", children: /* @__PURE__ */ jsx4(TextInput, { value: form.description, onChange: (e) => setForm((f) => ({ ...f, description: e.target.value })) }) }),
951
+ /* @__PURE__ */ jsx4(Field, { label: "Volume header format", hint: 'e.g. "MMM yyyy" for "Jan 2025", or "MMM_yyyy VehicleVolume" for AFS', children: /* @__PURE__ */ jsx4(TextInput, { placeholder: "MMM yyyy", value: form.volumeHeaderFormat, onChange: (e) => setForm((f) => ({ ...f, volumeHeaderFormat: e.target.value })) }) }),
952
+ /* @__PURE__ */ jsx4(Field, { label: "Header row index (0-based)", children: /* @__PURE__ */ jsx4(TextInput, { type: "number", value: form.headerRowIndex, onChange: (e) => setForm((f) => ({ ...f, headerRowIndex: parseInt(e.target.value, 10) || 0 })) }) })
504
953
  ]
505
954
  }
506
955
  ),
507
- /* @__PURE__ */ jsxs3(
956
+ /* @__PURE__ */ jsxs4(
508
957
  Modal,
509
958
  {
510
959
  open: showTemplates,
511
960
  onClose: () => setShowTemplates(false),
512
961
  title: "Add source from template",
513
- footer: /* @__PURE__ */ jsx3(Btn, { variant: "outline", onClick: () => setShowTemplates(false), children: "Close" }),
962
+ footer: /* @__PURE__ */ jsx4(Btn, { variant: "outline", onClick: () => setShowTemplates(false), children: "Close" }),
514
963
  children: [
515
- /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", children: "Templates ship with their segments and default mappings wired up \u2014 pick one to skip manual setup. You can rename, edit columns, or change the layout on the source detail page afterward." }),
516
- availableTemplates.length === 0 ? /* @__PURE__ */ jsxs3("p", { className: "cfi-vi-muted", children: [
964
+ /* @__PURE__ */ jsx4("p", { className: "cfi-vi-muted", children: "Templates ship with their segments and default mappings wired up \u2014 pick one to skip manual setup. You can rename, edit columns, or change the layout on the source detail page afterward." }),
965
+ availableTemplates.length === 0 ? /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-muted", children: [
517
966
  "You already have every available template. Use ",
518
- /* @__PURE__ */ jsx3("strong", { children: "Add Source" }),
967
+ /* @__PURE__ */ jsx4("strong", { children: "Add Source" }),
519
968
  " to add another by hand."
520
- ] }) : availableTemplates.map((t) => /* @__PURE__ */ jsxs3(Card, { className: "cfi-vi-card--hover", children: [
521
- /* @__PURE__ */ jsx3(CardHeader, { children: /* @__PURE__ */ jsxs3("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
522
- /* @__PURE__ */ jsxs3("span", { className: "cfi-vi-card-title", children: [
969
+ ] }) : availableTemplates.map((t) => /* @__PURE__ */ jsxs4(Card, { className: "cfi-vi-card--hover", children: [
970
+ /* @__PURE__ */ jsx4(CardHeader, { children: /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
971
+ /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-card-title", children: [
523
972
  t.name,
524
973
  " ",
525
- /* @__PURE__ */ jsx3(Badge, { variant: "outline", children: t.code })
974
+ /* @__PURE__ */ jsx4(Badge, { variant: "outline", children: t.code })
526
975
  ] }),
527
- /* @__PURE__ */ jsx3(Btn, { size: "sm", onClick: () => void handleAddFromTemplate(t.code), disabled: addingTemplate !== null, children: addingTemplate === t.code ? "Adding\u2026" : "Add" })
976
+ /* @__PURE__ */ jsx4(Btn, { size: "sm", onClick: () => void handleAddFromTemplate(t.code), disabled: addingTemplate !== null, children: addingTemplate === t.code ? "Adding\u2026" : "Add" })
528
977
  ] }) }),
529
- t.description && /* @__PURE__ */ jsx3(CardBody, { children: /* @__PURE__ */ jsx3("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)" }, children: t.description }) })
978
+ t.description && /* @__PURE__ */ jsx4(CardBody, { children: /* @__PURE__ */ jsx4("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)" }, children: t.description }) })
530
979
  ] }, t.code))
531
980
  ]
532
981
  }
@@ -535,7 +984,7 @@ function VolumeSourcesList({ transport, onOpenSource, renderActiveSourceExtras,
535
984
  }
536
985
 
537
986
  // src/UnifiedSegmentMapper.tsx
538
- import { useEffect as useEffect3, useMemo as useMemo2, useState as useState3 } from "react";
987
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
539
988
  import { Search, CheckCircle2 as CheckCircle22 } from "lucide-react";
540
989
 
541
990
  // src/constants.ts
@@ -566,7 +1015,7 @@ var AUTOMOTIVE_TRANSFORM_LABELS = {
566
1015
  };
567
1016
 
568
1017
  // src/UnifiedSegmentMapper.tsx
569
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1018
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
570
1019
  var LEVELS = [1, 2, 3, 4, 5, 6];
571
1020
  function UnifiedSegmentMapper({
572
1021
  segments,
@@ -581,12 +1030,12 @@ function UnifiedSegmentMapper({
581
1030
  baseHierarchyHint
582
1031
  }) {
583
1032
  const isSparse = hierarchyMode === "sparse";
584
- const [hierAssign, setHierAssign] = useState3({});
585
- const [autoAssign, setAutoAssign] = useState3({});
586
- const [searchQuery, setSearchQuery] = useState3("");
587
- const [dragging, setDragging] = useState3(null);
588
- const [dropTarget, setDropTarget] = useState3(null);
589
- useEffect3(() => {
1033
+ const [hierAssign, setHierAssign] = useState4({});
1034
+ const [autoAssign, setAutoAssign] = useState4({});
1035
+ const [searchQuery, setSearchQuery] = useState4("");
1036
+ const [dragging, setDragging] = useState4(null);
1037
+ const [dropTarget, setDropTarget] = useState4(null);
1038
+ useEffect4(() => {
590
1039
  const initHier = {};
591
1040
  for (const lv of LEVELS) {
592
1041
  initHier[lv] = hierarchyInitial.find((m) => m.targetKey === `level${lv}`)?.segmentId ?? null;
@@ -602,18 +1051,18 @@ function UnifiedSegmentMapper({
602
1051
  }
603
1052
  setAutoAssign(initAuto);
604
1053
  }, [hierarchyInitial, automotiveInitial, automotiveSlots]);
605
- const segmentById = useMemo2(() => new Map(segments.map((s) => [s.id, s])), [segments]);
606
- const usedIds = useMemo2(() => {
1054
+ const segmentById = useMemo3(() => new Map(segments.map((s) => [s.id, s])), [segments]);
1055
+ const usedIds = useMemo3(() => {
607
1056
  const s = /* @__PURE__ */ new Set();
608
1057
  for (const v of Object.values(hierAssign)) if (v) s.add(v);
609
1058
  for (const a of Object.values(autoAssign)) if (a.segmentId) s.add(a.segmentId);
610
1059
  return s;
611
1060
  }, [hierAssign, autoAssign]);
612
- const poolSegments = useMemo2(() => {
1061
+ const poolSegments = useMemo3(() => {
613
1062
  const q = searchQuery.trim().toLowerCase();
614
1063
  return segments.filter((s) => !usedIds.has(s.id)).filter((s) => !q || s.label.toLowerCase().includes(q)).sort((a, b) => a.label.localeCompare(b.label));
615
1064
  }, [segments, usedIds, searchQuery]);
616
- const hierarchyCoveredKeys = useMemo2(() => {
1065
+ const hierarchyCoveredKeys = useMemo3(() => {
617
1066
  const covered = /* @__PURE__ */ new Set();
618
1067
  for (const slot of automotiveSlots) {
619
1068
  if (slot.hierarchyCoveredByLevel == null) continue;
@@ -622,7 +1071,7 @@ function UnifiedSegmentMapper({
622
1071
  }
623
1072
  return covered;
624
1073
  }, [automotiveSlots, hierAssign, autoAssign]);
625
- const hierarchyErrors = useMemo2(() => {
1074
+ const hierarchyErrors = useMemo3(() => {
626
1075
  if (isSparse) return [];
627
1076
  const errors = [];
628
1077
  for (let n = 2; n <= 6; n++) {
@@ -632,7 +1081,7 @@ function UnifiedSegmentMapper({
632
1081
  }
633
1082
  return errors;
634
1083
  }, [hierAssign, isSparse]);
635
- const missingAutomotive = useMemo2(() => {
1084
+ const missingAutomotive = useMemo3(() => {
636
1085
  const out = [];
637
1086
  for (const slot of automotiveSlots) {
638
1087
  if (hierarchyCoveredKeys.has(slot.key)) continue;
@@ -641,7 +1090,7 @@ function UnifiedSegmentMapper({
641
1090
  }
642
1091
  return out;
643
1092
  }, [automotiveSlots, hierarchyCoveredKeys, hierAssign, autoAssign]);
644
- const isDirty = useMemo2(() => {
1093
+ const isDirty = useMemo3(() => {
645
1094
  for (const lv of LEVELS) {
646
1095
  const cur = hierAssign[lv] ?? null;
647
1096
  const saved = hierarchyInitial.find((m) => m.targetKey === `level${lv}`)?.segmentId ?? null;
@@ -740,14 +1189,14 @@ function UnifiedSegmentMapper({
740
1189
  await onSave(hierEntries, autoEntries);
741
1190
  }
742
1191
  void transformRules;
743
- return /* @__PURE__ */ jsxs4("div", { className: "cfi-vi cfi-vi-mapper", children: [
744
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-mapper-col", children: [
745
- /* @__PURE__ */ jsxs4("section", { className: "cfi-vi-mapper-section", children: [
746
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-mapper-section-head", children: [
747
- /* @__PURE__ */ jsx4("h3", { className: "cfi-vi-mapper-h3", children: "Hierarchy Tree" }),
748
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-mapper-note", children: isSparse ? "Drag chips onto whichever levels your file actually has. Empty levels are fine." : "Drag a chip onto a level. L(n) needs L(n\u22121) first." })
1192
+ return /* @__PURE__ */ jsxs5("div", { className: "cfi-vi cfi-vi-mapper", children: [
1193
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-mapper-col", children: [
1194
+ /* @__PURE__ */ jsxs5("section", { className: "cfi-vi-mapper-section", children: [
1195
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-mapper-section-head", children: [
1196
+ /* @__PURE__ */ jsx5("h3", { className: "cfi-vi-mapper-h3", children: "Hierarchy Tree" }),
1197
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-mapper-note", children: isSparse ? "Drag chips onto whichever levels your file actually has. Empty levels are fine." : "Drag a chip onto a level. L(n) needs L(n\u22121) first." })
749
1198
  ] }),
750
- /* @__PURE__ */ jsx4("div", { className: "cfi-vi-mapper-box", children: LEVELS.map((level) => /* @__PURE__ */ jsx4(
1199
+ /* @__PURE__ */ jsx5("div", { className: "cfi-vi-mapper-box", children: LEVELS.map((level) => /* @__PURE__ */ jsx5(
751
1200
  HierarchyRow,
752
1201
  {
753
1202
  level,
@@ -765,21 +1214,21 @@ function UnifiedSegmentMapper({
765
1214
  },
766
1215
  level
767
1216
  )) }),
768
- hierarchyErrors.length > 0 && /* @__PURE__ */ jsx4("div", { children: hierarchyErrors.map((err) => /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-mapper-err", children: [
1217
+ hierarchyErrors.length > 0 && /* @__PURE__ */ jsx5("div", { children: hierarchyErrors.map((err) => /* @__PURE__ */ jsxs5("p", { className: "cfi-vi-mapper-err", children: [
769
1218
  "\u26A0 ",
770
1219
  err
771
1220
  ] }, err)) })
772
1221
  ] }),
773
- automotiveSlots.length > 0 && /* @__PURE__ */ jsxs4("section", { className: "cfi-vi-mapper-section", children: [
774
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-mapper-section-head", children: [
775
- /* @__PURE__ */ jsx4("h3", { className: "cfi-vi-mapper-h3", children: "Automotive Fields" }),
776
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-mapper-note", children: "Brand / Nameplate / Plant Name come from the hierarchy unless overridden." })
1222
+ automotiveSlots.length > 0 && /* @__PURE__ */ jsxs5("section", { className: "cfi-vi-mapper-section", children: [
1223
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-mapper-section-head", children: [
1224
+ /* @__PURE__ */ jsx5("h3", { className: "cfi-vi-mapper-h3", children: "Automotive Fields" }),
1225
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-mapper-note", children: "Brand / Nameplate / Plant Name come from the hierarchy unless overridden." })
777
1226
  ] }),
778
- /* @__PURE__ */ jsx4("div", { className: "cfi-vi-mapper-box", children: automotiveSlots.map((slot) => {
1227
+ /* @__PURE__ */ jsx5("div", { className: "cfi-vi-mapper-box", children: automotiveSlots.map((slot) => {
779
1228
  const covered = hierarchyCoveredKeys.has(slot.key);
780
1229
  const hierarchySegId = slot.hierarchyCoveredByLevel != null ? hierAssign[slot.hierarchyCoveredByLevel] : null;
781
1230
  const assignment = autoAssign[slot.key];
782
- return /* @__PURE__ */ jsx4(
1231
+ return /* @__PURE__ */ jsx5(
783
1232
  AutomotiveRow,
784
1233
  {
785
1234
  slot,
@@ -801,32 +1250,32 @@ function UnifiedSegmentMapper({
801
1250
  slot.key
802
1251
  );
803
1252
  }) }),
804
- missingAutomotive.length > 0 && /* @__PURE__ */ jsxs4("p", { className: "cfi-vi-mapper-err", children: [
1253
+ missingAutomotive.length > 0 && /* @__PURE__ */ jsxs5("p", { className: "cfi-vi-mapper-err", children: [
805
1254
  "\u26A0 Required: ",
806
1255
  missingAutomotive.join(", ")
807
1256
  ] })
808
1257
  ] }),
809
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-mapper-save", children: [
810
- /* @__PURE__ */ jsx4(Btn, { size: "sm", onClick: handleSave, disabled: !canSave, children: saving ? "Saving\u2026" : "Save Mapping" }),
811
- isDirty && hierarchyErrors.length === 0 && missingAutomotive.length === 0 && !saving && /* @__PURE__ */ jsx4("span", { className: "cfi-vi-mapper-dirty", children: "Unsaved changes" }),
812
- !isDirty && /* @__PURE__ */ jsx4("span", { className: "cfi-vi-muted", children: "Up to date" })
1258
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-mapper-save", children: [
1259
+ /* @__PURE__ */ jsx5(Btn, { size: "sm", onClick: handleSave, disabled: !canSave, children: saving ? "Saving\u2026" : "Save Mapping" }),
1260
+ isDirty && hierarchyErrors.length === 0 && missingAutomotive.length === 0 && !saving && /* @__PURE__ */ jsx5("span", { className: "cfi-vi-mapper-dirty", children: "Unsaved changes" }),
1261
+ !isDirty && /* @__PURE__ */ jsx5("span", { className: "cfi-vi-muted", children: "Up to date" })
813
1262
  ] })
814
1263
  ] }),
815
- /* @__PURE__ */ jsxs4("aside", { className: "cfi-vi-pool-col", children: [
816
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-mapper-section-head", children: [
817
- /* @__PURE__ */ jsx4("h3", { className: "cfi-vi-mapper-h3", children: "Segment Pool" }),
818
- /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-mapper-note", children: [
1264
+ /* @__PURE__ */ jsxs5("aside", { className: "cfi-vi-pool-col", children: [
1265
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-mapper-section-head", children: [
1266
+ /* @__PURE__ */ jsx5("h3", { className: "cfi-vi-mapper-h3", children: "Segment Pool" }),
1267
+ /* @__PURE__ */ jsxs5("span", { className: "cfi-vi-mapper-note", children: [
819
1268
  poolSegments.length,
820
1269
  " of ",
821
1270
  segments.length,
822
1271
  " unused"
823
1272
  ] })
824
1273
  ] }),
825
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-search", children: [
826
- /* @__PURE__ */ jsx4(Search, { size: 14, className: "cfi-vi-search-icon", "aria-hidden": true }),
827
- /* @__PURE__ */ jsx4(TextInput, { type: "search", placeholder: "Filter segments\u2026", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })
1274
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-search", children: [
1275
+ /* @__PURE__ */ jsx5(Search, { size: 14, className: "cfi-vi-search-icon", "aria-hidden": true }),
1276
+ /* @__PURE__ */ jsx5(TextInput, { type: "search", placeholder: "Filter segments\u2026", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })
828
1277
  ] }),
829
- /* @__PURE__ */ jsx4(
1278
+ /* @__PURE__ */ jsx5(
830
1279
  "div",
831
1280
  {
832
1281
  className: `cfi-vi-pool ${dropTarget === "pool" ? "cfi-vi-pool--active" : ""}`,
@@ -841,10 +1290,10 @@ function UnifiedSegmentMapper({
841
1290
  e.preventDefault();
842
1291
  if (dragging) dropOnPool(dragging);
843
1292
  },
844
- children: segments.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "cfi-vi-pool-empty", children: "No segments detected. Run \u201CDetect segments\u201D from the source page first." }) : poolSegments.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "cfi-vi-pool-empty", children: searchQuery ? "No segments match the filter." : "All segments assigned \u2014 drop a chip here to return it." }) : /* @__PURE__ */ jsx4("div", { className: "cfi-vi-chips", children: poolSegments.map((seg) => /* @__PURE__ */ jsx4(SegmentChip, { label: seg.label, onDragStart: () => startDrag(`pool:${seg.id}`), onDragEnd: endDrag }, seg.id)) })
1293
+ children: segments.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "cfi-vi-pool-empty", children: "No segments detected. Run \u201CDetect segments\u201D from the source page first." }) : poolSegments.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "cfi-vi-pool-empty", children: searchQuery ? "No segments match the filter." : "All segments assigned \u2014 drop a chip here to return it." }) : /* @__PURE__ */ jsx5("div", { className: "cfi-vi-chips", children: poolSegments.map((seg) => /* @__PURE__ */ jsx5(SegmentChip, { label: seg.label, onDragStart: () => startDrag(`pool:${seg.id}`), onDragEnd: endDrag }, seg.id)) })
845
1294
  }
846
1295
  ),
847
- /* @__PURE__ */ jsx4("p", { className: "cfi-vi-mapper-note", children: "Drag chips onto a hierarchy level or an automotive field. Drop a chip back here to unassign." })
1296
+ /* @__PURE__ */ jsx5("p", { className: "cfi-vi-mapper-note", children: "Drag chips onto a hierarchy level or an automotive field. Drop a chip back here to unassign." })
848
1297
  ] })
849
1298
  ] });
850
1299
  }
@@ -866,12 +1315,12 @@ function HierarchyRow({
866
1315
  const isLeaf = level === 6;
867
1316
  const indent = sparse ? 0 : (level - 1) * 22;
868
1317
  const levelName = DEFAULT_LEVEL_NAMES[level];
869
- return /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-hier-row", style: { paddingLeft: `${indent}px` }, children: [
870
- !sparse && level > 1 && /* @__PURE__ */ jsx4("div", { className: "cfi-vi-hier-elbow" }),
871
- /* @__PURE__ */ jsx4("div", { className: `cfi-vi-hier-dot ${seg ? "cfi-vi-hier-dot--filled" : ""}` }),
872
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-hier-name", children: levelName }),
873
- isLeaf && !sparse && /* @__PURE__ */ jsx4("span", { className: "cfi-vi-leaf", children: "Leaf" }),
874
- /* @__PURE__ */ jsx4(
1318
+ return /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-hier-row", style: { paddingLeft: `${indent}px` }, children: [
1319
+ !sparse && level > 1 && /* @__PURE__ */ jsx5("div", { className: "cfi-vi-hier-elbow" }),
1320
+ /* @__PURE__ */ jsx5("div", { className: `cfi-vi-hier-dot ${seg ? "cfi-vi-hier-dot--filled" : ""}` }),
1321
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-hier-name", children: levelName }),
1322
+ isLeaf && !sparse && /* @__PURE__ */ jsx5("span", { className: "cfi-vi-leaf", children: "Leaf" }),
1323
+ /* @__PURE__ */ jsx5(
875
1324
  "div",
876
1325
  {
877
1326
  className: `cfi-vi-dropzone ${isDropTarget ? "cfi-vi-dropzone--active" : seg ? "cfi-vi-dropzone--filled" : "cfi-vi-dropzone--empty"}`,
@@ -886,10 +1335,10 @@ function HierarchyRow({
886
1335
  e.preventDefault();
887
1336
  onDrop();
888
1337
  },
889
- children: seg ? /* @__PURE__ */ jsx4(AssignedChip, { seg, onDragStart: () => onChipDragStart(seg.id), onDragEnd: onChipDragEnd, onRemove: onChipRemove }) : /* @__PURE__ */ jsx4("span", { className: "cfi-vi-dropzone-ph", children: isDropTarget ? "Drop here" : "Drop a segment\u2026" })
1338
+ children: seg ? /* @__PURE__ */ jsx5(AssignedChip, { seg, onDragStart: () => onChipDragStart(seg.id), onDragEnd: onChipDragEnd, onRemove: onChipRemove }) : /* @__PURE__ */ jsx5("span", { className: "cfi-vi-dropzone-ph", children: isDropTarget ? "Drop here" : "Drop a segment\u2026" })
890
1339
  }
891
1340
  ),
892
- baseHint && /* @__PURE__ */ jsxs4("span", { className: "cfi-vi-base-hint", title: `Base source uses "${baseHint}" on ${levelName}. Match here for the overlay to join.`, children: [
1341
+ baseHint && /* @__PURE__ */ jsxs5("span", { className: "cfi-vi-base-hint", title: `Base source uses "${baseHint}" on ${levelName}. Match here for the overlay to join.`, children: [
893
1342
  "base: ",
894
1343
  baseHint
895
1344
  ] })
@@ -913,20 +1362,20 @@ function AutomotiveRow({
913
1362
  }) {
914
1363
  const assignedSeg = assignment?.segmentId ? segmentById.get(assignment.segmentId) : void 0;
915
1364
  const requiredBadge = (slot.required || hierarchyEmpty) && !covered && !assignedSeg;
916
- return /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-auto-row", children: [
917
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-auto-label", children: [
918
- /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-row", children: [
919
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-auto-label-text", children: slot.label }),
920
- requiredBadge && /* @__PURE__ */ jsx4(Badge, { variant: "outline", children: "required" })
1365
+ return /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-auto-row", children: [
1366
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-auto-label", children: [
1367
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-row", children: [
1368
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-auto-label-text", children: slot.label }),
1369
+ requiredBadge && /* @__PURE__ */ jsx5(Badge, { variant: "outline", children: "required" })
921
1370
  ] }),
922
- slot.hierarchyCoveredByLevel != null && /* @__PURE__ */ jsxs4("p", { className: `cfi-vi-auto-cover ${covered ? "cfi-vi-auto-cover--on" : ""}`, children: [
1371
+ slot.hierarchyCoveredByLevel != null && /* @__PURE__ */ jsxs5("p", { className: `cfi-vi-auto-cover ${covered ? "cfi-vi-auto-cover--on" : ""}`, children: [
923
1372
  covered ? "\u2713 " : "",
924
1373
  "From L",
925
1374
  slot.hierarchyCoveredByLevel,
926
1375
  " hierarchy"
927
1376
  ] })
928
1377
  ] }),
929
- /* @__PURE__ */ jsx4(
1378
+ /* @__PURE__ */ jsx5(
930
1379
  "div",
931
1380
  {
932
1381
  className: `cfi-vi-dropzone ${isDropTarget ? "cfi-vi-dropzone--active" : assignedSeg ? "cfi-vi-dropzone--filled" : covered ? "cfi-vi-dropzone--covered" : "cfi-vi-dropzone--empty"}`,
@@ -941,15 +1390,15 @@ function AutomotiveRow({
941
1390
  e.preventDefault();
942
1391
  onDrop();
943
1392
  },
944
- children: assignedSeg ? /* @__PURE__ */ jsx4(AssignedChip, { seg: assignedSeg, onDragStart: () => onChipDragStart(assignedSeg.id), onDragEnd: onChipDragEnd, onRemove: onChipRemove }) : covered && hierarchySegment ? /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-auto-auto", title: "Auto-supplied from hierarchy. Drop a different chip here to override.", children: [
945
- /* @__PURE__ */ jsx4(CheckCircle22, { size: 14, "aria-hidden": true }),
946
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-auto-auto-label", children: hierarchySegment.label }),
947
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-auto-auto-tag", children: "auto" })
948
- ] }) : /* @__PURE__ */ jsx4("span", { className: "cfi-vi-dropzone-ph", children: isDropTarget ? "Drop here" : "Drop a segment\u2026" })
1393
+ children: assignedSeg ? /* @__PURE__ */ jsx5(AssignedChip, { seg: assignedSeg, onDragStart: () => onChipDragStart(assignedSeg.id), onDragEnd: onChipDragEnd, onRemove: onChipRemove }) : covered && hierarchySegment ? /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-auto-auto", title: "Auto-supplied from hierarchy. Drop a different chip here to override.", children: [
1394
+ /* @__PURE__ */ jsx5(CheckCircle22, { size: 14, "aria-hidden": true }),
1395
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-auto-auto-label", children: hierarchySegment.label }),
1396
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-auto-auto-tag", children: "auto" })
1397
+ ] }) : /* @__PURE__ */ jsx5("span", { className: "cfi-vi-dropzone-ph", children: isDropTarget ? "Drop here" : "Drop a segment\u2026" })
949
1398
  }
950
1399
  ),
951
- slot.defaultTransform && !covered && /* @__PURE__ */ jsxs4("div", { className: "cfi-vi-auto-transform", children: [
952
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-auto-transform-label", children: "Transform:" }),
1400
+ slot.defaultTransform && !covered && /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-auto-transform", children: [
1401
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-auto-transform-label", children: "Transform:" }),
953
1402
  " ",
954
1403
  transformRuleLabels[slot.defaultTransform] ?? slot.defaultTransform
955
1404
  ] })
@@ -961,38 +1410,38 @@ function AssignedChip({
961
1410
  onDragEnd,
962
1411
  onRemove
963
1412
  }) {
964
- return /* @__PURE__ */ jsxs4("div", { draggable: true, onDragStart, onDragEnd, className: "cfi-vi-chip--assigned", children: [
965
- /* @__PURE__ */ jsx4("div", { className: "cfi-vi-chip-dot cfi-vi-chip-dot--on" }),
966
- /* @__PURE__ */ jsx4("span", { className: "cfi-vi-chip-label", children: seg.label }),
967
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: (e) => {
1413
+ return /* @__PURE__ */ jsxs5("div", { draggable: true, onDragStart, onDragEnd, className: "cfi-vi-chip--assigned", children: [
1414
+ /* @__PURE__ */ jsx5("div", { className: "cfi-vi-chip-dot cfi-vi-chip-dot--on" }),
1415
+ /* @__PURE__ */ jsx5("span", { className: "cfi-vi-chip-label", children: seg.label }),
1416
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: (e) => {
968
1417
  e.stopPropagation();
969
1418
  onRemove();
970
1419
  }, className: "cfi-vi-chip-x", title: "Remove \u2014 returns to pool", children: "\xD7" })
971
1420
  ] });
972
1421
  }
973
1422
  function SegmentChip({ label, onDragStart, onDragEnd }) {
974
- return /* @__PURE__ */ jsxs4("div", { draggable: true, onDragStart, onDragEnd, className: "cfi-vi-chip", children: [
975
- /* @__PURE__ */ jsx4("div", { className: "cfi-vi-chip-dot" }),
1423
+ return /* @__PURE__ */ jsxs5("div", { draggable: true, onDragStart, onDragEnd, className: "cfi-vi-chip", children: [
1424
+ /* @__PURE__ */ jsx5("div", { className: "cfi-vi-chip-dot" }),
976
1425
  label
977
1426
  ] });
978
1427
  }
979
1428
 
980
1429
  // src/VolumeSourceDetail.tsx
981
- import { useEffect as useEffect6, useRef as useRef2, useState as useState6 } from "react";
982
- import { KeyRound, Lock, Rows, Columns, AlertTriangle as AlertTriangle2, Layers } from "lucide-react";
1430
+ import { useEffect as useEffect7, useRef as useRef3, useState as useState7 } from "react";
1431
+ import { KeyRound, Lock, Rows, Columns, AlertTriangle as AlertTriangle3, Layers } from "lucide-react";
983
1432
 
984
1433
  // src/TallLayoutMappings.tsx
985
- import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
986
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1434
+ import { useEffect as useEffect5, useMemo as useMemo4, useState as useState5 } from "react";
1435
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
987
1436
  var NONE = "__none__";
988
1437
  function TallLayoutMappings({ transport, source, locked }) {
989
- const [loading, setLoading] = useState4(true);
990
- const [saving, setSaving] = useState4(null);
991
- const [error, setError] = useState4(null);
992
- const [periodConfigured, setPeriodConfigured] = useState4(false);
993
- const [valueConfigured, setValueConfigured] = useState4(false);
994
- const [periodSegmentId, setPeriodSegmentId] = useState4(NONE);
995
- const [valueSegmentId, setValueSegmentId] = useState4(NONE);
1438
+ const [loading, setLoading] = useState5(true);
1439
+ const [saving, setSaving] = useState5(null);
1440
+ const [error, setError] = useState5(null);
1441
+ const [periodConfigured, setPeriodConfigured] = useState5(false);
1442
+ const [valueConfigured, setValueConfigured] = useState5(false);
1443
+ const [periodSegmentId, setPeriodSegmentId] = useState5(NONE);
1444
+ const [valueSegmentId, setValueSegmentId] = useState5(NONE);
996
1445
  async function load() {
997
1446
  try {
998
1447
  setLoading(true);
@@ -1010,10 +1459,10 @@ function TallLayoutMappings({ transport, source, locked }) {
1010
1459
  setLoading(false);
1011
1460
  }
1012
1461
  }
1013
- useEffect4(() => {
1462
+ useEffect5(() => {
1014
1463
  void load();
1015
1464
  }, [source.id]);
1016
- const sortedSegments = useMemo3(
1465
+ const sortedSegments = useMemo4(
1017
1466
  () => source.segments.slice().sort((a, b) => a.label.localeCompare(b.label)),
1018
1467
  [source.segments]
1019
1468
  );
@@ -1031,19 +1480,19 @@ function TallLayoutMappings({ transport, source, locked }) {
1031
1480
  setSaving(null);
1032
1481
  }
1033
1482
  }
1034
- if (loading) return /* @__PURE__ */ jsx5("p", { className: "cfi-vi-muted", children: "Loading tall-layout mappings\u2026" });
1483
+ if (loading) return /* @__PURE__ */ jsx6("p", { className: "cfi-vi-muted", children: "Loading tall-layout mappings\u2026" });
1035
1484
  const ready = periodConfigured && valueConfigured;
1036
- return /* @__PURE__ */ jsxs5("section", { className: "cfi-vi-panel", children: [
1037
- /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
1038
- /* @__PURE__ */ jsx5("h2", { className: "cfi-vi-h2", children: "Tall-Layout Mappings" }),
1039
- /* @__PURE__ */ jsx5("span", { style: { fontSize: "var(--cfi-font-size-xs, 12px)", color: ready ? "#16a34a" : "#b45309" }, children: ready ? "Ready for upload" : "Missing period or value mapping" })
1485
+ return /* @__PURE__ */ jsxs6("section", { className: "cfi-vi-panel", children: [
1486
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
1487
+ /* @__PURE__ */ jsx6("h2", { className: "cfi-vi-h2", children: "Tall-Layout Mappings" }),
1488
+ /* @__PURE__ */ jsx6("span", { style: { fontSize: "var(--cfi-font-size-xs, 12px)", color: ready ? "#16a34a" : "#b45309" }, children: ready ? "Ready for upload" : "Missing period or value mapping" })
1040
1489
  ] }),
1041
- /* @__PURE__ */ jsx5("p", { className: "cfi-vi-muted", children: "Tall sources need to know which file column carries the period date and the volume value." }),
1042
- error && /* @__PURE__ */ jsx5("p", { className: "cfi-vi-error", children: error }),
1043
- /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-field", children: [
1044
- /* @__PURE__ */ jsx5("label", { className: "cfi-vi-label", children: "Period column (Week Ending)" }),
1045
- /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-row", children: [
1046
- /* @__PURE__ */ jsxs5(
1490
+ /* @__PURE__ */ jsx6("p", { className: "cfi-vi-muted", children: "Tall sources need to know which file column carries the period date and the volume value." }),
1491
+ error && /* @__PURE__ */ jsx6("p", { className: "cfi-vi-error", children: error }),
1492
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-field", children: [
1493
+ /* @__PURE__ */ jsx6("label", { className: "cfi-vi-label", children: "Period column (Week Ending)" }),
1494
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row", children: [
1495
+ /* @__PURE__ */ jsxs6(
1047
1496
  "select",
1048
1497
  {
1049
1498
  className: "cfi-vi-input",
@@ -1051,18 +1500,18 @@ function TallLayoutMappings({ transport, source, locked }) {
1051
1500
  disabled: locked || saving !== null,
1052
1501
  onChange: (e) => setPeriodSegmentId(e.target.value),
1053
1502
  children: [
1054
- /* @__PURE__ */ jsx5("option", { value: NONE, children: "\u2014 Not mapped \u2014" }),
1055
- sortedSegments.map((s) => /* @__PURE__ */ jsx5("option", { value: s.id, children: s.label }, s.id))
1503
+ /* @__PURE__ */ jsx6("option", { value: NONE, children: "\u2014 Not mapped \u2014" }),
1504
+ sortedSegments.map((s) => /* @__PURE__ */ jsx6("option", { value: s.id, children: s.label }, s.id))
1056
1505
  ]
1057
1506
  }
1058
1507
  ),
1059
- /* @__PURE__ */ jsx5(Btn, { size: "sm", onClick: () => void saveCategory("period", periodSegmentId, "week_date"), disabled: locked || saving !== null, children: saving === "period" ? "Saving\u2026" : "Save" })
1508
+ /* @__PURE__ */ jsx6(Btn, { size: "sm", onClick: () => void saveCategory("period", periodSegmentId, "week_date"), disabled: locked || saving !== null, children: saving === "period" ? "Saving\u2026" : "Save" })
1060
1509
  ] })
1061
1510
  ] }),
1062
- /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-field", children: [
1063
- /* @__PURE__ */ jsx5("label", { className: "cfi-vi-label", children: "Quantity column (Volume)" }),
1064
- /* @__PURE__ */ jsxs5("div", { className: "cfi-vi-row", children: [
1065
- /* @__PURE__ */ jsxs5(
1511
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-field", children: [
1512
+ /* @__PURE__ */ jsx6("label", { className: "cfi-vi-label", children: "Quantity column (Volume)" }),
1513
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row", children: [
1514
+ /* @__PURE__ */ jsxs6(
1066
1515
  "select",
1067
1516
  {
1068
1517
  className: "cfi-vi-input",
@@ -1070,31 +1519,31 @@ function TallLayoutMappings({ transport, source, locked }) {
1070
1519
  disabled: locked || saving !== null,
1071
1520
  onChange: (e) => setValueSegmentId(e.target.value),
1072
1521
  children: [
1073
- /* @__PURE__ */ jsx5("option", { value: NONE, children: "\u2014 Not mapped \u2014" }),
1074
- sortedSegments.map((s) => /* @__PURE__ */ jsx5("option", { value: s.id, children: s.label }, s.id))
1522
+ /* @__PURE__ */ jsx6("option", { value: NONE, children: "\u2014 Not mapped \u2014" }),
1523
+ sortedSegments.map((s) => /* @__PURE__ */ jsx6("option", { value: s.id, children: s.label }, s.id))
1075
1524
  ]
1076
1525
  }
1077
1526
  ),
1078
- /* @__PURE__ */ jsx5(Btn, { size: "sm", onClick: () => void saveCategory("value", valueSegmentId, "quantity"), disabled: locked || saving !== null, children: saving === "value" ? "Saving\u2026" : "Save" })
1527
+ /* @__PURE__ */ jsx6(Btn, { size: "sm", onClick: () => void saveCategory("value", valueSegmentId, "quantity"), disabled: locked || saving !== null, children: saving === "value" ? "Saving\u2026" : "Save" })
1079
1528
  ] })
1080
1529
  ] })
1081
1530
  ] });
1082
1531
  }
1083
1532
 
1084
1533
  // src/ValueAliasesCard.tsx
1085
- import { useEffect as useEffect5, useMemo as useMemo4, useState as useState5 } from "react";
1534
+ import { useEffect as useEffect6, useMemo as useMemo5, useState as useState6 } from "react";
1086
1535
  import { Plus, Trash2, ArrowRight, Save, RotateCw } from "lucide-react";
1087
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1536
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1088
1537
  function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1089
- const [selectedLevel, setSelectedLevel] = useState5(4);
1090
- const [aliases, setAliases] = useState5([]);
1091
- const [draft, setDraft] = useState5([]);
1092
- const [saving, setSaving] = useState5(false);
1093
- const [error, setError] = useState5(null);
1094
- const [loading, setLoading] = useState5(true);
1095
- const [relinking, setRelinking] = useState5(false);
1096
- const [relinkResult, setRelinkResult] = useState5(null);
1097
- useEffect5(() => {
1538
+ const [selectedLevel, setSelectedLevel] = useState6(4);
1539
+ const [aliases, setAliases] = useState6([]);
1540
+ const [draft, setDraft] = useState6([]);
1541
+ const [saving, setSaving] = useState6(false);
1542
+ const [error, setError] = useState6(null);
1543
+ const [loading, setLoading] = useState6(true);
1544
+ const [relinking, setRelinking] = useState6(false);
1545
+ const [relinkResult, setRelinkResult] = useState6(null);
1546
+ useEffect6(() => {
1098
1547
  let cancelled = false;
1099
1548
  setLoading(true);
1100
1549
  void transport.listValueAliases(sourceId).then((items) => {
@@ -1111,12 +1560,12 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1111
1560
  cancelled = true;
1112
1561
  };
1113
1562
  }, [sourceId, transport]);
1114
- useEffect5(() => {
1563
+ useEffect6(() => {
1115
1564
  setDraft(
1116
1565
  aliases.filter((a) => a.level === selectedLevel).map((a) => ({ id: a.id, rawValue: a.rawValue, canonicalValue: a.canonicalValue }))
1117
1566
  );
1118
1567
  }, [aliases, selectedLevel]);
1119
- const isDirty = useMemo4(() => {
1568
+ const isDirty = useMemo5(() => {
1120
1569
  const saved = aliases.filter((a) => a.level === selectedLevel).map((a) => `${a.rawValue}${a.canonicalValue}`).sort();
1121
1570
  const current = draft.filter((d) => d.rawValue.trim() && d.canonicalValue.trim()).map((d) => `${d.rawValue.trim().toUpperCase()}${d.canonicalValue.trim().toUpperCase()}`).sort();
1122
1571
  if (saved.length !== current.length) return true;
@@ -1152,20 +1601,20 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1152
1601
  setSaving(false);
1153
1602
  }
1154
1603
  }
1155
- if (loading) return /* @__PURE__ */ jsx6("p", { className: "cfi-vi-muted", children: "Loading aliases\u2026" });
1156
- return /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-aliases", children: [
1157
- /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
1158
- /* @__PURE__ */ jsxs6("div", { children: [
1159
- /* @__PURE__ */ jsx6("h2", { className: "cfi-vi-h2", children: "Value Aliases" }),
1160
- /* @__PURE__ */ jsxs6("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)" }, children: [
1604
+ if (loading) return /* @__PURE__ */ jsx7("p", { className: "cfi-vi-muted", children: "Loading aliases\u2026" });
1605
+ return /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-aliases", children: [
1606
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row cfi-vi-row--between", children: [
1607
+ /* @__PURE__ */ jsxs7("div", { children: [
1608
+ /* @__PURE__ */ jsx7("h2", { className: "cfi-vi-h2", children: "Value Aliases" }),
1609
+ /* @__PURE__ */ jsxs7("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 11px)" }, children: [
1161
1610
  "Normalise level values when this source uses different vocabulary than the base/overlay it joins to (e.g. ",
1162
- /* @__PURE__ */ jsx6("span", { className: "cfi-vi-mono", children: '"MICHIGAN" \u2192 "MICHIGAN ASSEMBLY"' }),
1611
+ /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mono", children: '"MICHIGAN" \u2192 "MICHIGAN ASSEMBLY"' }),
1163
1612
  "). Applied at match time \u2014 no re-upload."
1164
1613
  ] })
1165
1614
  ] }),
1166
- /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-field", style: { minWidth: 140 }, children: [
1167
- /* @__PURE__ */ jsx6("label", { className: "cfi-vi-label", children: "Level" }),
1168
- /* @__PURE__ */ jsx6("select", { className: "cfi-vi-input", value: String(selectedLevel), onChange: (e) => setSelectedLevel(parseInt(e.target.value, 10)), children: [1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxs6("option", { value: n, children: [
1615
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { minWidth: 140 }, children: [
1616
+ /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Level" }),
1617
+ /* @__PURE__ */ jsx7("select", { className: "cfi-vi-input", value: String(selectedLevel), onChange: (e) => setSelectedLevel(parseInt(e.target.value, 10)), children: [1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxs7("option", { value: n, children: [
1169
1618
  "L",
1170
1619
  n,
1171
1620
  " \u2014 ",
@@ -1173,17 +1622,17 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1173
1622
  ] }, n)) })
1174
1623
  ] })
1175
1624
  ] }),
1176
- /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-panel", children: [
1177
- draft.length === 0 ? /* @__PURE__ */ jsxs6("p", { className: "cfi-vi-muted", style: { fontStyle: "italic", fontSize: "var(--cfi-font-size-xs, 12px)" }, children: [
1625
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-panel", children: [
1626
+ draft.length === 0 ? /* @__PURE__ */ jsxs7("p", { className: "cfi-vi-muted", style: { fontStyle: "italic", fontSize: "var(--cfi-font-size-xs, 12px)" }, children: [
1178
1627
  "No aliases at L",
1179
1628
  selectedLevel,
1180
1629
  " (",
1181
1630
  DEFAULT_LEVEL_NAMES[selectedLevel],
1182
1631
  "). Click ",
1183
- /* @__PURE__ */ jsx6("strong", { children: "+ Add alias" }),
1632
+ /* @__PURE__ */ jsx7("strong", { children: "+ Add alias" }),
1184
1633
  " to create one."
1185
- ] }) : /* @__PURE__ */ jsx6("div", { className: "cfi-vi-alias-rows", children: draft.map((row, i) => /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row", children: [
1186
- /* @__PURE__ */ jsx6(
1634
+ ] }) : /* @__PURE__ */ jsx7("div", { className: "cfi-vi-alias-rows", children: draft.map((row, i) => /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", children: [
1635
+ /* @__PURE__ */ jsx7(
1187
1636
  "input",
1188
1637
  {
1189
1638
  className: "cfi-vi-input cfi-vi-mono",
@@ -1194,8 +1643,8 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1194
1643
  onChange: (e) => updateRow(i, { rawValue: e.target.value })
1195
1644
  }
1196
1645
  ),
1197
- /* @__PURE__ */ jsx6(ArrowRight, { size: 14, className: "cfi-vi-muted", "aria-hidden": true }),
1198
- /* @__PURE__ */ jsx6(
1646
+ /* @__PURE__ */ jsx7(ArrowRight, { size: 14, className: "cfi-vi-muted", "aria-hidden": true }),
1647
+ /* @__PURE__ */ jsx7(
1199
1648
  "input",
1200
1649
  {
1201
1650
  className: "cfi-vi-input cfi-vi-mono",
@@ -1206,21 +1655,21 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1206
1655
  onChange: (e) => updateRow(i, { canonicalValue: e.target.value })
1207
1656
  }
1208
1657
  ),
1209
- /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-vi-icon-btn", onClick: () => removeRow(i), disabled: locked, title: "Remove row", children: /* @__PURE__ */ jsx6(Trash2, { size: 14, "aria-hidden": true }) })
1658
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "cfi-vi-icon-btn", onClick: () => removeRow(i), disabled: locked, title: "Remove row", children: /* @__PURE__ */ jsx7(Trash2, { size: 14, "aria-hidden": true }) })
1210
1659
  ] }, i)) }),
1211
- /* @__PURE__ */ jsxs6("div", { className: "cfi-vi-row", style: { flexWrap: "wrap", paddingTop: 4 }, children: [
1212
- /* @__PURE__ */ jsxs6(Btn, { variant: "outline", size: "sm", onClick: addRow, disabled: locked, children: [
1213
- /* @__PURE__ */ jsx6(Plus, { size: 14, "aria-hidden": true }),
1660
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { flexWrap: "wrap", paddingTop: 4 }, children: [
1661
+ /* @__PURE__ */ jsxs7(Btn, { variant: "outline", size: "sm", onClick: addRow, disabled: locked, children: [
1662
+ /* @__PURE__ */ jsx7(Plus, { size: 14, "aria-hidden": true }),
1214
1663
  " Add alias"
1215
1664
  ] }),
1216
- /* @__PURE__ */ jsxs6(Btn, { size: "sm", onClick: () => void handleSave(), disabled: !isDirty || saving || locked, children: [
1217
- /* @__PURE__ */ jsx6(Save, { size: 14, "aria-hidden": true }),
1665
+ /* @__PURE__ */ jsxs7(Btn, { size: "sm", onClick: () => void handleSave(), disabled: !isDirty || saving || locked, children: [
1666
+ /* @__PURE__ */ jsx7(Save, { size: 14, "aria-hidden": true }),
1218
1667
  " ",
1219
1668
  saving ? "Saving\u2026" : "Save"
1220
1669
  ] }),
1221
- isDirty && !saving && /* @__PURE__ */ jsx6("span", { className: "cfi-vi-mapper-dirty", children: "Unsaved changes" }),
1222
- !isDirty && !saving && draft.length > 0 && /* @__PURE__ */ jsx6("span", { className: "cfi-vi-muted", children: "Up to date" }),
1223
- isOverlay && /* @__PURE__ */ jsxs6(
1670
+ isDirty && !saving && /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mapper-dirty", children: "Unsaved changes" }),
1671
+ !isDirty && !saving && draft.length > 0 && /* @__PURE__ */ jsx7("span", { className: "cfi-vi-muted", children: "Up to date" }),
1672
+ isOverlay && /* @__PURE__ */ jsxs7(
1224
1673
  Btn,
1225
1674
  {
1226
1675
  variant: "outline",
@@ -1229,46 +1678,46 @@ function ValueAliasesCard({ transport, sourceId, locked, isOverlay }) {
1229
1678
  disabled: relinking || isDirty,
1230
1679
  title: isDirty ? "Save aliases first, then re-link" : "Re-run overlay \u2192 base resolution against current aliases",
1231
1680
  children: [
1232
- /* @__PURE__ */ jsx6(RotateCw, { size: 14, className: relinking ? "cfi-vi-spin" : "", "aria-hidden": true }),
1681
+ /* @__PURE__ */ jsx7(RotateCw, { size: 14, className: relinking ? "cfi-vi-spin" : "", "aria-hidden": true }),
1233
1682
  " ",
1234
1683
  relinking ? "Re-linking\u2026" : "Re-link overlay"
1235
1684
  ]
1236
1685
  }
1237
1686
  )
1238
1687
  ] }),
1239
- error && /* @__PURE__ */ jsx6("p", { className: "cfi-vi-error", children: error }),
1240
- relinkResult && /* @__PURE__ */ jsx6("p", { style: { fontSize: "var(--cfi-font-size-xs, 12px)", color: "#15803d" }, children: relinkResult })
1688
+ error && /* @__PURE__ */ jsx7("p", { className: "cfi-vi-error", children: error }),
1689
+ relinkResult && /* @__PURE__ */ jsx7("p", { style: { fontSize: "var(--cfi-font-size-xs, 12px)", color: "#15803d" }, children: relinkResult })
1241
1690
  ] })
1242
1691
  ] });
1243
1692
  }
1244
1693
 
1245
1694
  // src/VolumeSourceDetail.tsx
1246
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1695
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1247
1696
  function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, className }) {
1248
1697
  const id = sourceId;
1249
- const [source, setSource] = useState6(null);
1250
- const [allSources, setAllSources] = useState6([]);
1251
- const [loading, setLoading] = useState6(true);
1252
- const [error, setError] = useState6(null);
1253
- const [detecting, setDetecting] = useState6(false);
1254
- const [detectMsg, setDetectMsg] = useState6(null);
1255
- const [savingKey, setSavingKey] = useState6(false);
1256
- const [selectedKeyId, setSelectedKeyId] = useState6("__none__");
1257
- const [hasData, setHasData] = useState6(false);
1258
- const fileRef = useRef2(null);
1259
- const [savingLayout, setSavingLayout] = useState6(false);
1260
- const [editLayout, setEditLayout] = useState6("wide");
1261
- const [editValueDateFormat, setEditValueDateFormat] = useState6("yyyy-MM-dd");
1262
- const [newSegmentLabel, setNewSegmentLabel] = useState6("");
1263
- const [newSegmentDataType, setNewSegmentDataType] = useState6("string");
1264
- const [addingSegment, setAddingSegment] = useState6(false);
1265
- const [clearConfirm, setClearConfirm] = useState6("");
1266
- const [clearing, setClearing] = useState6(false);
1267
- const [clearResult, setClearResult] = useState6(null);
1268
- const [mappingKeys, setMappingKeys] = useState6(null);
1269
- const [mappingRows, setMappingRows] = useState6([]);
1270
- const [savingMapping, setSavingMapping] = useState6(false);
1271
- const [baseHierarchyHint, setBaseHierarchyHint] = useState6({});
1698
+ const [source, setSource] = useState7(null);
1699
+ const [allSources, setAllSources] = useState7([]);
1700
+ const [loading, setLoading] = useState7(true);
1701
+ const [error, setError] = useState7(null);
1702
+ const [detecting, setDetecting] = useState7(false);
1703
+ const [detectMsg, setDetectMsg] = useState7(null);
1704
+ const [savingKey, setSavingKey] = useState7(false);
1705
+ const [selectedKeyId, setSelectedKeyId] = useState7("__none__");
1706
+ const [hasData, setHasData] = useState7(false);
1707
+ const fileRef = useRef3(null);
1708
+ const [savingLayout, setSavingLayout] = useState7(false);
1709
+ const [editLayout, setEditLayout] = useState7("wide");
1710
+ const [editValueDateFormat, setEditValueDateFormat] = useState7("yyyy-MM-dd");
1711
+ const [newSegmentLabel, setNewSegmentLabel] = useState7("");
1712
+ const [newSegmentDataType, setNewSegmentDataType] = useState7("string");
1713
+ const [addingSegment, setAddingSegment] = useState7(false);
1714
+ const [clearConfirm, setClearConfirm] = useState7("");
1715
+ const [clearing, setClearing] = useState7(false);
1716
+ const [clearResult, setClearResult] = useState7(null);
1717
+ const [mappingKeys, setMappingKeys] = useState7(null);
1718
+ const [mappingRows, setMappingRows] = useState7([]);
1719
+ const [savingMapping, setSavingMapping] = useState7(false);
1720
+ const [baseHierarchyHint, setBaseHierarchyHint] = useState7({});
1272
1721
  async function load() {
1273
1722
  if (!id) return;
1274
1723
  try {
@@ -1321,7 +1770,7 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1321
1770
  setLoading(false);
1322
1771
  }
1323
1772
  }
1324
- useEffect6(() => {
1773
+ useEffect7(() => {
1325
1774
  void load();
1326
1775
  }, [id]);
1327
1776
  async function handleDetect(file) {
@@ -1420,15 +1869,15 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1420
1869
  setSavingLayout(false);
1421
1870
  }
1422
1871
  }
1423
- if (loading) return /* @__PURE__ */ jsx7(Root, { className, children: /* @__PURE__ */ jsx7("p", { className: "cfi-vi-muted", children: "Loading\u2026" }) });
1424
- if (!source) return /* @__PURE__ */ jsx7(Root, { className, children: /* @__PURE__ */ jsx7("p", { className: "cfi-vi-error", children: "Source not found" }) });
1872
+ if (loading) return /* @__PURE__ */ jsx8(Root, { className, children: /* @__PURE__ */ jsx8("p", { className: "cfi-vi-muted", children: "Loading\u2026" }) });
1873
+ if (!source) return /* @__PURE__ */ jsx8(Root, { className, children: /* @__PURE__ */ jsx8("p", { className: "cfi-vi-error", children: "Source not found" }) });
1425
1874
  const keySegment = source.segments.find((s) => s.id === source.uniqueKeySegmentId);
1426
1875
  const isOverlay = source.kind === "overlay";
1427
- return /* @__PURE__ */ jsx7(Root, { className, children: /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-detail", children: [
1428
- /* @__PURE__ */ jsxs7("div", { children: [
1429
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { gap: 8 }, children: [
1430
- /* @__PURE__ */ jsx7("span", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Source:" }),
1431
- /* @__PURE__ */ jsx7(
1876
+ return /* @__PURE__ */ jsx8(Root, { className, children: /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-detail", children: [
1877
+ /* @__PURE__ */ jsxs8("div", { children: [
1878
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { gap: 8 }, children: [
1879
+ /* @__PURE__ */ jsx8("span", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Source:" }),
1880
+ /* @__PURE__ */ jsx8(
1432
1881
  "select",
1433
1882
  {
1434
1883
  className: "cfi-vi-input",
@@ -1437,7 +1886,7 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1437
1886
  onChange: (e) => {
1438
1887
  if (e.target.value !== source.id) onOpenSource(e.target.value);
1439
1888
  },
1440
- children: allSources.slice().sort((a, b) => a.name.localeCompare(b.name)).map((s) => /* @__PURE__ */ jsxs7("option", { value: s.id, children: [
1889
+ children: allSources.slice().sort((a, b) => a.name.localeCompare(b.name)).map((s) => /* @__PURE__ */ jsxs8("option", { value: s.id, children: [
1441
1890
  s.name,
1442
1891
  " (",
1443
1892
  s.code,
@@ -1446,51 +1895,51 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1446
1895
  ] }, s.id))
1447
1896
  }
1448
1897
  ),
1449
- onBack && /* @__PURE__ */ jsx7("button", { type: "button", className: "cfi-vi-link cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, onClick: onBack, children: "All sources \u2192" })
1898
+ onBack && /* @__PURE__ */ jsx8("button", { type: "button", className: "cfi-vi-link cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, onClick: onBack, children: "All sources \u2192" })
1450
1899
  ] }),
1451
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { flexWrap: "wrap", marginTop: 4 }, children: [
1452
- /* @__PURE__ */ jsx7("h1", { className: "cfi-vi-h1", children: source.name }),
1453
- /* @__PURE__ */ jsx7(Badge, { variant: "outline", children: source.code }),
1454
- isOverlay && /* @__PURE__ */ jsx7(Badge, { variant: "purple", children: "Overlay" })
1900
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { flexWrap: "wrap", marginTop: 4 }, children: [
1901
+ /* @__PURE__ */ jsx8("h1", { className: "cfi-vi-h1", children: source.name }),
1902
+ /* @__PURE__ */ jsx8(Badge, { variant: "outline", children: source.code }),
1903
+ isOverlay && /* @__PURE__ */ jsx8(Badge, { variant: "purple", children: "Overlay" })
1455
1904
  ] }),
1456
- /* @__PURE__ */ jsxs7("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)", marginTop: 2 }, children: [
1905
+ /* @__PURE__ */ jsxs8("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)", marginTop: 2 }, children: [
1457
1906
  "Header row ",
1458
1907
  source.headerRowIndex,
1459
1908
  " \xB7 Format ",
1460
- /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mono", children: source.volumeHeaderFormat }),
1909
+ /* @__PURE__ */ jsx8("span", { className: "cfi-vi-mono", children: source.volumeHeaderFormat }),
1461
1910
  " \xB7",
1462
1911
  " ",
1463
- source.layout === "tall" ? /* @__PURE__ */ jsxs7("span", { className: "cfi-vi-row", style: { display: "inline-flex", gap: 4 }, children: [
1464
- /* @__PURE__ */ jsx7(Rows, { size: 12, "aria-hidden": true }),
1912
+ source.layout === "tall" ? /* @__PURE__ */ jsxs8("span", { className: "cfi-vi-row", style: { display: "inline-flex", gap: 4 }, children: [
1913
+ /* @__PURE__ */ jsx8(Rows, { size: 12, "aria-hidden": true }),
1465
1914
  " tall"
1466
- ] }) : /* @__PURE__ */ jsxs7("span", { className: "cfi-vi-row", style: { display: "inline-flex", gap: 4 }, children: [
1467
- /* @__PURE__ */ jsx7(Columns, { size: 12, "aria-hidden": true }),
1915
+ ] }) : /* @__PURE__ */ jsxs8("span", { className: "cfi-vi-row", style: { display: "inline-flex", gap: 4 }, children: [
1916
+ /* @__PURE__ */ jsx8(Columns, { size: 12, "aria-hidden": true }),
1468
1917
  " wide"
1469
1918
  ] }),
1470
- source.layout === "tall" && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1919
+ source.layout === "tall" && /* @__PURE__ */ jsxs8(Fragment3, { children: [
1471
1920
  " \xB7 Period ",
1472
- /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mono", children: source.valueDateFormat })
1921
+ /* @__PURE__ */ jsx8("span", { className: "cfi-vi-mono", children: source.valueDateFormat })
1473
1922
  ] }),
1474
- source.description && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1923
+ source.description && /* @__PURE__ */ jsxs8(Fragment3, { children: [
1475
1924
  " \xB7 ",
1476
1925
  source.description
1477
1926
  ] })
1478
1927
  ] })
1479
1928
  ] }),
1480
- hasData && /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-lock", children: [
1481
- /* @__PURE__ */ jsx7(Lock, { size: 14, "aria-hidden": true }),
1929
+ hasData && /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-lock", children: [
1930
+ /* @__PURE__ */ jsx8(Lock, { size: 14, "aria-hidden": true }),
1482
1931
  " This source has loaded data. Configuration is locked \u2014 clear data below before making changes."
1483
1932
  ] }),
1484
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-grid2", children: [
1485
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-panel", children: [
1486
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", children: [
1487
- editLayout === "tall" ? /* @__PURE__ */ jsx7(Rows, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }) : /* @__PURE__ */ jsx7(Columns, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
1488
- /* @__PURE__ */ jsx7("h2", { className: "cfi-vi-h2", children: "Layout" })
1933
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-grid2", children: [
1934
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-panel", children: [
1935
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", children: [
1936
+ editLayout === "tall" ? /* @__PURE__ */ jsx8(Rows, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }) : /* @__PURE__ */ jsx8(Columns, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
1937
+ /* @__PURE__ */ jsx8("h2", { className: "cfi-vi-h2", children: "Layout" })
1489
1938
  ] }),
1490
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { alignItems: "flex-end", gap: 12 }, children: [
1491
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1492
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Layout" }),
1493
- /* @__PURE__ */ jsxs7(
1939
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { alignItems: "flex-end", gap: 12 }, children: [
1940
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1941
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Layout" }),
1942
+ /* @__PURE__ */ jsxs8(
1494
1943
  "select",
1495
1944
  {
1496
1945
  className: "cfi-vi-input",
@@ -1498,15 +1947,15 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1498
1947
  disabled: hasData || savingLayout,
1499
1948
  onChange: (e) => setEditLayout(e.target.value),
1500
1949
  children: [
1501
- /* @__PURE__ */ jsx7("option", { value: "wide", children: "wide" }),
1502
- /* @__PURE__ */ jsx7("option", { value: "tall", children: "tall" })
1950
+ /* @__PURE__ */ jsx8("option", { value: "wide", children: "wide" }),
1951
+ /* @__PURE__ */ jsx8("option", { value: "tall", children: "tall" })
1503
1952
  ]
1504
1953
  }
1505
1954
  )
1506
1955
  ] }),
1507
- editLayout === "tall" && /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1508
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Period format" }),
1509
- /* @__PURE__ */ jsx7(
1956
+ editLayout === "tall" && /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1957
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Period format" }),
1958
+ /* @__PURE__ */ jsx8(
1510
1959
  TextInput,
1511
1960
  {
1512
1961
  className: "cfi-vi-mono",
@@ -1518,18 +1967,18 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1518
1967
  )
1519
1968
  ] })
1520
1969
  ] }),
1521
- /* @__PURE__ */ jsx7(Btn, { size: "sm", onClick: () => void saveLayoutAndRouting(), disabled: hasData || savingLayout, children: savingLayout ? "Saving\u2026" : "Save layout" })
1970
+ /* @__PURE__ */ jsx8(Btn, { size: "sm", onClick: () => void saveLayoutAndRouting(), disabled: hasData || savingLayout, children: savingLayout ? "Saving\u2026" : "Save layout" })
1522
1971
  ] }),
1523
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-panel", children: [
1524
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", children: [
1525
- /* @__PURE__ */ jsx7(KeyRound, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
1526
- /* @__PURE__ */ jsx7("h2", { className: "cfi-vi-h2", children: "Unique Key Column" }),
1527
- keySegment && /* @__PURE__ */ jsx7(Badge, { variant: "secondary", children: keySegment.label })
1972
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-panel", children: [
1973
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", children: [
1974
+ /* @__PURE__ */ jsx8(KeyRound, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
1975
+ /* @__PURE__ */ jsx8("h2", { className: "cfi-vi-h2", children: "Unique Key Column" }),
1976
+ keySegment && /* @__PURE__ */ jsx8(Badge, { variant: "secondary", children: keySegment.label })
1528
1977
  ] }),
1529
- source.segments.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Detect segments first to enable this option." }) : /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { alignItems: "flex-end" }, children: [
1530
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1531
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Key Segment" }),
1532
- /* @__PURE__ */ jsxs7(
1978
+ source.segments.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Detect segments first to enable this option." }) : /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { alignItems: "flex-end" }, children: [
1979
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1980
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Key Segment" }),
1981
+ /* @__PURE__ */ jsxs8(
1533
1982
  "select",
1534
1983
  {
1535
1984
  className: "cfi-vi-input",
@@ -1537,24 +1986,24 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1537
1986
  disabled: hasData,
1538
1987
  onChange: (e) => setSelectedKeyId(e.target.value),
1539
1988
  children: [
1540
- /* @__PURE__ */ jsx7("option", { value: "__none__", children: "None \u2014 use display name" }),
1541
- source.segments.slice().sort((a, b) => a.label.localeCompare(b.label)).map((seg) => /* @__PURE__ */ jsx7("option", { value: seg.id, children: seg.label }, seg.id))
1989
+ /* @__PURE__ */ jsx8("option", { value: "__none__", children: "None \u2014 use display name" }),
1990
+ source.segments.slice().sort((a, b) => a.label.localeCompare(b.label)).map((seg) => /* @__PURE__ */ jsx8("option", { value: seg.id, children: seg.label }, seg.id))
1542
1991
  ]
1543
1992
  }
1544
1993
  )
1545
1994
  ] }),
1546
- /* @__PURE__ */ jsx7(Btn, { size: "sm", onClick: saveUniqueKey, disabled: savingKey || hasData, children: savingKey ? "Saving\u2026" : "Save" })
1995
+ /* @__PURE__ */ jsx8(Btn, { size: "sm", onClick: saveUniqueKey, disabled: savingKey || hasData, children: savingKey ? "Saving\u2026" : "Save" })
1547
1996
  ] })
1548
1997
  ] })
1549
1998
  ] }),
1550
- source.layout === "tall" && /* @__PURE__ */ jsx7(TallLayoutMappings, { transport, source, locked: hasData }),
1551
- /* @__PURE__ */ jsxs7("div", { children: [
1552
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", children: [
1553
- /* @__PURE__ */ jsx7(Layers, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
1554
- /* @__PURE__ */ jsx7("h2", { className: "cfi-vi-h2", children: "Segment Mapping" }),
1555
- isOverlay && /* @__PURE__ */ jsx7("span", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "\xB7 Map at least the levels your base source uses for the overlay merge to land." })
1999
+ source.layout === "tall" && /* @__PURE__ */ jsx8(TallLayoutMappings, { transport, source, locked: hasData }),
2000
+ /* @__PURE__ */ jsxs8("div", { children: [
2001
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", children: [
2002
+ /* @__PURE__ */ jsx8(Layers, { size: 16, className: "cfi-vi-muted", "aria-hidden": true }),
2003
+ /* @__PURE__ */ jsx8("h2", { className: "cfi-vi-h2", children: "Segment Mapping" }),
2004
+ isOverlay && /* @__PURE__ */ jsx8("span", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "\xB7 Map at least the levels your base source uses for the overlay merge to land." })
1556
2005
  ] }),
1557
- source.segments.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "cfi-vi-muted", children: "No segments yet. Add segments below (Detect from file or Add manually) before mapping." }) : /* @__PURE__ */ jsx7(
2006
+ source.segments.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "cfi-vi-muted", children: "No segments yet. Add segments below (Detect from file or Add manually) before mapping." }) : /* @__PURE__ */ jsx8(
1558
2007
  UnifiedSegmentMapper,
1559
2008
  {
1560
2009
  segments: source.segments.slice().sort((a, b) => a.label.localeCompare(b.label)),
@@ -1570,16 +2019,16 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1570
2019
  }
1571
2020
  )
1572
2021
  ] }),
1573
- /* @__PURE__ */ jsx7(ValueAliasesCard, { transport, sourceId: source.id, locked: false, isOverlay }),
1574
- /* @__PURE__ */ jsxs7("div", { children: [
1575
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", children: [
1576
- /* @__PURE__ */ jsxs7("h2", { className: "cfi-vi-h2", children: [
2022
+ /* @__PURE__ */ jsx8(ValueAliasesCard, { transport, sourceId: source.id, locked: false, isOverlay }),
2023
+ /* @__PURE__ */ jsxs8("div", { children: [
2024
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", children: [
2025
+ /* @__PURE__ */ jsxs8("h2", { className: "cfi-vi-h2", children: [
1577
2026
  "Segments (",
1578
2027
  source.segments.length,
1579
2028
  ")"
1580
2029
  ] }),
1581
- /* @__PURE__ */ jsx7(Btn, { variant: "outline", size: "sm", onClick: () => fileRef.current?.click(), disabled: detecting || hasData, children: detecting ? "Detecting\u2026" : "Detect from file" }),
1582
- /* @__PURE__ */ jsx7(
2030
+ /* @__PURE__ */ jsx8(Btn, { variant: "outline", size: "sm", onClick: () => fileRef.current?.click(), disabled: detecting || hasData, children: detecting ? "Detecting\u2026" : "Detect from file" }),
2031
+ /* @__PURE__ */ jsx8(
1583
2032
  "input",
1584
2033
  {
1585
2034
  ref: fileRef,
@@ -1594,14 +2043,14 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1594
2043
  }
1595
2044
  )
1596
2045
  ] }),
1597
- detectMsg && /* @__PURE__ */ jsx7("p", { style: { fontSize: "var(--cfi-font-size-sm, 13px)", color: "#16a34a" }, children: detectMsg }),
1598
- error && /* @__PURE__ */ jsx7("p", { className: "cfi-vi-error", children: error }),
1599
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-panel", style: { maxWidth: "42rem" }, children: [
1600
- /* @__PURE__ */ jsx7("div", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Add segment manually \u2014 for columns not covered by auto-detect." }),
1601
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { alignItems: "flex-end" }, children: [
1602
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1603
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Label" }),
1604
- /* @__PURE__ */ jsx7(
2046
+ detectMsg && /* @__PURE__ */ jsx8("p", { style: { fontSize: "var(--cfi-font-size-sm, 13px)", color: "#16a34a" }, children: detectMsg }),
2047
+ error && /* @__PURE__ */ jsx8("p", { className: "cfi-vi-error", children: error }),
2048
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-panel", style: { maxWidth: "42rem" }, children: [
2049
+ /* @__PURE__ */ jsx8("div", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-xs, 12px)" }, children: "Add segment manually \u2014 for columns not covered by auto-detect." }),
2050
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { alignItems: "flex-end" }, children: [
2051
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
2052
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Label" }),
2053
+ /* @__PURE__ */ jsx8(
1605
2054
  TextInput,
1606
2055
  {
1607
2056
  className: "cfi-vi-mono",
@@ -1615,9 +2064,9 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1615
2064
  }
1616
2065
  )
1617
2066
  ] }),
1618
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { width: 128 }, children: [
1619
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Data Type" }),
1620
- /* @__PURE__ */ jsxs7(
2067
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { width: 128 }, children: [
2068
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Data Type" }),
2069
+ /* @__PURE__ */ jsxs8(
1621
2070
  "select",
1622
2071
  {
1623
2072
  className: "cfi-vi-input",
@@ -1625,33 +2074,33 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1625
2074
  disabled: hasData || addingSegment,
1626
2075
  onChange: (e) => setNewSegmentDataType(e.target.value),
1627
2076
  children: [
1628
- /* @__PURE__ */ jsx7("option", { value: "string", children: "string" }),
1629
- /* @__PURE__ */ jsx7("option", { value: "number", children: "number" }),
1630
- /* @__PURE__ */ jsx7("option", { value: "date", children: "date" })
2077
+ /* @__PURE__ */ jsx8("option", { value: "string", children: "string" }),
2078
+ /* @__PURE__ */ jsx8("option", { value: "number", children: "number" }),
2079
+ /* @__PURE__ */ jsx8("option", { value: "date", children: "date" })
1631
2080
  ]
1632
2081
  }
1633
2082
  )
1634
2083
  ] }),
1635
- /* @__PURE__ */ jsx7(Btn, { size: "sm", onClick: () => void handleAddSegment(), disabled: hasData || addingSegment || !newSegmentLabel.trim(), children: addingSegment ? "Adding\u2026" : "Add segment" })
2084
+ /* @__PURE__ */ jsx8(Btn, { size: "sm", onClick: () => void handleAddSegment(), disabled: hasData || addingSegment || !newSegmentLabel.trim(), children: addingSegment ? "Adding\u2026" : "Add segment" })
1636
2085
  ] })
1637
2086
  ] }),
1638
- source.segments.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "cfi-vi-muted", children: "No segments yet. Upload a sample file to auto-detect." }) : /* @__PURE__ */ jsxs7("table", { className: "cfi-vi-table", children: [
1639
- /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
1640
- /* @__PURE__ */ jsx7("th", { style: { width: 48 }, children: "#" }),
1641
- /* @__PURE__ */ jsx7("th", { children: "Label" }),
1642
- /* @__PURE__ */ jsx7("th", { children: "Data Type" }),
1643
- /* @__PURE__ */ jsx7("th", { style: { width: 80 }, children: "Key" }),
1644
- /* @__PURE__ */ jsx7("th", { style: { width: 64 } })
2087
+ source.segments.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "cfi-vi-muted", children: "No segments yet. Upload a sample file to auto-detect." }) : /* @__PURE__ */ jsxs8("table", { className: "cfi-vi-table", children: [
2088
+ /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsxs8("tr", { children: [
2089
+ /* @__PURE__ */ jsx8("th", { style: { width: 48 }, children: "#" }),
2090
+ /* @__PURE__ */ jsx8("th", { children: "Label" }),
2091
+ /* @__PURE__ */ jsx8("th", { children: "Data Type" }),
2092
+ /* @__PURE__ */ jsx8("th", { style: { width: 80 }, children: "Key" }),
2093
+ /* @__PURE__ */ jsx8("th", { style: { width: 64 } })
1645
2094
  ] }) }),
1646
- /* @__PURE__ */ jsx7("tbody", { children: source.segments.map((seg) => /* @__PURE__ */ jsxs7("tr", { children: [
1647
- /* @__PURE__ */ jsx7("td", { className: "cfi-vi-muted", children: seg.sortOrder }),
1648
- /* @__PURE__ */ jsx7("td", { className: "cfi-vi-mono", children: seg.label }),
1649
- /* @__PURE__ */ jsx7("td", { className: "cfi-vi-muted", children: seg.dataType }),
1650
- /* @__PURE__ */ jsx7("td", { children: seg.id === source.uniqueKeySegmentId && /* @__PURE__ */ jsxs7(Badge, { variant: "secondary", children: [
1651
- /* @__PURE__ */ jsx7(KeyRound, { size: 12, "aria-hidden": true }),
2095
+ /* @__PURE__ */ jsx8("tbody", { children: source.segments.map((seg) => /* @__PURE__ */ jsxs8("tr", { children: [
2096
+ /* @__PURE__ */ jsx8("td", { className: "cfi-vi-muted", children: seg.sortOrder }),
2097
+ /* @__PURE__ */ jsx8("td", { className: "cfi-vi-mono", children: seg.label }),
2098
+ /* @__PURE__ */ jsx8("td", { className: "cfi-vi-muted", children: seg.dataType }),
2099
+ /* @__PURE__ */ jsx8("td", { children: seg.id === source.uniqueKeySegmentId && /* @__PURE__ */ jsxs8(Badge, { variant: "secondary", children: [
2100
+ /* @__PURE__ */ jsx8(KeyRound, { size: 12, "aria-hidden": true }),
1652
2101
  " Key"
1653
2102
  ] }) }),
1654
- /* @__PURE__ */ jsx7("td", { children: /* @__PURE__ */ jsx7(
2103
+ /* @__PURE__ */ jsx8("td", { children: /* @__PURE__ */ jsx8(
1655
2104
  "button",
1656
2105
  {
1657
2106
  type: "button",
@@ -1666,26 +2115,26 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1666
2115
  ] }, seg.id)) })
1667
2116
  ] })
1668
2117
  ] }),
1669
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-danger", children: [
1670
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { color: "var(--cfi-color-error, #dc2626)" }, children: [
1671
- /* @__PURE__ */ jsx7(AlertTriangle2, { size: 16, "aria-hidden": true }),
1672
- /* @__PURE__ */ jsx7("h2", { className: "cfi-vi-h2", children: "Danger zone \u2014 clear source data" })
2118
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-danger", children: [
2119
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { color: "var(--cfi-color-error, #dc2626)" }, children: [
2120
+ /* @__PURE__ */ jsx8(AlertTriangle3, { size: 16, "aria-hidden": true }),
2121
+ /* @__PURE__ */ jsx8("h2", { className: "cfi-vi-h2", children: "Danger zone \u2014 clear source data" })
1673
2122
  ] }),
1674
- /* @__PURE__ */ jsxs7("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
2123
+ /* @__PURE__ */ jsxs8("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
1675
2124
  "Deletes every upload, criteria, volume actual, prediction, and forecast edit tied to",
1676
2125
  " ",
1677
- /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mono", children: source.name }),
2126
+ /* @__PURE__ */ jsx8("span", { className: "cfi-vi-mono", children: source.name }),
1678
2127
  ". Other sources are untouched. Configuration (segments, mappings, key column, layout) stays in place. There is no undo."
1679
2128
  ] }),
1680
- /* @__PURE__ */ jsxs7("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
2129
+ /* @__PURE__ */ jsxs8("p", { className: "cfi-vi-muted", style: { fontSize: "var(--cfi-font-size-sm, 13px)" }, children: [
1681
2130
  "To confirm, type ",
1682
- /* @__PURE__ */ jsx7("span", { className: "cfi-vi-mono", style: { fontWeight: 600 }, children: "DELETE" }),
2131
+ /* @__PURE__ */ jsx8("span", { className: "cfi-vi-mono", style: { fontWeight: 600 }, children: "DELETE" }),
1683
2132
  " below."
1684
2133
  ] }),
1685
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-row", style: { alignItems: "flex-end", maxWidth: "28rem" }, children: [
1686
- /* @__PURE__ */ jsxs7("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
1687
- /* @__PURE__ */ jsx7("label", { className: "cfi-vi-label", children: "Confirmation" }),
1688
- /* @__PURE__ */ jsx7(
2134
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-row", style: { alignItems: "flex-end", maxWidth: "28rem" }, children: [
2135
+ /* @__PURE__ */ jsxs8("div", { className: "cfi-vi-field", style: { flex: 1 }, children: [
2136
+ /* @__PURE__ */ jsx8("label", { className: "cfi-vi-label", children: "Confirmation" }),
2137
+ /* @__PURE__ */ jsx8(
1689
2138
  TextInput,
1690
2139
  {
1691
2140
  className: "cfi-vi-mono",
@@ -1696,9 +2145,9 @@ function VolumeSourceDetail({ transport, sourceId, onOpenSource, onBack, classNa
1696
2145
  }
1697
2146
  )
1698
2147
  ] }),
1699
- /* @__PURE__ */ jsx7(Btn, { variant: "destructive", size: "sm", onClick: () => void handleClearData(), disabled: clearConfirm !== "DELETE" || clearing, children: clearing ? "Clearing\u2026" : "Clear all data" })
2148
+ /* @__PURE__ */ jsx8(Btn, { variant: "destructive", size: "sm", onClick: () => void handleClearData(), disabled: clearConfirm !== "DELETE" || clearing, children: clearing ? "Clearing\u2026" : "Clear all data" })
1700
2149
  ] }),
1701
- clearResult && /* @__PURE__ */ jsx7("p", { style: { fontSize: "var(--cfi-font-size-sm, 13px)", color: "#15803d" }, children: clearResult })
2150
+ clearResult && /* @__PURE__ */ jsx8("p", { style: { fontSize: "var(--cfi-font-size-sm, 13px)", color: "#15803d" }, children: clearResult })
1702
2151
  ] })
1703
2152
  ] }) });
1704
2153
  }
@@ -1710,6 +2159,7 @@ export {
1710
2159
  TallLayoutMappings,
1711
2160
  UnifiedSegmentMapper,
1712
2161
  ValueAliasesCard,
2162
+ VolumeFiles,
1713
2163
  VolumeImport,
1714
2164
  VolumeSourceDetail,
1715
2165
  VolumeSourcesList