@jmruthers/pace-core 0.5.191 → 0.6.1
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/CHANGELOG.md +29 -0
- package/README.md +7 -1
- package/cursor-rules/00-pace-core-compliance.mdc +372 -0
- package/cursor-rules/01-standards-compliance.mdc +275 -0
- package/cursor-rules/02-project-structure.mdc +200 -0
- package/cursor-rules/03-solid-principles.mdc +341 -0
- package/cursor-rules/04-testing-standards.mdc +315 -0
- package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
- package/cursor-rules/06-code-quality.mdc +392 -0
- package/cursor-rules/07-tech-stack-compliance.mdc +309 -0
- package/cursor-rules/CHANGELOG.md +101 -0
- package/cursor-rules/README.md +191 -0
- package/dist/{AuthService-CbP_utw2.d.ts → AuthService-DjnJHDtC.d.ts} +1 -0
- package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-CH1U5Tpy.d.ts} +1 -1
- package/dist/{DataTable-WKRZD47S.js → DataTable-DQ7RSOHE.js} +8 -7
- package/dist/{PublicPageProvider-ULXC_u6U.d.ts → PublicPageProvider-ce4xlHYA.d.ts} +37 -156
- package/dist/{UnifiedAuthProvider-BYA9qB-o.d.ts → UnifiedAuthProvider-185Ih4dj.d.ts} +2 -0
- package/dist/{UnifiedAuthProvider-FTSG5XH7.js → UnifiedAuthProvider-ATAP5UTR.js} +3 -3
- package/dist/{api-IHKALJZD.js → api-N774RPUA.js} +2 -2
- package/dist/{chunk-6C4YBBJM.js → chunk-3QRJFVBR.js} +1 -1
- package/dist/chunk-3QRJFVBR.js.map +1 -0
- package/dist/{chunk-OETXORNB.js → chunk-3XTALGJF.js} +211 -136
- package/dist/chunk-3XTALGJF.js.map +1 -0
- package/dist/{chunk-6TQDD426.js → chunk-4N5C5XZU.js} +47 -228
- package/dist/chunk-4N5C5XZU.js.map +1 -0
- package/dist/{chunk-LOMZXPSN.js → chunk-4ZC4GX36.js} +47 -74
- package/dist/chunk-4ZC4GX36.js.map +1 -0
- package/dist/{chunk-6LTQQAT6.js → chunk-BYFSK72L.js} +357 -158
- package/dist/chunk-BYFSK72L.js.map +1 -0
- package/dist/{chunk-XYXSXPUK.js → chunk-EXUD6RNJ.js} +50 -10
- package/dist/chunk-EXUD6RNJ.js.map +1 -0
- package/dist/{chunk-VKB2CO4Z.js → chunk-GLK6VM3F.js} +244 -249
- package/dist/chunk-GLK6VM3F.js.map +1 -0
- package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
- package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
- package/dist/{chunk-XNYQOL3Z.js → chunk-JBKQ3SAO.js} +9 -18
- package/dist/chunk-JBKQ3SAO.js.map +1 -0
- package/dist/{chunk-ROXMHMY2.js → chunk-KNC55RTG.js} +13 -3
- package/dist/{chunk-ROXMHMY2.js.map → chunk-KNC55RTG.js.map} +1 -1
- package/dist/{chunk-QWWZ5CAQ.js → chunk-LXQLPRQ2.js} +2 -2
- package/dist/{chunk-ULHIJK66.js → chunk-T33XF5ZC.js} +255 -140
- package/dist/chunk-T33XF5ZC.js.map +1 -0
- package/dist/{chunk-VRGWKHDB.js → chunk-XM25TVIE.js} +100 -33
- package/dist/chunk-XM25TVIE.js.map +1 -0
- package/dist/components.d.ts +4 -4
- package/dist/components.js +9 -9
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +20 -25
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +18 -21
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +2 -20
- package/dist/rbac/index.js +7 -9
- package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-BJAlWfuJ.d.ts} +3 -3
- package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -3
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +2 -2
- package/docs/api/classes/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +10 -10
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +24 -11
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
- package/docs/api/interfaces/ProgressProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +2 -2
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +2 -2
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +2 -2
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +2 -2
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +2 -2
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +2 -2
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +2 -2
- package/docs/api/interfaces/RouteConfig.md +2 -2
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +60 -38
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +194 -209
- package/docs/getting-started/cursor-rules.md +262 -0
- package/docs/getting-started/installation-guide.md +6 -1
- package/docs/getting-started/quick-start.md +6 -1
- package/docs/migration/MIGRATION_GUIDE.md +4 -4
- package/docs/migration/REACT_19_MIGRATION.md +227 -0
- package/docs/migration/database-changes-december-2025.md +2 -1
- package/docs/rbac/event-based-apps.md +124 -6
- package/docs/standards/README.md +39 -0
- package/docs/troubleshooting/migration.md +4 -4
- package/examples/PublicPages/PublicEventPage.tsx +1 -1
- package/package.json +11 -6
- package/scripts/audit-consuming-app.cjs +961 -0
- package/scripts/check-pace-core-compliance.cjs +315 -61
- package/scripts/install-cursor-rules.cjs +236 -0
- package/src/__tests__/helpers/test-providers.tsx +1 -1
- package/src/__tests__/helpers/test-utils.tsx +1 -1
- package/src/__tests__/rls-policies.test.ts +3 -1
- package/src/components/Badge/Badge.tsx +2 -4
- package/src/components/Button/Button.tsx +5 -4
- package/src/components/Calendar/Calendar.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +57 -93
- package/src/components/DataTable/DataTable.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +172 -45
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +121 -28
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +9 -8
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +20 -52
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +170 -34
- package/src/components/DataTable/__tests__/keyboard.test.tsx +75 -12
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +88 -16
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
- package/src/components/DataTable/components/AccessDeniedPage.tsx +1 -1
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
- package/src/components/DataTable/components/DataTableCore.tsx +4 -7
- package/src/components/DataTable/components/DataTableModals.tsx +1 -1
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +86 -17
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
- package/src/components/DataTable/hooks/useColumnReordering.ts +2 -2
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +75 -10
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
- package/src/components/Dialog/Dialog.tsx +6 -5
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +1 -1
- package/src/components/EventSelector/EventSelector.tsx +1 -1
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -3
- package/src/components/FileDisplay/FileDisplay.tsx +16 -4
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +36 -15
- package/src/components/Form/Form.tsx +30 -26
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
- package/src/components/Input/Input.tsx +28 -30
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
- package/src/components/LoginForm/LoginForm.test.tsx +42 -42
- package/src/components/LoginForm/LoginForm.tsx +8 -8
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +6 -4
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -11
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -1
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +75 -52
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +98 -69
- package/src/components/PaceAppLayout/README.md +1 -1
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -8
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
- package/src/components/PasswordChange/PasswordChangeForm.tsx +1 -1
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +5 -9
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +0 -1
- package/src/components/PublicLayout/PublicPageLayout.tsx +1 -1
- package/src/components/PublicLayout/PublicPageProvider.tsx +0 -1
- package/src/components/Select/Select.tsx +33 -22
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Textarea/Textarea.tsx +27 -29
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/UserMenu/UserMenu.tsx +1 -1
- package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +14 -7
- package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
- package/src/hooks/public/usePublicEvent.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.ts +1 -1
- package/src/hooks/services/useAuthService.ts +21 -3
- package/src/hooks/services/useEventService.ts +21 -3
- package/src/hooks/services/useInactivityService.ts +21 -3
- package/src/hooks/services/useOrganisationService.ts +21 -3
- package/src/hooks/useDataTableState.ts +8 -18
- package/src/hooks/useFileDisplay.ts +10 -17
- package/src/hooks/useFocusManagement.ts +2 -2
- package/src/hooks/useFocusTrap.ts +4 -4
- package/src/hooks/useFormDialog.ts +8 -7
- package/src/hooks/useInactivityTracker.ts +1 -1
- package/src/hooks/usePermissionCache.ts +1 -1
- package/src/hooks/useSecureDataAccess.test.ts +16 -9
- package/src/hooks/useSecureDataAccess.ts +22 -6
- package/src/hooks/useToast.ts +2 -2
- package/src/providers/__tests__/OrganisationProvider.test.tsx +57 -13
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
- package/src/providers/services/EventServiceProvider.tsx +0 -8
- package/src/providers/services/UnifiedAuthProvider.tsx +196 -46
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +13 -3
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +34 -40
- package/src/rbac/__tests__/isSuperAdmin.real.test.ts +82 -0
- package/src/rbac/adapters.tsx +3 -22
- package/src/rbac/api.test.ts +2 -2
- package/src/rbac/api.ts +7 -1
- package/src/rbac/components/EnhancedNavigationMenu.tsx +3 -16
- package/src/rbac/components/NavigationGuard.tsx +2 -11
- package/src/rbac/components/NavigationProvider.tsx +1 -2
- package/src/rbac/components/PagePermissionGuard.tsx +1 -1
- package/src/rbac/components/PagePermissionProvider.tsx +1 -1
- package/src/rbac/components/PermissionEnforcer.tsx +46 -13
- package/src/rbac/components/RoleBasedRouter.tsx +1 -1
- package/src/rbac/components/SecureDataProvider.tsx +1 -2
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +7 -43
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +4 -11
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +3 -3
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +1 -1
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +1 -1
- package/src/rbac/engine.ts +14 -2
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/usePermissions.ts +51 -11
- package/src/rbac/hooks/useRBAC.ts +3 -13
- package/src/rbac/hooks/useResolvedScope.test.ts +75 -54
- package/src/rbac/hooks/useResolvedScope.ts +58 -33
- package/src/rbac/hooks/useSecureSupabase.ts +4 -9
- package/src/rbac/secureClient.ts +43 -0
- package/src/services/EventService.ts +4 -57
- package/src/services/InactivityService.ts +127 -34
- package/src/services/OrganisationService.ts +68 -10
- package/src/utils/security/secureDataAccess.test.ts +31 -20
- package/src/utils/security/secureDataAccess.ts +4 -3
- package/dist/chunk-6C4YBBJM.js.map +0 -1
- package/dist/chunk-6LTQQAT6.js.map +0 -1
- package/dist/chunk-6TQDD426.js.map +0 -1
- package/dist/chunk-LOMZXPSN.js.map +0 -1
- package/dist/chunk-OETXORNB.js.map +0 -1
- package/dist/chunk-ULHIJK66.js.map +0 -1
- package/dist/chunk-VKB2CO4Z.js.map +0 -1
- package/dist/chunk-VRGWKHDB.js.map +0 -1
- package/dist/chunk-XNYQOL3Z.js.map +0 -1
- package/dist/chunk-XYXSXPUK.js.map +0 -1
- package/scripts/check-pace-core-compliance.js +0 -512
- package/src/rbac/hooks/useSuperAdminBypass.ts +0 -126
- package/src/utils/context/superAdminOverride.ts +0 -58
- /package/dist/{DataTable-WKRZD47S.js.map → DataTable-DQ7RSOHE.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-FTSG5XH7.js.map → UnifiedAuthProvider-ATAP5UTR.js.map} +0 -0
- /package/dist/{api-IHKALJZD.js.map → api-N774RPUA.js.map} +0 -0
- /package/dist/{chunk-QWWZ5CAQ.js.map → chunk-LXQLPRQ2.js.map} +0 -0
- /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
- /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
- /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
- /package/examples/{rbac → RBAC}/index.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/AddressField/AddressField.tsx","../src/components/Label/Label.tsx","../src/components/Textarea/Textarea.tsx","../src/components/FileDisplay/FileDisplay.tsx","../src/hooks/useFileUrl.ts","../src/hooks/useFileReference.ts","../src/components/Avatar/Avatar.tsx","../src/components/Badge/Badge.tsx","../src/components/Switch/Switch.tsx","../src/components/Tabs/Tabs.tsx","../src/components/Calendar/Calendar.tsx","../src/components/Toast/Toast.tsx","../src/components/Form/Form.tsx","../src/components/LoginForm/LoginForm.tsx","../src/components/EventSelector/EventSelector.tsx","../src/components/OrganisationSelector/OrganisationSelector.tsx","../src/components/PasswordChange/PasswordChangeForm.tsx","../src/components/UserMenu/UserMenu.tsx","../src/components/NavigationMenu/NavigationMenu.tsx","../src/components/Header/Header.tsx","../src/components/Footer/Footer.tsx","../src/components/PaceAppLayout/PaceAppLayout.tsx","../src/components/PaceLoginPage/PaceLoginPage.tsx","../src/components/SessionRestorationLoader/SessionRestorationLoader.tsx","../src/components/ProtectedRoute/ProtectedRoute.tsx","../src/components/FileUpload/FileUpload.tsx","../src/components/Table/Table.tsx","../src/components/PublicLayout/PublicPageLayout.tsx"],"sourcesContent":["/**\n * @file AddressField Component\n * @package @jmruthers/pace-core\n * @module Components/AddressField\n * @since 0.1.0\n *\n * Address input field with Google Places API autocomplete.\n * Provides address suggestions, keyboard navigation, and accessibility.\n *\n * Features:\n * - Google Places API autocomplete integration\n * - Debounced input with caching\n * - Keyboard navigation (Arrow keys, Enter, Escape)\n * - Accessible ARIA attributes\n * - Semantic HTML (description list for suggestions)\n * - Loading and error states\n * - place_id storage for later retrieval\n *\n * @accessibility\n * - Uses semantic HTML: `<dl>`, `<dt>`, `<dd>` for address suggestions\n * - Proper ARIA attributes for combobox pattern\n * - Keyboard navigation support\n * - Screen reader friendly\n */\n\nimport * as React from 'react';\nimport { Input } from '../Input/Input';\nimport { LoadingSpinner } from '../LoadingSpinner';\nimport { cn } from '../../utils/core/cn';\nimport { useAddressAutocomplete } from '../../hooks/useAddressAutocomplete';\nimport type { AddressFieldProps, AddressFieldRef } from './types';\nimport type { ParsedAddress } from '../../utils/google-places';\n\n/**\n * AddressField component\n * \n * A production-ready address input field with Google Places API autocomplete.\n * Returns structured address data including place_id for later retrieval.\n * \n * @param props - AddressField configuration\n * @param ref - Forwarded ref for imperative access\n * @returns JSX.Element - The rendered address field\n * \n * @example\n * ```tsx\n * <AddressField\n * apiKey={apiKey}\n * onChange={(address) => {\n * // address includes place_id, full_address, lat, lng, etc.\n * console.log(address.place_id);\n * }}\n * placeholder=\"Enter your address\"\n * />\n * ```\n */\nconst AddressField = React.forwardRef<HTMLInputElement, AddressFieldProps>(\n (\n {\n apiKey,\n value: controlledValue,\n defaultValue = '',\n onChange,\n onInputChange,\n placeholder = 'Enter address',\n error,\n disabled,\n className,\n size = 'md',\n variant = 'default',\n autocompleteOptions,\n debounceDelay,\n cacheEnabled = true,\n cacheTTL,\n ...props\n },\n ref\n ) => {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isOpen, setIsOpen] = React.useState(false);\n const [selectedIndex, setSelectedIndex] = React.useState(-1);\n const [inputFocused, setInputFocused] = React.useState(false);\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const suggestionsRef = React.useRef<HTMLDListElement>(null);\n const containerRef = React.useRef<HTMLFormElement>(null);\n\n // Use controlled or uncontrolled value\n const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n // Use autocomplete hook\n const { suggestions, isLoading, error: autocompleteError, selectAddress, clearSuggestions } =\n useAddressAutocomplete(apiKey, value, {\n autocompleteOptions,\n debounceDelay,\n cacheEnabled,\n cacheTTL,\n });\n\n // Update suggestions visibility\n React.useEffect(() => {\n if (suggestions.length > 0 && inputFocused && value.trim()) {\n setIsOpen(true);\n } else if (suggestions.length === 0 || !value.trim()) {\n setIsOpen(false);\n }\n }, [suggestions, inputFocused, value]);\n\n // Handle input change\n const handleInputChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInputChange?.(newValue);\n setSelectedIndex(-1);\n if (!newValue.trim()) {\n onChange?.(null);\n clearSuggestions();\n }\n },\n [controlledValue, onInputChange, onChange, clearSuggestions]\n );\n\n // Handle address selection\n const handleSelectAddress = React.useCallback(\n async (placeId: string) => {\n setIsOpen(false);\n setSelectedIndex(-1);\n const address = await selectAddress(placeId);\n if (address) {\n // Update input with formatted address\n const displayValue = address.full_address || '';\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInputChange?.(displayValue);\n onChange?.(address);\n }\n inputRef.current?.blur();\n },\n [selectAddress, onChange, onInputChange, controlledValue]\n );\n\n // Handle keyboard navigation\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || suggestions.length === 0) {\n if (e.key === 'Escape') {\n setIsOpen(false);\n inputRef.current?.blur();\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setSelectedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : prev));\n break;\n case 'ArrowUp':\n e.preventDefault();\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1));\n break;\n case 'Enter':\n e.preventDefault();\n if (selectedIndex >= 0 && selectedIndex < suggestions.length) {\n handleSelectAddress(suggestions[selectedIndex].place_id);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.blur();\n break;\n case 'Tab':\n setIsOpen(false);\n setSelectedIndex(-1);\n break;\n }\n },\n [isOpen, suggestions, selectedIndex, handleSelectAddress]\n );\n\n // Handle focus\n const handleFocus = React.useCallback(() => {\n setInputFocused(true);\n if (suggestions.length > 0 && value.trim()) {\n setIsOpen(true);\n }\n }, [suggestions, value]);\n\n // Handle blur\n const handleBlur = React.useCallback(\n (e: React.FocusEvent<HTMLInputElement>) => {\n // Delay to allow click events on suggestions\n setTimeout(() => {\n if (!containerRef.current?.contains(document.activeElement)) {\n setInputFocused(false);\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n }, 200);\n },\n []\n );\n\n // Click outside handler\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }\n }, [isOpen]);\n\n // Generate unique ID for suggestions list\n const suggestionsId = React.useId();\n\n // Scroll selected item into view\n // Uses getElementById instead of querySelector to handle React.useId() generated IDs\n // which may contain colons (e.g., ':r15:') that are invalid in CSS selectors\n React.useEffect(() => {\n if (selectedIndex >= 0) {\n const selectedItem = document.getElementById(\n `${suggestionsId}-item-${selectedIndex}`\n ) as HTMLElement;\n if (selectedItem && typeof selectedItem.scrollIntoView === 'function') {\n selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }\n }\n }, [selectedIndex, suggestionsId]);\n\n // Combine refs\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const hasError = error || !!autocompleteError;\n\n return (\n <form ref={containerRef} className={cn('relative w-full', className)}>\n <Input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n disabled={disabled}\n error={hasError}\n size={size}\n variant={variant}\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n aria-controls={suggestionsId}\n aria-haspopup=\"listbox\"\n aria-activedescendant={\n selectedIndex >= 0 ? `${suggestionsId}-item-${selectedIndex}` : undefined\n }\n {...props}\n />\n {isLoading && (\n <p className=\"absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none\">\n <LoadingSpinner size=\"sm\" />\n </p>\n )}\n\n {isOpen && suggestions.length > 0 && (\n <dl\n ref={suggestionsRef}\n id={suggestionsId}\n role=\"listbox\"\n className={cn(\n 'absolute z-[99999] w-full mt-1 max-h-60 overflow-y-auto',\n 'border border-main-300 bg-main-50 shadow-lg rounded-md',\n 'list-none p-0 m-0'\n )}\n data-testid=\"address-suggestions\"\n >\n {suggestions.map((suggestion, index) => (\n <React.Fragment key={suggestion.place_id}>\n <dt\n id={`${suggestionsId}-item-${index}`}\n role=\"option\"\n aria-selected={selectedIndex === index}\n className={cn(\n 'px-3 py-2 cursor-pointer text-sm',\n 'hover:bg-main-100 focus:bg-main-100',\n 'border-b border-main-200 last:border-b-0',\n selectedIndex === index && 'bg-main-100',\n 'font-medium text-main-900'\n )}\n onClick={() => handleSelectAddress(suggestion.place_id)}\n onMouseEnter={() => setSelectedIndex(index)}\n data-testid={`address-suggestion-${index}`}\n >\n {suggestion.structured_formatting?.main_text || suggestion.description}\n </dt>\n {suggestion.structured_formatting?.secondary_text && (\n <dd className=\"px-3 pb-2 text-xs text-main-600 mt-0.5\">\n {suggestion.structured_formatting.secondary_text}\n </dd>\n )}\n </React.Fragment>\n ))}\n </dl>\n )}\n\n {autocompleteError && (\n <p className=\"mt-1 text-sm text-destructive\" role=\"alert\">\n {autocompleteError.message}\n </p>\n )}\n </form>\n );\n }\n);\n\nAddressField.displayName = 'AddressField';\n\nexport { AddressField };\nexport type { AddressFieldProps, AddressFieldRef, ParsedAddress } from './types';\n\n","/**\n * @file Label Component\n * @package @jmruthers/pace-core\n * @module Components/Label\n * @since 0.1.0\n *\n * An accessible label component built on top of Radix UI primitives.\n * Provides form labels with helper text, error states, and required indicators.\n *\n * Features:\n * - Proper label association with form controls\n * - Required field indicators\n * - Helper text support\n * - Error state display\n * - Customizable styling\n * - Screen reader friendly\n * - Keyboard accessible\n *\n * @example\n * ```tsx\n * // Basic label\n * <Label htmlFor=\"email\">Email Address</Label>\n * <Input id=\"email\" type=\"email\" />\n * \n * // Label with required indicator\n * <Label htmlFor=\"name\" required>\n * Full Name\n * </Label>\n * <Input id=\"name\" />\n * \n * // Label with helper text\n * <Label \n * htmlFor=\"password\" \n * required \n * helperText=\"Must be at least 8 characters\"\n * >\n * Password\n * </Label>\n * <Input id=\"password\" type=\"password\" />\n * \n * // Label with error state\n * <Label \n * htmlFor=\"email\" \n * error=\"Please enter a valid email address\"\n * >\n * Email Address\n * </Label>\n * <Input id=\"email\" type=\"email\" />\n * \n * // Custom required indicator\n * <Label \n * htmlFor=\"terms\" \n * required \n * requiredIndicator=\"(required)\"\n * >\n * Accept Terms\n * </Label>\n * <Checkbox id=\"terms\" />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper label association with htmlFor\n * - Screen reader announcements for errors\n * - Required field indicators for screen readers\n * - Error messages with role=\"alert\"\n * - High contrast support\n *\n * @dependencies\n * - @radix-ui/react-label - Core label functionality\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cn } from '../../utils/core/cn';\n\nconst getLabelClasses = (): string => {\n return 'font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70';\n};\n\n/**\n * Props for the Label component\n */\nexport interface LabelProps\n extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n /** Whether the field is required */\n required?: boolean;\n /** Custom required indicator (default: '*') */\n requiredIndicator?: React.ReactNode;\n /** Whether to hide the required indicator visually */\n hideRequiredIndicator?: boolean;\n /** Helper text to display below the label */\n helperText?: string;\n /** CSS classes for helper text styling */\n helperTextClassName?: string;\n /** Error message to display */\n error?: string;\n /** CSS classes for error message styling */\n errorClassName?: string;\n}\n\n/**\n * Label component\n * An accessible label with helper text and error state support\n * \n * @param props - Label configuration and styling\n * @param ref - Forwarded ref to the label element\n * @returns JSX.Element - The rendered label with optional helper text and errors\n * \n * @example\n * ```tsx\n * <Label htmlFor=\"email\" required helperText=\"We'll never share your email\">\n * Email Address\n * </Label>\n * ```\n */\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n LabelProps\n>(({\n className,\n required = false,\n requiredIndicator,\n hideRequiredIndicator = false,\n helperText,\n helperTextClassName,\n error,\n errorClassName,\n children,\n htmlFor,\n ...props\n}, ref) => {\n const hasError = !!error;\n const showHelperText = helperText && !hasError;\n \n return (\n <>\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n getLabelClasses(),\n hasError && 'text-destructive',\n className\n )}\n htmlFor={htmlFor}\n {...props}\n >\n {children}\n {required && (\n <span\n aria-label=\"required\"\n className={cn(\n 'text-destructive ml-1',\n hideRequiredIndicator && 'sr-only'\n )}\n >\n {requiredIndicator || '*'}\n </span>\n )}\n </LabelPrimitive.Root>\n \n {showHelperText && (\n <p className={cn('text-muted-foreground', helperTextClassName)}>\n {helperText}\n </p>\n )}\n \n {hasError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className={cn('text-destructive', errorClassName)}\n >\n {error}\n </p>\n )}\n </>\n );\n});\n\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","/**\n * @file Textarea Component\n * @package @jmruthers/pace-core\n * @module Textarea\n * @since 0.5.141\n *\n * A multi-line text input component with consistent styling matching the Input component.\n * Provides flexible, accessible textarea component with consistent styling and behavior.\n *\n * Features:\n * - Multiple textarea variants (default, destructive)\n * - Multiple textarea sizes (sm, md, lg)\n * - Error state styling\n * - Forwarded ref support\n * - Consistent styling with Input component\n *\n * @example\n * ```tsx\n * // Basic textarea\n * <Textarea placeholder=\"Enter your message...\" />\n * \n * // Textarea with variants and sizes\n * <Textarea \n * variant=\"destructive\" \n * size=\"lg\" \n * placeholder=\"Error textarea\" \n * />\n * \n * // Textarea with error state\n * <Textarea \n * placeholder=\"Comments\" \n * error={true}\n * />\n * ```\n *\n * @accessibility\n * - Proper ARIA attributes and roles\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n */\n\nimport * as React from 'react';\nimport { cn } from '../../utils/core/cn';\n\n// ============================================================================\n// TEXTAREA COMPONENT\n// ============================================================================\n\nexport interface TextareaProps\n extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n /**\n * Textarea variant style\n */\n variant?: 'default' | 'destructive';\n \n /**\n * Textarea size\n */\n size?: 'sm' | 'md' | 'lg';\n \n /**\n * Error state for styling\n */\n error?: boolean;\n}\n\n/**\n * Textarea component\n * A flexible, accessible textarea component with multiple variants and sizes.\n * Matches the Input component API and styling for consistency.\n * \n * @param props - Textarea configuration and styling\n * @param ref - Forwarded ref to the textarea element\n * @returns JSX.Element - The rendered textarea element\n * \n * @example\n * ```tsx\n * // Basic textarea\n * <Textarea placeholder=\"Enter your message...\" />\n * \n * // Textarea with error state\n * <Textarea \n * placeholder=\"Comments\" \n * error={true}\n * />\n * \n * // Large textarea with destructive variant\n * <Textarea \n * variant=\"destructive\" \n * size=\"lg\" \n * placeholder=\"Error textarea\" \n * />\n * ```\n */\nfunction Textarea({ className, variant = 'default', size = 'md', error, ref, ...props }: TextareaProps & { ref?: React.Ref<HTMLTextAreaElement> }) {\n return (\n <textarea\n className={cn(\n // Base styles (matching Input component)\n 'flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',\n \n // Variant styles\n {\n 'border-input': variant === 'default' && !error,\n 'border-destructive focus-visible:ring-destructive': variant === 'destructive' || error,\n },\n \n // Size styles\n {\n 'min-h-[60px] px-2 py-1 text-xs': size === 'sm',\n 'min-h-[80px] px-3 py-2 text-sm': size === 'md',\n 'min-h-[100px] px-4 py-3 text-base': size === 'lg',\n },\n \n className\n )}\n ref={ref}\n {...props}\n />\n );\n}\n\nTextarea.displayName = 'Textarea';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Textarea };\n\n","import React, { useState, useEffect, useCallback, useRef, useContext, useMemo } from 'react';\nimport { FileText, ExternalLink } from 'lucide-react';\nimport { FileReference, FileCategory } from '../../types/file-reference';\nimport { usePublicFileDisplay } from '../../hooks/public/usePublicFileDisplay';\nimport { useFileDisplay } from '../../hooks/useFileDisplay';\nimport { useFileUrl } from '../../hooks/useFileUrl';\nimport { PublicPageContext, useIsPublicPage } from '../PublicLayout/PublicPageProvider';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter } from '../Dialog/Dialog';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { logger } from '../../utils/core/logger';\n\n/**\n * Size classes for fallback display\n */\nconst fallbackSizeClasses = {\n xs: 'size-4 text-xs',\n sm: 'size-6 text-sm',\n md: 'size-8 text-base',\n lg: 'size-12 text-lg',\n xl: 'size-16 text-xl',\n '2xl': 'size-20 text-2xl'\n};\n\n/**\n * Base classes for fallback display\n */\nconst fallbackBaseClasses = 'size-full grid place-items-center text-center text-sec-600 font-semibold';\n\n/**\n * Helper function to compute fallback classes for a given size\n */\nfunction getFallbackClasses(size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' = 'md'): string {\n const sizeClass = fallbackSizeClasses[size];\n return `${fallbackBaseClasses} ${sizeClass}`.trim();\n}\n\n/**\n * Default fallback text generator - extracts initials from file name\n */\nfunction defaultGenerateFallbackText(fileName?: string): string {\n if (!fileName) return 'FL';\n \n // Extract initials from file name (without extension)\n const baseName = fileName.replace(/\\.[^/.]+$/, '');\n const words = baseName.split(/[\\s\\-_]+/);\n \n if (words.length === 0) return 'FL';\n \n return words\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3); // Max 3 characters\n}\n\nexport interface FileDisplayProps {\n table_name: string;\n record_id: string;\n /** \n * Optional organisation ID. When not provided (undefined), the component will automatically\n * search for files in both user-scoped (organisation_id = null) and organisation-scoped contexts.\n * If both types of files exist, organisation-scoped files are preferred.\n * When explicitly set to null, only user-scoped files are searched.\n */\n organisation_id?: string;\n category?: FileCategory;\n /** Display only a single file instead of all files. Uses first file (prefers images) from all files, without category filtering */\n displayOnly?: boolean;\n showDelete?: boolean;\n className?: string;\n /** Classes to apply to the first child element of <figure> (img, p, or other elements) */\n imgClassName?: string;\n children?: React.ReactNode;\n /** Custom loading component to render during data fetching */\n loadingComponent?: React.ComponentType;\n /** Custom error component to render when an error occurs */\n errorComponent?: React.ComponentType<{ error: Error | string | null; retry?: () => void }>;\n /** Whether to show fallback UI when no file is available or image fails to load */\n showFallback?: boolean;\n /** Custom function to generate fallback text from file name or other context */\n generateFallbackText?: (fileName?: string) => string;\n /** Explicit fallback text to display (overrides generateFallbackText) */\n fallbackText?: string;\n /** Source text to use for generating fallback text (overrides filename) */\n fallbackSourceText?: string;\n /** Size variant for fallback display (only applies when showFallback is true) */\n fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** \n * Enable children rendering in displayOnly mode. When true, uses standard display path \n * (with children support) even if showDelete is false. The delete button will only appear \n * if showDelete is also true.\n */\n enableChildren?: boolean;\n /** Whether to show metadata (filename, filesize, mimetype) in figcaption. Defaults to true. */\n showMetadata?: boolean;\n}\n\n// Shared rendering logic for file display\ninterface FileDisplayContentProps {\n isLoading: boolean;\n error: string | Error | null;\n fileUrl: string | null;\n fileReference: FileReference | null;\n fileReferences: FileReference[];\n fileUrls: Map<string, string>;\n fileCount: number;\n category: FileCategory | undefined;\n displayOnly: boolean;\n showDelete: boolean;\n className: string;\n imgClassName?: string;\n children?: React.ReactNode;\n onDelete?: () => Promise<void>;\n clearError?: () => void;\n organisation_id: string | undefined;\n loadingComponent?: React.ComponentType;\n errorComponent?: React.ComponentType<{ error: Error | string | null; retry?: () => void }>;\n showFallback?: boolean;\n generateFallbackText?: (fileName?: string) => string;\n fallbackText?: string;\n fallbackSourceText?: string;\n fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n enableChildren?: boolean;\n showMetadata?: boolean;\n}\n\nfunction FileDisplayContent({\n isLoading,\n error,\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n category,\n displayOnly,\n showDelete,\n className,\n imgClassName,\n children,\n onDelete,\n clearError,\n organisation_id,\n loadingComponent: LoadingComponent,\n errorComponent: ErrorComponent,\n showFallback = false,\n generateFallbackText = defaultGenerateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize = 'md',\n enableChildren = false,\n showMetadata = true\n}: FileDisplayContentProps) {\n const [imageError, setImageError] = useState(false);\n const [internalFileUrls, setInternalFileUrls] = useState<Map<string, string>>(new Map(fileUrls));\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const fileReferencesRef = useRef<FileReference[]>([]);\n\n // Compute fallback text\n const computedFallbackText = useMemo(() => {\n if (fallbackText) return fallbackText;\n // Use fallbackSourceText if provided, otherwise fall back to filename\n const sourceText = fallbackSourceText ?? fileReference?.file_metadata?.fileName;\n return generateFallbackText(sourceText);\n }, [fallbackText, fallbackSourceText, fileReference, generateFallbackText]);\n\n // Compute fallback classes\n const fallbackClasses = useMemo(() => {\n return getFallbackClasses(fallbackSize);\n }, [fallbackSize]);\n\n // Sync fileUrls prop with internal state\n // Track file references to detect when they change and sync URLs\n useEffect(() => {\n const currentIds = fileReferences.map(f => f.id).join(',');\n const prevIds = fileReferencesRef.current.map(f => f.id).join(',');\n \n if (currentIds !== prevIds) {\n fileReferencesRef.current = fileReferences;\n // Reset internal URLs when file references change, then immediately sync from props\n setInternalFileUrls(new Map(fileUrls));\n } else {\n // If file references haven't changed, just sync URLs\n setInternalFileUrls(new Map(fileUrls));\n }\n }, [fileReferences, fileUrls]);\n\n const handleDeleteClick = () => {\n setDeleteDialogOpen(true);\n };\n\n const handleDeleteConfirm = async () => {\n setDeleteDialogOpen(false);\n if (onDelete) {\n await onDelete();\n }\n setImageError(false);\n };\n\n const handleImageError = () => {\n setImageError(true);\n };\n\n const getFileIcon = (fileType: string) => {\n if (fileType.startsWith('image/')) return '🖼️';\n if (fileType.startsWith('video/')) return '🎥';\n if (fileType.startsWith('audio/')) return '🎵';\n if (fileType.includes('pdf')) return '📄';\n if (fileType.includes('word')) return '📝';\n if (fileType.includes('excel') || fileType.includes('spreadsheet')) return '📊';\n if (fileType.includes('powerpoint') || fileType.includes('presentation')) return '📊';\n return '📁';\n };\n\n const formatFileSize = (bytes: number) => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n };\n\n // Check for errors first - errors should be shown even if fileCount is 0\n if (error) {\n if (ErrorComponent) {\n return <ErrorComponent error={error} retry={clearError} />;\n }\n \n // Show fallback if enabled\n if (showFallback) {\n return (\n <figure className={className} title=\"File unavailable\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Error loading file: {error instanceof Error ? error.message : String(error)}\n </p>\n {clearError && (\n <Button\n onClick={clearError}\n className=\"mt-2\"\n aria-label=\"Retry loading file\"\n >\n Try again\n </Button>\n )}\n </figure>\n );\n }\n\n // Show fallback immediately if enabled and we have no files (even during loading)\n // This provides better UX by showing fallback UI instead of a spinner when we know there are no files\n if (fileCount === 0 && !isLoading) {\n // Show fallback if enabled\n if (showFallback) {\n return (\n <figure className={className} title=\"No file\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n {children}\n </figure>\n );\n }\n \n return (\n <figure className={`text-sec-500 text-center p-4 ${className}`}>\n <p>No files found</p>\n {children}\n </figure>\n );\n }\n\n // During loading, show fallback if enabled (better UX than spinner for empty states)\n if (isLoading && showFallback && fileCount === 0) {\n return (\n <figure className={className} title=\"Loading...\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n {children}\n </figure>\n );\n }\n\n if (isLoading) {\n if (LoadingComponent) {\n return <LoadingComponent />;\n }\n return (\n <figure className={className} title=\"Loading\">\n <p className=\"flex items-center justify-center p-4\">\n <LoadingSpinner />\n </p>\n </figure>\n );\n }\n\n // Single file display (when category or displayOnly is specified)\n if ((category || displayOnly) && fileReference) {\n const isImage = fileReference.file_metadata.fileType?.startsWith('image/');\n \n // Simplified image-only display when displayOnly is true and it's an image\n // Only use simplified path if enableChildren is not explicitly enabled\n if (displayOnly && isImage && !showDelete && !enableChildren) {\n // Show fallback if image error occurred and fallback is enabled\n if (imageError && showFallback) {\n return (\n <figure className={className} title={fileReference.file_metadata.fileName || 'File'}>\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n // Show loading skeleton if URL is not available yet\n if (!fileUrl) {\n return (\n <figure className={className || \"max-w-full h-48\"} title=\"Loading\">\n <p className={fallbackClasses}>\n <LoadingSpinner />\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={className || \"\"}>\n <img\n src={fileUrl}\n alt={fileReference.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n />\n </figure>\n );\n }\n \n // Document link display when displayOnly is true and file is not an image\n // Render non-image files as clickable links that open in a new tab\n if (displayOnly && !isImage && fileUrl && fileReference && !showDelete) {\n const fileName = fileReference.file_metadata?.fileName || 'Document';\n const ariaLabel = `Open ${fileName} in new tab`;\n \n return (\n <figure className={className}>\n <a\n href={fileUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={ariaLabel}\n className=\"flex items-center gap-2 p-3 bg-sec-50 border border-sec-200 rounded-lg hover:bg-sec-100 transition-colors text-main-600 hover:text-main-700 focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2\"\n >\n <FileText className=\"size-5 shrink-0\" aria-hidden=\"true\" />\n <span className=\"flex-1 font-medium truncate\">\n {fileName}\n </span>\n <ExternalLink className=\"size-5 shrink-0\" aria-hidden=\"true\" />\n </a>\n {showMetadata && (\n <figcaption>\n <p>{fileName}</p>\n {fileReference.file_metadata.fileSize && (\n <p>{formatFileSize(fileReference.file_metadata.fileSize)} • {fileReference.file_metadata.fileType}</p>\n )}\n </figcaption>\n )}\n </figure>\n );\n }\n \n // Standard single file display with wrapper\n // For displayOnly mode, if fallback is enabled and there's no URL or image error, show fallback instead of folder icon\n if (displayOnly && showFallback && (!fileUrl || imageError || !isImage)) {\n return (\n <figure className={className} title={fileReference.file_metadata.fileName || 'File'}>\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={`relative ${className}`}>\n {isImage && fileUrl && !imageError ? (\n <>\n <img\n src={fileUrl}\n alt={fileReference.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n />\n {showDelete && (\n <>\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n className=\"absolute top-2 right-2\"\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogContent size=\"sm\">\n <DialogHeader>\n <DialogTitle>Confirm Delete</DialogTitle>\n </DialogHeader>\n <DialogBody>\n <p>Are you sure you want to delete this file? This action cannot be undone.</p>\n </DialogBody>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={handleDeleteConfirm}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )}\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n ) : isImage && imageError && showFallback ? (\n // Show fallback when image fails to load and fallback is enabled\n <>\n <p className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>\n {computedFallbackText}\n </p>\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n ) : (\n <>\n <p className=\"flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200\">\n <span className=\"text-2xl\">\n {getFileIcon(fileReference.file_metadata.fileType || '')}\n </span>\n {showDelete && (\n <>\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n className=\"ml-auto\"\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogContent size=\"sm\">\n <DialogHeader>\n <DialogTitle>Confirm Delete</DialogTitle>\n </DialogHeader>\n <DialogBody>\n <p>Are you sure you want to delete this file? This action cannot be undone.</p>\n </DialogBody>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={handleDeleteConfirm}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )}\n </p>\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n )}\n </figure>\n );\n }\n\n // Multiple files display\n return (\n <figure className={`space-y-2 ${className}`}>\n {fileReferences.map((fileRef) => {\n const isImage = fileRef.file_metadata.fileType?.startsWith('image/');\n const fileUrl = internalFileUrls.get(fileRef.id) || null;\n const canDownload = !isImage && fileUrl;\n \n return (\n <figure key={fileRef.id} className=\"flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200\">\n {isImage && fileUrl ? (\n <img\n src={fileUrl}\n alt={fileRef.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n />\n ) : (\n <span className=\"text-2xl\">\n {getFileIcon(fileRef.file_metadata.fileType || '')}\n </span>\n )}\n {showMetadata && (\n <figcaption className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-sec-900 truncate\">\n {fileRef.file_metadata.fileName || 'Unknown file'}\n </p>\n {(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType || fileRef.file_metadata.category) && (\n <p className=\"text-sm text-sec-500\">\n {fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize)}\n {fileRef.file_metadata.fileSize && fileRef.file_metadata.fileType && ' • '}\n {fileRef.file_metadata.fileType}\n {(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType) && fileRef.file_metadata.category && ' • '}\n {fileRef.file_metadata.category}\n </p>\n )}\n </figcaption>\n )}\n <p className=\"flex items-center space-x-2\">\n {canDownload && (\n <a\n href={fileRef.file_path}\n download={fileRef.file_metadata.fileName || 'download'}\n className=\"text-main-500 hover:text-main-700 p-1\"\n title=\"Download file\"\n >\n ↓\n </a>\n )}\n {showDelete && onDelete && (\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n )}\n </p>\n </figure>\n );\n })}\n {children}\n </figure>\n );\n}\n\n/**\n * Internal component for public page context\n * Uses PublicPageContext to get Supabase client\n */\nfunction FileDisplayPublic({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n const publicPageContext = useContext(PublicPageContext);\n const supabase = publicPageContext?.supabase ?? null;\n\n if (!supabase) {\n // If fallback is enabled, show fallback UI instead of error\n if (showFallback) {\n return (\n <FileDisplayContent\n isLoading={false}\n error={null}\n fileUrl={null}\n fileReference={null}\n fileReferences={[]}\n fileUrls={new Map()}\n fileCount={0}\n category={category}\n displayOnly={displayOnly}\n showDelete={false}\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={undefined}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n }\n \n // Only show error if fallback is not enabled\n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Supabase client not available in public context\n </p>\n </figure>\n );\n }\n\n const {\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n isLoading,\n error,\n refetch\n } = usePublicFileDisplay(\n table_name,\n record_id,\n organisation_id,\n category,\n { supabase }\n );\n\n // Log errors for debugging public file display issues\n if (error) {\n logger.error('FileDisplayPublic', 'Error fetching file', {\n table_name,\n record_id,\n organisation_id,\n category,\n error: error.message,\n errorStack: error.stack\n });\n }\n\n // Public context doesn't support delete operations\n const handleDelete = async () => {\n // Delete operations are not available in public context for security reasons\n };\n\n // Handle displayOnly mode: select first file (prefer images) from all files\n let finalFileReference = fileReference;\n let finalFileUrl = fileUrl;\n let finalFileReferences = fileReferences;\n let finalFileCount = fileCount;\n\n if (displayOnly && !category && fileReferences.length > 0) {\n // Prefer image files\n const imageFiles = fileReferences.filter(f => \n f.file_metadata.fileType?.startsWith('image/')\n );\n const targetFile = imageFiles.length > 0 ? imageFiles[0] : fileReferences[0];\n finalFileReference = targetFile;\n finalFileReferences = [targetFile];\n finalFileCount = 1;\n \n // Get URL for target file from fileUrls map\n finalFileUrl = fileUrls.get(targetFile.id) || null;\n }\n\n return (\n <FileDisplayContent\n isLoading={isLoading}\n error={error}\n fileUrl={finalFileUrl}\n fileReference={finalFileReference}\n fileReferences={finalFileReferences}\n fileUrls={fileUrls}\n fileCount={finalFileCount}\n category={category}\n displayOnly={displayOnly}\n showDelete={false} // Never show delete in public context\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={showDelete ? handleDelete : undefined}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n\n/**\n * Internal component for authenticated page context\n * Uses UnifiedAuthProvider to get Supabase client\n */\nfunction FileDisplayAuthenticated({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n const { supabase } = useUnifiedAuth();\n\n if (!supabase) {\n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Supabase client not available in authenticated context\n </p>\n </figure>\n );\n }\n\n const {\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n isLoading,\n error,\n refetch\n } = useFileDisplay(\n table_name,\n record_id,\n organisation_id,\n category,\n { supabase }\n );\n\n // Consolidated state for displayOnly mode\n const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState<FileReference | null>(null);\n \n // Use fileUrls map if available, otherwise use useFileUrl hook\n const displayOnlyFileUrlFromMap = displayOnlyFileReference ? fileUrls.get(displayOnlyFileReference.id) : null;\n const displayOnlyFileUrlHook = useFileUrl(\n displayOnlyFileReference && !displayOnlyFileUrlFromMap ? displayOnlyFileReference : null,\n {\n supabase,\n organisation_id,\n autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference\n }\n );\n const displayOnlyFileUrl = displayOnlyFileUrlFromMap || displayOnlyFileUrlHook.url;\n\n // Handle displayOnly mode: select first file (prefer images) from all files\n useEffect(() => {\n if (displayOnly && !category && fileReferences.length > 0) {\n // Prefer image files\n const imageFiles = fileReferences.filter(f => \n f.file_metadata.fileType?.startsWith('image/')\n );\n const targetFile = imageFiles.length > 0 ? imageFiles[0] : fileReferences[0];\n setDisplayOnlyFileReference(targetFile);\n // URL generation is handled by useFileUrl hook or fileUrls map\n } else {\n // Clear displayOnly files when not in displayOnly mode or when category is specified\n setDisplayOnlyFileReference(null);\n }\n }, [displayOnly, category, fileReferences, fileUrls]);\n\n // Delete operation - implementation pending\n const handleDelete = async () => {\n // TODO: Implement delete via FileReferenceService when delete functionality is needed\n };\n\n // Determine final file reference and URL based on mode\n let finalFileReference = fileReference;\n let finalFileUrl = fileUrl;\n let finalFileReferences = fileReferences;\n let finalFileCount = fileCount;\n let finalIsLoading = isLoading;\n let finalError = error;\n\n if (displayOnly && !category) {\n // DisplayOnly mode: use state-managed file reference and URL\n finalFileReference = displayOnlyFileReference;\n finalFileUrl = displayOnlyFileUrl;\n finalFileReferences = displayOnlyFileReference ? [displayOnlyFileReference] : [];\n finalFileCount = displayOnlyFileReference ? 1 : 0;\n // Include URL loading state in overall loading state\n if (!displayOnlyFileUrlFromMap) {\n finalIsLoading = isLoading || displayOnlyFileUrlHook.isLoading;\n finalError = error || displayOnlyFileUrlHook.error;\n }\n }\n\n return (\n <FileDisplayContent\n isLoading={finalIsLoading}\n error={finalError}\n fileUrl={finalFileUrl}\n fileReference={finalFileReference}\n fileReferences={finalFileReferences}\n fileUrls={fileUrls}\n fileCount={finalFileCount}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={showDelete ? handleDelete : undefined}\n clearError={refetch}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n\n/**\n * Component for displaying file references with context-awareness\n * \n * This component is context-aware and automatically detects whether it's being used\n * in a public or authenticated context. It fetches and displays files from storage.\n * \n * The component automatically detects context and uses:\n * - PublicPageProvider context for public pages\n * - UnifiedAuthProvider context for authenticated pages\n * \n * @param props - File display configuration\n * @param props.displayOnly - Display only a single file instead of all files. Uses first file (prefers images) from all files, without category filtering. When true:\n * - **Image files**: Renders a simplified image-only display without metadata or wrapper divs\n * - **Non-image files** (PDFs, Word docs, Excel files, etc.): Renders as clickable links that open in a new tab with document icon, filename, and external link icon. Links include proper security attributes (`rel=\"noopener noreferrer\"`) and accessibility features (ARIA labels, keyboard navigation, visible focus states)\n * - If `showDelete={true}`, uses standard wrapper behavior instead of simplified display\n * @param props.category - Optional category filter. When specified, only displays files matching this category and uses single file display variant.\n * @returns React element with file display\n */\nexport function FileDisplay({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n // Check which context we're in and route to the appropriate component\n const isPublicPage = useIsPublicPage();\n \n // If we're in a public page context, use the public component\n if (isPublicPage) {\n return (\n <FileDisplayPublic\n table_name={table_name}\n record_id={record_id}\n organisation_id={organisation_id}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n }\n\n // Otherwise, use the authenticated component\n // It will show an error if not in UnifiedAuthProvider\n return (\n <FileDisplayAuthenticated\n table_name={table_name}\n record_id={record_id}\n organisation_id={organisation_id}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n","/**\n * @file Custom Hook for File URL Generation\n * @package @jmruthers/pace-core\n * @module Hooks/FileDisplay\n * \n * Extracts URL generation logic to eliminate duplication across FileDisplay components.\n * Handles both public and private file URL generation with proper error handling.\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { FileReference } from '../types/file-reference';\nimport { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useFileUrl');\n\nexport interface UseFileUrlOptions {\n /** Organisation ID for signed URL generation */\n organisation_id: string | undefined;\n /** Supabase client instance */\n supabase: SupabaseClient;\n /** Whether to auto-load URLs on mount */\n autoLoad?: boolean;\n}\n\nexport interface UseFileUrlReturn {\n /** Generated URL for the file reference */\n url: string | null;\n /** Whether URL is currently being generated */\n isLoading: boolean;\n /** Error if URL generation failed */\n error: Error | null;\n /** Manually trigger URL generation */\n loadUrl: () => Promise<void>;\n /** Clear the current URL and error */\n clear: () => void;\n}\n\n/**\n * Custom hook for generating file URLs (public or signed) for a single file reference\n * \n * @param fileReference - The file reference to generate URL for (null if no file)\n * @param options - Configuration options\n * @returns Hook return object with URL, loading state, and controls\n */\nexport function useFileUrl(\n fileReference: FileReference | null,\n options: UseFileUrlOptions\n): UseFileUrlReturn {\n const { organisation_id, supabase, autoLoad = true } = options;\n \n const [url, setUrl] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n const fileReferenceIdRef = useRef<string | null>(null);\n\n const loadUrl = useCallback(async () => {\n if (!fileReference) {\n setUrl(null);\n setIsLoading(false);\n setError(null);\n return;\n }\n\n // Skip if already loading or URL already exists for this file\n if (isLoading || (url && fileReferenceIdRef.current === fileReference.id)) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n fileReferenceIdRef.current = fileReference.id;\n\n try {\n let generatedUrl: string | null = null;\n\n if (fileReference.is_public) {\n // Public files: generate public URL\n generatedUrl = getPublicUrl(supabase, fileReference.file_path, true);\n } else {\n // Private files: generate signed URL\n const signedUrlResult = await getSignedUrl(supabase, fileReference.file_path, {\n appName: 'file-reference',\n orgId: organisation_id,\n expiresIn: 3600\n });\n generatedUrl = signedUrlResult?.url || null;\n }\n\n setUrl(generatedUrl);\n setError(null);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to generate file URL');\n setError(error);\n setUrl(null);\n log.error('Error generating URL:', error);\n } finally {\n setIsLoading(false);\n }\n }, [fileReference, supabase, organisation_id, isLoading, url]);\n\n const clear = useCallback(() => {\n setUrl(null);\n setError(null);\n setIsLoading(false);\n fileReferenceIdRef.current = null;\n }, []);\n\n // Auto-load URL when fileReference changes\n useEffect(() => {\n if (autoLoad) {\n // Reset URL when file reference changes\n if (fileReferenceIdRef.current !== fileReference?.id) {\n setUrl(null);\n setError(null);\n }\n \n if (fileReference && !url && !isLoading) {\n loadUrl();\n }\n }\n }, [fileReference?.id, autoLoad, loadUrl, url, isLoading]);\n\n return {\n url,\n isLoading,\n error,\n loadUrl,\n clear\n };\n}\n\n","// File Reference React Hooks\n// Provides React hooks for managing file references\n\nimport { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { \n FileReference, \n FileUploadOptions, \n FileReferenceService,\n FileUploadResult,\n FileCategory\n} from '../types/file-reference';\nimport { createFileReferenceService, uploadFileWithReference } from '../utils/file-reference';\nimport { getPublicUrl, getSignedUrl, generateFileUrlsBatch } from '../utils/storage/helpers';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useFileReference');\n\ntype UrlRefreshCallback = () => void;\n\n/**\n * Shared interval manager to avoid spawning multiple intervals for the same file reference\n */\nconst urlRefreshManager = {\n subscriptions: new Map<string, { callbacks: Set<UrlRefreshCallback>; intervalId: NodeJS.Timeout | null }>(),\n\n subscribe(key: string, callback: UrlRefreshCallback) {\n let entry = this.subscriptions.get(key);\n if (!entry) {\n entry = { callbacks: new Set(), intervalId: null };\n this.subscriptions.set(key, entry);\n }\n\n entry.callbacks.add(callback);\n\n if (!entry.intervalId) {\n entry.intervalId = setInterval(() => {\n entry?.callbacks.forEach((cb) => cb());\n }, 55 * 60 * 1000);\n }\n\n return () => {\n this.unsubscribe(key, callback);\n };\n },\n\n unsubscribe(key: string, callback: UrlRefreshCallback) {\n const entry = this.subscriptions.get(key);\n if (!entry) return;\n\n entry.callbacks.delete(callback);\n\n if (entry.callbacks.size === 0) {\n if (entry.intervalId) {\n clearInterval(entry.intervalId);\n }\n this.subscriptions.delete(key);\n }\n }\n};\n\nexport function useFileReference(supabase: SupabaseClient) {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const service = useMemo(() => createFileReferenceService(supabase), [supabase]);\n\n const uploadFile = useCallback(async (options: FileUploadOptions, file: File): Promise<FileUploadResult | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n const result = await uploadFileWithReference(supabase, options, file);\n return result;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Upload failed';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [supabase]);\n\n const getFileReference = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileReference(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file reference';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileUrl = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<string | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileUrl(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file URL';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getSignedUrl = useCallback(async (table_name: string, record_id: string, organisation_id: string, expires_in?: number): Promise<string | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getSignedUrl(table_name, record_id, organisation_id, expires_in);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get signed URL';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const updateFileReference = useCallback(async (id: string, updates: Partial<FileReference>): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.updateFileReference(id, updates);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to update file reference';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const deleteFileReference = useCallback(async (table_name: string, record_id: string, organisation_id: string, delete_file?: boolean): Promise<boolean> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.deleteFileReference(table_name, record_id, organisation_id, delete_file);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to delete file reference';\n setError(errorMessage);\n return false;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const listFileReferences = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<FileReference[]> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.listFileReferences(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to list file references';\n setError(errorMessage);\n return [];\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileCount = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<number> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileCount(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file count';\n setError(errorMessage);\n return 0;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileReferenceById = useCallback(async (id: string, organisation_id: string): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileReferenceById(id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file reference by ID';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFilesByCategory = useCallback(async (\n table_name: string, \n record_id: string, \n category: FileCategory, \n organisation_id: string\n ): Promise<FileReference[]> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFilesByCategory(table_name, record_id, category, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get files by category';\n setError(errorMessage);\n return [];\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n return {\n isLoading,\n error,\n uploadFile,\n getFileReference,\n getFileReferenceById,\n getFileUrl,\n getSignedUrl,\n updateFileReference,\n deleteFileReference,\n listFileReferences,\n getFilesByCategory,\n getFileCount,\n clearError\n };\n}\n\nexport function useFileReferenceForRecord(\n supabase: SupabaseClient,\n table_name: string,\n record_id: string,\n organisation_id: string\n) {\n const {\n isLoading,\n error,\n getFileUrl,\n getFileReference,\n updateFileReference,\n deleteFileReference,\n listFileReferences,\n getFileCount,\n clearError\n } = useFileReference(supabase);\n\n const [fileUrl, setFileUrl] = useState<string | null>(null);\n const [fileReference, setFileReference] = useState<FileReference | null>(null);\n const [fileReferences, setFileReferences] = useState<FileReference[]>([]);\n const [fileCount, setFileCount] = useState<number>(0);\n const refreshSubscriptionRef = useRef<(() => void) | null>(null);\n\n const loadFileReference = useCallback(async () => {\n const reference = await getFileReference(table_name, record_id, organisation_id);\n setFileReference(reference);\n return reference;\n }, [getFileReference, table_name, record_id, organisation_id]);\n\n const loadFileUrl = useCallback(async () => {\n const url = await getFileUrl(table_name, record_id, organisation_id);\n setFileUrl(url);\n return url;\n }, [getFileUrl, table_name, record_id, organisation_id]);\n\n const loadFileReferences = useCallback(async () => {\n const references = await listFileReferences(table_name, record_id, organisation_id);\n setFileReferences(references);\n return references;\n }, [listFileReferences, table_name, record_id, organisation_id]);\n\n const loadFileCount = useCallback(async () => {\n const count = await getFileCount(table_name, record_id, organisation_id);\n setFileCount(count);\n return count;\n }, [getFileCount, table_name, record_id, organisation_id]);\n\n const deleteFile = useCallback(async (delete_file?: boolean) => {\n const success = await deleteFileReference(table_name, record_id, organisation_id, delete_file);\n if (success) {\n setFileReference(null);\n setFileUrl(null);\n await loadFileCount();\n }\n return success;\n }, [deleteFileReference, table_name, record_id, organisation_id, loadFileCount]);\n\n // Auto-refresh signed URLs before expiration (refresh 5 minutes before 1 hour expiry)\n useEffect(() => {\n if (refreshSubscriptionRef.current) {\n refreshSubscriptionRef.current();\n refreshSubscriptionRef.current = null;\n }\n\n if (!fileReference || fileReference.is_public) {\n // Only refresh private files (signed URLs expire)\n return;\n }\n\n // Refresh signed URL 5 minutes before expiration (55 minutes into the 1-hour expiry)\n const key = `${fileReference.table_name}:${fileReference.record_id}:${organisation_id}`;\n refreshSubscriptionRef.current = urlRefreshManager.subscribe(key, () => {\n loadFileUrl();\n });\n\n return () => {\n if (refreshSubscriptionRef.current) {\n refreshSubscriptionRef.current();\n refreshSubscriptionRef.current = null;\n }\n };\n }, [fileReference, loadFileUrl, organisation_id]);\n\n return {\n isLoading,\n error,\n fileUrl,\n fileReference,\n fileReferences,\n fileCount,\n loadFileReference,\n loadFileUrl,\n loadFileReferences,\n loadFileCount,\n deleteFile,\n updateFileReference,\n clearError\n };\n}\n\n/**\n * Hook for getting a file reference by ID\n */\nexport function useFileReferenceById(\n supabase: SupabaseClient,\n fileReferenceId: string | null,\n organisationId: string | null\n) {\n const {\n isLoading,\n error,\n getFileReferenceById,\n clearError\n } = useFileReference(supabase);\n\n const [fileReference, setFileReference] = useState<FileReference | null>(null);\n const [fileUrl, setFileUrl] = useState<string | null>(null);\n\n const loadFileReference = useCallback(async () => {\n if (!fileReferenceId || !organisationId) {\n setFileReference(null);\n setFileUrl(null);\n return null;\n }\n\n const reference = await getFileReferenceById(fileReferenceId, organisationId);\n setFileReference(reference);\n return reference;\n }, [getFileReferenceById, fileReferenceId, organisationId]);\n\n useEffect(() => {\n loadFileReference();\n }, [loadFileReference]);\n\n // Load URL when file reference changes\n useEffect(() => {\n if (!fileReference || !fileReferenceId || !organisationId) {\n setFileUrl(null);\n return;\n }\n\n const loadUrl = async () => {\n const service = createFileReferenceService(supabase);\n const url = await service.getFileUrl(\n fileReference.table_name,\n fileReference.record_id,\n organisationId\n );\n setFileUrl(url);\n };\n\n loadUrl();\n }, [fileReference, fileReferenceId, organisationId, supabase]);\n\n return {\n isLoading,\n error,\n fileReference,\n fileUrl,\n loadFileReference,\n clearError\n };\n}\n\n/**\n * Convenience hook for getting files by category with automatic URL loading.\n * \n * This hook wraps useFileReference().getFilesByCategory and automatically:\n * - Loads file references filtered by category\n * - Generates URLs for all files (public URLs for public files, signed URLs for private files)\n * - Manages state for fileReferences and fileUrls\n * - Auto-refetches when table_name, record_id, category, or organisation_id changes\n * \n * Use this hook when you need files by category with their URLs ready to display.\n * For more control, use useFileReference() directly and manage URLs yourself.\n */\nexport function useFilesByCategory(\n supabase: SupabaseClient,\n table_name: string,\n record_id: string,\n category: FileCategory | null,\n organisation_id: string | null\n) {\n const {\n isLoading,\n error,\n getFilesByCategory,\n clearError\n } = useFileReference(supabase);\n\n const [fileReferences, setFileReferences] = useState<FileReference[]>([]);\n const [fileUrls, setFileUrls] = useState<Map<string, string>>(new Map());\n\n const loadFiles = useCallback(async () => {\n if (!category || !organisation_id) {\n setFileReferences([]);\n setFileUrls(new Map());\n return [];\n }\n\n const files = await getFilesByCategory(table_name, record_id, category, organisation_id);\n setFileReferences(files);\n\n // Load URLs for all files in batch\n const urlMap = await generateFileUrlsBatch(supabase, files, {\n appName: 'file-reference',\n orgId: organisation_id,\n expiresIn: 3600\n });\n \n setFileUrls(urlMap);\n return files;\n }, [table_name, record_id, category, organisation_id, supabase, getFilesByCategory]);\n\n useEffect(() => {\n loadFiles();\n }, [loadFiles]);\n\n return {\n isLoading,\n error,\n fileReferences,\n fileUrls,\n loadFiles,\n clearError\n };\n}\n\n// Type definitions for the hooks\nexport type UseFileReferenceOptions = {\n table_name: string;\n record_id: string;\n organisation_id: string;\n};\n\nexport type UseFileReferenceReturn = {\n isLoading: boolean;\n error: string | null;\n uploadFile: (options: FileUploadOptions, file: File) => Promise<FileUploadResult | null>;\n getFileReference: (table_name: string, record_id: string, organisation_id: string) => Promise<FileReference | null>;\n getFileUrl: (table_name: string, record_id: string, organisation_id: string) => Promise<string | null>;\n getSignedUrl: (table_name: string, record_id: string, organisation_id: string, expires_in?: number) => Promise<string | null>;\n updateFileReference: (id: string, updates: Partial<FileReference>) => Promise<FileReference | null>;\n deleteFileReference: (table_name: string, record_id: string, organisation_id: string, delete_file?: boolean) => Promise<boolean>;\n listFileReferences: (table_name: string, record_id: string, organisation_id: string) => Promise<FileReference[]>;\n getFileCount: (table_name: string, record_id: string, organisation_id: string) => Promise<number>;\n clearError: () => void;\n};\n\nexport type UseFileReferenceForRecordReturn = {\n isLoading: boolean;\n error: string | null;\n fileUrl: string | null;\n fileReference: FileReference | null;\n fileReferences: FileReference[];\n fileCount: number;\n loadFileReference: () => Promise<FileReference | null>;\n loadFileUrl: () => Promise<string | null>;\n loadFileReferences: () => Promise<FileReference[]>;\n loadFileCount: () => Promise<number>;\n deleteFile: (delete_file?: boolean) => Promise<boolean>;\n updateFileReference: (id: string, updates: Partial<FileReference>) => Promise<FileReference | null>;\n clearError: () => void;\n};\n","/**\n * @file Avatar Component\n * @package @jmruthers/pace-core\n * @module Components\n * @since 0.1.0\n *\n * A simple and accessible avatar component for displaying user profile images or initials.\n * Supports three approaches for image display:\n * - File reference props (uses FileDisplay for Supabase storage)\n * - File ID (uses file reference lookup)\n * - Direct URL (simple img tag for public images)\n *\n * Features:\n * - Circular avatar display\n * - Image, fallback, and initials support\n * - Customizable size and style\n * - Keyboard and screen reader accessible\n * - Graceful fallback for missing images\n *\n * @example\n * ```tsx\n * // Avatar with direct URL\n * <Avatar \n * src=\"/user.jpg\" \n * alt=\"User\" \n * fallback=\"AB\"\n * />\n *\n * // Avatar with file reference props\n * <Avatar\n * table_name=\"user_profiles\"\n * record_id={userId}\n * organisation_id={orgId}\n * category={FileCategory.PROFILE_PHOTOS}\n * fallback=\"JD\"\n * />\n *\n * // Avatar with file ID\n * <Avatar\n * fileId={fileReferenceId}\n * organisation_id={orgId}\n * fallback=\"JD\"\n * />\n *\n * // Avatar with fallback only\n * <Avatar fallback=\"JD\" />\n * ```\n *\n * @accessibility\n * - Uses alt text for images\n * - Fallback content is accessible to screen readers\n * - Keyboard focusable and navigable\n */\n\nimport * as React from \"react\"\nimport { FileCategory } from \"../../types/file-reference\"\nimport { FileDisplay } from \"../FileDisplay/FileDisplay\"\nimport { useFileReferenceById } from \"../../hooks/useFileReference\"\nimport { useUnifiedAuth } from \"../../providers/services/UnifiedAuthProvider\"\nimport { cn } from \"../../utils/core/cn\"\n\n/**\n * Size variants for avatar\n */\nconst sizeClasses = {\n xs: 'size-4 text-xs',\n sm: 'size-6 text-sm',\n md: 'size-10 text-base',\n lg: 'size-12 text-lg',\n xl: 'size-16 text-xl',\n '2xl': 'size-20 text-2xl'\n}\n\ninterface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {\n // File reference approach (uses FileDisplay)\n table_name?: string\n record_id?: string\n organisation_id?: string\n category?: FileCategory\n \n // OR file ID approach (uses file reference lookup)\n fileId?: string\n \n // OR direct URL approach (simple <img> tag)\n src?: string\n alt?: string\n \n // Fallback (always required)\n fallback: string\n \n // Styling\n className?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n}\n\n/**\n * Avatar component for displaying user profile images or initials\n */\nconst Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(\n ({ \n table_name,\n record_id,\n organisation_id,\n category,\n fileId,\n src,\n alt,\n fallback,\n className,\n size = 'md',\n ...props \n }, ref) => {\n const [imageError, setImageError] = React.useState(false)\n const { supabase } = useUnifiedAuth()\n \n // For fileId approach, get file reference and URL\n // Only fetch if we have all required values\n const canFetchFileId = Boolean(fileId && organisation_id && supabase)\n const { fileReference, fileUrl: fileIdUrl, isLoading: fileIdLoading } = useFileReferenceById(\n supabase || ({} as any), // Hook requires SupabaseClient, but we check canFetchFileId before using result\n canFetchFileId ? fileId! : null,\n canFetchFileId ? organisation_id! : null\n )\n \n // Determine which approach to use\n const hasFileProps = table_name && record_id && organisation_id && category && supabase\n const hasFileId = canFetchFileId && fileIdUrl && !fileIdLoading\n const hasDirectUrl = src && !imageError\n \n // Determine if we should show fallback\n const showFallback = !hasDirectUrl && (!hasFileProps && !hasFileId) || imageError || (canFetchFileId && !fileIdUrl && !fileIdLoading)\n \n // Base classes for avatar container\n const baseClasses = size === 'md' \n ? \" size-10 overflow-hidden rounded-full\"\n : ` ${sizeClasses[size]} overflow-hidden rounded-full`\n \n // Fallback classes (don't include className to avoid conflicts)\n const fallbackClasses = \"size-full grid place-items-center text-center text-sec-50 bg-sec-500\"\n \n // Image classes for direct URL and fileId approaches\n const imageClasses = \"object-cover size-full\"\n \n // Container classes (include className here for container styling)\n const containerClasses = cn(baseClasses, className)\n \n // Handle image error for direct URL\n const handleImageError = React.useCallback(() => {\n setImageError(true)\n }, [])\n \n // Reset error when src changes\n React.useEffect(() => {\n if (src) {\n setImageError(false)\n }\n }, [src])\n \n return (\n <figure\n ref={ref}\n className={containerClasses}\n {...props}\n >\n {showFallback ? (\n <figcaption className={fallbackClasses} aria-label={alt || fallback}>\n {fallback}\n </figcaption>\n ) : hasFileProps ? (\n // File reference props approach - use FileDisplay\n <FileDisplay\n table_name={table_name!}\n record_id={record_id!}\n organisation_id={organisation_id!}\n category={category!}\n displayOnly={true}\n showFallback={true}\n fallbackText={fallback}\n className={cn(imageClasses, className)}\n />\n ) : hasFileId && fileIdUrl ? (\n // File ID approach - use img tag with fetched URL\n <img\n src={fileIdUrl}\n alt={alt || fallback}\n className={imageClasses}\n onError={handleImageError}\n />\n ) : hasDirectUrl ? (\n // Direct URL approach - use img tag\n <img\n src={src}\n alt={alt || fallback}\n className={imageClasses}\n onError={handleImageError}\n />\n ) : (\n // Fallback if nothing else works\n <figcaption className={fallbackClasses} aria-label={alt || fallback}>\n {fallback}\n </figcaption>\n )}\n </figure>\n )\n }\n)\n\nAvatar.displayName = \"Avatar\"\n\nexport { Avatar, type AvatarProps }\n","/**\n * @file Badge Component\n * @package @jmruthers/pace-core\n * @module Components\n * @since 0.1.0\n *\n * A small, non-interactive visual label component for displaying concise information\n * such as status indicators, tags, or labels. Acts as a visual alternative to buttons\n * for non-interactive content.\n *\n * Features:\n * - 27 combined variants (3 styles × 3 colors × 3 shades)\n * - Non-interactive by default (renders as <span>)\n * - Supports all pace-core color palettes (main, sec, acc)\n * - Customizable styling via className prop\n * - Accessible and screen reader friendly\n *\n * @example\n * ```tsx\n * // Basic badge with default variant\n * <Badge>New</Badge>\n *\n * // Badge with specific variant\n * <Badge variant=\"solid-main-normal\">Active</Badge>\n *\n * // Outline variant\n * <Badge variant=\"outline-sec-muted\">Pending</Badge>\n *\n * // Soft variant with accent color\n * <Badge variant=\"soft-acc-strong\">Featured</Badge>\n *\n * // Custom styling\n * <Badge variant=\"solid-main-normal\" className=\"px-4\">\n * Custom Badge\n * </Badge>\n * ```\n *\n * @accessibility\n * - Renders as semantic <span> element\n * - No focus styles (non-interactive by default)\n * - Screen reader friendly through semantic HTML\n * - Can be wrapped in interactive elements if needed\n */\n\nimport * as React from 'react';\nimport { cn } from '../../utils/core/cn';\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\nexport type BadgeVariant =\n | 'solid-main-muted' | 'solid-main-normal' | 'solid-main-strong'\n | 'solid-sec-muted' | 'solid-sec-normal' | 'solid-sec-strong'\n | 'solid-acc-muted' | 'solid-acc-normal' | 'solid-acc-strong'\n | 'outline-main-muted' | 'outline-main-normal' | 'outline-main-strong'\n | 'outline-sec-muted' | 'outline-sec-normal' | 'outline-sec-strong'\n | 'outline-acc-muted' | 'outline-acc-normal' | 'outline-acc-strong'\n | 'soft-main-muted' | 'soft-main-normal' | 'soft-main-strong'\n | 'soft-sec-muted' | 'soft-sec-normal' | 'soft-sec-strong'\n | 'soft-acc-muted' | 'soft-acc-normal' | 'soft-acc-strong';\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual variant of the badge (style-color-shade) */\n variant?: BadgeVariant;\n}\n\n// ============================================================================\n// VARIANT CONFIGURATION\n// ============================================================================\n\n/**\n * Shade configuration mapping\n * Maps shade names to background, text, border, and outline text color shades\n */\nconst shadeConfig = {\n muted: {\n bg: 200,\n text: 600,\n border: 400,\n outlineText: 600,\n outlineBg: 100,\n },\n normal: {\n bg: 500,\n text: 50,\n border: 700,\n outlineText: 700,\n outlineBg: 200,\n },\n strong: {\n bg: 700,\n text: 50,\n border: 800,\n outlineText: 900,\n outlineBg: 400,\n },\n} as const;\n\ntype Shade = keyof typeof shadeConfig;\n\n/**\n * Color palette options\n */\nconst colors = ['main', 'sec', 'acc'] as const;\ntype Color = typeof colors[number];\n\n/**\n * Style options\n */\nconst styles = ['solid', 'outline', 'soft'] as const;\ntype Style = typeof styles[number];\n\n/**\n * Build variant class string for a given style, color, and shade\n * Generates classes programmatically from configuration\n */\nfunction buildVariantClasses(style: Style, color: Color, shade: Shade): string {\n const cfg = shadeConfig[shade];\n const parts: string[] = [];\n \n if (style === 'solid') {\n // Solid: flat background colors\n parts.push(`bg-${color}-${cfg.bg}`, `text-${color}-${cfg.text}`);\n } else if (style === 'outline') {\n // Outline: outlined with light background\n parts.push('outline outline-1 -outline-offset-1', `outline-${color}-${cfg.border}`, `bg-${color}-${cfg.outlineBg}`, `text-${color}-${cfg.outlineText}`);\n } else if (style === 'soft') {\n // Soft: uses shadow-badge-soft utility with colored shadows\n parts.push(\n `bg-${color}-${cfg.bg}`,\n 'shadow-badge-soft',\n `shadow-${color}-${cfg.bg}`,\n `text-${color}-${cfg.text}`,\n 'my-1', 'ml-1', 'mr-2', 'py-0', 'px-2'\n );\n }\n \n return parts.join(' ');\n}\n\n/**\n * Generate all class name patterns for Tailwind scanning\n * This ensures Tailwind can detect all dynamically generated classes\n * \n * Tailwind v4 content scanning: These classes are listed here so Tailwind\n * can detect them during content scanning, even when built dynamically.\n * \n * Classes used: shadow-badge-soft shadow-main-200 shadow-main-500 shadow-main-700\n * shadow-sec-200 shadow-sec-500 shadow-sec-700 shadow-acc-200 shadow-acc-500 shadow-acc-700\n */\nconst tailwindClassScan = [\n // Solid background classes\n 'bg-main-100', 'bg-main-600', 'bg-main-900',\n 'bg-sec-100', 'bg-sec-600', 'bg-sec-900',\n 'bg-acc-100', 'bg-acc-600', 'bg-acc-900',\n // Solid text classes\n 'text-main-50', 'text-main-900',\n 'text-sec-50', 'text-sec-900',\n 'text-acc-50', 'text-acc-900',\n // Outline classes\n 'outline outline-1',\n 'outline-main-400', 'outline-main-700', 'outline-main-800',\n 'outline-sec-400', 'outline-sec-700', 'outline-sec-800',\n 'outline-acc-400', 'outline-acc-700', 'outline-acc-800',\n // Outline background classes\n 'bg-main-100', 'bg-main-200', 'bg-main-300',\n 'bg-sec-100', 'bg-sec-200', 'bg-sec-300',\n 'bg-acc-100', 'bg-acc-200', 'bg-acc-300',\n // Outline text classes\n 'text-main-500', 'text-main-600', 'text-main-800',\n 'text-sec-500', 'text-sec-600', 'text-sec-800',\n 'text-acc-500', 'text-acc-600', 'text-acc-800',\n // Soft background classes (solid, no opacity)\n 'bg-main-200', 'bg-main-500', 'bg-main-700',\n 'bg-sec-200', 'bg-sec-500', 'bg-sec-700',\n 'bg-acc-200', 'bg-acc-500', 'bg-acc-700',\n // Soft shadow utility classes - CRITICAL: These must be detected by Tailwind\n 'shadow-badge-soft',\n 'shadow-main-200', 'shadow-main-500', 'shadow-main-700',\n 'shadow-sec-200', 'shadow-sec-500', 'shadow-sec-700',\n 'shadow-acc-200', 'shadow-acc-500', 'shadow-acc-700',\n // Soft margin/padding classes\n 'my-3', 'mx-3', 'py-0', 'px-2',\n] as const;\n\n/**\n * Generate all variant class combinations programmatically\n * Uses the configuration to build the lookup map dynamically\n */\nfunction generateVariantClasses(): Record<BadgeVariant, string> {\n const variantClasses = {} as Record<BadgeVariant, string>;\n \n for (const style of styles) {\n for (const color of colors) {\n for (const shade of Object.keys(shadeConfig) as Shade[]) {\n const variant = `${style}-${color}-${shade}` as BadgeVariant;\n variantClasses[variant] = buildVariantClasses(style, color, shade);\n }\n }\n }\n \n return variantClasses;\n}\n\n// Pre-generate all variant classes\nconst variantClassesMap = generateVariantClasses();\n\n// Ensure Tailwind detects shadow-badge-soft class\n// This string literal ensures Tailwind v4 content scanning includes the class\nconst _tailwindShadowDetection = 'shadow-badge-soft';\n\n// ============================================================================\n// CLASS GENERATION FUNCTION\n// ============================================================================\n\n/**\n * Get badge classes based on variant\n * \n * Variant format: {style}-{color}-{shade}\n * - style: solid (flat), outline (bordered), soft (blurred)\n * - color: main, sec, acc\n * - shade: muted (dark on light), normal (light on medium), strong (light on dark)\n */\nfunction getBadgeClasses(variant: BadgeVariant = 'solid-main-normal'): string {\n const baseClasses = 'text-balance rounded-2xl px-3 py-1 mr-1 text-xs font-medium transition-colors box-border';\n return `${baseClasses} ${variantClassesMap[variant]}`;\n}\n\n// ============================================================================\n// BADGE COMPONENT\n// ============================================================================\n\n/**\n * Badge Component\n * A small, non-interactive visual label for displaying concise information.\n * \n * @component\n * @example\n * ```tsx\n * // Default variant\n * <Badge>New</Badge>\n * \n * // Specific variant\n * <Badge variant=\"solid-main-normal\">Active</Badge>\n * \n * // Outline variant\n * <Badge variant=\"outline-sec-muted\">Pending</Badge>\n * \n * // Soft variant\n * <Badge variant=\"soft-acc-strong\">Featured</Badge>\n * ```\n */\nfunction Badge({ className, variant = 'solid-main-normal', ref, ...props }: BadgeProps & { ref?: React.Ref<HTMLSpanElement> }) {\n const isSoftVariant = variant.startsWith('soft-');\n \n if (isSoftVariant) {\n // For soft variants, we need both shadow-badge-soft and shadow color class\n // twMerge treats all shadow-* classes as conflicting, so we need to add them after merging\n const variantClasses = getBadgeClasses(variant);\n // Extract the shadow color class from variantClasses (e.g., shadow-main-200)\n const shadowColorMatch = variantClasses.match(/\\bshadow-(\\w+)-(\\d+)\\b/);\n const shadowColorClass = shadowColorMatch ? shadowColorMatch[0] : '';\n \n // Remove shadow classes from variantClasses to avoid twMerge conflicts\n const classesWithoutShadows = variantClasses\n .replace(/\\bshadow-badge-soft\\b/g, '')\n .replace(/\\bshadow-\\w+-\\d+\\b/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n \n // Merge non-shadow classes first, then append shadow classes to ensure both are present\n // shadow-badge-soft first (defines shape), then shadow color (defines color)\n const mergedClasses = cn(classesWithoutShadows, className);\n const finalClasses = `${mergedClasses} shadow-badge-soft ${shadowColorClass}`.trim();\n \n return (\n <span\n ref={ref}\n className={finalClasses}\n {...props}\n />\n );\n }\n \n return (\n <span\n ref={ref}\n className={cn(getBadgeClasses(variant), className)}\n {...props}\n />\n );\n}\n\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Badge };\n\n","/**\n * @file Switch Component\n * @package @jmruthers/pace-core\n * @module Components/Switch\n * @since 0.5.67\n * \n * A toggle switch component built on Radix UI primitives.\n * Provides an accessible, keyboard-navigable switch for boolean states.\n * \n * Features:\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Space/Enter)\n * - Focus visible indicators\n * - Disabled state support\n * - Smooth animations\n * - Tailwind v4 compatible\n * - Theme-aware colors\n * \n * @example\n * ```tsx\n * import { Switch } from '@jmruthers/pace-core';\n * \n * function Example() {\n * const [checked, setChecked] = React.useState(false);\n * \n * return (\n * <div className=\"flex items-center gap-2\">\n * <Switch \n * checked={checked} \n * onCheckedChange={setChecked}\n * id=\"notifications\"\n * />\n * <label htmlFor=\"notifications\">\n * Enable notifications\n * </label>\n * </div>\n * );\n * }\n * ```\n * \n * @example With Form\n * ```tsx\n * import { Switch, Label } from '@jmruthers/pace-core';\n * \n * function FormExample() {\n * return (\n * <div className=\"flex items-center gap-2\">\n * <Switch id=\"terms\" />\n * <Label htmlFor=\"terms\">\n * I agree to the terms and conditions\n * </Label>\n * </div>\n * );\n * }\n * ```\n * \n * @example Disabled State\n * ```tsx\n * <Switch disabled checked />\n * ```\n * \n * @accessibility\n * - Uses Radix UI's accessible switch primitive\n * - Proper keyboard navigation (Space to toggle)\n * - Screen reader announcements for state changes\n * - Focus visible styles for keyboard users\n * - ARIA attributes handled automatically\n */\n\nimport * as React from \"react\";\nimport * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport { cn } from \"../../utils/core/cn\";\n\n/**\n * Switch component props\n * Extends all props from Radix UI Switch.Root\n */\nexport interface SwitchProps\n extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {\n /**\n * Additional CSS classes to apply to the switch\n */\n className?: string;\n}\n\n/**\n * Switch component\n * \n * A toggle switch for boolean states. Built on Radix UI for accessibility.\n * \n * @component\n * @example\n * ```tsx\n * <Switch checked={isEnabled} onCheckedChange={setIsEnabled} />\n * ```\n */\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitive.Root>,\n SwitchProps\n>(({ className, ...props }, ref) => (\n <SwitchPrimitive.Root\n className={cn(\n // Base styles\n \"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full\",\n // Border\n \"border-2 border-transparent\",\n // Transitions\n \"transition-colors\",\n // Focus styles\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600\",\n \"focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n // State-based colors (using theme variables)\n \"data-[state=checked]:bg-main-600\",\n \"data-[state=unchecked]:bg-sec-200\",\n className\n )}\n {...props}\n ref={ref}\n >\n <SwitchPrimitive.Thumb\n className={cn(\n // Base styles\n \"pointer-events-none block size-5 rounded-full\",\n // Background and shadow\n \"bg-background shadow-lg ring-0\",\n // Transition\n \"transition-transform\",\n // State-based position\n \"data-[state=checked]:translate-x-5\",\n \"data-[state=unchecked]:translate-x-0\"\n )}\n />\n </SwitchPrimitive.Root>\n));\n\nSwitch.displayName = SwitchPrimitive.Root.displayName;\n\nexport { Switch };\n","/**\n * @file Tabs Component System\n * @package @jmruthers/pace-core\n * @module Components/Tabs\n * @since 0.5.141\n *\n * A comprehensive tabs component system built on top of Radix UI primitives.\n * Provides accessible tabbed interfaces with keyboard navigation and ARIA support.\n *\n * Features:\n * - Controlled and uncontrolled modes\n * - Keyboard navigation (arrow keys)\n * - Accessible ARIA attributes\n * - Customizable styling via className\n * - Support for icons in triggers\n * - Compound component pattern\n *\n * @example\n * ```tsx\n * // Basic tabs\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * \n * // Controlled tabs\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"transport\">\n * <Plane size={16} /> Transport\n * </TabsTrigger>\n * <TabsTrigger value=\"accommodation\">\n * <Building size={16} /> Accommodation\n * </TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"transport\">\n * <TransportPlanningView />\n * </TabsContent>\n * <TabsContent value=\"accommodation\">\n * <AccommodationPlanningView />\n * </TabsContent>\n * </Tabs>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Arrow keys, Home, End)\n * - Screen reader support with proper ARIA attributes\n * - Focus management\n * - Tab panel association\n */\n\nimport * as React from 'react';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cn } from '../../utils/core/cn';\nimport { Button, type ButtonProps } from '../Button/Button';\n\n// ============================================================================\n// TABS ROOT COMPONENT\n// ============================================================================\n\nexport interface TabsProps extends TabsPrimitive.TabsProps {}\n\n/**\n * Tabs root component\n * Provides the context for tab navigation and state management\n * \n * @component\n * @example\n * ```tsx\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>...</TabsList>\n * <TabsContent value=\"tab1\">...</TabsContent>\n * </Tabs>\n * ```\n */\nconst Tabs = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Root>,\n TabsProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Root asChild {...props}>\n <section ref={ref} className={className}>\n {children}\n </section>\n </TabsPrimitive.Root>\n));\n\nTabs.displayName = TabsPrimitive.Root.displayName || 'Tabs';\n\n// ============================================================================\n// TABS LIST COMPONENT\n// ============================================================================\n\nexport interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> {}\n\n/**\n * TabsList component\n * Container for tab triggers\n * \n * @component\n * @example\n * ```tsx\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * ```\n */\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.List asChild {...props}>\n <nav\n ref={ref}\n className={cn(\n 'mb-0',\n className\n )}\n >\n {children}\n </nav>\n </TabsPrimitive.List>\n));\n\nTabsList.displayName = TabsPrimitive.List.displayName || 'TabsList';\n\n// ============================================================================\n// TABS TRIGGER COMPONENT\n// ============================================================================\n\nexport interface TabsTriggerProps \n extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'asChild'>,\n Pick<ButtonProps, 'variant' | 'size'> {}\n\n/**\n * TabsTrigger component\n * Individual tab button that activates a tab panel\n * \n * Uses Button component internally, allowing Button props (variant, size) to be passed through.\n * \n * @component\n * @example\n * ```tsx\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * \n * // With icon\n * <TabsTrigger value=\"transport\">\n * <Plane size={16} /> Transport\n * </TabsTrigger>\n * \n * // With Button variant\n * <TabsTrigger value=\"tab1\" variant=\"outline\" size=\"sm\">\n * Tab 1\n * </TabsTrigger>\n * ```\n */\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, variant, size, children, ...props }, ref) => {\n return (\n <TabsPrimitive.Trigger asChild {...props}>\n <Button\n ref={ref}\n variant={variant}\n size={size}\n className={cn(\n 'rounded-b-none',\n 'data-[state=active]:bg-main-50 data-[state=active]:text-main-950 data-[state=active]:border-t-1 data-[state=active]:border-x-1 data-[state=active]:shadow-md',\n 'data-[state=inactive]:bg-main-300 data-[state=inactive]:text-main-800 ',\n 'data-[state=inactive]:hover:bg-acc-400',\n className\n )}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n});\n\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName || 'TabsTrigger';\n\n// ============================================================================\n// TABS CONTENT COMPONENT\n// ============================================================================\n\nexport interface TabsContentProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> {}\n\n/**\n * TabsContent component\n * Container for tab panel content\n * \n * @component\n * @example\n * ```tsx\n * <TabsContent value=\"tab1\">\n * <div>Content for tab 1</div>\n * </TabsContent>\n * ```\n */\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n TabsContentProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Content asChild {...props}>\n <aside\n ref={ref}\n className={cn(\n 'focus-visible:outline-none focus-visible:bg-main-300',\n className\n )}\n >\n {children}\n </aside>\n </TabsPrimitive.Content>\n));\n\nTabsContent.displayName = TabsPrimitive.Content.displayName || 'TabsContent';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n\n","/**\n * @file Calendar Component\n * @package @jmruthers/pace-core\n * @module Components/Calendar\n * @since 0.5.141\n *\n * A date picker calendar component built on react-day-picker.\n * Provides accessible date selection with keyboard navigation and ARIA support.\n *\n * Features:\n * - Single, range, and multiple date selection modes\n * - Date disabling (past dates, weekends, etc.)\n * - Localization support (defaults to Australian locale with Monday as first day of week)\n * - Keyboard navigation\n * - Accessible date selection\n * - Customizable styling\n *\n * @example\n * ```tsx\n * // Single date selection\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * />\n * \n * // Date range selection\n * <Calendar\n * mode=\"range\"\n * selected={dateRange}\n * onSelect={setDateRange}\n * />\n * \n * // Multiple date selection\n * <Calendar\n * mode=\"multiple\"\n * selected={dates}\n * onSelect={setDates}\n * />\n * \n * // With disabled dates\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * disabled={(date) => date < new Date()}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Arrow keys, Page Up/Down, Home, End)\n * - Screen reader support with proper ARIA attributes\n * - Focus management\n * - Date announcements\n */\n\nimport * as React from 'react';\nimport { \n DayPicker, \n type DayPickerProps,\n useDayPicker,\n type DayProps,\n type MonthsProps,\n type DateRange,\n} from 'react-day-picker';\nimport { enAU } from 'date-fns/locale';\nimport { cn } from '../../utils/core/cn';\n\n// Define custom types for components that don't have exported types\ntype MonthGridProps = React.TableHTMLAttributes<HTMLTableElement>;\ntype WeekdaysProps = React.HTMLAttributes<HTMLTableRowElement> & {\n children?: React.ReactNode;\n};\ntype MonthProps = {\n calendarMonth: { date: Date };\n displayIndex: number;\n className?: string;\n children?: React.ReactNode;\n};\ntype RootProps = {\n children?: React.ReactNode;\n rootRef?: React.Ref<HTMLDivElement>;\n className?: string;\n style?: React.CSSProperties;\n};\n\n// ============================================================================\n// CALENDAR COMPONENT\n// ============================================================================\n\nexport interface CalendarProps extends Omit<DayPickerProps, 'className' | 'classNames' | 'styles' | 'onSelect'> {\n /**\n * Additional CSS classes to apply to the calendar table\n */\n className?: string;\n /**\n * Custom classNames for DayPicker sub-components\n */\n classNames?: DayPickerProps['classNames'];\n /**\n * Currently selected value; mirrors DayPicker's `selected` prop so callers\n * can control the selection state.\n */\n selected?: Date | Date[] | DateRange | undefined;\n /**\n * Date selection handler. Signature depends on mode:\n * - mode=\"single\": (date: Date | undefined) => void\n * - mode=\"range\": (range: { from: Date; to?: Date } | undefined) => void\n * - mode=\"multiple\": (dates: Date[]) => void\n */\n onSelect?: ((date: Date | undefined) => void) | ((range: { from: Date; to?: Date } | undefined) => void) | ((dates: Date[]) => void);\n}\n\ntype StoredRootProps = {\n className?: string;\n style?: React.CSSProperties;\n rootRef?: React.Ref<HTMLDivElement>;\n restProps?: React.HTMLAttributes<HTMLTableElement>;\n};\n\nconst assignToRef = <T,>(ref: React.Ref<T | null> | undefined, value: T | null) => {\n if (!ref) {\n return;\n }\n if (typeof ref === 'function') {\n ref(value);\n return;\n }\n (ref as React.MutableRefObject<T | null>).current = value;\n};\n\n/**\n * Calendar component\n * A flexible, accessible calendar component for date selection.\n * Built on react-day-picker with pace-core styling.\n * \n * Defaults to Australian locale (en-AU) with Monday as the first day of the week.\n * The locale can be overridden by passing a `locale` prop.\n * \n * Month navigation is automatically managed internally when `month` and `onMonthChange` props\n * are not provided. The displayed month will sync with the selected date when available,\n * or default to the current month. Navigation buttons (prev/next) work automatically.\n * \n * For controlled month state, pass `month` and `onMonthChange` props.\n * \n * @param props - Calendar configuration and styling\n * @param ref - Forwarded ref (not used directly, but maintained for API consistency)\n * @returns JSX.Element - The rendered calendar element\n * \n * @example\n * ```tsx\n * // Single date selection (uses default Australian locale)\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * />\n * \n * // With disabled dates\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * disabled={(date) => date < new Date()}\n * />\n * \n * // Override locale (e.g., US locale with Sunday as first day)\n * import { enUS } from 'date-fns/locale';\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * locale={enUS}\n * />\n * \n * // Controlled month state (optional - month is auto-managed if not provided)\n * const [month, setMonth] = useState(new Date());\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * month={month}\n * onMonthChange={setMonth}\n * />\n * ```\n */\nconst Calendar = React.forwardRef<HTMLTableElement, CalendarProps>(\n ({ className, classNames, mode, components, locale, month: controlledMonth, onMonthChange: controlledOnMonthChange, onSelect, ...props }, ref) => {\n const tableRef = React.useRef<HTMLTableElement | null>(null);\n const setForwardedRef = React.useCallback(\n (node: HTMLTableElement | null) => {\n tableRef.current = node;\n if (!ref) {\n return;\n }\n if (typeof ref === 'function') {\n ref(node);\n } else {\n (ref as React.MutableRefObject<HTMLTableElement | null>).current = node;\n }\n },\n [ref]\n );\n \n // Store root props so we can re-apply them to the table element\n const rootPropsRef = React.useRef<StoredRootProps | null>(null);\n // Get selected from props to avoid TypeScript union type issues\n const selected = (props as any).selected;\n // Determine if we're in controlled or uncontrolled mode for month\n const isMonthControlled = controlledMonth !== undefined;\n \n // Internal state for uncontrolled month mode - always default to current month\n const [internalMonth, setInternalMonth] = React.useState<Date>(() => {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1);\n });\n \n // Use controlled month if provided, otherwise use internal state\n // Normalize month to first day of month to ensure consistency\n const month = React.useMemo(() => {\n const monthToUse = isMonthControlled ? controlledMonth : internalMonth;\n if (!monthToUse) {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1);\n }\n // Ensure month is normalized to first day\n const normalized = new Date(monthToUse.getFullYear(), monthToUse.getMonth(), 1);\n return normalized;\n }, [isMonthControlled, controlledMonth, internalMonth]);\n \n // Handler for month changes - must be stable reference\n const handleMonthChange = React.useCallback((newMonth: Date) => {\n if (!isMonthControlled) {\n setInternalMonth(newMonth);\n }\n controlledOnMonthChange?.(newMonth);\n }, [isMonthControlled, controlledOnMonthChange]);\n \n // Create a wrapped handler to ensure it's always a function\n const wrappedHandleMonthChange = React.useCallback((newMonth: Date) => {\n handleMonthChange(newMonth);\n }, [handleMonthChange]);\n \n // Removed mount logging - was for debugging only\n \n // Custom Root: capture provided props so we can attach them to the table directly\n const CustomRoot = React.memo(({ children, rootRef: dayPickerRootRef, ...rootProps }: RootProps) => {\n const {\n className: rootClassName,\n style: rootStyle,\n children: _ignoredChildren,\n ...restProps\n } = rootProps as React.HTMLAttributes<HTMLDivElement> & { children?: React.ReactNode };\n \n rootPropsRef.current = {\n className: rootClassName,\n style: rootStyle as React.CSSProperties | undefined,\n rootRef: dayPickerRootRef,\n restProps: restProps as React.HTMLAttributes<HTMLTableElement>,\n };\n return <>{children}</>;\n });\n CustomRoot.displayName = 'CustomRoot';\n \n // Custom Months: Remove wrapper div, return children directly\n const CustomMonths = React.memo(({ children }: MonthsProps) => {\n return <>{children}</>;\n });\n CustomMonths.displayName = 'CustomMonths';\n \n const CustomMonthGrid = React.forwardRef<HTMLTableElement, MonthGridProps>((props, forwardedRef) => {\n return <table ref={forwardedRef} {...props} />;\n });\n CustomMonthGrid.displayName = 'CustomMonthGrid';\n \n // Custom Month: inject caption + navigation directly inside the <table>\n const CustomMonth = React.memo(({ calendarMonth, displayIndex, className, children }: MonthProps) => {\n const { formatters, components, labels, classNames, previousMonth, nextMonth, goToMonth } = useDayPicker();\n const caption = formatters.formatCaption(calendarMonth.date, {});\n const Chevron = components?.Chevron;\n \n const childrenArray = React.Children.toArray(children);\n const monthGridIndex = childrenArray.findIndex((child: any) => {\n if (!React.isValidElement(child)) return false;\n const childType = child.type as any;\n return (typeof childType === 'function' && childType.displayName === 'MonthGrid') ||\n child.type === 'table';\n });\n \n return (\n <>\n {childrenArray.map((child, index) => {\n if (React.isValidElement(child) && (child.type as any)?.displayName === 'MonthCaption') {\n return null;\n }\n \n if (index === monthGridIndex && React.isValidElement(child)) {\n const monthGridChild = child as React.ReactElement<MonthGridProps>;\n const applyRootProps = displayIndex === 0 && index === monthGridIndex;\n const storedRootProps = applyRootProps ? rootPropsRef.current : null;\n \n const { children: monthGridChildren, className: monthGridClassName, style: monthGridStyle, ...monthGridRest } =\n monthGridChild.props as React.TableHTMLAttributes<HTMLTableElement>;\n \n const mergedClassName = cn(\n 'w-full border-collapse rounded-md border border-sec-200 bg-background',\n applyRootProps ? storedRootProps?.className : undefined,\n className,\n monthGridClassName\n );\n \n const mergedStyle = {\n ...(applyRootProps ? storedRootProps?.style ?? {} : {}),\n ...(monthGridStyle ?? {}),\n };\n \n const tableProps: React.TableHTMLAttributes<HTMLTableElement> = {\n ...(applyRootProps && storedRootProps?.restProps ? storedRootProps.restProps : {}),\n ...monthGridRest,\n className: mergedClassName,\n ...(Object.keys(mergedStyle).length ? { style: mergedStyle } : {}),\n };\n \n if (mode && (tableProps as Record<string, unknown>)['data-mode'] === undefined) {\n (tableProps as Record<string, unknown>)['data-mode'] = mode;\n }\n \n const shouldAttachRef = applyRootProps || storedRootProps?.rootRef;\n const handleTableRef = shouldAttachRef\n ? (node: HTMLTableElement | null) => {\n if (applyRootProps) {\n setForwardedRef(node);\n }\n if (storedRootProps?.rootRef) {\n assignToRef(storedRootProps.rootRef as React.Ref<HTMLTableElement | null>, node);\n }\n }\n : undefined;\n \n const handlePreviousClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n if (!previousMonth) return;\n goToMonth(previousMonth);\n };\n \n const handleNextClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n if (!nextMonth) return;\n goToMonth(nextMonth);\n };\n \n const monthGridElement = monthGridChild as React.ReactElement<any> & {\n ref?: React.Ref<HTMLTableElement | null>;\n };\n const mergedRef =\n handleTableRef || monthGridElement.ref\n ? (node: HTMLTableElement | null) => {\n if (handleTableRef) {\n handleTableRef(node);\n }\n assignToRef(monthGridElement.ref as React.Ref<HTMLTableElement | null> | undefined, node);\n }\n : undefined;\n \n return React.cloneElement(\n monthGridElement,\n {\n key: child.key ?? `month-grid-${displayIndex}`,\n ...tableProps,\n ...(mergedRef ? { ref: mergedRef } : {}),\n },\n <>\n <caption className=\"relative\">\n <nav className=\"relative flex items-center justify-center gap-1\">\n <button\n type=\"button\"\n className={cn(\n 'h-7 w-7 bg-transparent p-0',\n 'inline-flex items-center justify-center rounded-md',\n 'hover:bg-acc-100',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'disabled:opacity-50 disabled:pointer-events-none',\n classNames?.button_previous\n )}\n tabIndex={previousMonth ? undefined : -1}\n aria-disabled={previousMonth ? undefined : true}\n aria-label={previousMonth ? labels.labelPrevious(previousMonth) : undefined}\n onClick={handlePreviousClick}\n disabled={!previousMonth}\n >\n {Chevron ? <Chevron orientation=\"left\" className=\"size-4\" disabled={!previousMonth} /> : <span>‹</span>}\n </button>\n <span className=\"text-sm font-medium\">{caption}</span>\n <button\n type=\"button\"\n className={cn(\n 'h-7 w-7 bg-transparent p-0',\n 'inline-flex items-center justify-center rounded-md',\n 'hover:bg-acc-100',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'disabled:opacity-50 disabled:pointer-events-none',\n classNames?.button_next\n )}\n tabIndex={nextMonth ? undefined : -1}\n aria-disabled={nextMonth ? undefined : true}\n aria-label={nextMonth ? labels.labelNext(nextMonth) : undefined}\n onClick={handleNextClick}\n disabled={!nextMonth}\n >\n {Chevron ? <Chevron orientation=\"right\" className=\"size-4\" disabled={!nextMonth} /> : <span>›</span>}\n </button>\n </nav>\n </caption>\n {monthGridChildren}\n </>\n );\n }\n \n return child;\n })}\n </>\n );\n });\n CustomMonth.displayName = 'CustomMonth';\n\n // Custom Weekdays: render table head with semantic row\n const CustomWeekdays = React.memo(({ className, children, ...props }: WeekdaysProps) => {\n return (\n <thead>\n <tr className={cn('text-xs text-sec-500', className)} {...props}>\n {children}\n </tr>\n </thead>\n );\n });\n CustomWeekdays.displayName = 'CustomWeekdays';\n\n // Memoize components to ensure stable references\n const defaultComponents = React.useMemo(() => ({\n Root: CustomRoot,\n Months: CustomMonths,\n Month: CustomMonth,\n MonthGrid: CustomMonthGrid,\n // MonthCaption is now handled inside CustomMonth (injected into table)\n Weekdays: CustomWeekdays,\n // Spread user components AFTER ours so ours take precedence\n ...(components || {}),\n }), [components, CustomRoot, CustomMonths, CustomMonth, CustomWeekdays]);\n\n return (\n <DayPicker\n {...(mode ? { mode } : {})}\n locale={locale ?? enAU}\n hideNavigation={true}\n {...(props as any)}\n // CRITICAL: Explicit props must come AFTER spread to ensure they override any props from spread\n // This ensures month, onMonthChange, selected, and onSelect are always correct\n selected={selected}\n onSelect={onSelect}\n month={month}\n onMonthChange={wrappedHandleMonthChange}\n className={className}\n classNames={{\n // v9 API: Updated for table-based structure\n months: '', // No wrapper - removed by CustomMonths\n month: '', // No wrapper - removed by CustomMonth\n month_caption: '', // Now handled by custom component (renders as <caption>)\n caption_label: 'text-sm font-medium',\n nav: 'relative flex items-center justify-center space-x-1',\n // v9: button_previous and button_next for navigation buttons\n button_previous: cn(\n 'absolute left-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n 'border border-input hover:bg-acc-100',\n 'inline-flex items-center justify-center rounded-md',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'\n ),\n button_next: cn(\n 'absolute right-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n 'border border-input hover:bg-acc-100',\n 'inline-flex items-center justify-center rounded-md',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'\n ),\n // v9: table -> month_grid (now a proper <table>)\n month_grid: '', // Styles applied directly to table in CustomMonth\n // v9: head_row -> weekdays (now wrapped in <thead> by custom component)\n weekdays: '', // Styles applied to <tr> inside <thead>\n weekday: 'text-sec-600 rounded-md w-9 font-normal text-[0.8rem]',\n // v9: row -> week (now a proper <tr>)\n week: 'mt-2',\n // v9: cell -> day (now a proper <td> by custom component)\n day: '', // Styles moved to <td> in custom component\n // v9: day -> day_button (the button inside the cell)\n day_button: cn(\n 'h-9 w-9 p-0 font-normal aria-selected:opacity-100',\n 'hover:bg-acc-100 hover:text-main-600',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'inline-flex items-center justify-center rounded-md'\n ),\n // v9: day_range_end -> range_end\n range_end: 'range-end',\n // v9: day_selected -> selected\n selected: 'bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50 focus:bg-main-600 focus:text-main-50',\n // v9: day_today -> today\n today: 'bg-sec-100 text-main-600 font-semibold',\n // v9: day_outside -> outside\n outside: 'outside text-sec-400 opacity-50 aria-selected:bg-acc-50/50 aria-selected:text-sec-400 aria-selected:opacity-30',\n // v9: day_disabled -> disabled\n disabled: 'text-sec-400 opacity-50 cursor-not-allowed',\n // v9: day_range_middle -> range_middle\n range_middle: 'aria-selected:bg-acc-100 aria-selected:text-main-600',\n // v9: day_hidden -> hidden\n hidden: 'invisible',\n ...classNames,\n }}\n components={defaultComponents}\n />\n );\n }\n);\n\nCalendar.displayName = 'Calendar';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Calendar };\n\n","/**\n * @file Toast Component System\n * @package @jmruthers/pace-core\n * @module Components/Toast\n * @since 0.1.0\n *\n * A comprehensive toast notification system built on top of Radix UI primitives.\n * Provides accessible, customizable toast notifications with smooth animations.\n *\n * Features:\n * - Multiple toast types (success, error, warning, info)\n * - Customizable positioning and styling\n * - Swipe gestures for dismissal\n * - Keyboard navigation support\n * - Auto-dismiss with default 5 second duration managed internally\n * - Action buttons and close functionality\n * - Responsive design\n * - Accessibility compliant\n * - Smooth animations and transitions\n * - Toast queue management\n *\n * @example\n * ```tsx\n * // Basic toast usage\n * import { useToast } from '@jmruthers/pace-core';\n * \n * function MyComponent() {\n * const { toast } = useToast();\n * \n * const handleSuccess = () => {\n * toast({\n * title: \"Success!\",\n * description: \"Your changes have been saved.\",\n * variant: \"success\"\n * });\n * };\n * \n * return <button onClick={handleSuccess}>Save Changes</button>;\n * }\n * \n * // Toast with action\n * toast({\n * title: \"Undo Changes\",\n * description: \"Your changes have been saved.\",\n * action: <ToastAction altText=\"Undo\">Undo</ToastAction>\n * });\n * \n * // Custom toast component\n * <Toast>\n * <ToastTitle>Custom Toast</ToastTitle>\n * <ToastDescription>This is a custom toast message.</ToastDescription>\n * <ToastClose />\n * </Toast>\n * \n * // Toast provider setup\n * function App() {\n * return (\n * <ToastProvider>\n * <YourApp />\n * <Toaster />\n * </ToastProvider>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA attributes and roles\n * - Keyboard navigation support\n * - Screen reader announcements\n * - Focus management\n * - High contrast support\n * - Swipe gesture alternatives\n *\n * @performance\n * - Efficient toast queue management\n * - Optimized animations\n * - Memory leak prevention\n * - Lazy rendering\n *\n * @dependencies\n * - @radix-ui/react-toast - Core toast functionality\n * - lucide-react - Icons\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from \"react\"\nimport * as ToastPrimitives from \"@radix-ui/react-toast\"\nimport { X } from \"lucide-react\"\nimport { cn } from \"../../utils/core/cn\"\nimport { useToast, type ToasterToast } from \"../../hooks/useToast\"\n\nconst ToastProvider = ToastPrimitives.Provider\n\n/**\n * ToastViewport component\n * Container for all toast notifications with customizable positioning\n * \n * @param props - Viewport configuration and styling\n * @param ref - Forwarded ref to the viewport element\n * @returns JSX.Element - The toast viewport container\n */\nconst ToastViewport = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Viewport>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Viewport\n ref={ref}\n data-testid=\"toast-viewport\"\n className={cn(\n \"fixed top-0 z-[9999] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]\",\n className\n )}\n {...props}\n />\n))\nToastViewport.displayName = ToastPrimitives.Viewport.displayName\n\n/**\n * Toast component\n * The main toast notification component with animations and interactions\n * \n * @param props - Toast configuration and content\n * @param ref - Forwarded ref to the toast element\n * @returns JSX.Element - The rendered toast notification\n * \n * @example\n * ```tsx\n * <Toast>\n * <ToastTitle>Success!</ToastTitle>\n * <ToastDescription>Your changes have been saved.</ToastDescription>\n * <ToastClose />\n * </Toast>\n * ```\n */\nconst Toast = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Root>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root>\n>(({ className, ...props }, ref) => {\n return (\n <ToastPrimitives.Root\n ref={ref}\n data-testid=\"toast-root\"\n className={cn(\n \"group pointer-events-auto bg-background relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full\",\n className\n )}\n {...props}\n />\n )\n})\nToast.displayName = ToastPrimitives.Root.displayName\n\n/**\n * ToastAction component\n * Action button within a toast notification\n * \n * @param props - Action button configuration\n * @param ref - Forwarded ref to the action button\n * @returns JSX.Element - The action button element\n * \n * @example\n * ```tsx\n * <ToastAction altText=\"Undo changes\">Undo</ToastAction>\n * ```\n */\nconst ToastAction = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Action>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Action\n ref={ref}\n data-testid=\"toast-action\"\n className={cn(\n \"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive\",\n className\n )}\n {...props}\n />\n))\nToastAction.displayName = ToastPrimitives.Action.displayName\n\n/**\n * ToastClose component\n * Close button for dismissing toast notifications\n * \n * @param props - Close button configuration\n * @param ref - Forwarded ref to the close button\n * @returns JSX.Element - The close button with X icon\n * \n * @example\n * ```tsx\n * <ToastClose />\n * ```\n */\nconst ToastClose = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Close>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Close\n ref={ref}\n data-testid=\"toast-close\"\n className={cn(\n \"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-acc-300 group-[.destructive]:hover:text-acc-50 group-[.destructive]:focus:ring-acc-400 group-[.destructive]:focus:ring-offset-acc-600\",\n className\n )}\n toast-close=\"\"\n {...props}\n >\n <X className=\"size-4\" />\n </ToastPrimitives.Close>\n))\nToastClose.displayName = ToastPrimitives.Close.displayName\n\n/**\n * ToastTitle component\n * Title text for toast notifications\n * \n * @param props - Title configuration and styling\n * @param ref - Forwarded ref to the title element\n * @returns JSX.Element - The toast title\n * \n * @example\n * ```tsx\n * <ToastTitle>Success!</ToastTitle>\n * ```\n */\nconst ToastTitle = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Title>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Title\n ref={ref}\n data-testid=\"toast-title\"\n className={cn(\"text-sm font-semibold\", className)}\n {...props}\n />\n))\nToastTitle.displayName = ToastPrimitives.Title.displayName\n\n/**\n * ToastDescription component\n * Description text for toast notifications\n * \n * @param props - Description configuration and styling\n * @param ref - Forwarded ref to the description element\n * @returns JSX.Element - The toast description\n * \n * @example\n * ```tsx\n * <ToastDescription>Your changes have been saved successfully.</ToastDescription>\n * ```\n */\nconst ToastDescription = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Description>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Description\n ref={ref}\n data-testid=\"toast-description\"\n className={cn(\"text-sm opacity-90\", className)}\n {...props}\n />\n))\nToastDescription.displayName = ToastPrimitives.Description.displayName\n\nexport interface ToastProps extends React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> {}\n\nexport interface ToastActionElement extends React.ReactElement<typeof ToastAction> {}\n\n/**\n * Toaster component\n * Container component that renders actual toast notifications\n * Should be placed at the root of your application\n * \n * @returns JSX.Element - The toast provider with viewport and rendered toasts\n * \n * @example\n * ```tsx\n * function App() {\n * return (\n * <ToastProvider>\n * <YourApp />\n * <Toaster />\n * </ToastProvider>\n * );\n * }\n * ```\n */\nexport function Toaster() {\n const { toasts } = useToast();\n \n return (\n <ToastProvider data-testid=\"toast-provider\">\n <ToastViewport />\n {toasts.map((toast: ToasterToast) => {\n // Destructure custom properties that shouldn't be passed to DOM\n const { id, title, description, action, dismiss, duration, ...toastProps } = toast;\n\n return (\n <Toast key={id} {...toastProps} duration={duration}>\n {title && <ToastTitle>{title}</ToastTitle>}\n {description && <ToastDescription>{description}</ToastDescription>}\n {action && action}\n <ToastClose onClick={dismiss} />\n </Toast>\n );\n })}\n </ToastProvider>\n );\n}\n\nexport {\n ToastProvider,\n ToastViewport,\n Toast,\n ToastTitle,\n ToastDescription,\n ToastClose,\n ToastAction,\n}\n","/**\n * @file Form Component\n * @package @jmruthers/pace-core\n * @module Components/Form\n * @since 0.1.0\n *\n * A comprehensive form component with React Hook Form integration and Zod validation.\n * Provides a clean, accessible form interface with built-in validation and error handling.\n *\n * Features:\n * - React Hook Form integration for efficient form state management\n * - Zod schema validation with type safety\n * - Flexible rendering with children function or JSX\n * - Built-in error handling and validation modes\n * - Accessible form structure\n * - TypeScript support with generic field values\n * - Customizable styling and layout\n *\n * @example\n * ```tsx\n * // Basic form with schema validation\n * const userSchema = z.object({\n * name: z.string().min(2, \"Name must be at least 2 characters\"),\n * email: z.string().email(\"Invalid email address\"),\n * age: z.number().min(18, \"Must be at least 18 years old\")\n * });\n * \n * <Form\n * schema={userSchema}\n * defaultValues={{ name: \"\", email: \"\", age: 0 }}\n * onSubmit={(data) => console.log(data)}\n * onError={(errors) => console.error(errors)}\n * >\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" type=\"email\" />\n * <FormField name=\"age\" label=\"Age\" type=\"number\" />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * \n * // Form with render function\n * <Form\n * schema={userSchema}\n * onSubmit={handleSubmit}\n * >\n * {(methods) => (\n * <>\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" />\n * <Button \n * type=\"submit\" \n * disabled={methods.formState.isSubmitting}\n * >\n * {methods.formState.isSubmitting ? \"Submitting...\" : \"Submit\"}\n * </Button>\n * </>\n * )}\n * </Form>\n * ```\n *\n * @accessibility\n * - Proper form structure with labels and descriptions\n * - Error announcements for screen readers\n * - Keyboard navigation support\n * - Focus management\n * - ARIA attributes for form validation\n *\n * @dependencies\n * - react-hook-form - Form state management\n * - @hookform/resolvers/zod - Zod validation integration\n * - zod - Schema validation\n * - React 19+ - Hooks and context\n */\n\nimport React from 'react';\nimport { useForm, FormProvider, UseFormReturn, FieldValues, DefaultValues, SubmitHandler, SubmitErrorHandler, useFormContext, Controller, FieldPath, ControllerRenderProps, ControllerFieldState, UseFormStateReturn } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { cn } from '../../utils/core/cn';\nimport { Label } from '../Label';\n\n/**\n * Props for the Form component\n */\nexport interface FormProps<TFieldValues extends FieldValues = FieldValues> {\n /**\n * Form schema for validation\n */\n schema?: z.ZodType<TFieldValues>;\n \n /**\n * Default values for the form\n */\n defaultValues?: DefaultValues<TFieldValues>;\n \n /**\n * Handler called when form is submitted successfully\n */\n onSubmit: SubmitHandler<TFieldValues>;\n \n /**\n * Handler called when form submission has errors\n */\n onError?: SubmitErrorHandler<TFieldValues>;\n \n /**\n * Form mode for react-hook-form\n * @default \"onSubmit\"\n */\n mode?: \"onSubmit\" | \"onChange\" | \"onBlur\" | \"onTouched\" | \"all\";\n \n /**\n * Children components or render function\n */\n children: React.ReactNode | ((methods: UseFormReturn<TFieldValues>) => React.ReactNode);\n \n /**\n * Class name for the form\n */\n className?: string;\n}\n\n/**\n * Form component with validation and React Hook Form integration\n * \n * @template TFieldValues - The type of form field values\n * @param props - Form configuration and handlers\n * @returns JSX.Element - The rendered form with FormProvider context\n * \n * @example\n * ```tsx\n * <Form\n * schema={userSchema}\n * defaultValues={{ name: \"\", email: \"\" }}\n * onSubmit={handleSubmit}\n * mode=\"onBlur\"\n * >\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * ```\n */\nexport function Form<TFieldValues extends FieldValues = FieldValues>({\n schema,\n defaultValues,\n onSubmit,\n onError,\n mode = \"onSubmit\",\n children,\n className,\n}: FormProps<TFieldValues>) {\n const methods = useForm<TFieldValues>({\n resolver: schema ? zodResolver(schema) : undefined,\n defaultValues,\n mode,\n shouldUnregister: false,\n });\n\n const handleSubmit = methods.handleSubmit(onSubmit, onError);\n\n return (\n <FormProvider {...methods}>\n <form onSubmit={handleSubmit} className={cn(\"space-y-4\", className)}>\n {typeof children === 'function' ? children(methods) : children}\n </form>\n </FormProvider>\n );\n}\n\n/**\n * Props for the FormField component\n */\nexport interface FormFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> {\n /**\n * Field name\n */\n name: TName;\n \n /**\n * Field label\n */\n label?: string;\n \n /**\n * Field type\n */\n type?: string;\n \n /**\n * Placeholder text\n */\n placeholder?: string;\n \n /**\n * Additional props for the input\n */\n inputProps?: React.InputHTMLAttributes<HTMLInputElement>;\n \n /**\n * Validation rules\n */\n validation?: {\n required?: boolean;\n pattern?: {\n value: RegExp;\n message: string;\n };\n minLength?: {\n value: number;\n message: string;\n };\n maxLength?: {\n value: number;\n message: string;\n };\n };\n \n /**\n * Custom render function\n */\n render?: (props: {\n field: ControllerRenderProps<TFieldValues, TName>;\n fieldState: ControllerFieldState;\n formState: UseFormStateReturn<TFieldValues>;\n }) => React.ReactElement<any>;\n \n /**\n * Test ID\n */\n 'data-testid'?: string;\n \n /**\n * Class name\n */\n className?: string;\n}\n\n/**\n * FormField component for React Hook Form integration\n * \n * A flexible form field component that integrates with React Hook Form and provides\n * built-in validation, error handling, and accessibility features.\n * \n * Features:\n * - React Hook Form integration with Controller\n * - Built-in validation with error display\n * - Accessible labels and error messages\n * - Custom render function support\n * - TypeScript support with generic field paths\n * - Consistent styling with error states\n * - Test ID support for testing\n * - Flexible input types and props\n * \n * @template TFieldValues - The type of form field values\n * @template TName - The type of the field name (must be a valid field path)\n * @param props - Form field configuration and validation\n * @returns JSX.Element - The rendered form field with validation\n * \n * @example\n * ```tsx\n * // Basic text field\n * <FormField\n * name=\"username\"\n * label=\"Username\"\n * placeholder=\"Enter your username\"\n * validation={{ required: true }}\n * />\n * \n * // Email field with custom validation\n * <FormField\n * name=\"email\"\n * label=\"Email Address\"\n * type=\"email\"\n * validation={{\n * required: true,\n * pattern: {\n * value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$/i,\n * message: \"Invalid email address\"\n * }\n * }}\n * />\n * \n * // Custom render function\n * <FormField\n * name=\"avatar\"\n * label=\"Profile Picture\"\n * render={({ field }) => (\n * <input\n * {...field}\n * type=\"file\"\n * accept=\"image/*\"\n * />\n * )}\n * />\n * ```\n * \n * @accessibility\n * - Proper label association with htmlFor\n * - Error messages with role=\"alert\"\n * - Required field indicators\n * - Focus management\n * - Screen reader friendly error announcements\n * - Keyboard navigation support\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n name,\n label,\n type = \"text\",\n placeholder,\n inputProps,\n validation,\n render,\n 'data-testid': testId,\n className,\n}: FormFieldProps<TFieldValues, TName>) {\n const { control } = useFormContext<TFieldValues>();\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <Label htmlFor={name}>\n {label}\n {validation?.required && (\n <span className=\"text-destructive ml-1\" aria-label=\"required\">\n *\n </span>\n )}\n </Label>\n )}\n \n <Controller\n name={name}\n control={control}\n rules={validation}\n render={(props) => {\n const { field, fieldState } = props;\n const fieldError = fieldState.error;\n \n // Safely extract error message\n const errorMessage = fieldError && typeof fieldError === 'object' && 'message' in fieldError \n ? String(fieldError.message) \n : undefined;\n\n if (render) {\n return render(props);\n }\n \n return (\n <>\n <input\n {...field}\n id={name}\n type={type}\n placeholder={placeholder}\n data-testid={testId}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n fieldError && \"border-destructive focus-visible:ring-destructive\"\n )}\n {...inputProps}\n />\n {errorMessage && (\n <p className=\"text-destructive\" role=\"alert\">\n {errorMessage}\n </p>\n )}\n </>\n );\n }}\n />\n </div>\n );\n}\n","/**\n * @file LoginForm Component\n * @package @jmruthers/pace-core\n * @module Components/LoginForm\n * @since 0.1.0\n *\n * A comprehensive login form component with built-in validation, error handling,\n * and loading states for user authentication.\n *\n * Features:\n * - Email and password validation\n * - Loading states with disabled form\n * - Error handling and display\n * - Customizable branding and messaging\n * - Sign-up link integration\n * - Performance optimized with React.memo\n * - Accessibility compliant\n * - Responsive design\n * - Form validation\n * - Success and error callbacks\n *\n * @example\n * ```tsx\n * // Basic login form\n * <LoginForm\n * onSignIn={async (data) => {\n * await signIn(data.email, data.password);\n * }}\n * onSuccess={() => navigate('/dashboard')}\n * onError={(error) => console.error('Login failed:', error)}\n * />\n * \n * // Login form with custom branding\n * <LoginForm\n * appName=\"My Application\"\n * title=\"Welcome Back\"\n * subtitle=\"Please sign in to access your account\"\n * onSignIn={handleSignIn}\n * onSuccess={handleSuccess}\n * onError={handleError}\n * />\n * \n * // Login form with sign-up integration\n * <LoginForm\n * appName=\"My App\"\n * showSignUp={true}\n * onSignUp={() => navigate('/signup')}\n * onSignIn={handleSignIn}\n * isLoading={isAuthenticating}\n * />\n * \n * // Login form with custom error handling\n * <LoginForm\n * onSignIn={async (data) => {\n * try {\n * const result = await authService.signIn(data);\n * if (result.success) {\n * onSuccess();\n * } else {\n * throw new Error(result.error);\n * }\n * } catch (error) {\n * onError(error);\n * }\n * }}\n * onSuccess={() => {\n * toast.success('Successfully signed in!');\n * navigate('/dashboard');\n * }}\n * onError={(error) => {\n * toast.error(`Sign in failed: ${error.message}`);\n * }}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper form labels and associations\n * - Screen reader friendly error messages\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear error identification\n *\n * @performance\n * - React.memo for efficient re-rendering\n * - useCallback for stable event handlers\n * - useMemo for computed values\n * - Minimal re-renders\n *\n * @dependencies\n * - React 19+ - Hooks and memo\n * - Button component\n * - Input component\n * - Label component\n * - Card components\n * - Alert component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState, useCallback, useMemo } from 'react';\nimport { Button } from '../Button/Button';\nimport { Input } from '../Input/Input';\nimport { Label } from '../Label/Label';\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../Card/index';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { cn } from '../../utils/core/cn';\n\nexport interface LoginFormProps {\n /** Callback invoked when the form is submitted */\n onSignIn: (data: { email: string; password: string }) => Promise<void>;\n /** Callback invoked on successful sign-in */\n onSuccess?: () => void;\n /** Callback invoked if sign-in fails */\n onError?: (error: Error) => void;\n /** Show loading spinner and disable form while true */\n isLoading?: boolean;\n /** Application name for display in the form */\n appName?: string;\n /** Custom title for the form */\n title?: string;\n /** Custom subtitle for the form */\n subtitle?: string;\n /** Show a sign-up link or button */\n showSignUp?: boolean;\n /** Optional callback for sign-up button */\n onSignUp?: () => void;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * LoginForm component that provides a ready-to-use authentication form for user sign-in.\n * It supports validation, loading state, error handling, and can be customized via props.\n * Now includes performance optimizations and onSignUp support.\n * \n * @param props - Login form configuration and handlers\n * @returns JSX.Element - The rendered login form\n * \n * @example\n * ```tsx\n * <LoginForm\n * onSignIn={handleSignIn}\n * onSuccess={() => navigate('/dashboard')}\n * onError={(error) => toast.error(error.message)}\n * isLoading={isAuthenticating}\n * />\n * ```\n */\nexport const LoginForm = React.memo<LoginFormProps>(({\n onSignIn,\n onSuccess,\n onError,\n isLoading = false,\n appName,\n title,\n subtitle,\n showSignUp = false,\n onSignUp,\n className\n}) => {\n const [formData, setFormData] = useState({ email: '', password: '' });\n const [error, setError] = useState<string | null>(null);\n\n // Memoized validation state\n const isFormValid = useMemo(() => {\n return formData.email.length > 0 && formData.password.length > 0;\n }, [formData.email, formData.password]);\n\n // React Compiler handles memoization automatically\n const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData(prev => ({ ...prev, email: e.target.value }));\n };\n\n const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData(prev => ({ ...prev, password: e.target.value }));\n };\n\n const handleSubmit = useCallback(async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!isFormValid || isLoading) return;\n try {\n await onSignIn(formData);\n onSuccess?.();\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Sign in failed';\n setError(errorMessage);\n onError?.(err instanceof Error ? err : new Error(errorMessage));\n }\n }, [formData, isFormValid, isLoading, onSignIn, onSuccess, onError]);\n\n const handleSignUpClick = () => {\n onSignUp?.();\n };\n\n const displayTitle = useMemo(() => title || (appName ? `Sign in to ${appName}` : 'Sign In'), [title, appName]);\n const displaySubtitle = useMemo(() => subtitle || 'Enter your credentials to continue.', [subtitle]);\n\n return (\n <Card className={cn('w-full max-w-md mx-auto', className)}>\n <form onSubmit={handleSubmit} data-testid=\"login-form\">\n <CardHeader className=\"space-y-1\">\n <CardTitle className=\"text-2xl text-center\">{displayTitle}</CardTitle>\n <CardDescription className=\"text-center\">\n {displaySubtitle}\n </CardDescription>\n </CardHeader>\n\n <CardContent className=\"space-y-4\">\n {error && (\n <Alert variant=\"destructive\" role=\"alert\" aria-live=\"assertive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n \n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"Enter your email\"\n value={formData.email}\n onChange={handleEmailChange}\n required\n disabled={isLoading}\n />\n \n \n <Label htmlFor=\"password\">Password</Label>\n <Input\n id=\"password\"\n type=\"password\"\n placeholder=\"Enter your password\"\n value={formData.password}\n onChange={handlePasswordChange}\n required\n disabled={isLoading}\n />\n \n </CardContent>\n <CardFooter className=\"flex flex-col space-y-4\">\n <Button \n type=\"submit\" \n className=\"w-full\" \n disabled={isLoading || !isFormValid}\n >\n {isLoading ? 'Signing in...' : 'Sign In'}\n </Button>\n {showSignUp && (\n onSignUp ? (\n <div className=\"text-sm text-center text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleSignUpClick}\n className=\"text-primary hover:underline\"\n >\n Don't have an account? Sign up\n </button>\n </div>\n ) : (\n <p className=\"text-center text-muted-foreground\">\n Don't have an account?{' '}\n <a href=\"/signup\" className=\"text-primary hover:underline\">\n Sign up\n </a>\n </p>\n )\n )}\n </CardFooter>\n </form>\n </Card>\n );\n});\n","/**\n * @file EventSelector Component\n * @package @jmruthers/pace-core\n * @module Components/EventSelector\n * @since 0.1.0\n *\n * A secure event selector component that allows users to choose from events they have\n * access to based on their role-based permissions. Integrates with the RBAC system\n * to ensure users only see events they're authorized to access.\n *\n * Features:\n * - Role-based event access control\n * - Automatic next event detection and selection\n * - Cross-device synchronization via Supabase\n * - Offline support with localStorage fallback\n * - Comprehensive error handling and retry functionality\n * - Event details display in dropdown\n * - Next/upcoming event indicators\n * - Loading states and user feedback\n * - Accessible interface design\n * - Integration with EventProvider\n *\n * @example\n * ```tsx\n * // Basic event selector\n * <EventSelector \n * onEventChange={(event) => console.log('Selected event:', event)}\n * />\n * \n * // With custom configuration\n * <EventSelector\n * placeholder=\"Choose an event...\"\n * showEventDetails={true}\n * showNextEventIndicator={true}\n * showRetryButton={true}\n * onEventChange={handleEventChange}\n * />\n * \n * // In a header component\n * <Header>\n * <EventSelector \n * className=\"w-64\"\n * showEventDetails={false}\n * onEventChange={setCurrentEvent}\n * />\n * </Header>\n * \n * // With error handling\n * <EventSelector\n * showNoEventsMessage={true}\n * showRetryButton={true}\n * onEventChange={(event) => {\n * if (event) {\n * setCurrentEvent(event);\n * navigate(`/events/${event.id}`);\n * }\n * }}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA labels and descriptions\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - High contrast support\n * - Clear error identification\n *\n * @security\n * - Role-based access control integration\n * - Secure event data handling\n * - User permission validation\n * - No unauthorized event exposure\n * - Secure session management\n *\n * @dependencies\n * - EventProvider - Event context and state\n * - Select components - Dropdown interface\n * - Button component - Retry functionality\n * - Alert component - Error display\n * - LoadingSpinner - Loading states\n * - React 19+ - Hooks and effects\n * - Tailwind CSS - Styling\n */\n\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { RefreshCw, AlertCircle, Lock, Calendar, Star } from 'lucide-react';\nimport { useEvents } from '../../hooks/useEvents';\nimport { Event } from '../../types/event';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { cn } from '../../utils/core/cn';\nimport { logger } from '../../utils/core/logger';\n\nexport interface EventSelectorProps {\n /** Placeholder text for the dropdown */\n placeholder?: string;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when an event changes, providing full event object */\n onEventChange?: (event: Event | null) => void;\n /** Show friendly message when no events available */\n showNoEventsMessage?: boolean;\n /** Show retry button on errors */\n showRetryButton?: boolean;\n /** Show event details in dropdown */\n showEventDetails?: boolean;\n /** Show indicator for next/upcoming events */\n showNextEventIndicator?: boolean;\n}\n\n/**\n * EventSelector component for selecting events with built-in access control\n * \n * This component provides secure event selection with:\n * - Database integration via rbac_event_app_roles table\n * - Auto-selection of next upcoming event by date\n * - Cross-device sync via Supabase user session metadata\n * - localStorage fallback for offline scenarios\n * - Comprehensive error handling and user feedback\n * \n * @component\n * @example\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"PACE\">\n * <EventSelector onEventChange={(event) => console.log(event)} />\n * </UnifiedAuthProvider>\n */\nexport function EventSelector({\n placeholder = \"Select an event\",\n className,\n onEventChange,\n showNoEventsMessage = true,\n showRetryButton = true,\n showEventDetails = true,\n showNextEventIndicator = true\n}: EventSelectorProps) {\n const { \n events, \n selectedEvent, \n isLoading, \n error, \n setSelectedEvent, \n refreshEvents,\n } = useEvents();\n\n // Removed excessive debug logging - only log on significant state changes, not every render\n\n\n const handleValueChange = (eventId: string) => {\n const event = events.find((e) => (e.event_id || e.id) === eventId);\n \n if (event) {\n setSelectedEvent(event);\n if (onEventChange) {\n onEventChange(event);\n }\n }\n };\n\n const handleRetry = () => {\n refreshEvents();\n };\n\n // Helper function to check if an event is the next upcoming event\n const isNextEvent = (event: Event): boolean => {\n if (!event.event_date) return false;\n \n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const eventDate = new Date(event.event_date);\n \n return eventDate >= today;\n };\n\n // Helper function to format event date\n const formatEventDate = (dateString: string): string => {\n const date = new Date(dateString);\n const today = new Date();\n const tomorrow = new Date(today);\n tomorrow.setDate(tomorrow.getDate() + 1);\n \n // Normalize dates to compare only the date part (ignore time)\n const normalizeDate = (d: Date) => {\n const normalized = new Date(d);\n normalized.setHours(0, 0, 0, 0);\n return normalized;\n };\n \n const normalizedDate = normalizeDate(date);\n const normalizedToday = normalizeDate(today);\n const normalizedTomorrow = normalizeDate(tomorrow);\n \n \n if (normalizedDate.getTime() === normalizedToday.getTime()) {\n return 'Today';\n } else if (normalizedDate.getTime() === normalizedTomorrow.getTime()) {\n return 'Tomorrow';\n } else {\n return date.toLocaleDateString();\n }\n };\n\n // Compute sorted list: descending by event_date (newest first); events without date go last\n const sortedEvents = useMemo(() => {\n const getTime = (e: Event) => (e.event_date ? new Date(e.event_date).getTime() : Number.NEGATIVE_INFINITY);\n return [...events].sort((a, b) => getTime(b) - getTime(a));\n }, [events]);\n\n // Default to the next upcoming event if none selected, fallback to most recent past event\n // IMPORTANT: Only auto-select if there's no persisted event being restored\n // EventService handles all persistence internally - we don't check storage directly\n // Use refs to track previous values and prevent unnecessary effect runs\n const prevEventsLengthRef = useRef(events.length);\n const prevSelectedEventIdRef = useRef(selectedEvent?.event_id);\n const hasAutoSelectedRef = useRef(false);\n \n useEffect(() => {\n // Track changes to detect when events are actually loaded\n const eventsLengthChanged = events.length !== prevEventsLengthRef.current;\n const selectedEventChanged = selectedEvent?.event_id !== prevSelectedEventIdRef.current;\n \n if (eventsLengthChanged) {\n prevEventsLengthRef.current = events.length;\n // Reset auto-select flag when new events are loaded\n if (events.length > 0) {\n hasAutoSelectedRef.current = false;\n }\n }\n if (selectedEventChanged) {\n prevSelectedEventIdRef.current = selectedEvent?.event_id;\n // Reset auto-select flag when selected event changes externally\n if (selectedEvent) {\n hasAutoSelectedRef.current = false;\n }\n }\n \n // Only auto-select if:\n // 1. Events are loaded (length > 0)\n // 2. No event is selected\n // 3. Not currently loading\n // 4. Events actually changed (new events loaded)\n // 5. Haven't already auto-selected (prevent loops)\n if (!selectedEvent && events.length > 0 && !isLoading && eventsLengthChanged && !hasAutoSelectedRef.current) {\n // No event selected - safe to auto-select\n // EventService has already checked for persisted events during initialization\n hasAutoSelectedRef.current = true;\n autoSelectEvent();\n }\n \n function autoSelectEvent() {\n const today = new Date();\n const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();\n \n // Try to find next future event\n const next = [...events]\n .filter(e => e.event_date && new Date(e.event_date).getTime() >= startOfToday)\n .sort((a, b) => new Date(a.event_date as string).getTime() - new Date(b.event_date as string).getTime())[0];\n \n if (next) {\n setSelectedEvent(next);\n if (onEventChange) onEventChange(next);\n } else {\n // Fallback to most recent past event if no future events found\n const mostRecentPast = [...events]\n .filter(e => {\n if (!e.event_date) return false;\n const eventDate = new Date(e.event_date);\n const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();\n return startOfEventDate < startOfToday;\n })\n .sort((a, b) => new Date(b.event_date as string).getTime() - new Date(a.event_date as string).getTime())[0];\n \n if (mostRecentPast) {\n setSelectedEvent(mostRecentPast);\n if (onEventChange) onEventChange(mostRecentPast);\n }\n }\n }\n }, [events.length, selectedEvent?.event_id, isLoading, setSelectedEvent, onEventChange]);\n\n // Loading state\n if (isLoading) {\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n <LoadingSpinner size=\"sm\" />\n <span className=\"text-sm text-muted-foreground\">Loading events...</span>\n </div>\n );\n }\n\n // Access error state\n if (error) {\n return (\n <div className={className}>\n <Alert variant=\"destructive\">\n <Lock className=\"size-4\" />\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{error.message}</span>\n {showRetryButton && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRetry}\n className=\"ml-2\"\n >\n <RefreshCw className=\"size-3 mr-1\" />\n Retry\n </Button>\n )}\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n\n // No events available state\n if (events.length === 0) {\n if (showNoEventsMessage) {\n return (\n <div className={className}>\n <Alert variant=\"inline\">\n <AlertCircle className=\"size-4 text-acc-700\" />\n <AlertDescription className=\"flex items-center justify-between\">\n <span>No events available.</span>\n {showRetryButton && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRetry}\n className=\"ml-2\"\n >\n <RefreshCw className=\"size-3 mr-1\" />\n Refresh\n </Button>\n )}\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n return null;\n }\n\n // Normal selector state\n return (\n <Select \n value={selectedEvent ? (selectedEvent.event_id || selectedEvent.id) : ''}\n onValueChange={handleValueChange}\n className={className}\n >\n <SelectTrigger className=\"text-left\" variant=\"outline\">\n <SelectValue placeholder={placeholder}>\n {selectedEvent && (\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"size-4 flex-shrink-0\" />\n <span className=\"truncate\">{selectedEvent.event_name}</span>\n {selectedEvent.event_date && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0\">\n ({formatEventDate(selectedEvent.event_date)})\n </span>\n )}\n </div>\n )}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {sortedEvents\n .map((event) => {\n const isNext = isNextEvent(event);\n const isSelected = selectedEvent && (selectedEvent.event_id === event.event_id || selectedEvent.id === event.id);\n \n return (\n <SelectItem \n key={event.event_id || event.id}\n value={event.event_id || event.id}\n className=\"flex items-center justify-between\"\n >\n <div className=\"flex items-center gap-2 w-full\">\n {showNextEventIndicator && isNext && (\n <Star className=\"size-3 text-acc-500\" />\n )}\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className={isSelected ? \"font-semibold\" : \"\"}>\n {event.event_name}\n </span>\n {isSelected && (\n <span className=\"text-xs bg-primary text-primary-foreground px-1 rounded\">\n Current\n </span>\n )}\n </div>\n {showEventDetails && event.event_date && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Calendar className=\"size-3\" />\n <span>{formatEventDate(event.event_date)}</span>\n {showNextEventIndicator && isNext && (\n <span className=\"text-acc-600 font-medium\">\n (Next)\n </span>\n )}\n </div>\n )}\n {showEventDetails && event.event_venue && (\n <div className=\"text-xs text-muted-foreground\">\n 📍 {event.event_venue}\n </div>\n )}\n </div>\n </div>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n );\n}\n","/**\n * @file Organisation Selector Component\n * @package @jmruthers/pace-core\n * @module Components/OrganisationSelector\n * @since 0.4.0\n *\n * A secure organisation selector component that allows users to switch between organisations\n * they have access to. Includes role display and security validation.\n *\n * Features:\n * - Secure organisation switching with validation\n * - Role display for each organisation\n * - Real-time organisation validation\n * - Accessible dropdown interface\n * - Error handling for security violations\n * - Loading states and feedback\n * - Integration with OrganisationProvider\n *\n * @example\n * ```tsx\n * // Basic organisation selector\n * <OrganisationSelector \n * onOrganisationChange={(org) => console.log('Switched to:', org.display_name)}\n * />\n * \n * // Compact version for header\n * <OrganisationSelector \n * className=\"w-48\" \n * compact={true}\n * showRole={true}\n * />\n * \n * // With custom placeholder\n * <OrganisationSelector \n * placeholder=\"Choose organisation...\"\n * showNoOrganisationsMessage={true}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - ARIA labels and descriptions\n * - High contrast support\n *\n * @security\n * - Validates user access to organisations\n * - Prevents switching to unauthorised organisations\n * - Error handling for security violations\n * - Real-time access validation\n * - Secure organisation data handling\n */\n\nimport React, { useState, useCallback, useMemo } from 'react';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { RefreshCw, AlertCircle, Building2, Shield } from 'lucide-react';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport type { Organisation } from '../../types/organisation';\nimport { logger } from '../../utils/core/logger';\n\nexport interface OrganisationSelectorProps {\n /** Placeholder text for the dropdown */\n placeholder?: string;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when organisation changes, providing full organisation object */\n onOrganisationChange?: (org: Organisation) => void;\n /** Show friendly message when no organisations available */\n showNoOrganisationsMessage?: boolean;\n /** Show retry button on errors */\n showRetryButton?: boolean;\n /** Show user's role in each organisation */\n showRole?: boolean;\n /** Compact display mode */\n compact?: boolean;\n /** Disabled state */\n disabled?: boolean;\n}\n\n/**\n * OrganisationSelector component for secure organisation switching\n * \n * This component provides secure organisation selection with:\n * - User membership validation\n * - Role-based access display\n * - Security error handling\n * - Real-time organisation switching\n * - Accessible interface design\n * \n * Security: Only shows organisations the user has valid access to\n */\nexport function OrganisationSelector({\n placeholder = \"Select organisation\",\n className,\n onOrganisationChange,\n showNoOrganisationsMessage = true,\n showRetryButton = true,\n showRole = false,\n compact = false,\n disabled = false\n}: OrganisationSelectorProps) {\n const [isLoading, setIsLoading] = useState(false);\n const [switchError, setSwitchError] = useState<string | null>(null);\n \n const { \n organisations, \n selectedOrganisation, \n isLoading: orgLoading,\n error: orgError,\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations\n } = useOrganisations();\n\n // Removed debug logging useEffect - it was causing render loops because organisations array\n // is recreated on every render, triggering the effect constantly\n\n\n const handleOrganisationChange = useCallback(async (orgId: string) => {\n if (disabled || isLoading) return;\n \n setSwitchError(null);\n setIsLoading(true);\n \n try {\n // Validate access before attempting switch\n if (!validateOrganisationAccess(orgId)) {\n throw new Error('You do not have access to this organisation');\n }\n \n await switchOrganisation(orgId);\n \n const newOrganisation = organisations.find(org => org.id === orgId);\n if (newOrganisation && onOrganisationChange) {\n onOrganisationChange(newOrganisation);\n }\n \n } catch (error) {\n logger.error('OrganisationSelector', 'Failed to switch organisation:', error);\n setSwitchError(error instanceof Error ? error.message : 'Failed to switch organisation');\n } finally {\n setIsLoading(false);\n }\n }, [\n disabled, \n isLoading, \n validateOrganisationAccess, \n switchOrganisation, \n organisations, \n onOrganisationChange\n ]);\n\n const handleRetry = useCallback(async () => {\n setIsLoading(true);\n setSwitchError(null);\n try {\n await refreshOrganisations();\n } catch (error) {\n logger.error('OrganisationSelector', 'Failed to refresh organisations:', error);\n setSwitchError('Failed to refresh organisations');\n } finally {\n setIsLoading(false);\n }\n }, [refreshOrganisations]);\n\n // Loading state\n if (orgLoading) {\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n <LoadingSpinner size=\"sm\" />\n <span className=\"text-sm text-muted-foreground\">\n {compact ? \"Loading...\" : \"Loading organisations...\"}\n </span>\n </div>\n );\n }\n\n // Error state\n if (orgError) {\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert variant=\"destructive\">\n <AlertCircle className=\"size-4\" />\n <AlertDescription>\n Failed to load organisations: {orgError.message}\n </AlertDescription>\n </Alert>\n {showRetryButton && (\n <Button \n variant=\"outline\" \n size=\"sm\" \n onClick={handleRetry}\n disabled={isLoading}\n className=\"w-full\"\n >\n <RefreshCw className={`size-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Retry\n </Button>\n )}\n </div>\n );\n }\n\n // No organisations available\n if (organisations.length === 0) {\n if (showNoOrganisationsMessage) {\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert>\n <Building2 className=\"size-4\" />\n <AlertDescription>\n No organisations available. Please contact your administrator to be added to an organisation.\n </AlertDescription>\n </Alert>\n {showRetryButton && (\n <Button \n variant=\"outline\" \n size=\"sm\" \n onClick={handleRetry}\n disabled={isLoading}\n className=\"w-full\"\n >\n <RefreshCw className={`size-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Check Again\n </Button>\n )}\n </div>\n );\n }\n return null;\n }\n\n // Switch error display\n const switchErrorDisplay = switchError && (\n <Alert variant=\"destructive\" className=\"mt-2\">\n <AlertCircle className=\"size-4\" />\n <AlertDescription>{switchError}</AlertDescription>\n </Alert>\n );\n\n // Normal selector state - allow opening even if no organisation is selected\n const isSelectDisabled = disabled || isLoading;\n\n // Memoize the value to prevent render loops\n const selectValue = useMemo(() => {\n return selectedOrganisation?.id || '';\n }, [selectedOrganisation?.id]);\n\n return (\n <div className={className}>\n <Select \n value={selectValue}\n onValueChange={handleOrganisationChange}\n disabled={isSelectDisabled}\n >\n <SelectTrigger \n className=\"text-left\"\n variant=\"outline\"\n >\n <SelectValue placeholder={placeholder}>\n {selectedOrganisation && (\n <div className=\"flex items-center gap-2\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Building2 className=\"size-4 flex-shrink-0\" />\n )}\n <span className=\"truncate\">{selectedOrganisation.display_name}</span>\n </div>\n )}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {organisations.map((org) => {\n const userRole = getUserRole(org.id);\n const hasAccess = validateOrganisationAccess(org.id);\n \n return (\n <SelectItem \n key={org.id} \n value={org.id}\n disabled={!hasAccess}\n className={!hasAccess ? 'opacity-50' : ''}\n >\n <div className=\"flex items-center justify-between w-full\">\n <div className=\"flex items-center gap-2\">\n <Building2 className=\"size-4\" />\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{org.display_name}</span>\n {!compact && org.description && (\n <span className=\"text-xs text-muted-foreground truncate max-w-40\">\n {org.description}\n </span>\n )}\n </div>\n </div>\n {showRole && (\n <div className=\"flex items-center gap-1 ml-4\">\n <Shield className=\"size-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground capitalize\">\n {userRole?.replace('_', ' ') || 'No Role'}\n </span>\n </div>\n )}\n </div>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n {switchErrorDisplay && (\n <div className=\"mt-2\">\n {switchErrorDisplay}\n </div>\n )}\n </div>\n );\n} ","/**\n * @file Password Change Form Component\n * @package @jmruthers/pace-core\n * @module Components/PasswordChange\n * @since 0.1.0\n *\n * A secure password change form component with validation, confirmation matching,\n * and proper error handling for updating user passwords.\n *\n * Features:\n * - Password strength validation (minimum 8 characters)\n * - Password confirmation matching\n * - Loading states with disabled form\n * - Error handling and display\n * - Accessibility compliant\n * - Responsive design\n * - Form validation\n * - Secure password input\n * - Success and error callbacks\n *\n * @example\n * ```tsx\n * // Basic password change form\n * <PasswordChangeForm\n * onSubmit={async (values) => {\n * try {\n * await updatePassword(values.newPassword);\n * toast.success('Password updated successfully!');\n * return {};\n * } catch (error) {\n * return { error: { message: error.message } };\n * }\n * }}\n * />\n * \n * // Password change form with custom styling\n * <PasswordChangeForm\n * className=\"max-w-md mx-auto p-6 bg-main-50 rounded-lg shadow-md\"\n * onSubmit={async (values) => {\n * const result = await authService.changePassword(values.newPassword);\n * if (result.success) {\n * navigate('/profile');\n * return {};\n * } else {\n * return { error: { message: result.error } };\n * }\n * }}\n * />\n * \n * // Password change form in a modal\n * <Modal isOpen={showPasswordChange} onClose={() => setShowPasswordChange(false)}>\n * <ModalContent>\n * <ModalHeader>\n * <ModalTitle>Change Password</ModalTitle>\n * </ModalHeader>\n * <ModalBody>\n * <PasswordChangeForm\n * onSubmit={async (values) => {\n * const result = await changePassword(values.newPassword);\n * if (result.success) {\n * setShowPasswordChange(false);\n * toast.success('Password changed successfully');\n * return {};\n * } else {\n * return { error: { message: result.error } };\n * }\n * }}\n * />\n * </ModalBody>\n * </ModalContent>\n * </Modal>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper form labels and associations\n * - Screen reader friendly error messages\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear error identification\n * - Role=\"alert\" for error announcements\n * - Password field security\n *\n * @security\n * - Password strength validation\n * - Secure password input fields\n * - Confirmation matching\n * - No password logging\n * - Proper error handling\n *\n * @dependencies\n * - React 19+ - Hooks and state\n * - Button component\n * - Input component\n * - Label component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState } from 'react';\nimport { Button } from '../Button/Button';\nimport { Input } from '../Input/Input';\nimport { Label } from '../Label';\nimport { cn } from '../../utils/core/cn';\n\nexport interface PasswordChangeFormValues {\n newPassword: string;\n confirmPassword: string;\n}\n\nexport interface PasswordChangeFormError {\n message?: string;\n code?: string;\n}\n\nexport interface PasswordChangeFormProps {\n onSubmit: (values: PasswordChangeFormValues) => Promise<{ error?: PasswordChangeFormError }>;\n className?: string;\n}\n\nexport function PasswordChangeForm({ onSubmit, className }: PasswordChangeFormProps) {\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (newPassword.length < 8) {\n setError('Password must be at least 8 characters.');\n return;\n }\n if (newPassword !== confirmPassword) {\n setError('Passwords do not match.');\n return;\n }\n\n setIsSubmitting(true);\n try {\n const result = await onSubmit({ newPassword, confirmPassword });\n if (result && result.error) {\n setError(result.error.message || 'Failed to change password.');\n }\n } catch (err) {\n const errorObj = err instanceof Error ? err : new Error('An unexpected error occurred');\n setError(errorObj.message);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <form onSubmit={handleSubmit} className={cn('space-y-4', className)}>\n {error && (\n <div role=\"alert\">\n {error}\n </div>\n )}\n <div className=\"space-y-2\">\n <Label htmlFor=\"new-password\">New Password</Label>\n <Input\n id=\"new-password\"\n type=\"password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n required\n disabled={isSubmitting}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"confirm-password\">Confirm Password</Label>\n <Input\n id=\"confirm-password\"\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isSubmitting}\n />\n </div>\n <Button\n type=\"submit\"\n className=\"w-full\"\n disabled={isSubmitting || !newPassword || !confirmPassword}\n >\n {isSubmitting ? 'Changing...' : 'Change Password'}\n </Button>\n </form>\n );\n} ","/**\n * @file User Menu Component\n * @package @jmruthers/pace-core\n * @module Components/UserMenu\n * @since 0.1.0\n *\n * A comprehensive user menu component that displays user information and provides\n * access to user-specific actions like password changes and sign out.\n *\n * Features:\n * - User avatar and display name\n * - Dropdown menu with user actions\n * - Password change functionality\n * - Sign out capability\n * - Loading state component\n * - Responsive design\n * - Accessibility compliant\n * - Performance optimized with React.memo\n * - Integration with Supabase User\n * - Customizable styling\n *\n * @example\n * ```tsx\n * // Basic user menu\n * <UserMenu\n * user={currentUser}\n * onSignOut={async () => {\n * await signOut();\n * navigate('/login');\n * }}\n * onChangePassword={async (newPassword, confirmPassword) => {\n * try {\n * await updatePassword(newPassword);\n * toast.success('Password updated successfully!');\n * return {};\n * } catch (error) {\n * return { error: { message: error.message } };\n * }\n * }}\n * />\n * \n * // User menu without avatar\n * <UserMenu\n * user={currentUser}\n * showAvatar={false}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * />\n * \n * // User menu with loading state\n * {isLoading ? (\n * <UserMenu.Loading />\n * ) : (\n * <UserMenu\n * user={user}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * />\n * )}\n * \n * // User menu in header\n * <Header>\n * <div className=\"flex items-center gap-4\">\n * <Navigation />\n * <UserMenu\n * user={user}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * className=\"ml-auto\"\n * />\n * </div>\n * </Header>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA labels and roles\n * - Keyboard navigation support\n * - Focus management\n * - Screen reader friendly\n * - High contrast support\n * - Loading state announcements\n * - Clear action identification\n *\n * @performance\n * - React.memo for efficient re-rendering\n * - useCallback for stable event handlers\n * - useMemo for computed values\n * - Minimal re-renders\n * - Optimized avatar rendering\n *\n * @dependencies\n * - React 19+ - Hooks and memo\n * - @supabase/supabase-js - User type\n * - lucide-react - Icons\n * - DropdownMenu components\n * - Dialog components\n * - PasswordChangeForm component\n * - Avatar component\n * - Button component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useCallback, useMemo, useState } from 'react';\nimport { User } from '@supabase/supabase-js';\nimport { ChevronDown, LogOut, KeyRound } from 'lucide-react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n} from '../Select';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n DialogOverlay\n} from '../Dialog';\nimport { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\nimport { Avatar } from '../Avatar';\nimport { Button } from '../Button';\n\nexport interface UserMenuProps {\n user: User | null;\n onSignOut?: () => Promise<void>;\n onChangePassword?: (newPassword: string, confirmPassword: string) => Promise<{ error?: PasswordChangeFormError }>;\n className?: string;\n showAvatar?: boolean;\n}\n\nexport const UserMenu = React.memo<UserMenuProps>(function UserMenu({\n user,\n onSignOut,\n onChangePassword,\n className,\n showAvatar = true,\n}) {\n const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);\n\n const userInfo = useMemo(() => {\n if (!user) return null;\n return {\n email: user.email,\n displayName: user.user_metadata?.display_name || user.user_metadata?.full_name || user.email?.split('@')[0],\n avatarUrl: user.user_metadata?.avatar_url,\n initial: (user.user_metadata?.display_name || user.user_metadata?.full_name || user.email || 'U').charAt(0).toUpperCase(),\n };\n }, [user]);\n\n const handleSignOut = useCallback(async () => {\n if (onSignOut) await onSignOut();\n }, [onSignOut]);\n\n if (!user || !userInfo) {\n return null; // Or a loading/login button\n }\n\n return (\n <Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>\n <Select className={className}>\n <SelectTrigger asChild>\n <Button variant=\"outline\" className=\"flex items-center gap-2\" aria-label={userInfo.displayName}>\n {showAvatar && (\n <Avatar \n src={userInfo.avatarUrl} \n alt={userInfo.displayName}\n fallback={userInfo.initial}\n className=\"size-7\"\n />\n )}\n <span>{userInfo.displayName}</span>\n <ChevronDown className=\"size-4\" />\n </Button>\n </SelectTrigger>\n <SelectContent>\n <SelectLabel className=\"font-normal\">\n <div className=\"flex flex-col space-y-1\">\n <p className=\"font-medium\">{userInfo.displayName}</p>\n <p className=\"text-muted-foreground\">{userInfo.email}</p>\n </div>\n </SelectLabel>\n <SelectSeparator />\n <DialogTrigger asChild>\n <SelectItem value=\"change-password\">\n <KeyRound className=\"mr-2 size-4\" />\n <span>Change Password</span>\n </SelectItem>\n </DialogTrigger>\n <SelectItem value=\"sign-out\" onClick={handleSignOut}>\n <LogOut className=\"mr-2 size-4\" />\n <span>Sign out</span>\n </SelectItem>\n </SelectContent>\n </Select>\n \n <DialogOverlay />\n <DialogContent className={className}>\n <DialogHeader>\n <DialogTitle>Change Password</DialogTitle>\n </DialogHeader>\n <PasswordChangeForm\n onSubmit={async ({ newPassword, confirmPassword }) => {\n if (onChangePassword) {\n const { error } = await onChangePassword(newPassword, confirmPassword);\n if (!error) {\n setPasswordDialogOpen(false);\n }\n return { error };\n }\n return {};\n }}\n />\n </DialogContent>\n </Dialog>\n );\n});\n\nexport const UserMenuLoading = React.memo(function UserMenuLoading() {\n return (\n <div className=\"relative inline-block text-left\">\n <button\n type=\"button\"\n disabled\n className=\"flex items-center space-x-2 px-3 py-2 text-sm font-medium text-muted-foreground bg-muted border border-input rounded-md\"\n >\n <div className=\"w-6 h-6 rounded-full bg-muted animate-pulse\" />\n <span className=\"truncate max-w-[150px]\">Loading...</span>\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n </button>\n <div role=\"status\" aria-label=\"Loading user menu\" aria-live=\"polite\" className=\"w-6 h-6 rounded-full bg-muted animate-pulse\" />\n </div>\n );\n});\n\n// Add Loading as a property to UserMenu for backward compatibility\ntype UserMenuWithLoading = typeof UserMenu & {\n Loading: typeof UserMenuLoading;\n};\n\n(UserMenu as UserMenuWithLoading).Loading = UserMenuLoading;\n","/**\n * @file Unified Navigation Menu Component\n * @package @jmruthers/pace-core\n * @module Navigation\n * @since 0.1.0\n * \n * A flexible navigation menu component that supports both dropdown and hierarchical modes.\n * \n * Features:\n * - Dropdown mode: Menu button that opens a dropdown list\n * - Hierarchical mode: Expandable tree navigation with nested items\n * - Icon support for navigation items\n * - Current page highlighting\n * - Keyboard navigation support\n * - Accessible design with proper ARIA attributes\n * - Click outside to close (dropdown mode)\n * - Recursive rendering for nested items (hierarchical mode)\n * \n * @example\n * Basic dropdown navigation (most common use case):\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * { id: 'reports', label: 'Reports', href: '/reports', icon: 'FileText' },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Main Menu\"\n * showIcons={true}\n * />\n * );\n * }\n * \n * @example\n * Hierarchical navigation with nested items:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function SidebarNavigation() {\n * const hierarchicalItems = [\n * { \n * id: 'user-management', \n * label: 'User Management',\n * icon: 'Users',\n * children: [\n * { id: 'users-list', label: 'All Users', href: '/users' },\n * { id: 'users-create', label: 'Create User', href: '/users/create' },\n * { id: 'user-roles', label: 'User Roles', href: '/users/roles' }\n * ]\n * },\n * { \n * id: 'reports', \n * label: 'Reports',\n * icon: 'BarChart',\n * children: [\n * { id: 'sales-reports', label: 'Sales Reports', href: '/reports/sales' },\n * { id: 'user-reports', label: 'User Reports', href: '/reports/users' }\n * ]\n * },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={hierarchicalItems}\n * mode=\"hierarchical\"\n * currentPath={window.location.pathname}\n * onNavigate={(item) => {\n * if (item.href) {\n * window.location.href = item.href;\n * }\n * }}\n * className=\"w-64 bg-sec-50 p-4\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * Integration with React Router and authentication:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * import { useUnifiedAuth } from '@jmruthers/pace-core/providers';\n * \n * function AuthenticatedNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const { hasRole, hasPermission } = useUnifiedAuth();\n * \n * // Build navigation items based on user permissions\n * const navItems = [\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * ...(hasPermission('meals:read') ? [\n * { id: 'meals', label: 'Meals', href: '/meals', icon: 'UtensilsCrossed' }\n * ] : []),\n * ...(hasRole('admin') ? [\n * { id: 'admin', label: 'Admin Panel', href: '/admin', icon: 'Shield' }\n * ] : []),\n * { id: 'profile', label: 'Profile', href: '/profile', icon: 'User' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Navigation\"\n * navigationLabel=\"Main application navigation\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * ```tsx\n * // Custom navigation with external links and actions\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function CustomNavigation() {\n * const handleNavigation = (item) => {\n * if (item.id === 'logout') {\n * // Handle logout action\n * handleLogout();\n * } else if (item.href?.startsWith('http')) {\n * // Handle external links\n * window.open(item.href, '_blank');\n * } else if (item.href) {\n * // Handle internal navigation\n * navigate(item.href);\n * }\n * };\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'help', label: 'Help Center', href: 'https://help.example.com', icon: 'HelpCircle' },\n * { id: 'logout', label: 'Sign Out', icon: 'LogOut' } // No href for actions\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * onNavigate={handleNavigation}\n * buttonText=\"Menu\"\n * disabled={false}\n * />\n * );\n * }\n * ```\n * \n * @accessibility\n * - WCAG 2.1 AA compliant navigation structure\n * - Proper ARIA attributes for screen readers\n * - Keyboard navigation with Enter, Space, and Escape keys\n * - Focus management for dropdown menus\n * - Semantic HTML structure with nav, menu, and menuitem roles\n * - Clear visual indicators for active/current page\n * \n * @performance\n * - Lightweight component with minimal re-renders\n * - Efficient click outside detection\n * - Optimized keyboard event handling\n * - Memory cleanup for event listeners\n * \n * @styling\n * - Uses Tailwind CSS for consistent styling\n * - Supports custom className for additional styling\n * - Responsive design considerations\n * \n * @dependencies\n * - React 19+ - Component framework and hooks\n * - Lucide React - Icon components\n * - Radix UI - Dropdown menu primitives\n * - React Router (optional) - For navigation handling\n * - Tailwind CSS - Styling system\n */\n\nimport * as React from \"react\";\nimport { Menu, ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/core/cn\";\nimport { Button } from \"../Button\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../Select\";\nimport { useUnifiedAuth } from \"../../providers/services/UnifiedAuthProvider\";\nimport { useRBAC } from \"../../rbac/hooks/useRBAC\";\nimport { useResolvedScope } from \"../../rbac/hooks\";\nimport { usePermissions } from \"../../rbac/hooks/usePermissions\";\nimport type { Permission, AccessLevel as RBACAccessLevel, UUID } from \"../../rbac/types\";\nimport { logger } from \"../../utils/core/logger\";\n\n/**\n * Navigation mode type\n */\nexport type NavigationMode = 'dropdown' | 'hierarchical';\n\n/**\n * Navigation item metadata\n */\nexport interface NavigationItemMeta {\n hidden?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Navigation item interface\n */\nexport interface NavigationItem {\n id: string;\n label: string;\n href?: string;\n icon?: string;\n children?: NavigationItem[];\n permissions?: (Permission | string)[];\n roles?: string[];\n accessLevel?: RBACAccessLevel | string;\n meta?: NavigationItemMeta;\n pageId?: string;\n}\n\n/**\n * Navigation menu component props\n */\nexport interface NavigationMenuProps extends React.HTMLAttributes<HTMLDivElement> {\n items: NavigationItem[];\n mode?: NavigationMode;\n currentPath?: string;\n onNavigate?: (item: NavigationItem) => void;\n className?: string;\n disabled?: boolean;\n buttonText?: string;\n showIcons?: boolean;\n navigationLabel?: string;\n strictMode?: boolean;\n auditLog?: boolean;\n onNavigationAccessDenied?: (item: NavigationItem) => void;\n onStrictModeViolation?: (item: NavigationItem, reason: string) => void;\n /** \n * If true, indicates that items have already been filtered by the parent component (e.g., PaceAppLayout).\n * When true, NavigationMenu will skip expensive permission checks and trust the provided items.\n * This significantly improves performance when items are pre-filtered.\n */\n itemsPreFiltered?: boolean;\n}\n\n/**\n * Unified NavigationMenu component that supports both dropdown and hierarchical navigation modes.\n * \n * A flexible navigation menu component with support for icons, current page highlighting,\n * keyboard navigation, and nested menu items.\n * \n * Features:\n * - Dropdown mode: Menu button that opens a dropdown list\n * - Hierarchical mode: Expandable tree navigation with nested items\n * - Icon support for navigation items\n * - Current page highlighting\n * - Keyboard navigation support (Enter, Space, Escape)\n * - Accessible design with proper ARIA attributes\n * - Click outside to close (dropdown mode)\n * - Recursive rendering for nested items (hierarchical mode)\n * \n * @example\n * Basic dropdown navigation (most common use case):\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * { id: 'reports', label: 'Reports', href: '/reports', icon: 'FileText' },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Main Menu\"\n * showIcons={true}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Hierarchical navigation with nested items:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function SidebarNavigation() {\n * const hierarchicalItems = [\n * { \n * id: 'user-management', \n * label: 'User Management',\n * icon: 'Users',\n * children: [\n * { id: 'users-list', label: 'All Users', href: '/users' },\n * { id: 'users-create', label: 'Create User', href: '/users/create' },\n * { id: 'user-roles', label: 'User Roles', href: '/users/roles' }\n * ]\n * },\n * { \n * id: 'reports', \n * label: 'Reports',\n * icon: 'BarChart',\n * children: [\n * { id: 'sales-reports', label: 'Sales Reports', href: '/reports/sales' },\n * { id: 'user-reports', label: 'User Reports', href: '/reports/users' }\n * ]\n * },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={hierarchicalItems}\n * mode=\"hierarchical\"\n * currentPath={window.location.pathname}\n * onNavigate={(item) => {\n * if (item.href) {\n * window.location.href = item.href;\n * }\n * }}\n * className=\"w-64 bg-sec-50 p-4\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * Integration with React Router and authentication:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * import { useUnifiedAuth } from '@jmruthers/pace-core/providers';\n * \n * function AuthenticatedNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const { hasRole, hasPermission } = useUnifiedAuth();\n * \n * // Build navigation items with permission requirements\n * const navItems = [\n * { \n * id: 'dashboard', \n * label: 'Dashboard', \n * href: '/dashboard', \n * icon: 'LayoutDashboard',\n * permissions: ['dashboard:read']\n * },\n * { \n * id: 'meals', \n * label: 'Meals', \n * href: '/meals', \n * icon: 'UtensilsCrossed',\n * permissions: ['meals:read']\n * },\n * { \n * id: 'admin', \n * label: 'Admin Panel', \n * href: '/admin', \n * icon: 'Shield',\n * roles: ['admin', 'super_admin']\n * },\n * { \n * id: 'profile', \n * label: 'Profile', \n * href: '/profile', \n * icon: 'User'\n * }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Navigation\"\n * navigationLabel=\"Main application navigation\"\n * // Permission filtering is always enabled - no prop needed\n * auditLog={true}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Custom navigation with external links and actions:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function CustomNavigation() {\n * const handleNavigation = (item) => {\n * if (item.id === 'logout') {\n * // Handle logout action\n * handleLogout();\n * } else if (item.href?.startsWith('http')) {\n * // Handle external links\n * window.open(item.href, '_blank');\n * } else if (item.href) {\n * // Handle internal navigation\n * navigate(item.href);\n * }\n * };\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'help', label: 'Help Center', href: 'https://help.example.com', icon: 'HelpCircle' },\n * { id: 'logout', label: 'Sign Out', icon: 'LogOut' } // No href for actions\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * onNavigate={handleNavigation}\n * buttonText=\"Menu\"\n * disabled={false}\n * />\n * );\n * }\n * ```\n * \n * @param props - NavigationMenu component props including items, mode, navigation handlers, and styling options\n * @returns React element with navigation menu functionality\n * \n * @since 0.1.0\n */\nexport const NavigationMenu = React.forwardRef<\n HTMLDivElement,\n NavigationMenuProps\n>(({ \n items, \n mode = 'dropdown',\n currentPath, \n onNavigate, \n className, \n disabled = false,\n buttonText = \"Menu\",\n showIcons = true,\n navigationLabel = \"Main navigation\",\n // NEW: Phase 2 - Enhanced Security Features\n strictMode = true,\n auditLog = true,\n onNavigationAccessDenied,\n onStrictModeViolation,\n itemsPreFiltered = false,\n ...props \n}, ref) => {\n const [expandedItems, setExpandedItems] = React.useState<Set<string>>(new Set());\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n\n // Get authentication context\n let authContext = null;\n try {\n authContext = useUnifiedAuth();\n } catch (error) {\n // NavigationMenu is being used outside of UnifiedAuthProvider\n logger.warn('NavigationMenu', 'useUnifiedAuth not available, running in unauthenticated mode');\n }\n\n // Get RBAC context for permission and role checks\n let rbacContext = null;\n try {\n rbacContext = useRBAC();\n } catch (error) {\n // RBAC not available - permission filtering will be disabled\n logger.warn('NavigationMenu', 'useRBAC not available, permission filtering disabled');\n }\n\n // Get event context state for checking readiness\n // Store the raw value to check if it's undefined (tests without event provider)\n const eventLoadingRaw = authContext?.eventLoading;\n const eventLoading = eventLoadingRaw ?? false;\n const selectedEvent = authContext?.selectedEvent || null;\n // Check org context readiness: use isContextReady if available, otherwise fall back to checking selectedOrganisation\n // This handles both production (with isContextReady) and test scenarios (without it)\n const orgContextReady = authContext?.isContextReady ?? (authContext?.selectedOrganisation?.id ? true : false);\n\n // Get resolved scope for permission checks\n // Note: Always call useResolvedScope (hooks must be called unconditionally)\n // However, if itemsPreFiltered is true, we'll skip using the results to avoid blocking\n // Permission filtering is always enabled - scope is always needed (unless items are pre-filtered)\n const { supabase } = authContext || {};\n const { selectedOrganisation } = authContext || {};\n const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({\n supabase: itemsPreFiltered ? null : (supabase || null), // Skip expensive resolution if pre-filtered\n selectedOrganisationId: itemsPreFiltered ? null : (selectedOrganisation?.id || null),\n selectedEventId: itemsPreFiltered ? null : (selectedEvent?.event_id || null)\n });\n\n // Resolve appId when useResolvedScope fails but context is ready\n // This is needed because usePermissions requires appId to fetch permissions correctly\n const [resolvedAppId, setResolvedAppId] = React.useState<string | undefined>(undefined);\n React.useEffect(() => {\n // Only resolve appId if:\n // 1. useResolvedScope errored or returned null\n // 2. But we have organisation context ready\n // 3. And we have appName from authContext\n // 4. And we haven't resolved it yet\n if (\n !scopeLoading && \n !resolvedScope?.appId && \n selectedOrganisation?.id && \n authContext?.appName && \n authContext?.user?.id &&\n !resolvedAppId\n ) {\n // Resolve appId using the same method as useRBAC\n // Double-check user exists (TypeScript narrowing) and capture values\n if (!authContext.user || !authContext.appName) {\n return;\n }\n const userId = authContext.user.id;\n const appName = authContext.appName;\n import('../../rbac/api').then(({ resolveAppContext }) => {\n resolveAppContext({\n userId,\n appName\n }).then((result) => {\n if (result?.appId) {\n setResolvedAppId(result.appId);\n }\n }).catch((error) => {\n // Silently fail - usePermissions will handle it\n });\n });\n }\n }, [scopeLoading, resolvedScope?.appId, selectedOrganisation?.id, authContext?.appName, authContext?.user?.id, resolvedAppId]);\n\n // Build scope from resolvedScope if available, otherwise fall back to context values\n // This handles the case where useResolvedScope errored initially but context is now ready\n // IMPORTANT: We need appId for usePermissions to work correctly\n // CRITICAL: Use selectedOrganisation?.id immediately when available, even during loading\n // This prevents usePermissions from skipping fetch due to empty organisationId\n const effectiveScope = React.useMemo(() => {\n // Prefer resolvedScope if available (includes appId)\n if (resolvedScope?.organisationId) {\n return resolvedScope;\n }\n \n // Fall back to building scope from context if resolvedScope is not available yet\n // Use selectedOrganisation?.id immediately when available, even if scopeLoading is true\n // This prevents delay in permission fetching\n if (selectedOrganisation?.id) {\n const fallbackScope = {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: resolvedAppId\n };\n return fallbackScope;\n }\n \n return null;\n }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id, resolvedAppId]);\n\n // Create a stable scope object that changes when effectiveScope changes\n // This ensures usePermissions detects scope changes and re-runs\n // We memoize it to prevent unnecessary re-renders while still triggering usePermissions when scope changes\n // IMPORTANT: Use a string key for dependencies to ensure React detects changes\n // This is more reliable than depending on the object itself\n const scopeKey = effectiveScope \n ? `${effectiveScope.organisationId || ''}-${effectiveScope.eventId || ''}-${effectiveScope.appId || ''}`\n : 'empty';\n \n const stableScope = React.useMemo(() => {\n if (effectiveScope?.organisationId) {\n return {\n organisationId: effectiveScope.organisationId,\n eventId: effectiveScope.eventId,\n appId: effectiveScope.appId\n };\n }\n // Return empty scope object (not null) so usePermissions can handle it\n return {\n organisationId: '',\n eventId: undefined,\n appId: undefined\n };\n }, [scopeKey, effectiveScope]);\n\n // Get permissions map for synchronous permission checks\n // Skip expensive permission fetching if items are pre-filtered\n const userId = (authContext?.user?.id || '') as UUID;\n \n // Call usePermissions with primitive parameters\n // If itemsPreFiltered is true, pass null/undefined to skip expensive permission fetching\n // CRITICAL: Pass null for userId and undefined for organisationId to skip the 3-second timeout\n // Empty string '' triggers the timeout, but null/undefined allows immediate early return\n const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading, error: permissionsError } = usePermissions(\n itemsPreFiltered ? (null as any) : userId, // Pass null to trigger early return (empty string would wait 3s)\n itemsPreFiltered ? undefined : stableScope.organisationId, // Pass undefined to skip timeout\n itemsPreFiltered ? undefined : stableScope.eventId, // Skip if pre-filtered\n itemsPreFiltered ? undefined : stableScope.appId // Skip if pre-filtered\n );\n \n \n\n // NEW: Phase 2 - Enhanced Security Features\n // Filter navigation items based on permissions using RBAC hooks\n // Use ref to preserve previous filtered items during permission refetches (e.g., when event changes)\n const previousFilteredItemsRef = React.useRef<NavigationItem[]>([]);\n \n const filteredItems = React.useMemo(() => {\n // PERFORMANCE OPTIMIZATION: If items are pre-filtered, skip all expensive permission checks\n // This significantly improves load time when PaceAppLayout has already filtered items\n if (itemsPreFiltered && items && items.length > 0) {\n // Items are pre-filtered by parent (e.g., PaceAppLayout) - trust them and only filter hidden items\n const visibleItems = (items || []).filter(item => !item.meta?.hidden);\n previousFilteredItemsRef.current = visibleItems;\n // Don't log here - logging happens in useEffect to avoid spam on re-renders\n return visibleItems;\n }\n \n // SECURITY: Permission filtering is ALWAYS enabled - users only see navigation items they have permission to access\n // Security: If we're missing required context or still loading, show NO items\n // This prevents security risk of showing items before permissions are verified\n \n // CRITICAL: Wait for BOTH organisation AND event context to be ready before checking permissions\n // This prevents the error \"No organisation or event context available\" when event context is still loading\n const isOrgContextReady = orgContextReady && selectedOrganisation?.id;\n // Event context is ready when not loading\n // If eventLoadingRaw is undefined (tests without event provider), consider it ready\n // Only wait for event context if we're actually loading events\n const isEventContextReady = eventLoadingRaw === undefined ? true : !eventLoading;\n \n // Check if we have valid context for permission checking\n // Use actual context values, not just resolvedScope, because resolvedScope might be null\n // if useResolvedScope errored initially but context is now ready\n const hasValidContext = isOrgContextReady && isEventContextReady;\n \n // If scope is still loading or we don't have valid context yet, show nothing\n // BUT: If scope errored but context is now ready, retry (don't block forever)\n const shouldWaitForScope = scopeLoading || (!hasValidContext);\n const shouldRetryAfterError = scopeError && hasValidContext && !scopeLoading;\n \n // During initial load or when scope/context is loading, check if we can trust PaceAppLayout's filtering\n // CRITICAL: If items are provided and we have valid context, trust PaceAppLayout's filtering\n // This prevents delay - PaceAppLayout already filtered items, so show them immediately\n // even if scope is still loading or rbacContext is not yet available\n if (items && items.length > 0 && selectedOrganisation?.id) {\n // Items are provided by PaceAppLayout - trust its filtering and show immediately\n // This eliminates delay while usePermissions/useResolvedScope are still loading\n // Items provided - trusting PaceAppLayout filtering (removed verbose logging)\n // Filter out hidden items only - PaceAppLayout already did permission filtering\n const visibleItems = (items || []).filter(item => !item.meta?.hidden);\n // Store in ref for use during permission refetches\n previousFilteredItemsRef.current = visibleItems;\n return visibleItems;\n }\n \n // If no items provided or no valid context, wait for context to be ready\n if (!authContext || !rbacContext || (shouldWaitForScope && !shouldRetryAfterError)) {\n // Still loading - show nothing to prevent security risk\n // Note: We check both org and event context readiness to prevent premature permission checks\n // Exception: If scope errored but context is now ready, we'll retry below\n return [];\n }\n \n // If scope errored but context is now ready, we can proceed with permission checks\n // The resolvedScope might be null, but we'll use the actual context values\n // usePermissions will handle the scope resolution internally\n \n // During permission refetch (after initial load), preserve previous items if we have them\n // This prevents navigation from disappearing when switching events\n if (permissionsLoading) {\n // If we have previous items, keep showing them during refetch\n // This prevents the navigation from disappearing when event changes\n if (previousFilteredItemsRef.current.length > 0) {\n return previousFilteredItemsRef.current;\n }\n // CRITICAL: If items are provided and we have valid scope, trust PaceAppLayout's filtering\n // This prevents delay - PaceAppLayout already filtered items, so show them immediately\n // even if usePermissions is still loading\n if (items && items.length > 0 && stableScope.organisationId) {\n // Permissions loading but items provided - trusting PaceAppLayout filtering (removed verbose logging)\n // Filter out hidden items only - PaceAppLayout already did permission filtering\n return (items || []).filter(item => !item.meta?.hidden);\n }\n // Otherwise, show nothing during initial load\n return [];\n }\n \n // If there's an error after loading, show nothing\n // Security: Better to show nothing than risk showing unauthorized items\n if (permissionsError) {\n logger.warn('NavigationMenu', 'Permission check error - showing no items for security', {\n permissionsError: permissionsError?.message\n });\n return [];\n }\n \n // If permission map is empty after loading, we need to handle this carefully:\n // 1. If items were already filtered by PaceAppLayout (which uses getPermissionMap directly),\n // we should trust those items and show them (they've already been filtered)\n // 2. If NavigationMenu is used standalone, we need permissions to filter - show nothing\n // \n // Since PaceAppLayout filters items before passing to NavigationMenu, and NavigationMenu\n // uses usePermissions hook which may return empty map while PaceAppLayout gets permissions,\n // we should trust items that are provided if permission map is empty but we have valid scope.\n // This is safe because PaceAppLayout already filtered them using getPermissionMap.\n if (!permissionMap || Object.keys(permissionMap).length === 0) {\n // If we have valid scope and items are provided, they were likely already filtered by PaceAppLayout\n // In this case, trust the items and show them (they've already been filtered for security)\n if (stableScope.organisationId && items && items.length > 0) {\n // Permission map empty but items provided - trusting PaceAppLayout filtering (removed verbose logging)\n // Items were already filtered by PaceAppLayout - trust them and only filter hidden items\n return (items || []).filter(item => !item.meta?.hidden);\n }\n \n // If no items provided or no valid scope, show nothing (can't verify permissions)\n if (stableScope.organisationId) {\n logger.warn('NavigationMenu', 'Permission map is empty and no items provided - showing nothing', {\n permissionMapSize: 0,\n organisationId: stableScope.organisationId,\n eventId: stableScope.eventId,\n appId: stableScope.appId\n });\n }\n return [];\n }\n \n // SECURITY: Permission filtering is always enabled - filtering cannot be disabled\n // Helper function to derive page ID from href\n const getPageIdFromHref = (href?: string): string | null => {\n if (!href) return null;\n // Remove leading slash and any query params/hash\n const path = href.split('?')[0].split('#')[0].replace(/^\\//, '');\n return path || 'home';\n };\n \n // Helper function to check if item has permission to be shown\n const hasItemPermission = (item: NavigationItem): boolean => {\n // If item has href, we'll check page permissions later - skip explicit permission check\n // This allows items with href to be filtered by page permissions instead of explicit permissions\n // Check permissions if available AND item doesn't have href\n if (item.permissions && item.permissions.length > 0 && !item.href) {\n // Convert string permissions to Permission type and check\n const permissions = item.permissions\n .filter((p): p is string => typeof p === 'string')\n .map(p => p as Permission);\n \n if (permissions.length > 0) {\n const hasPermission = hasAnyPermission(permissions);\n if (!hasPermission) {\n return false;\n }\n }\n }\n \n // Check roles if available\n if (item.roles && item.roles.length > 0) {\n const hasRole = item.roles.some(role => {\n if (typeof role !== 'string') return true;\n \n // Map role strings to RBAC role checks\n switch (role.toLowerCase()) {\n case 'super_admin':\n case 'super admin':\n return rbacContext.isSuperAdmin;\n case 'org_admin':\n case 'org admin':\n case 'admin':\n return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;\n case 'event_admin':\n case 'event admin':\n return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;\n default:\n // For other roles, check against organisationRole or eventAppRole\n return (\n rbacContext.organisationRole === role ||\n rbacContext.eventAppRole === role ||\n rbacContext.isSuperAdmin\n );\n }\n });\n if (!hasRole) {\n return false;\n }\n }\n \n // Check access level if available\n if (item.accessLevel) {\n if (typeof item.accessLevel === 'string') {\n // Map access level string to RBAC access level\n const accessLevel = item.accessLevel.toLowerCase() as RBACAccessLevel;\n const userEventRole = rbacContext.eventAppRole;\n \n // If user is super admin, they have all access levels\n if (rbacContext.isSuperAdmin) {\n // Super admin has access\n } else {\n // Map eventAppRole to access level for comparison\n // eventAppRole: 'viewer' | 'participant' | 'planner' | 'event_admin'\n const roleToAccessLevel: Record<string, RBACAccessLevel> = {\n 'viewer': 'viewer',\n 'participant': 'participant',\n 'planner': 'planner',\n 'event_admin': 'admin',\n };\n const userAccessLevel = userEventRole ? (roleToAccessLevel[userEventRole] || 'viewer') : null;\n \n // Check if user's access level meets the required access level\n const levelHierarchy: Record<RBACAccessLevel, number> = {\n viewer: 1,\n participant: 2,\n planner: 3,\n admin: 4,\n super: 5\n };\n const requiredLevel = levelHierarchy[accessLevel] || 0;\n const userLevel = userAccessLevel ? levelHierarchy[userAccessLevel] || 0 : 0;\n \n if (userLevel < requiredLevel) {\n return false;\n }\n }\n }\n }\n \n // NEW: Auto-check page permissions for items with href\n // Always check page permissions for items with href, even if they have explicit permissions/roles/accessLevel\n // This ensures that items are filtered out if the user doesn't have access to the page itself\n if (item.href) {\n const pageId = item.pageId || getPageIdFromHref(item.href);\n if (pageId) {\n // Check for read permission on the page\n const pagePermission: Permission = `read:page.${pageId}` as Permission;\n \n // Check permission map (super admin has access to everything via '*' key)\n // Only allow if permission is explicitly true (undefined/false means no access)\n const isSuperAdmin = permissionMap['*'] === true;\n const hasPagePermission = permissionMap[pagePermission] === true;\n const finalHasPermission = isSuperAdmin || hasPagePermission;\n \n if (!finalHasPermission) {\n return false;\n }\n }\n }\n \n return true;\n };\n \n // Helper function to filter items recursively (creates new objects to avoid mutations)\n const filterItem = (item: NavigationItem): NavigationItem | null => {\n // Check if item should be hidden\n if (item.meta?.hidden) return null;\n \n // Check if item has permission\n if (!hasItemPermission(item)) return null;\n \n // Recursively filter children if present\n let filteredChildren: NavigationItem[] | undefined;\n if (item.children && item.children.length > 0) {\n filteredChildren = item.children\n .map(child => filterItem(child))\n .filter((child): child is NavigationItem => child !== null);\n \n // If parent has no accessible children, hide the parent too (unless it has its own href)\n if (filteredChildren.length === 0 && !item.href) {\n return null;\n }\n }\n \n // Return filtered item (with filtered children if applicable)\n return {\n ...item,\n children: filteredChildren\n };\n };\n \n // Filter items based on permissions - only show items with explicit permission\n // Security: No fallback - if items don't have permission, they are hidden\n const filtered = (items || [])\n .map(item => filterItem(item))\n .filter((item): item is NavigationItem => item !== null);\n \n // Update the ref with the new filtered items so we can preserve them during refetches\n previousFilteredItemsRef.current = filtered;\n \n return filtered;\n }, [\n items, \n itemsPreFiltered, // Add itemsPreFiltered to dependencies\n authContext, \n rbacContext, \n permissionMap, \n hasAnyPermission, \n scopeLoading, \n scopeError,\n permissionsLoading,\n resolvedScope,\n effectiveScope,\n auditLog,\n // Add event context state to dependencies so we re-check permissions when event context becomes available\n eventLoadingRaw,\n eventLoading,\n selectedEvent,\n orgContextReady,\n selectedOrganisation?.id\n ]);\n\n // Note: Navigation access attempts are logged in handleItemClick, not here\n // This prevents excessive logging on every render\n\n\n // Handle keyboard navigation for hierarchical mode\n const handleHierarchicalKeyDown = (event: React.KeyboardEvent, item: NavigationItem) => {\n switch (event.key) {\n case 'Enter':\n case ' ':\n event.preventDefault();\n if (item.children && item.children.length > 0) {\n toggleExpanded(item.id);\n } else if (item.href) {\n onNavigate?.(item);\n }\n break;\n case 'Escape':\n if (expandedItems.has(item.id)) {\n toggleExpanded(item.id);\n }\n break;\n }\n };\n\n // Toggle expanded state for hierarchical items\n const toggleExpanded = (itemId: string) => {\n const newExpanded = new Set(expandedItems);\n if (newExpanded.has(itemId)) {\n newExpanded.delete(itemId);\n } else {\n newExpanded.add(itemId);\n }\n setExpandedItems(newExpanded);\n };\n\n // Handle navigation item click\n const handleItemClick = (item: NavigationItem) => {\n // NEW: Phase 2 - Enhanced Security Features\n // Log navigation access attempt for audit (minimal logging)\n if (auditLog) {\n // Navigation access attempt logged\n }\n \n // Check if user has permission to access this navigation item\n if (!authContext) {\n // No auth context - allow access (for unauthenticated scenarios)\n if (onNavigate) {\n onNavigate(item);\n } else if (item.href) {\n window.location.href = item.href;\n }\n return;\n }\n \n // Check if item should be visible (already filtered)\n // If item is in filteredItems, it has already passed permission checks in PaceAppLayout\n const isItemVisible = filteredItems.some(filtered => filtered.id === item.id);\n \n // If item is not visible, it was filtered out - don't allow navigation\n if (!isItemVisible) {\n logger.warn('NavigationMenu', 'Navigation attempt to filtered item blocked', {\n itemId: item.id,\n label: item.label,\n href: item.href\n });\n return;\n }\n \n // Check permissions if the item requires them using RBAC hooks\n // Only check if item has explicit permission requirements AND we have permission checking capability\n let hasPermission = true; // Default to true if no permission requirements\n \n // Only check permissions if:\n // 1. Item has explicit permission requirements\n // 2. We have RBAC context\n // 3. We have hasAnyPermission function AND permission map is loaded (not empty)\n if (item.permissions && item.permissions.length > 0 && rbacContext && hasAnyPermission && permissionMap && Object.keys(permissionMap).length > 0) {\n // Convert string permissions to Permission type and check\n const permissions = item.permissions\n .filter((p): p is string => typeof p === 'string')\n .map(p => p as Permission);\n \n if (permissions.length > 0) {\n hasPermission = hasAnyPermission(permissions);\n }\n }\n \n // If permission check failed, try role-based access\n if (!hasPermission && rbacContext) {\n // Check roles if permissions check failed or item has role requirements\n if (item.roles && item.roles.length > 0) {\n hasPermission = item.roles.some(role => {\n if (typeof role !== 'string') return true;\n \n // Map role strings to RBAC role checks (same logic as filtering)\n switch (role.toLowerCase()) {\n case 'super_admin':\n case 'super admin':\n return rbacContext.isSuperAdmin;\n case 'org_admin':\n case 'org admin':\n case 'admin':\n return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;\n case 'event_admin':\n case 'event admin':\n return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;\n default:\n // For other roles, check against organisationRole or eventAppRole\n return (\n rbacContext.organisationRole === role ||\n rbacContext.eventAppRole === role ||\n rbacContext.isSuperAdmin\n );\n }\n });\n }\n }\n \n // If permission map is empty but item is in filteredItems, trust PaceAppLayout's filtering\n // This handles the case where NavigationMenu's usePermissions returns empty map\n // but PaceAppLayout already filtered items correctly\n if (!hasPermission && (!permissionMap || Object.keys(permissionMap).length === 0) && isItemVisible) {\n // Permission map is empty but item passed filtering - trust PaceAppLayout\n // Permission map empty but item passed filtering - trusting PaceAppLayout (removed verbose logging)\n hasPermission = true;\n }\n \n if (!hasPermission) {\n // Handle access denied\n if (onNavigationAccessDenied) {\n onNavigationAccessDenied(item);\n }\n \n if (strictMode) {\n logger.error('NavigationMenu', 'STRICT MODE VIOLATION: User attempted to access protected navigation item without permission', {\n itemId: item.id,\n label: item.label,\n href: item.href,\n permissions: item.permissions,\n roles: item.roles,\n accessLevel: item.accessLevel,\n timestamp: new Date().toISOString()\n });\n \n if (onStrictModeViolation) {\n onStrictModeViolation(item, 'Insufficient permissions');\n }\n }\n \n return; // Don't navigate if access is denied\n }\n \n if (onNavigate) {\n onNavigate(item);\n } else if (item.href) {\n // Default navigation behavior\n window.location.href = item.href;\n }\n };\n\n // Check if item is currently active\n const isActiveItem = (item: NavigationItem): boolean => {\n if (currentPath === item.href) return true;\n if (item.children && item.children.length > 0) {\n return item.children.some(child => isActiveItem(child));\n }\n return false;\n };\n\n // Handle navigation item selection\n const handleNavigationSelect = (itemId: string) => {\n const item = filteredItems.find(i => i.id === itemId);\n if (item) {\n handleItemClick(item);\n }\n };\n\n // Render hierarchical navigation item\n const renderHierarchicalItem = (item: NavigationItem, level: number = 0) => {\n const hasChildren = item.children && item.children.length > 0;\n const isExpanded = expandedItems.has(item.id);\n const itemIsActive = isActiveItem(item);\n\n return (\n <li role=\"none\">\n {hasChildren ? (\n <div>\n <button\n onClick={() => toggleExpanded(item.id)}\n onKeyDown={(e) => handleHierarchicalKeyDown(e, item)}\n aria-expanded={isExpanded}\n aria-controls={`submenu-${item.id}`}\n aria-current={itemIsActive ? \"page\" : undefined}\n >\n <span>{item.label}</span>\n <ChevronDown aria-hidden=\"true\" />\n </button>\n \n {isExpanded && item.children && (\n <ul\n id={`submenu-${item.id}`}\n role=\"menu\"\n aria-label={`${item.label} submenu`}\n >\n {item.children.map(child => (\n <React.Fragment key={child.id}>\n {renderHierarchicalItem(child, level + 1)}\n </React.Fragment>\n ))}\n </ul>\n )}\n </div>\n ) : (\n <a\n href={item.href || '#'}\n onClick={(e) => {\n if (onNavigate && item.href) {\n e.preventDefault();\n onNavigate(item);\n }\n }}\n onKeyDown={(e) => handleHierarchicalKeyDown(e, item)}\n role=\"menuitem\"\n aria-current={itemIsActive ? \"page\" : undefined}\n >\n {item.label}\n </a>\n )}\n </li>\n );\n };\n\n // Render based on mode\n if (mode === 'dropdown') {\n return (\n <Select \n onValueChange={handleNavigationSelect}\n className={className}\n data-testid=\"navigation-menu-root\"\n >\n <SelectTrigger \n ref={buttonRef}\n disabled={disabled} \n aria-label={buttonText}\n data-testid=\"navigation-menu-trigger\"\n >\n <SelectValue placeholder={buttonText} />\n </SelectTrigger>\n <SelectContent>\n {filteredItems.map((item) => {\n const isActive = isActiveItem(item);\n return (\n <SelectItem\n key={item.id}\n value={item.id}\n disabled={!item.href}\n data-testid={`navigation-menu-item-${item.id}`}\n >\n {item.label}\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n );\n }\n\n // Hierarchical mode\n return (\n <nav \n ref={ref}\n className={className}\n aria-label={navigationLabel}\n {...props}\n >\n <ul role=\"menubar\">\n {filteredItems.map(item => (\n <React.Fragment key={item.id}>\n {renderHierarchicalItem(item, 0)}\n </React.Fragment>\n ))}\n </ul>\n </nav>\n );\n});\n\nNavigationMenu.displayName = \"NavigationMenu\";","/**\n * @file Header Component\n * @package @jmruthers/pace-core\n * @module Components/Header\n * @since 0.1.0\n *\n * A comprehensive header component for application layouts with navigation,\n * user menu, organisation selector, event selector, and customizable branding.\n *\n * Features:\n * - Customizable logo (URL or component)\n * - Clickable logo that routes to dashboard (configurable)\n * - Navigation menu integration\n * - User menu with authentication\n * - Organisation selector for multi-organisation applications\n * - Event selector for multi-tenant applications\n * - Custom actions support\n * - Responsive design\n * - Accessibility compliant\n * - Backdrop blur effects\n * - Flexible layout options\n *\n * @example\n * ```tsx\n * // Basic header with logo and user menu (logo routes to /dashboard by default)\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoAlt=\"My App\"\n * logoHref=\"/dashboard\"\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header with navigation and custom actions\n * <Header\n * logo={<CustomLogo />}\n * logoHref=\"/home\"\n * navItems={[\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard' },\n * { id: 'users', label: 'Users', href: '/users' },\n * { id: 'settings', label: 'Settings', href: '/settings' }\n * ]}\n * currentPath=\"/dashboard\"\n * actions={\n * <div className=\"flex gap-2\">\n * <Button variant=\"outline\">Export</Button>\n * <Button>New Item</Button>\n * </div>\n * }\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header without event selector\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoHref=\"/dashboard\"\n * showEventSelector={false}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header with custom user menu\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoHref=\"/home\"\n * userMenu={<CustomUserMenu user={currentUser} />}\n * showUserMenu={true}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML with role=\"banner\"\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - High contrast support\n * - Focus management\n *\n * @dependencies\n * - @supabase/supabase-js - User authentication\n * - React 19+ - Component framework\n * - Tailwind CSS - Styling\n * - NavigationMenu component\n * - UserMenu component\n * - OrganisationSelector component\n * - EventSelector component\n */\n\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { User } from '@supabase/supabase-js';\nimport { cn } from '../../utils/core/cn';\nimport { EventSelector } from '../EventSelector';\nimport { OrganisationSelector } from '../OrganisationSelector';\nimport { UserMenu } from '../UserMenu';\nimport { NavigationMenu } from '../NavigationMenu';\nimport type { NavigationItem } from '../NavigationMenu';\nimport type { PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\nimport { useOrganisations } from '../../hooks/useOrganisations';\n\n/**\n * Props for the Header component\n */\nexport interface HeaderProps {\n /** URL to the app logo image */\n logoUrl?: string;\n /** Alt text for the logo */\n logoAlt?: string;\n /** Custom logo component (overrides logoUrl) */\n logo?: React.ReactNode;\n /** Navigation items for the menu - uses NavigationItem interface */\n navItems?: NavigationItem[];\n /** Current user for the user menu */\n user?: User | null;\n /** Sign out handler for user menu */\n onSignOut?: () => Promise<void>;\n /** Password change handler for user menu */\n onChangePassword?: (newPassword: string, confirmPassword: string) => Promise<{ error?: PasswordChangeFormError }>;\n /** Additional actions to display (will be placed between event selector and user menu) */\n actions?: React.ReactNode;\n /** Custom user menu component (overrides default UserMenu) */\n userMenu?: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Show/hide event selector */\n showEventSelector?: boolean;\n /** Show/hide organisation selector */\n showOrgSelector?: boolean;\n /** Show/hide user menu */\n showUserMenu?: boolean;\n /** Current path for navigation highlighting */\n currentPath?: string;\n /** Custom navigation handler */\n onNavigate?: (item: NavigationItem) => void;\n /** URL to navigate to when logo is clicked (e.g., '/dashboard') */\n logoHref?: string;\n}\n\n/**\n * Header component for application layouts with comprehensive navigation, user management, \n * and customizable branding support.\n * \n * A flexible header component that supports various configurations including custom logos,\n * navigation menus, user authentication, event selection, and custom actions.\n * \n * **Logo Display:** When used via PaceAppLayout, the logo URL is automatically constructed\n * from the appName prop as `/${appName.toLowerCase()}_logo_wide.svg`. The appName should\n * come from an APP_NAME constant declared in your App.tsx file to ensure consistency across\n * authenticated and public pages.\n * \n * Features:\n * - Customizable logo (URL or custom component)\n * - Clickable logo that automatically routes to dashboard (configurable via logoHref)\n * - Navigation menu integration with highlighting\n * - User menu with authentication and password management\n * - Event selector for multi-tenant applications\n * - Custom actions support\n * - Responsive design with mobile considerations\n * - Accessibility compliant with proper ARIA attributes\n * - Backdrop blur effects for modern UI\n * - Flexible layout with configurable sections\n *\n * @example\n * Basic header with logo and navigation (logo routes to /dashboard when clicked):\n * ```tsx\n * import { Header } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppHeader() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard' },\n * { id: 'meals', label: 'Meals', href: '/meals' },\n * { id: 'settings', label: 'Settings', href: '/settings' }\n * ];\n * \n * return (\n * <Header\n * logoUrl=\"/company-logo.svg\"\n * logoAlt=\"My Company\"\n * logoHref=\"/dashboard\"\n * navItems={navItems}\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Header with custom actions:\n * ```tsx\n * import { Header, Button } from '@jmruthers/pace-core';\n * \n * function HeaderWithActions() {\n * const customActions = (\n * <div className=\"flex items-center gap-2\">\n * <Button variant=\"outline\" size=\"sm\">Export</Button>\n * <Button size=\"sm\">New Item</Button>\n * </div>\n * );\n * \n * return (\n * <Header\n * logoUrl=\"/logo.svg\"\n * navItems={navigationItems}\n * actions={customActions}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Minimal header configuration:\n * ```tsx\n * function MinimalHeader() {\n * return (\n * <Header\n * logoUrl=\"/simple-logo.svg\"\n * logoAlt=\"Simple App\"\n * showEventSelector={false}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @param props - Header configuration including logo, navigation, user settings, and custom content\n * @returns React element with complete header functionality\n * \n * @since 0.1.0\n */\nexport function Header({\n logoUrl,\n logoAlt = 'Logo',\n logo,\n navItems = [],\n user,\n onSignOut,\n onChangePassword,\n actions,\n userMenu,\n className,\n showEventSelector = true,\n showOrgSelector = false,\n showUserMenu = true,\n currentPath,\n onNavigate,\n logoHref\n}: HeaderProps) {\n // Conditional wrapper for organisation selector - only show if user has organisations\n const OrganisationSelectorConditional = () => {\n const { organisations, isContextReady } = useOrganisations();\n // Only show selector if user has organisations and context is ready\n if (!isContextReady || !organisations || organisations.length === 0) {\n return null;\n }\n return (\n <OrganisationSelector \n placeholder=\"Select organisation\" \n className=\"w-64\" \n data-testid=\"org-selector\"\n compact={true}\n />\n );\n };\n\n return (\n <header className={cn(\n \"w-full border-b border-main-200 h-16 shadow-sm bg-main-100 \",\n className\n )} role=\"banner\">\n <nav className=\"px-4 w-[min(var(--app-width),100%)] mx-auto flex items-center gap-4 h-full\">\n {/* Logo */}\n {logo ? (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n {logo}\n </Link>\n ) : (\n logo\n )\n ) : logoUrl ? (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n <img\n src={logoUrl}\n alt={logoAlt || 'Logo'}\n className=\"h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent\"\n />\n </Link>\n ) : (\n <img\n src={logoUrl}\n alt={logoAlt || 'Logo'}\n className=\"h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent\"\n />\n )\n ) : (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n <img\n src=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E\"\n alt={logoAlt || 'Logo'}\n className=\"size-8 shadow-md\"\n />\n </Link>\n ) : (\n <img\n src=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E\"\n alt={logoAlt || 'Logo'}\n className=\"size-8 shadow-md\"\n />\n )\n )}\n\n {/* Navigation Menu */}\n {navItems && navItems.length > 0 && (\n <NavigationMenu\n items={navItems}\n currentPath={currentPath}\n onNavigate={onNavigate}\n buttonText=\"Menu\"\n className=\"w-48\"\n itemsPreFiltered={true}\n />\n )}\n \n\n {/* Right side: Organisation Selector, Event Selector, Actions, and User Menu */}\n <div className=\"flex items-center gap-4 ml-auto\">\n {/* Organisation Selector - Only show if user has organisations */}\n {showOrgSelector ? (\n <OrganisationSelectorConditional />\n ) : null}\n\n {/* Event Selector */}\n {showEventSelector ? (\n <EventSelector \n placeholder=\"Select event\" \n className=\"w-96\" \n data-testid=\"event-selector\" \n />\n ) : null}\n \n {/* Custom Actions */}\n {actions}\n \n {/* User Menu */}\n {showUserMenu && (\n userMenu ? (\n userMenu\n ) : (\n <UserMenu\n user={user || null}\n onSignOut={onSignOut}\n onChangePassword={onChangePassword}\n className=\"w-70\"\n />\n )\n )}\n </div>\n\n </nav>\n </header>\n );\n}\n","/**\n * @file Footer Component\n * @package @jmruthers/pace-core\n * @module Components/Footer\n * @since 0.1.0\n *\n * A flexible footer component for application layouts with copyright information,\n * navigation links, and customizable content.\n *\n * Features:\n * - Copyright information with automatic year generation\n * - Customizable company name and branding\n * - Optional navigation links\n * - Logo display support\n * - Custom footer content via children\n * - Responsive design\n * - Accessibility compliant\n * - Flexible layout options\n * - Consistent styling with design system\n *\n * @example\n * ```tsx\n * // Basic footer with default copyright\n * <Footer />\n * \n * // Footer with custom company name and year\n * <Footer \n * companyName=\"My Company Inc.\"\n * year={2024}\n * />\n * \n * // Footer with navigation links\n * <Footer\n * companyName=\"My Company\"\n * links={[\n * { label: 'Privacy Policy', href: '/privacy' },\n * { label: 'Terms of Service', href: '/terms' },\n * { label: 'Contact', href: '/contact' }\n * ]}\n * />\n * \n * // Footer with logo and custom copyright\n * <Footer\n * logo=\"/logo.svg\"\n * copyright=\"© 2024 My Company. All rights reserved.\"\n * />\n * \n * // Footer with custom content\n * <Footer companyName=\"My Company\">\n * <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-8\">\n * <div>\n * <h3 className=\"font-semibold mb-2\">About Us</h3>\n * <p className=\"text-sm text-muted-foreground\">\n * We provide innovative solutions for modern businesses.\n * </p>\n * </div>\n * <div>\n * <h3 className=\"font-semibold mb-2\">Contact</h3>\n * <p className=\"text-sm text-muted-foreground\">\n * Email: info@mycompany.com<br />\n * Phone: (555) 123-4567\n * </p>\n * </div>\n * <div>\n * <h3 className=\"font-semibold mb-2\">Follow Us</h3>\n * <div className=\"flex gap-2\">\n * <a href=\"#\" className=\"text-muted-foreground hover:text-foreground\">Twitter</a>\n * <a href=\"#\" className=\"text-muted-foreground hover:text-foreground\">LinkedIn</a>\n * </div>\n * </div>\n * </div>\n * </Footer>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML with role=\"contentinfo\"\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - High contrast support\n * - Clear link identification\n *\n * @dependencies\n * - React 19+ - Component framework\n * - Tailwind CSS - Styling\n */\nimport React from 'react';\nimport { cn } from '../../utils/core/cn';\n\nexport interface FooterProps {\n /**\n * Company or organization name\n */\n companyName?: string;\n\n /**\n * Current year or custom year for copyright\n * @default current year\n */\n year?: number;\n\n /**\n * Optional array of navigation links to display\n */\n links?: Array<{\n label: string;\n href: string;\n }>;\n\n /**\n * Optional CSS class name\n */\n className?: string;\n\n /**\n * Logo image URL (from UI version)\n */\n logo?: string;\n\n /**\n * Copyright text (from UI version)\n */\n copyright?: string;\n\n /**\n * Footer content - children to render inside footer\n */\n children?: React.ReactNode;\n}\n\n/**\n * Footer component that displays copyright information and navigation\n * \n * @example\n * ```tsx\n * // Basic usage\n * <Footer />\n * \n * // With children\n * <Footer>\n * <div>Custom footer content</div>\n * </Footer>\n * \n * // With logo and copyright\n * <Footer logo=\"/logo.png\" copyright=\"© 2024 Company. All rights reserved.\" />\n * ```\n */\nconst FooterComponent: React.FC<FooterProps> = ({\n companyName = 'Solvera Solutions Pty Ltd',\n year = new Date().getFullYear(),\n links,\n className = '',\n logo,\n copyright,\n children\n}) => {\n // Use custom copyright if provided, otherwise generate default\n const copyrightText = copyright || `© Copyright 2022–${year} all rights reserved, ${companyName}.`;\n\n return (\n <footer className={cn('mt-8 py-6 flex justify-center border-t border-border bg-main-100', className)}>\n\n <section className='px-4 w-[min(var(--app-width),100%)] mx-auto text-center'>\n {logo && (\n <img src={logo} alt=\"Logo\" className=\"h-8 w-auto\" />\n )}\n\n {children && (\n <>\n {children}\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {copyrightText}\n </span>\n\n {links && links.length > 0 && (\n <ul className=\"flex gap-4 mt-2 md:mt-0\">\n {links.map((link, index) => (\n <li key={index}>\n <a href={link.href} className=\"text-muted-foreground hover:text-foreground\">\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n )}\n </section>\n </footer>\n );\n};\n\nFooterComponent.displayName = 'Footer';\n\nexport const Footer = React.memo(FooterComponent);\nFooter.displayName = 'Footer';\n","/**\n * @file PACE App Layout Component\n * @package @jmruthers/pace-core\n * @module Components/PaceAppLayout\n * @since 0.1.0\n *\n * A comprehensive application layout component that provides a consistent\n * structure for all PACE suite applications with header, navigation, and footer.\n * \n * NEW: Layout-level permission enforcement to ensure consuming apps can't\n * forget to implement permission checks on individual pages.\n *\n * Features:\n * - Consistent application layout structure\n * - Header with logo, navigation, and user menu\n * - Footer with copyright and links\n * - React Router integration with Outlet\n * - Unified authentication integration\n * - Navigation menu with configurable items\n * - User sign-out functionality\n * - Password change capability\n * - Responsive design\n * - Accessibility compliant\n * - Flexible content area\n * - Branding support\n * - Layout-level permission enforcement\n * - Automatic page permission validation\n * - Permission-based navigation filtering\n *\n * @example\n * ```tsx\n * // Basic app layout with React Router (RECOMMENDED)\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={<PaceAppLayout appName=\"My Application\" />}>\n * <Route index element={<HomePage />} />\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"settings\" element={<SettingsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * \n * // App layout with custom permission configuration\n * function MyApp() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"My App\">\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"My Application\"\n * enforcePermissions={true}\n * defaultPermission=\"read\"\n * permissionFallback={<AccessDeniedPage />}\n * />\n * }>\n * <Route index element={<HomePage />} />\n * <Route path=\"events\" element={<EventsPage />} />\n * <Route path=\"reports\" element={<ReportsPage />} />\n * <Route path=\"admin\" element={<AdminPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * \n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear content hierarchy\n * - Consistent navigation patterns\n *\n * @routing\n * - React Router v6 integration\n * - Nested route support\n * - Dynamic navigation handling\n * - Path-based navigation\n * - Route outlet rendering\n * - Permission-based route protection\n *\n * @dependencies\n * - React 19+ - Component framework\n * - React Router v6 - Routing\n * - UnifiedAuthProvider - Authentication\n * - usePermissionCache - Permission management\n * - Header component\n * - Footer component\n * - Button component\n * - NavigationMenu types\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { Outlet, useNavigate, useLocation } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport { useCan, useResolvedScope, useRBAC } from '../../rbac/hooks';\nimport { createScopeFromEvent } from '../../rbac/utils/eventContext';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { isSuperAdmin as checkSuperAdminApi } from '../../rbac/api';\nimport { logger } from '../../utils/core/logger';\nimport type { Permission, Scope } from '../../rbac/types';\n\n// Stable empty objects to prevent infinite loops\nconst EMPTY_PAGE_ID_MAPPING = {};\nconst EMPTY_ROUTE_PERMISSIONS = {};\nimport { Button } from '../Button';\nimport { Footer } from '../Footer';\nimport { Header } from '../Header';\nimport type { NavigationItem } from '../NavigationMenu/NavigationMenu';\nimport type { PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\n// Define Operation type locally since old RBAC types are removed\ntype Operation = 'read' | 'create' | 'update' | 'delete' | 'manage';\n\nexport interface PaceAppLayoutProps {\n /** The name of the application to be displayed in the header. */\n appName: string;\n /** Optional navigation items for the header menu. If not provided, uses default navigation. */\n navItems?: NavigationItem[];\n /** Show/hide event selector in the header */\n showEventSelector?: boolean;\n /** Show/hide organisation selector in the header */\n showOrgSelector?: boolean;\n /** Custom actions to display in the header (between event selector and user menu) */\n headerActions?: React.ReactNode;\n /** Custom logo component (overrides default logo) */\n customLogo?: React.ReactNode;\n /** URL to navigate to when logo is clicked (defaults to '/dashboard') */\n logoHref?: string;\n /** Custom user menu component (overrides default user menu) */\n customUserMenu?: React.ReactNode;\n /** Custom className for the header */\n headerClassName?: string;\n /** Show/hide user menu */\n showUserMenu?: boolean;\n /** Enable layout-level permission enforcement */\n enforcePermissions?: boolean;\n /** Default permission to check for all routes (when enforcePermissions is true) */\n defaultPermission?: Operation;\n /** Route-specific permissions mapping */\n routePermissions?: Record<string, Operation>;\n /** Fallback component to show when user lacks permission */\n permissionFallback?: React.ReactNode;\n /** Custom permission page ID mapping */\n pageIdMapping?: Record<string, string>;\n \n // NEW: Phase 1 - Enhanced Security Features\n /** Enable strict mode to prevent bypassing permission checks (default: true) */\n strictMode?: boolean;\n /** Enable page-level permission enforcement (default: false) */\n enforcePagePermissions?: boolean;\n /** Default page permission fallback component */\n pagePermissionFallback?: React.ReactNode;\n /** Enable audit logging for all permission checks (default: true) */\n auditLog?: boolean;\n /** Callback when page access is denied */\n onPageAccessDenied?: (pageName: string, operation: string) => void;\n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (pageName: string, operation: string) => void;\n \n // NEW: Phase 2 - Enhanced Routing Features\n /** Enable role-based routing (default: false) */\n roleBasedRouting?: boolean;\n /** Route configuration for role-based routing */\n routeConfig?: Array<{\n path: string;\n component: React.ComponentType;\n permissions: string[];\n roles?: string[];\n accessLevel?: string;\n pageId?: string;\n strictMode?: boolean;\n meta?: {\n title?: string;\n description?: string;\n requiresAuth?: boolean;\n hidden?: boolean;\n };\n }>;\n /** Fallback route for unauthorized access */\n fallbackRoute?: string;\n /** Callback when route access is denied */\n onRouteAccessDenied?: (route: string, reason: string) => void;\n /** Callback when route strict mode violation occurs */\n onRouteStrictModeViolation?: (route: string, reason: string) => void;\n}\n\n/**\n * A consistent layout component for all PACE suite applications that provides a standard\n * structure with header, main content area, and footer.\n * \n * NEW: This component now includes layout-level permission enforcement to ensure\n * consuming apps can't forget to implement permission checks on individual pages.\n * \n * This component is designed to work with React Router's nested routing pattern using\n * Outlet to render child routes. It provides integrated authentication, navigation,\n * and user management functionality.\n * \n * **Super Admin Access:** When `enforcePermissions={true}`, PaceAppLayout automatically\n * checks if the user is a super admin before enforcing permissions. Super admins bypass\n * all permission checks and can access any route without violations. The component extracts\n * base page names from route paths (e.g., `/organisation/scouts-victoria` → `\"organisation\"`)\n * for permission checking, which can be overridden using `pageIdMapping`.\n * \n * **Important:** The appName prop should use an APP_NAME constant declared in your App.tsx\n * file. This ensures consistency with public pages (via PublicPageProvider) which should\n * also receive the same APP_NAME constant. The logo URL is automatically constructed as\n * `/${appName.toLowerCase()}_logo_wide.svg` from the public folder.\n * \n * Features:\n * - React Router v6 integration with nested routing\n * - Unified authentication integration\n * - Consistent header with navigation and user menu\n * - Flexible main content area with Outlet\n * - Footer with application branding\n * - User sign-out and password change functionality\n * - Responsive design and accessibility compliant\n * - Layout-level permission enforcement\n * - Permission-based navigation filtering\n * - Automatic page permission validation\n * - Super admin bypass (super admins automatically bypass all permission checks)\n * \n * @example\n * Basic React Router setup with permission enforcement (RECOMMENDED):\n * ```tsx\n * import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';\n * import { UnifiedAuthProvider } from '@jmruthers/pace-core/providers';\n * import { PaceAppLayout, PaceLoginPage, PublicPageApp } from '@jmruthers/pace-core';\n * \n * const APP_NAME = 'CORE';\n * \n * function App() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName={APP_NAME}>\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={<PaceLoginPage appName={APP_NAME} />} />\n * <Route path=\"/events/*\" element={<PublicPageApp appName={APP_NAME} />} />\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName={APP_NAME}\n * enforcePermissions={true}\n * defaultPermission=\"read\"\n * />\n * }>\n * <Route index element={<HomePage />} />\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"meals\" element={<MealsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * ```\n * \n * \n * @example\n * Custom navigation items with permission filtering (works independently of route enforcement):\n * ```tsx\n * import { NavigationItem } from '@jmruthers/pace-core';\n * \n * function App() {\n * const customNavItems: NavigationItem[] = [\n * { id: 'components', label: 'Components', href: '/components', icon: 'Component' },\n * { id: 'styles', label: 'Styles', href: '/styles', icon: 'Palette' },\n * { id: 'meals', label: 'Meals', href: '/meals', icon: 'UtensilsCrossed' }\n * ];\n * \n * return (\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"My Custom App\" \n * navItems={customNavItems}\n * // Permission filtering is always enabled - no prop needed\n * routePermissions={{\n * '/components': 'read',\n * '/styles': 'read',\n * '/meals': 'read'\n * }}\n * // Optionally enable route-level enforcement (separate from navigation filtering)\n * // enforcePermissions={true}\n * />\n * }>\n * <Route path=\"components\" element={<ComponentsPage />} />\n * <Route path=\"styles\" element={<StylesPage />} />\n * <Route path=\"meals\" element={<MealsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * );\n * }\n * ```\n * \n * @example\n * Route-specific permissions with custom page IDs:\n * ```tsx\n * function AdminApp() {\n * return (\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"Admin Panel\"\n * enforcePermissions={true}\n * routePermissions={{\n * '/dashboard': 'read',\n * '/user-management': 'read',\n * '/system-settings': 'update'\n * }}\n * pageIdMapping={{\n * '/dashboard': 'dashboard',\n * '/user-management': 'user-management',\n * '/system-settings': 'system-admin'\n * }}\n * permissionFallback={<AccessDeniedPage />}\n * />\n * }>\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"user-management\" element={<UserManagementPage />} />\n * <Route path=\"system-settings\" element={<SystemSettingsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * );\n * }\n * ```\n * \n * @param props - Layout configuration including app name for branding and permission settings\n * @returns React element with complete application layout structure and permission enforcement\n * \n * @since 0.1.0\n */\nexport function PaceAppLayout({ \n appName, \n navItems, \n showEventSelector,\n showOrgSelector,\n headerActions,\n customLogo,\n logoHref = '/dashboard',\n customUserMenu,\n headerClassName,\n showUserMenu = true,\n enforcePermissions = false,\n defaultPermission = 'read',\n routePermissions = EMPTY_ROUTE_PERMISSIONS,\n permissionFallback,\n pageIdMapping = EMPTY_PAGE_ID_MAPPING,\n // NEW: Phase 1 - Enhanced Security Features\n strictMode = true,\n enforcePagePermissions = false,\n pagePermissionFallback,\n auditLog = true,\n onPageAccessDenied,\n onStrictModeViolation,\n // NEW: Phase 2 - Enhanced Routing Features\n roleBasedRouting = false,\n routeConfig = [],\n fallbackRoute = '/unauthorized',\n onRouteAccessDenied,\n onRouteStrictModeViolation\n}: PaceAppLayoutProps) {\n const { user, signOut, updatePassword, supabase, appId: contextAppId, selectedOrganisationId } = useUnifiedAuth(); // Get appId from context (resolved on login)\n const { \n selectedOrganisation, \n isContextReady, \n hasValidOrganisationContext,\n ensureOrganisationContext,\n isLoading: organisationLoading \n } = useOrganisations();\n // Use useRBAC to get super admin status - it's more reliable than async check\n // Note: isSuperAdmin might be false initially while loading, but that's OK - we'll allow rendering\n // if organisation loading completes or if we're a super admin\n const { isSuperAdmin: isSuperAdminFromRBAC, isLoading: rbacLoading } = useRBAC();\n\n // Also check super admin status directly as a fallback (for ADMIN/PORTAL apps)\n // This allows super admins to proceed even if RBAC hasn't loaded yet\n const [isSuperAdminDirect, setIsSuperAdminDirect] = useState<boolean>(false);\n const [isCheckingSuperAdminDirect, setIsCheckingSuperAdminDirect] = useState<boolean>(false);\n\n useEffect(() => {\n const checkSuperAdminDirect = async () => {\n if (!user?.id) {\n setIsSuperAdminDirect(false);\n setIsCheckingSuperAdminDirect(false);\n return;\n }\n\n // Only skip if RBAC already confirmed super admin\n if (isSuperAdminFromRBAC) {\n setIsCheckingSuperAdminDirect(false);\n return;\n }\n\n setIsCheckingSuperAdminDirect(true);\n try {\n const superAdminStatus = await checkSuperAdminApi(user.id);\n setIsSuperAdminDirect(superAdminStatus);\n } catch (error) {\n logger.error('PaceAppLayout', 'Error checking super admin status directly', { userId: user?.id, error });\n setIsSuperAdminDirect(false);\n } finally {\n setIsCheckingSuperAdminDirect(false);\n }\n };\n\n checkSuperAdminDirect();\n }, [user?.id, isSuperAdminFromRBAC]);\n\n // Use direct check if RBAC hasn't loaded yet, otherwise use RBAC result\n const isSuperAdmin = isSuperAdminFromRBAC || isSuperAdminDirect;\n const navigate = useNavigate();\n const location = useLocation();\n \n // Apply event theme colors automatically\n useEventTheme();\n \n // Get selected event (optional)\n let selectedEvent: { event_id: string } | null = null;\n try {\n const eventsContext = useEvents();\n selectedEvent = eventsContext.selectedEvent;\n } catch (error) {\n // Event provider not available - continue without event context\n }\n \n // Resolve scope for permission checking\n const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({\n supabase: supabase || null,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n\n // Use appId from context (resolved immediately on login) or fallback to resolvedScope\n // This ensures appId is available immediately without waiting for additional resolution\n const resolvedAppId = contextAppId || resolvedScope?.appId;\n \n // Build scope from resolved values\n // Preserve appId from resolvedScope or fallback to resolvedAppId\n // CRITICAL: Always create a new scope object from primitive values to ensure stable reference\n // This prevents useCan from re-checking permissions when resolvedScope changes reference but values are the same\n const scopeOrgId = resolvedScope?.organisationId || selectedOrganisation?.id || '';\n const scopeEventId = resolvedScope?.eventId || selectedEvent?.event_id || undefined;\n const scopeAppId = resolvedScope?.appId || resolvedAppId || undefined;\n \n const scope = useMemo<Scope>(() => {\n const newScope: Scope = {};\n if (scopeOrgId) {\n newScope.organisationId = scopeOrgId;\n }\n if (scopeEventId) {\n newScope.eventId = scopeEventId;\n }\n if (scopeAppId) {\n newScope.appId = scopeAppId;\n }\n return newScope;\n }, [scopeOrgId, scopeEventId, scopeAppId]);\n\n // Default navigation items if none provided\n const defaultNavItems: NavigationItem[] = useMemo(() => [\n { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' },\n { id: 'ui-showcase', label: 'UI Showcase', href: '/ui-showcase', icon: 'Component' },\n { id: 'data-table-showcase', label: 'DataTable Showcase', href: '/data-table-showcase', icon: 'Table' },\n ], []);\n\n // Use provided navItems or fall back to default\n const baseMenuItems = useMemo(() => navItems || defaultNavItems, [navItems]);\n\n // Get current route permission requirements\n const currentRoutePermission = useMemo(() => {\n const currentPath = location.pathname;\n return routePermissions[currentPath] || defaultPermission;\n }, [location.pathname, routePermissions, defaultPermission]);\n\n // Get current page ID for permission checking\n // Extract base page name (first path segment) instead of full route path\n // Example: /organisation/scouts-victoria -> \"organisation\"\n const currentPageId = useMemo(() => {\n const currentPath = location.pathname;\n // Use pageIdMapping if provided (takes precedence)\n if (pageIdMapping[currentPath]) {\n return pageIdMapping[currentPath];\n }\n // Extract first path segment (base page name)\n const pathSegments = currentPath.slice(1).split('/').filter(Boolean);\n // Only return 'home' if there's actually a path segment, otherwise return empty string\n // This prevents checking permissions for a non-existent \"home\" page when the index route is used\n return pathSegments[0] || '';\n }, [location.pathname, pageIdMapping]);\n\n // Build permission string in format: operation:page.pageId\n const currentPermission = useMemo<Permission>(() => {\n // If enforcePermissions is false, don't check any permission (return empty string)\n // If currentPageId is empty (index route with no path segments), don't check permissions\n if (!enforcePermissions || !currentPageId) {\n return '' as Permission;\n }\n const permissionString = `${currentRoutePermission}:page.${currentPageId}`;\n return permissionString as Permission;\n }, [enforcePermissions, currentRoutePermission, currentPageId]);\n\n // Check super admin status before permission enforcement\n // Removed duplicate super admin check - using useRBAC hook instead\n // The useRBAC hook provides isSuperAdmin which is more reliable\n\n // Use useCan hook for permission checking (standardized approach)\n // Note: The database function already handles super admin bypass, but we check here\n // as an additional safety layer to prevent unnecessary permission checks\n // Pass appName to useCan so it can be passed to isPermitted for PORTAL/ADMIN special case\n // Only check permissions if enforcePermissions is true and we have a valid permission string\n const shouldCheckPermission = enforcePermissions && !!currentPermission && !!currentPageId;\n const { can: canFromHook, isLoading: isCheckingPermission, error: permissionError } = useCan(\n user?.id || '',\n scope,\n shouldCheckPermission ? currentPermission : ('' as Permission),\n shouldCheckPermission ? currentPageId : '',\n true, // useCache\n appName // Pass appName for PORTAL/ADMIN special case\n );\n\n // Permission enforcement state - super admin bypasses all checks\n // This ensures super admins never see permission errors even if useCan hasn't completed\n // Use combined super admin check (RBAC + direct check)\n const can = isSuperAdmin ? true : canFromHook;\n const hasPermission = enforcePermissions ? can : true;\n\n // Handle permission check results with audit logging and callbacks\n useEffect(() => {\n if (!enforcePermissions) {\n return;\n }\n\n // Only proceed when permission check is complete (not loading)\n // Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)\n // If RBAC is still loading, allow rendering to proceed (optimistic for super admins)\n if (isCheckingPermission) {\n return;\n }\n\n // NEW: Phase 1 - Enhanced Security Features\n // Handle strict mode violations - skip for super admins\n if (strictMode && !isSuperAdmin && !can) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected page without permission', {\n pageName: currentPageId,\n operation: currentRoutePermission,\n userId: user?.id,\n isSuperAdmin: isSuperAdmin,\n timestamp: new Date().toISOString()\n });\n \n if (onStrictModeViolation) {\n onStrictModeViolation(currentPageId, currentRoutePermission);\n }\n }\n \n // Handle page access denied callback - skip for super admins\n if (!isSuperAdmin && !can && onPageAccessDenied) {\n onPageAccessDenied(currentPageId, currentRoutePermission);\n }\n }, [enforcePermissions, can, isCheckingPermission, isSuperAdmin, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);\n\n // Filter navigation items based on permissions\n // Permission filtering is always enabled - users only see navigation items they have permission to access\n const [filteredMenuItems, setFilteredMenuItems] = useState<NavigationItem[]>(baseMenuItems);\n\n useEffect(() => {\n let isMounted = true;\n\n const filterItems = async () => {\n // Wait for organisation context to be ready before filtering\n // This prevents blocking navigation while context is loading\n if (!user?.id) {\n // User not loaded yet - show all items until context is ready\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // Use the scope from context (includes selectedOrganisation and selectedEvent)\n // This is critical for event-based apps where event context comes from EventService, not user metadata\n const currentScope = scope;\n \n // Wait for scope to be fully resolved (including appId) before filtering\n // This is important because getPermissionMap requires appId to fetch pages\n // Check both resolvedScope.appId and resolvedAppId (fallback)\n // appId is now resolved immediately on login in UnifiedAuthProvider, so it should be available\n const hasAppId = currentScope.appId || resolvedAppId;\n \n // OPTIMIZATION: Show items optimistically while permissions load\n // This makes the menu appear immediately, then we filter when permissions are ready\n const hasOrganisationContext = currentScope.organisationId;\n const hasUser = !!user?.id;\n \n // BUG FIX: When showOrgSelector is enabled, show navigation optimistically while waiting\n // for organisation selection. Only hide navigation if user is not loaded.\n // This prevents navigation from disappearing after initial render while waiting for org selection.\n if (!hasUser) {\n // User not loaded yet - show all items until user is ready\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // If no organisation context yet, show items optimistically if org selector is enabled\n // This allows users to see navigation while they select an organisation\n // Only proceed with permission filtering once organisation is selected\n if (!hasOrganisationContext) {\n if (isMounted) {\n // Show items optimistically when org selector is enabled, otherwise show all items\n // This prevents navigation from disappearing while waiting for organisation selection\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // For super admins, show all items (they bypass permission checks)\n // Gracefully handle RBAC not being initialized (e.g., in tests)\n try {\n const { isSuperAdmin: checkSuperAdminDynamic } = await import('../../rbac/api');\n const isSuper = await checkSuperAdminDynamic(user.id);\n \n if (isSuper) {\n // Super admins see all navigation items\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n } catch (error) {\n // If RBAC is not initialized (e.g., in tests), continue with normal filtering\n // This prevents errors from breaking navigation when RBAC isn't available\n if (error && typeof error === 'object' && 'code' in error && error.code === 'RBAC_NOT_INITIALIZED') {\n // RBAC not available - proceed with normal filtering without super admin check\n // In this case, we'll filter items normally based on permissions\n } else {\n // Re-throw unexpected errors\n throw error;\n }\n }\n\n // Organisation context is ready - now filter items based on permissions\n // OPTIMIZATION: Use batch permission map instead of individual checks to avoid rate limits\n // This makes 1 call instead of N calls (where N = number of navigation items)\n // OPTIMIZATION: Proceed even if appId is still resolving - permission checks work with organisationId\n try {\n const { getPermissionMap } = await import('../../rbac/api');\n \n // Build scope for permission check - use appId if available, but don't wait for it\n // Permission checks will work with resource permissions even without appId\n const permissionScope: Scope = {\n organisationId: currentScope.organisationId,\n eventId: currentScope.eventId,\n appId: currentScope.appId || resolvedAppId || undefined // Use appId if available, but proceed without it\n };\n \n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope: permissionScope,\n });\n\n // Filter items using the permission map (synchronous, no rate limit issues)\n const filtered = baseMenuItems.map((item) => {\n if (!item.href) return { item, hasAccess: true };\n \n // Extract page ID from href: remove leading slash, fallback to 'dashboard' for root\n // This matches database page names in rbac_app_pages\n const pageId = pageIdMapping[item.href] || (item.href === '/' ? 'dashboard' : item.href.slice(1)) || 'dashboard';\n const permission = routePermissions[item.href] || defaultPermission;\n const fullPermission: Permission = permission.includes(':')\n ? (permission as Permission)\n : (pageId ? `${permission}:page.${pageId}` : permission) as Permission;\n \n // Check permission map (super admin check already handled in getPermissionMap)\n const hasAccess = permissionMap['*'] === true || permissionMap[fullPermission] === true;\n \n return { item, hasAccess };\n });\n\n if (!isMounted) return;\n\n const accessibleItems = filtered\n .filter(({ hasAccess }) => hasAccess)\n .map(({ item }) => item);\n\n // SECURITY: Never show all items if permission check fails - this would be a security risk\n // If all items are filtered out, it means the user doesn't have permission to see any navigation\n // This is the correct behavior - better to show nothing than show unauthorized items\n setFilteredMenuItems(accessibleItems);\n } catch (error) {\n // On error, fall back to showing all items (graceful degradation)\n // This prevents navigation from being empty if permission checks fail\n logger.error('PaceAppLayout', 'Failed to load permission map for navigation filtering', { userId: user?.id, error });\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n }\n };\n\n filterItems();\n\n return () => {\n isMounted = false;\n };\n }, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, selectedOrganisation?.id]);\n\n // NEW: Phase 2 - Enhanced Routing Features\n // Check route access for role-based routing\n useEffect(() => {\n if (!roleBasedRouting || routeConfig.length === 0) return;\n \n let isMounted = true;\n \n const checkRouteAccess = async () => {\n const currentPath = location.pathname;\n const currentRoute = routeConfig.find(route => route.path === currentPath);\n \n if (!currentRoute) {\n // Route not found in configuration\n if (strictMode) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: Route not found in configuration', {\n route: currentPath,\n userId: user?.id,\n timestamp: new Date().toISOString()\n });\n \n if (onRouteStrictModeViolation) {\n onRouteStrictModeViolation(currentPath, 'Route not found in configuration');\n }\n }\n return;\n }\n \n // Check permissions using useCan hook result\n let hasAccess = true; // Default to true if no permission requirements\n \n // Check page permissions\n if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {\n // Use the permission check result from useCan hook\n // For now, we'll use a simple check - in future we might need useMultiplePermissions here\n try {\n const { isPermittedCached } = await import('../../rbac/api');\n const hasPagePermission = await isPermittedCached({\n userId: user?.id || '',\n scope,\n permission: currentRoute.permissions[0] as Permission,\n pageId: currentRoute.pageId,\n });\n if (!isMounted) return;\n hasAccess = hasPagePermission;\n } catch (error) {\n logger.error('PaceAppLayout', 'Failed to check page permission', { route: currentPath, pageId: currentRoute.pageId, error });\n if (!isMounted) return;\n hasAccess = false;\n }\n }\n \n // If permission check passed or not required, check roles\n if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {\n const { useUnifiedAuth } = await import('../../providers/services/UnifiedAuthProvider');\n // Note: We're already in the component with authContext via useUnifiedAuth at top\n // For this feature to work properly, we need the auth context\n // This is a limitation of the current implementation\n hasAccess = true; // Will be properly implemented when auth context is available in this effect\n }\n \n if (!isMounted) return;\n \n if (!hasAccess) {\n // Handle route access denied\n if (onRouteAccessDenied) {\n onRouteAccessDenied(currentPath, 'Insufficient permissions');\n }\n \n if (strictMode) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected route without permission', {\n route: currentPath,\n userId: user?.id,\n permissions: currentRoute.permissions,\n roles: currentRoute.roles,\n accessLevel: currentRoute.accessLevel,\n timestamp: new Date().toISOString()\n });\n \n if (onRouteStrictModeViolation) {\n onRouteStrictModeViolation(currentPath, 'Insufficient permissions');\n }\n }\n \n // Redirect to fallback route\n navigate(fallbackRoute, { replace: true });\n return;\n }\n };\n \n checkRouteAccess();\n \n return () => {\n isMounted = false;\n };\n }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);\n\n const handleSignOut = async () => {\n await signOut();\n };\n\n const handleChangePassword = async (newPassword: string, confirmPassword: string) => {\n // The form component in UserMenu already checks for matching passwords\n const result = await updatePassword(newPassword);\n if (result?.error) {\n // The form will display the error message\n logger.error('PaceAppLayout', 'Failed to change password', { error: result.error.message });\n // Convert AuthError to PasswordChangeFormError\n return {\n error: {\n message: result.error.message,\n code: result.error.name || 'PASSWORD_UPDATE_ERROR'\n }\n };\n }\n // The form will handle closing the modal on success\n return {};\n };\n\n // CRITICAL: Wait for organisation context to be ready before proceeding\n // The OrganisationService automatically selects an organisation when loading\n // We just need to wait for isContextReady to be true\n // No need to call ensureOrganisationContext() here - it will throw if no org is selected\n // and the service handles selection automatically during loadUserOrganisations()\n\n // Show loading state while organisation context is being set\n // This is critical - we must wait for organisation context before allowing any data access\n // BUT: Allow rendering to proceed if loading is complete, even if user has no organisations (valid state for profile pages)\n // Only block if we're actively loading - once loading completes (success or error), allow rendering\n // EXCEPTION: Super admins can proceed even during organisation loading (they can access all orgs)\n // Use combined super admin check (RBAC + direct check) to allow super admins to proceed immediately\n // IMPORTANT: If we're still checking super admin status, allow rendering to proceed (optimistic approach)\n // This prevents blocking super admins while their status is being determined\n // Also allow rendering if we already have a selectedOrganisationId (even if organisationLoading is still true)\n // This prevents blank pages when organisation context is available but loading state hasn't cleared yet\n if (user?.id && organisationLoading && !isSuperAdmin && !isCheckingSuperAdminDirect && !rbacLoading && !selectedOrganisationId) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4\"></div>\n <p className=\"text-sec-600\">Loading organisation context...</p>\n </div>\n </div>\n );\n }\n \n // Once loading is complete (whether success or error), allow rendering to proceed\n // For users without organisations, allow access to profile pages (dashboard, member-profile, medical-profile, additional-contacts)\n // These pages work with user context only and don't require organisation context\n // The app can check hasValidOrganisationContext() to determine if org context is available for org-specific features\n\n // Show loading state while checking permissions\n // Keep loading active until permission check completes to prevent exposing protected content\n // Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)\n if (enforcePermissions && isCheckingPermission) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4\"></div>\n <p className=\"text-sec-600\">Checking permissions...</p>\n </div>\n </div>\n );\n }\n\n // Show permission error (only after BOTH checks are complete)\n // Super admins bypass all permission checks, so don't show errors for them\n if (enforcePermissions && permissionError && !isSuperAdmin) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <h2 className=\"text-xl font-semibold text-acc-600 mb-2\">Permission Error</h2>\n <p className=\"text-sec-600 mb-4\">{permissionError.message}</p>\n <Button onClick={() => navigate('/')}>Go Home</Button>\n </div>\n </div>\n );\n }\n\n // Show permission fallback if user lacks permission\n // Only show this if super admin check is complete and user is not a super admin\n if (enforcePermissions && hasPermission === false && !isCheckingSuperAdminDirect && !isSuperAdmin) {\n // NEW: Phase 1 - Use page permission fallback if available\n if (enforcePagePermissions && pagePermissionFallback) {\n return <>{pagePermissionFallback}</>;\n }\n \n if (permissionFallback) {\n return <>{permissionFallback}</>;\n }\n \n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <h2 className=\"text-xl font-semibold text-acc-600 mb-2\">Access Denied</h2>\n <p className=\"text-sec-600 mb-4\">\n You don't have permission to access this page.\n </p>\n <div className=\"flex gap-2 justify-center\">\n <Button onClick={() => navigate('/')}>Go Home</Button>\n <Button \n variant=\"outline\" \n onClick={async () => {\n await handleSignOut();\n navigate('/login');\n }}\n >\n Sign out\n </Button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <>\n <Header\n logo={customLogo || undefined}\n logoUrl={!customLogo ? `/${appName.toLowerCase()}_logo_wide.svg` : undefined}\n logoAlt={`${appName} Logo`}\n logoHref={logoHref}\n navItems={filteredMenuItems}\n actions={headerActions}\n userMenu={customUserMenu}\n user={user}\n onSignOut={handleSignOut}\n onChangePassword={handleChangePassword}\n currentPath={window.location.pathname}\n onNavigate={(item) => {\n if (item.href) {\n navigate(item.href);\n }\n }}\n showEventSelector={showEventSelector}\n showOrgSelector={showOrgSelector}\n showUserMenu={showUserMenu}\n className={headerClassName || \"sticky top-0 z-[40] w-full\"}\n />\n <main className=\"px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n <Outlet />\n </main>\n <Footer />\n </>\n );\n} ","/**\n * @file PACE Login Page Component\n * @package @jmruthers/pace-core\n * @module Components/PaceLoginPage\n * @since 0.1.0\n *\n * A comprehensive login page component that provides a consistent authentication\n * experience for all PACE suite applications with role-based redirection and\n * enhanced error handling.\n *\n * Features:\n * - Consistent login page layout\n * - Unified authentication integration\n * - Role-based automatic redirection (admin users)\n * - Manual redirection for all successful logins\n * - Customizable app branding\n * - Configurable redirect paths\n * - Enhanced error handling and display\n * - Dual loading state management (auth + form)\n * - Navigation error recovery\n * - Responsive design\n * - Accessibility compliant\n * - Integration with LoginForm\n * - React Router navigation\n * - Centered layout design\n * - Error persistence and display\n *\n * @example\n * ```tsx\n * // Basic login page\n * <PaceLoginPage appName=\"My Application\" />\n * \n * // Login page with custom redirect\n * <PaceLoginPage\n * appName=\"Dashboard App\"\n * onSuccessRedirectPath=\"/dashboard\"\n * />\n * \n * // Login page in router setup\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage \n * appName=\"My App\"\n * onSuccessRedirectPath=\"/home\"\n * />\n * } />\n * <Route path=\"/home\" element={<HomePage />} />\n * </Routes>\n * </Router>\n * \n * // Login page with authentication provider\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"My App\">\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage appName=\"My Application\" />\n * } />\n * <Route path=\"/\" element={<PaceAppLayout appName=\"My Application\" />}>\n * <Route index element={<HomePage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * \n * // Login page with role-based access control\n * function App() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"Admin Portal\">\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage \n * appName=\"Admin Portal\"\n * onSuccessRedirectPath=\"/admin/dashboard\"\n * />\n * } />\n * <Route path=\"/admin/*\" element={<AdminRoutes />} />\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear page hierarchy\n * - Accessible form elements\n * - Error announcements\n *\n * @routing\n * - React Router v6 integration\n * - Automatic navigation on success\n * - Role-based redirect logic (admin users)\n * - Configurable redirect paths\n * - Replace navigation for login flow\n * - Navigation error handling\n *\n * @authentication\n * - Integration with UnifiedAuthProvider\n * - Role detection via hasRole('admin')\n * - Loading state management\n * - Error state handling\n * - Session validation\n * - Automatic redirect prevention loops\n *\n * @dependencies\n * - React 19+ - Hooks and effects\n * - React Router v6 - Navigation\n * - UnifiedAuthProvider - Authentication\n * - LoginForm component\n * - Button component\n * - Input component\n * - Label component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useEffect, useState, useContext } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers';\nimport { isSuperAdmin } from '../../rbac/api';\nimport { LoginForm } from '../LoginForm';\nimport { Button, Input, Label } from '..';\nimport { clearPalette } from '../../theming/runtime';\nimport { EventServiceContext } from '../../providers/services/EventServiceProvider';\nimport { logger } from '../../utils/core/logger';\n\nexport interface PaceLoginPageProps {\n /** The name of the application to be displayed on the login form. */\n appName: string;\n /** The path to redirect to upon successful login. Defaults to `/`. */\n onSuccessRedirectPath?: string;\n /** Whether to check app access using RBAC. Defaults to false. */\n requireAppAccess?: boolean;\n}\n\n/**\n * A consistent, reusable login page for all PACE suite applications.\n * It handles the sign-in logic with role-based automatic redirection for admin users,\n * enhanced error handling, and dual loading state management.\n * \n * Recent enhancements:\n * - Role-based redirection: Admin users are automatically redirected\n * - RBAC-based app access control: Checks if user has permission to access the app\n * - Enhanced error handling with navigation error recovery\n * - Dual loading states: auth loading + form submission loading\n * - Error persistence: Auth errors are displayed below the form\n * - Navigation safety: Try-catch blocks prevent navigation errors\n * \n * @param props - Login page configuration including app name and redirect path\n * @returns JSX.Element - The rendered login page with enhanced functionality\n * \n * @example\n * ```tsx\n * <PaceLoginPage \n * appName=\"My Application\" \n * onSuccessRedirectPath=\"/dashboard\" \n * />\n * ```\n */\nexport const PaceLoginPage: React.FC<PaceLoginPageProps> = ({\n appName = 'Pace',\n onSuccessRedirectPath = '/',\n requireAppAccess = false\n}) => {\n const { signIn, isAuthenticated, isLoading, authError, user, supabase } = useUnifiedAuth();\n \n const navigate = useNavigate();\n const location = useLocation();\n const [isSigningIn, setIsSigningIn] = useState(false);\n const [accessError, setAccessError] = useState<string | null>(null);\n const [isCheckingAccess, setIsCheckingAccess] = useState(false);\n\n // Get event service context (may not be available if outside EventServiceProvider)\n // Using useContext directly allows graceful handling when provider is not available\n const eventServiceContext = useContext(EventServiceContext);\n const eventService = eventServiceContext?.eventService || null;\n\n // Clear any active event theme when login page mounts\n // This ensures the login screen always uses default colors\n useEffect(() => {\n clearPalette();\n }, []);\n\n // Clear theme whenever on login route (including after navigation back to login)\n // This ensures event theme doesn't apply if events are restored while still on login\n useEffect(() => {\n const isOnLoginPage = location.pathname === '/login' || location.pathname.startsWith('/login');\n if (isOnLoginPage) {\n clearPalette();\n }\n }, [location.pathname]);\n\n // Restore persisted event after login screen has rendered\n // This happens after the login page is fully rendered, allowing events to be loaded first\n useEffect(() => {\n const restoreEvent = async () => {\n try {\n const isOnLoginPage = window.location.pathname === '/login' || window.location.pathname.startsWith('/login');\n if (isOnLoginPage && eventService) {\n await eventService.restorePersistedEvent();\n }\n } catch (error) {\n // Service may not be available yet or events not loaded - that's okay\n }\n };\n \n // Small delay to ensure login page is fully rendered before restoring\n const timeoutId = setTimeout(() => {\n restoreEvent();\n }, 100);\n \n return () => clearTimeout(timeoutId);\n }, [eventService]);\n\n // Check app access after authentication using RBAC\n useEffect(() => {\n if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {\n return;\n }\n\n const checkAccess = async () => {\n setIsCheckingAccess(true);\n setAccessError(null);\n\n try {\n const userId = user.id;\n logger.debug('PaceLoginPage', 'Checking app access using RBAC:', { appName, userId });\n\n // Step 1: Check if user is super admin (they have unrestricted access)\n const superAdminCheck = await isSuperAdmin(userId);\n \n if (superAdminCheck) {\n logger.debug('PaceLoginPage', 'User is super admin, granting access');\n setIsCheckingAccess(false);\n navigate(onSuccessRedirectPath, { replace: true });\n return;\n }\n\n // Step 2: Get the app ID\n const { data: appData, error: appError } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single();\n\n if (appError || !appData) {\n logger.error('PaceLoginPage', 'App not found:', { appName, error: appError });\n setAccessError(`Application \"${appName}\" is not configured. Please contact your administrator.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 3: Get all pages for this app\n const { data: pagesData, error: pagesError } = await supabase\n .from('rbac_app_pages')\n .select('id, page_name')\n .eq('app_id', appData.id);\n\n if (pagesError || !pagesData || pagesData.length === 0) {\n setAccessError(`You do not have permission to access ${appName}. This application is currently unavailable. Please contact your administrator if you believe you should have access.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 4: Get user's first organisation\n const { data: orgRow } = await supabase\n .from('rbac_organisation_roles')\n .select('organisation_id')\n .eq('user_id', userId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .limit(1)\n .maybeSingle();\n\n const organisationId = orgRow?.organisation_id;\n\n if (!organisationId) {\n setAccessError(`You do not have permission to access ${appName}. You are not assigned to any organisation. Please contact your administrator.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 5: Check if user has ANY read permission on ANY page in this app\n // We check each page and see if user has the 'read' operation allowed\n let hasAnyAccess = false;\n for (const page of pagesData) {\n const { data: hasPermission, error: permError } = await supabase\n .rpc('rbac_check_permission_simplified', {\n p_user_id: userId,\n p_permission: `read:page.${page.page_name}`, // Permission format: operation:resource\n p_organisation_id: organisationId,\n p_event_id: null,\n p_app_id: appData.id,\n p_page_id: page.page_name // Page name to resolve to UUID\n });\n\n if (!permError && hasPermission === true) {\n hasAnyAccess = true;\n break;\n }\n }\n\n if (hasAnyAccess) {\n setIsCheckingAccess(false);\n navigate(onSuccessRedirectPath, { replace: true });\n return;\n }\n\n // No access - deny\n setAccessError(`You do not have permission to access ${appName}. This application is restricted to authorized users only. Please contact your administrator if you believe you should have access.`);\n setIsCheckingAccess(false);\n } catch (error) {\n logger.error('PaceLoginPage', 'Error checking app access:', error);\n setAccessError('An error occurred while checking your permissions. Please try again or contact support.');\n setIsCheckingAccess(false);\n }\n };\n\n checkAccess();\n }, [isAuthenticated, isLoading, user, supabase, appName, requireAppAccess, navigate, onSuccessRedirectPath]);\n\n const handleSubmit = async (data: { email: string; password: string }) => {\n setIsSigningIn(true);\n setAccessError(null); // Clear previous access errors\n \n try {\n const { error } = await signIn(data.email, data.password);\n\n if (error) {\n // Throw error so LoginForm can catch and display it\n throw error;\n }\n\n // Navigation will be handled by the useEffect that checks app access\n // Don't navigate here if requireAppAccess is true\n if (!requireAppAccess) {\n try {\n navigate(onSuccessRedirectPath, { replace: true });\n } catch (navError) {\n logger.error('PaceLoginPage', 'Navigation error after sign-in:', navError);\n }\n }\n } finally {\n setIsSigningIn(false);\n }\n };\n\n return (\n <main className=\"min-h-screen grid mx-auto w-fit content-center justify-items-center gap-y-8\" aria-label={`${appName} Login Page`}>\n <img\n src={`/${appName.toLowerCase()}_logo_square.svg`}\n alt={`${appName} logo`}\n className=\"h-48\"\n />\n\n <LoginForm className=\"w-md\"\n onSignIn={handleSubmit}\n appName={appName}\n isLoading={isSigningIn}\n onError={(error) => {\n // LoginForm will handle display of the error\n logger.error('PaceLoginPage', 'Login error:', error);\n }}\n />\n {(() => {\n const benign = !!(authError && (\n authError.name === 'AuthSessionMissingError' || /Auth session missing/i.test(authError.message)\n ));\n return authError && !benign ? (\n <em className=\"mt-4 text-destructive text-center\">{authError.message}</em>\n ) : null;\n })()}\n {accessError && (\n <em className=\"mt-4 text-destructive text-center\">\n {accessError}\n </em>\n )}\n {isCheckingAccess && (\n <em className=\"mt-4 text-muted-foreground text-center\">\n Checking permissions...\n </em>\n )}\n </main>\n );\n} ","/**\n * @file SessionRestorationLoader Component\n * @package @jmruthers/pace-core\n * @module Components/SessionRestorationLoader\n * @since 0.1.0\n *\n * Displays a consistent loading state while the authentication service\n * restores the Supabase session from persistent storage.\n *\n * Features:\n * - Full-screen loading state\n * - Accessible with proper ARIA attributes\n * - Screen reader friendly\n * - Customizable message\n * - Uses LoadingSpinner component\n *\n * @example\n * ```tsx\n * // Basic usage\n * <SessionRestorationLoader />\n *\n * // With custom message\n * <SessionRestorationLoader message=\"Restoring your session...\" />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA role=\"status\"\n * - Screen reader announcement\n * - High contrast support\n *\n * @dependencies\n * - React 19+ - Component framework\n * - LoadingSpinner - Spinner component\n * - Tailwind CSS - Styling\n */\n\nimport React from 'react';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { cn } from '../../utils/core/cn';\n\nexport interface SessionRestorationLoaderProps {\n /** Customise the status message displayed under the spinner */\n message?: string;\n /** Additional CSS classes for styling */\n className?: string;\n}\n\nexport const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> = ({\n message = 'Restoring session...',\n className\n}) => {\n return (\n <div\n className={cn(\n 'flex flex-col items-center justify-center h-screen w-full gap-4 text-center p-4 bg-background',\n className\n )}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={message}\n >\n <LoadingSpinner size=\"lg\" />\n <div className=\"text-sm text-sec-600\">\n {message}\n </div>\n </div>\n );\n};\n\n","/**\n * @file Protected Route Component\n * @package @jmruthers/pace-core\n * @module Components/ProtectedRoute\n * @since 0.6.0\n *\n * A route protection component that handles authentication and optional event selection\n * without creating a chicken-and-egg problem where users cannot see the event selector.\n *\n * Features:\n * - Authentication checking with redirect to login\n * - Session restoration handling\n * - Event loading state management\n * - Smart event selection logic (allows rendering when events exist but none selected)\n * - Optional event requirement (can be disabled for apps that don't need events)\n * - Super admin bypass support\n * - Clear error states for no events available\n *\n * @example\n * Basic protected route:\n * ```tsx\n * import { ProtectedRoute } from '@jmruthers/pace-core';\n * import { Routes, Route } from 'react-router-dom';\n *\n * function App() {\n * return (\n * <Routes>\n * <Route path=\"/login\" element={<LoginPage />} />\n * <Route element={<ProtectedRoute />}>\n * <Route path=\"/dashboard\" element={<DashboardPage />} />\n * </Route>\n * </Routes>\n * );\n * }\n * ```\n *\n * @example\n * Protected route without event requirement:\n * ```tsx\n * <Route element={<ProtectedRoute requireEvent={false} />}>\n * <Route path=\"/settings\" element={<SettingsPage />} />\n * </Route>\n * ```\n *\n * @example\n * Protected route with custom no events message:\n * ```tsx\n * <Route element={\n * <ProtectedRoute\n * requireEvent={true}\n * noEventsFallback={<CustomNoEventsMessage />}\n * />\n * }>\n * <Route path=\"/dashboard\" element={<DashboardPage />} />\n * </Route>\n * ```\n *\n * @accessibility\n * - Proper loading states with screen reader support\n * - Clear error messages\n * - Keyboard navigation support\n *\n * @dependencies\n * - React Router v6 - Routing functionality\n * - useUnifiedAuth - Authentication context\n * - useEvents - Event context\n * - SessionRestorationLoader - Session restoration UI\n * - LoadingSpinner - Loading state UI\n */\n\nimport React, { useMemo, useEffect, useRef, useState } from 'react';\nimport { Navigate, Outlet } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useSessionRestoration } from '../../hooks/useSessionRestoration';\nimport { useEvents } from '../../hooks/useEvents';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { SessionRestorationLoader } from '../SessionRestorationLoader';\nimport { Alert, AlertDescription, AlertTitle } from '../Alert/Alert';\nimport { logger } from '../../utils/core/logger';\nimport { usePreventTabReload } from '../../hooks/usePreventTabReload';\n\nexport interface ProtectedRouteProps {\n /**\n * Whether an event is required for routes inside this component.\n * When true, routes will only render if an event is selected or can be selected.\n * When false, routes render regardless of event state.\n * @default true\n */\n requireEvent?: boolean;\n\n /**\n * Whether super admins can bypass event requirement.\n * Note: This feature requires additional RBAC setup. For simple bypass, set requireEvent={false} instead.\n * @default false\n * @deprecated Use requireEvent={false} for routes that don't need events\n */\n allowSuperAdminBypass?: boolean;\n\n /**\n * Custom component to render when no events are available.\n * If not provided, a default message is shown.\n */\n noEventsFallback?: React.ReactNode;\n\n /**\n * Custom component to render while events are loading.\n * If not provided, a default loading spinner is shown.\n */\n loadingFallback?: React.ReactNode;\n\n /**\n * Login redirect path when user is not authenticated.\n * @default '/login'\n */\n loginPath?: string;\n}\n\n/**\n * ProtectedRoute component that handles authentication and optional event selection.\n *\n * This component solves the chicken-and-egg problem where apps check for `selectedEvent`\n * before rendering, which blocks the event selector (typically in the header) from being visible.\n *\n * Strategy:\n * 1. Check authentication first - redirect to login if not authenticated\n * 2. Allow rendering during event loading - prevents blocking UI\n * 3. If events exist but none selected - allow rendering so selector is visible\n * 4. If no events available - show error message\n * 5. Individual pages should handle \"no selected event\" state gracefully\n *\n * @param props - Configuration for route protection\n * @returns React element with route protection logic\n */\nexport function ProtectedRoute({\n requireEvent = false,\n allowSuperAdminBypass = false,\n noEventsFallback,\n loadingFallback,\n loginPath = '/login'\n}: ProtectedRouteProps) {\n const { isAuthenticated, isLoading } = useUnifiedAuth();\n \n // Always call useEvents() - UnifiedAuthProvider always includes EventServiceProvider\n // Only use the values when requireEvent is true\n const eventsContext = useEvents();\n const selectedEvent = requireEvent ? eventsContext.selectedEvent : null;\n const events = requireEvent ? (eventsContext.events || []) : [];\n const eventLoading = requireEvent ? (eventsContext.isLoading || false) : false;\n \n const sessionRestoration = useSessionRestoration();\n\n // Prevent full page reloads when switching tabs (handles bfcache and visibility changes)\n usePreventTabReload({ enabled: true, gracePeriodMs: 2000 });\n\n // Track if user was previously authenticated to prevent redirects during session refresh\n const wasAuthenticatedRef = useRef(false);\n const [shouldRedirect, setShouldRedirect] = useState(false);\n const tabJustBecameVisibleRef = useRef(false);\n \n // Track authentication state to detect when user was previously logged in\n useEffect(() => {\n if (isAuthenticated) {\n wasAuthenticatedRef.current = true;\n setShouldRedirect(false);\n tabJustBecameVisibleRef.current = false; // Clear visibility flag when authenticated\n }\n }, [isAuthenticated]);\n\n // Handle tab visibility changes - prevent immediate redirects when tab becomes visible\n // This prevents the page from refreshing when switching back to the tab\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let wasHidden = document.hidden;\n\n const handleVisibilityChange = () => {\n const isNowVisible = !document.hidden;\n \n // When tab becomes visible, immediately prevent redirects and give session refresh time\n if (isNowVisible && wasHidden) {\n // Tab just became visible - immediately prevent redirects\n if (!isAuthenticated && wasAuthenticatedRef.current) {\n tabJustBecameVisibleRef.current = true;\n setShouldRedirect(false); // Immediately clear redirect flag\n \n // Clear any existing timeout\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n \n // Wait a bit to see if session refresh completes\n timeoutId = setTimeout(() => {\n // Only allow redirect if still not authenticated after delay\n tabJustBecameVisibleRef.current = false;\n // Use a function to get the latest state\n setShouldRedirect((prev) => {\n // Only set to true if we're still not authenticated\n // This will be checked again in the render logic\n return prev;\n });\n }, 2000); // 2 second grace period for session refresh\n }\n } else if (!isNowVisible) {\n // Tab became hidden - clear the visibility flag\n tabJustBecameVisibleRef.current = false;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n }\n \n wasHidden = !isNowVisible;\n };\n\n // Check initial state - if tab is visible and user appears logged out, give grace period\n if (!document.hidden && !isAuthenticated && wasAuthenticatedRef.current) {\n tabJustBecameVisibleRef.current = true;\n setShouldRedirect(false);\n timeoutId = setTimeout(() => {\n tabJustBecameVisibleRef.current = false;\n }, 2000);\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange);\n return () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n };\n }, [isAuthenticated]);\n\n // Reset redirect flag when authenticated\n useEffect(() => {\n if (isAuthenticated) {\n setShouldRedirect(false);\n tabJustBecameVisibleRef.current = false;\n }\n }, [isAuthenticated]);\n\n const isRestoringSession = useMemo(() => {\n return sessionRestoration.isRestoring &&\n !sessionRestoration.restorationComplete &&\n !sessionRestoration.restorationError &&\n !sessionRestoration.hasTimedOut;\n }, [\n sessionRestoration.isRestoring,\n sessionRestoration.restorationComplete,\n sessionRestoration.restorationError,\n sessionRestoration.hasTimedOut\n ]);\n\n // Show session restoration loader during restoration\n if (isRestoringSession) {\n return <SessionRestorationLoader />;\n }\n\n // Allow rendering during event loading - prevents blocking UI while events load\n // This must come before auth loading check to avoid blocking when only events are loading\n if (requireEvent && eventLoading) {\n return <Outlet />;\n }\n\n // Show loading state while auth is being determined (but not organisation/event loading)\n // Use isLoading (combined loading state) for consistency with simpler implementations\n if (isLoading && !sessionRestoration.hasTimedOut) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // Redirect to login if not authenticated\n // Priority order:\n // 1. If session restoration has timed out or errored → redirect immediately (even if loading)\n // 2. If user was never authenticated → redirect immediately (even if loading)\n // 3. If tab just became visible → show loading (prevent redirect during grace period)\n // 4. If we've confirmed they should redirect (after visibility change grace period) → redirect\n // 5. Otherwise, if loading → show loading spinner (session might be refreshing)\n // 6. Otherwise → redirect (user is not authenticated and not loading)\n if (!isAuthenticated) {\n // Session restoration timeout/error always redirects immediately\n if (sessionRestoration.hasTimedOut || sessionRestoration.restorationError) {\n logger.warn('ProtectedRoute', 'Session restoration failed, redirecting to login', {\n timedOut: sessionRestoration.hasTimedOut,\n error: sessionRestoration.restorationError?.message\n });\n return <Navigate to={loginPath} replace />;\n }\n\n // User was never authenticated → redirect immediately\n if (!wasAuthenticatedRef.current) {\n return <Navigate to={loginPath} replace />;\n }\n\n // Tab just became visible - show loading to prevent redirect during grace period\n // Also check document visibility state directly as a fallback\n const isTabVisible = typeof document !== 'undefined' && !document.hidden;\n if (tabJustBecameVisibleRef.current || (isTabVisible && wasAuthenticatedRef.current && isLoading)) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // We've confirmed redirect after grace period → redirect\n if (shouldRedirect) {\n return <Navigate to={loginPath} replace />;\n }\n\n // User was authenticated before but now appears logged out\n // Show loading state while we wait for session refresh (unless we're not loading)\n if (isLoading) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // Not loading and not authenticated → redirect\n return <Navigate to={loginPath} replace />;\n }\n\n // If event is not required, allow rendering\n if (!requireEvent) {\n return <Outlet />;\n }\n\n // Note: Super admin bypass would require useRBAC hook which adds complexity\n // Apps that need super admin access without events should set requireEvent={false}\n // For now, we keep it simple and always require events when requireEvent=true\n\n // Event loading check already handled above before auth loading check\n\n // If no events are available, show error message\n if (!events || events.length === 0) {\n return noEventsFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh', padding: '2rem' }}>\n <Alert variant=\"destructive\" className=\"max-w-md\">\n <AlertTitle>No Events Available</AlertTitle>\n <AlertDescription>\n You don't have access to any events. Please contact your administrator if you believe this is an error.\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n\n // KEY FIX: Allow rendering when events exist but none selected\n // This allows the event selector (typically in PaceAppLayout header) to be visible\n // Individual pages should handle \"no selected event\" state gracefully\n // Auto-selection will handle selecting the next event, or user can manually select\n \n // If no event selected but events exist, allow rendering\n // The event selector will be visible and user can select, or auto-selection will kick in\n if (!selectedEvent) {\n // Log for debugging - this is expected behavior, not an error\n return <Outlet />;\n }\n\n // Event is selected - allow rendering\n return <Outlet />;\n}\n\n","/**\n * @file File Upload Component\n * @package @jmruthers/pace-core\n * @module Components/FileUpload\n * \n * Provides a file upload interface using the file reference system.\n * Supports drag-and-drop, file validation, progress tracking, and accessibility.\n */\n\nimport React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { FileCategory, FileUploadResult, UploadProgress } from '../../types/file-reference';\nimport { useFileReference } from '../../hooks/useFileReference';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { getAppId } from '../../utils/app/appIdResolver';\nimport { assertAppId } from '../../types/core';\n\nexport interface FileUploadProps {\n supabase: SupabaseClient;\n table_name: string;\n record_id: string;\n organisation_id?: string | null; // Optional for user-scoped files (e.g., profile photos)\n userId?: string; // Optional userId for user-scoped files (required if organisation_id is not provided)\n app_id?: string; // Optional - will be resolved from app name if not provided\n category: FileCategory;\n folder: string; // Folder name in storage bucket (e.g., 'profile_photos', 'documents')\n pageContext: string; // The page context where the file upload occurs (e.g., 'configuration', 'forms', 'applications')\n event_id?: string; // Optional event ID for event-scoped permission checks (required for event-based apps)\n accept?: string;\n maxSize?: number;\n multiple?: boolean;\n disabled?: boolean;\n isPublic?: boolean; // Whether files should be uploaded to public-files bucket\n className?: string;\n showPreview?: boolean; // Show image preview for accepted files\n showProgress?: boolean; // Show upload progress bar\n onUploadSuccess?: (result: FileUploadResult) => void;\n onUploadError?: (error: string, file?: File) => void;\n onProgress?: (progress: UploadProgress) => void;\n children?: React.ReactNode;\n}\n\ninterface FileUploadState {\n file: File;\n progress: UploadProgress;\n preview?: string;\n result?: FileUploadResult;\n}\n\nexport function FileUpload({\n supabase,\n table_name,\n record_id,\n organisation_id,\n userId,\n app_id,\n category,\n folder,\n pageContext,\n event_id,\n accept = '*/*',\n maxSize = 10 * 1024 * 1024, // 10MB default\n multiple = false,\n disabled = false,\n isPublic = false,\n className = '',\n showPreview = true,\n showProgress = true,\n onUploadSuccess,\n onUploadError,\n onProgress,\n children\n}: FileUploadProps) {\n const [isDragging, setIsDragging] = useState(false);\n const [uploadStates, setUploadStates] = useState<Map<string, FileUploadState>>(new Map());\n const [resolvedAppId, setResolvedAppId] = useState<string | null>(app_id || null);\n const [isResolvingAppId, setIsResolvingAppId] = useState(!app_id);\n const [appIdError, setAppIdError] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const { uploadFile, isLoading, error } = useFileReference(supabase);\n\n // Resolve app_id from app name if not provided\n useEffect(() => {\n if (app_id) {\n // If app_id is provided, use it directly\n setResolvedAppId(app_id);\n setIsResolvingAppId(false);\n setAppIdError(null);\n return;\n }\n\n // Otherwise, resolve from app name\n const resolveAppId = async () => {\n setIsResolvingAppId(true);\n setAppIdError(null);\n\n try {\n const appName = getCurrentAppName();\n if (!appName) {\n const errorMsg = 'App ID is required. Either provide app_id prop or set app name via setRBACAppName()';\n setAppIdError(errorMsg);\n setIsResolvingAppId(false);\n return;\n }\n\n const resolvedId = await getAppId(supabase, appName);\n if (!resolvedId) {\n const errorMsg = `Failed to resolve app ID for app name \"${appName}\". Make sure the app is registered in rbac_apps table.`;\n setAppIdError(errorMsg);\n setIsResolvingAppId(false);\n return;\n }\n\n setResolvedAppId(resolvedId);\n setIsResolvingAppId(false);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to resolve app ID';\n setAppIdError(errorMessage);\n setIsResolvingAppId(false);\n }\n };\n\n resolveAppId();\n }, [app_id, supabase]);\n\n // Calculate isUploading and isDisabled early so they can be used in callbacks\n const isUploading = useMemo(() => {\n return uploadStates.size > 0 && Array.from(uploadStates.values()).some(state => \n state.progress.status === 'uploading' || state.progress.status === 'processing'\n );\n }, [uploadStates]);\n\n const isDisabled = useMemo(() => {\n return disabled || isUploading || isResolvingAppId || !resolvedAppId;\n }, [disabled, isUploading, isResolvingAppId, resolvedAppId]);\n\n // Generate preview URL for images\n const generatePreview = useCallback((file: File): Promise<string | null> => {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n \n const reader = new FileReader();\n reader.onload = (e) => {\n resolve(e.target?.result as string || null);\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }, []);\n\n // Validate file\n const validateFile = useCallback((file: File): string | null => {\n // Check file size\n if (file.size > maxSize) {\n return `File \"${file.name}\" exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`;\n }\n\n // Check file type if accept is specified\n if (accept !== '*/*') {\n const acceptedTypes = accept.split(',').map(type => type.trim());\n const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();\n const fileMimeType = file.type;\n\n const isAccepted = acceptedTypes.some(accepted => {\n if (accepted.startsWith('.')) {\n // Extension match\n return accepted === fileExtension;\n } else if (accepted.includes('/*')) {\n // MIME type wildcard (e.g., \"image/*\")\n const baseType = accepted.split('/')[0];\n return fileMimeType.startsWith(baseType + '/');\n } else {\n // Exact MIME type match\n return accepted === fileMimeType;\n }\n });\n\n if (!isAccepted) {\n return `File \"${file.name}\" is not an accepted format. Accepted: ${accept}`;\n }\n }\n\n return null;\n }, [accept, maxSize]);\n\n const handleFileSelect = useCallback(async (files: FileList | null) => {\n if (!files || files.length === 0) return;\n\n const fileArray = Array.from(files);\n \n // Validate all files first\n const validationErrors: string[] = [];\n const validFiles: File[] = [];\n\n for (const file of fileArray) {\n const error = validateFile(file);\n if (error) {\n validationErrors.push(error);\n onUploadError?.(error, file);\n } else {\n validFiles.push(file);\n }\n }\n\n if (validFiles.length === 0) {\n return;\n }\n\n // Initialize upload states\n const newUploadStates = new Map<string, FileUploadState>();\n \n for (const file of validFiles) {\n const fileId = `${file.name}-${file.size}-${Date.now()}`;\n const preview = showPreview ? (await generatePreview(file)) || undefined : undefined;\n \n const progress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'idle'\n };\n\n newUploadStates.set(fileId, {\n file,\n progress,\n preview\n });\n }\n\n setUploadStates(newUploadStates);\n\n // Upload files sequentially\n for (const [fileId, uploadState] of newUploadStates.entries()) {\n const { file } = uploadState;\n\n // Update status to uploading\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'uploading'\n }\n });\n }\n return updated;\n });\n\n try {\n // Simulate progress updates (Supabase doesn't provide real progress, so we estimate)\n const progressInterval = setInterval(() => {\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state && state.progress.status === 'uploading') {\n const estimatedProgress = Math.min(\n state.progress.percentage + 10,\n 90\n );\n const newProgress: UploadProgress = {\n ...state.progress,\n percentage: estimatedProgress,\n loaded: Math.floor((estimatedProgress / 100) * file.size)\n };\n onProgress?.(newProgress);\n updated.set(fileId, {\n ...state,\n progress: newProgress\n });\n }\n return updated;\n });\n }, 200);\n\n\n // Use resolved app_id\n if (!resolvedAppId) {\n const errorMsg = appIdError || 'App ID not available. Please provide app_id prop or set app name.';\n throw new Error(errorMsg);\n }\n\n const result = await uploadFile({\n table_name,\n record_id,\n organisation_id: organisation_id || null,\n userId: userId, // Pass userId prop directly - it's required for user-scoped files when organisation_id is null\n app_id: resolvedAppId ? assertAppId(resolvedAppId) : assertAppId(''),\n category,\n folder,\n pageContext,\n event_id,\n is_public: isPublic\n }, file);\n\n clearInterval(progressInterval);\n\n if (result) {\n // Update status to completed\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'completed',\n percentage: 100,\n loaded: file.size\n },\n result\n });\n }\n return updated;\n });\n\n const finalProgress: UploadProgress = {\n loaded: file.size,\n total: file.size,\n percentage: 100,\n fileName: file.name,\n status: 'completed'\n };\n onProgress?.(finalProgress);\n onUploadSuccess?.(result);\n\n // Upload preview and file information will persist until component unmounts\n // or new files are uploaded (replacing the uploadStates Map)\n } else {\n // Update status to error\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'error',\n error: 'Upload failed'\n }\n });\n }\n return updated;\n });\n\n const errorProgress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'error',\n error: 'Upload failed'\n };\n onProgress?.(errorProgress);\n onUploadError?.('Upload failed', file);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Upload failed';\n \n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'error',\n error: errorMessage\n }\n });\n }\n return updated;\n });\n\n const errorProgress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'error',\n error: errorMessage\n };\n onProgress?.(errorProgress);\n onUploadError?.(errorMessage, file);\n }\n }\n }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!isDisabled) {\n setIsDragging(true);\n }\n }, [isDisabled]);\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n }, []);\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n \n if (isDisabled) return;\n \n const files = e.dataTransfer.files;\n handleFileSelect(files);\n }, [isDisabled, handleFileSelect]);\n\n const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n handleFileSelect(e.target.files);\n // Reset input value to allow re-uploading the same file\n if (e.target) {\n e.target.value = '';\n }\n }, [handleFileSelect]);\n\n const handleClick = useCallback(() => {\n if (!isDisabled && fileInputRef.current) {\n fileInputRef.current.click();\n }\n }, [isDisabled]);\n\n const formatFileSize = (bytes: number): string => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n };\n\n const dragClasses = isDragging ? 'border-main-500 bg-main-50' : 'border-sec-300 hover:border-sec-400';\n const disabledClasses = isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-sec-50';\n\n return (\n <div className={`space-y-4 ${className}`}>\n <div\n role=\"button\"\n tabIndex={isDisabled ? -1 : 0}\n aria-label=\"File upload area\"\n aria-disabled={isDisabled}\n className={`relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${dragClasses} ${disabledClasses}`}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n onClick={!isDisabled ? handleClick : undefined}\n onKeyDown={!isDisabled ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick();\n }\n } : undefined}\n >\n {children || (\n <div className=\"space-y-2\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n onChange={handleFileInputChange}\n className=\"hidden\"\n disabled={isDisabled}\n data-testid=\"file-input\"\n />\n <div className=\"text-sec-600\">\n {isResolvingAppId ? (\n 'Resolving app configuration...'\n ) : isDragging ? (\n 'Drop files here...'\n ) : (\n <>\n <span className=\"font-medium\">Click to upload</span>\n {' '}or drag and drop\n </>\n )}\n </div>\n <div className=\"text-sm text-sec-500\">\n {!isResolvingAppId && accept !== '*/*' && `Accepted formats: ${accept}`}\n {!isResolvingAppId && maxSize && ` • Max size: ${Math.round(maxSize / 1024 / 1024)}MB`}\n {!isResolvingAppId && multiple && ' • Multiple files allowed'}\n </div>\n </div>\n )}\n \n {isUploading && !showProgress && (\n <div \n className=\"absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Uploading file\"\n >\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-main-500\" aria-hidden=\"true\"></div>\n </div>\n )}\n </div>\n\n {/* Upload Progress List */}\n {showProgress && uploadStates.size > 0 && (\n <div className=\"space-y-2\">\n {Array.from(uploadStates.entries()).map(([fileId, uploadState]) => {\n const { file, progress, preview, result } = uploadState;\n const isError = progress.status === 'error';\n const isCompleted = progress.status === 'completed';\n const isUploading = progress.status === 'uploading' || progress.status === 'processing';\n\n return (\n <div\n key={fileId}\n className={`flex items-center space-x-3 p-3 rounded-lg border ${\n isError \n ? 'bg-acc-50 border-acc-200' \n : isCompleted \n ? 'bg-success-50 border-success-200'\n : 'bg-sec-50 border-sec-200'\n }`}\n >\n {/* Preview/Icon */}\n <div className=\"flex-shrink-0\">\n {preview ? (\n <img\n src={preview}\n alt={file.name}\n className=\"w-12 h-12 object-cover rounded\"\n />\n ) : (\n <div className=\"w-12 h-12 flex items-center justify-center bg-sec-200 rounded\">\n <span className=\"text-2xl\">📄</span>\n </div>\n )}\n </div>\n\n {/* File Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sec-900 truncate\">\n {file.name}\n </div>\n <div className=\"text-sm text-sec-500\">\n {formatFileSize(file.size)}\n {isCompleted && result && ' • Uploaded'}\n {isError && progress.error && ` • ${progress.error}`}\n </div>\n \n {/* Progress Bar */}\n {showProgress && (isUploading || isError) && (\n <div className=\"mt-2\">\n <div className=\"w-full bg-sec-200 rounded-full h-2\">\n <div\n className={`h-2 rounded-full transition-all duration-300 ${\n isError ? 'bg-acc-500' : 'bg-main-500'\n }`}\n style={{ width: `${progress.percentage}%` }}\n />\n </div>\n {isUploading && (\n <div className=\"text-xs text-sec-500 mt-1\">\n {progress.percentage}% • {formatFileSize(progress.loaded)} / {formatFileSize(progress.total)}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Status Icon */}\n <div className=\"flex-shrink-0\">\n {isCompleted && (\n <span className=\"text-success-500 text-xl\">✓</span>\n )}\n {isError && (\n <span className=\"text-acc-500 text-xl\">✕</span>\n )}\n {isUploading && (\n <div \n className=\"animate-spin rounded-full size-5 border-b-2 border-main-500\"\n role=\"status\"\n aria-label=\"Uploading\"\n aria-hidden=\"true\"\n ></div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n \n {appIdError && (\n <div \n className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {appIdError}\n </div>\n )}\n {error && (\n <div \n className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {error}\n </div>\n )}\n </div>\n );\n}\n\n\n","/**\n * @file Table Component System\n * @package @jmruthers/pace-core\n * @module Components/Table\n * @since 0.1.0\n *\n * A comprehensive table component system for displaying tabular data.\n * Provides accessible table components with consistent styling and behavior.\n *\n * Features:\n * - Semantic HTML table structure\n * - Consistent styling and spacing\n * - Hover states and transitions\n * - Responsive design\n * - Accessibility compliant\n * - Customizable styling\n * - Checkbox support\n * - Caption support\n *\n * @example\n * ```tsx\n * // Basic table\n * <Table>\n * <TableCaption>A list of your recent invoices.</TableCaption>\n * <TableHeader>\n * <TableRow>\n * <TableHead>Invoice</TableHead>\n * <TableHead>Status</TableHead>\n * <TableHead>Method</TableHead>\n * <TableHead>Amount</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>INV001</TableCell>\n * <TableCell>Paid</TableCell>\n * <TableCell>Credit Card</TableCell>\n * <TableCell>$250.00</TableCell>\n * </TableRow>\n * <TableRow>\n * <TableCell>INV002</TableCell>\n * <TableCell>Pending</TableCell>\n * <TableCell>PayPal</TableCell>\n * <TableCell>$150.00</TableCell>\n * </TableRow>\n * </TableBody>\n * <TableFooter>\n * <TableRow>\n * <TableCell colSpan={3}>Total</TableCell>\n * <TableCell>$400.00</TableCell>\n * </TableRow>\n * </TableFooter>\n * </Table>\n * \n * // Table with checkboxes\n * <Table>\n * <TableHeader>\n * <TableRow>\n * <TableHead className=\"w-12\">\n * <Checkbox />\n * </TableHead>\n * <TableHead>Name</TableHead>\n * <TableHead>Email</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>\n * <Checkbox />\n * </TableCell>\n * <TableCell>John Doe</TableCell>\n * <TableCell>john@example.com</TableCell>\n * </TableRow>\n * </TableBody>\n * </Table>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper table semantics\n * - Screen reader support\n * - Keyboard navigation\n * - Focus management\n * - High contrast support\n * - Caption for table description\n *\n * @dependencies\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from \"react\"\n\nimport { cn } from \"../../utils/core/cn\"\n\n/**\n * Table component\n * The main table container with semantic HTML structure\n * \n * @param props - Table configuration and styling\n * @param ref - Forwarded ref to the table element\n * @returns JSX.Element - The rendered table element\n * \n * @example\n * ```tsx\n * <Table>\n * <TableHeader>...</TableHeader>\n * <TableBody>...</TableBody>\n * </Table>\n * ```\n */\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n))\nTable.displayName = \"Table\"\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n))\nTableHeader.displayName = \"TableHeader\"\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n))\nTableBody.displayName = \"TableBody\"\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n))\nTableFooter.displayName = \"TableFooter\"\n\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted\",\n className\n )}\n {...props}\n />\n))\nTableRow.displayName = \"TableRow\"\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n))\nTableHead.displayName = \"TableHead\"\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-4 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n))\nTableCell.displayName = \"TableCell\"\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"mt-4 text-sm text-muted-foreground\", className)}\n {...props}\n />\n))\nTableCaption.displayName = \"TableCaption\"\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableCaption,\n TableCell,\n TableFooter,\n TableHead,\n TableRow,\n}\n","/**\n * @file Public Page Layout Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A layout component specifically designed for public pages that don't require authentication.\n * Provides a consistent structure for public event pages with event-specific branding.\n *\n * Features:\n * - No authentication required\n * - Event-specific header and branding\n * - Automatic event color theming (applies event_colours when available)\n * - Responsive design\n * - Print-friendly styling\n * - Error boundary integration\n * - Loading state management\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { PublicPageLayout, usePublicRouteParams, usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams({ fetchEventData: false });\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode || '');\n * \n * // PublicPageLayout handles all loading, error, and missing event states\n * return (\n * <PublicPageLayout \n * eventCode={eventCode || ''}\n * event={event}\n * isLoading={isLoading}\n * error={error}\n * refetch={refetch}\n * >\n * <h1>Event Details</h1>\n * <div className=\"content\">\n * Your public page content\n * </div>\n * </PublicPageLayout>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - Keyboard navigation support\n * - High contrast support\n * - Clear content hierarchy\n *\n * @routing\n * - Works with React Router\n * - Supports public route patterns\n * - Event code validation\n * - Error handling for invalid routes\n *\n * @dependencies\n * - React 19+ - Component framework\n * - React Router - Routing integration\n * - Public hooks - Data access\n * - Tailwind CSS - Styling\n */\n\nimport React, { ReactNode } from 'react';\nimport { ErrorBoundary } from '../ErrorBoundary';\nimport { LoadingSpinner } from '../LoadingSpinner';\nimport { Button } from '../Button';\nimport { FileDisplay } from '../FileDisplay/FileDisplay';\nimport { FileCategory } from '../../types/file-reference';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport { useAppConfig } from '../../hooks/useAppConfig';\nimport { cn } from '../../utils/core/cn';\nimport type { Event } from '../../types/event';\n\nexport interface PublicPageLayoutProps {\n /** The event code for this public page */\n eventCode: string;\n /** Child components to render */\n children: ReactNode;\n /** Optional event data - if not provided, will be fetched by parent component */\n event?: Event | null;\n /** Loading state - if true, shows loading spinner */\n isLoading?: boolean;\n /** Error state - if provided, shows error message */\n error?: Error | null;\n /** Function to retry loading event data */\n refetch?: () => Promise<void> | void;\n /** Whether to show the footer (default: true) */\n showFooter?: boolean;\n /** @deprecated Custom CSS classes for the layout - no longer used as wrapper div was removed */\n className?: string;\n /** Custom error fallback component */\n errorFallback?: React.ComponentType<{ error: Error; retry: () => void }>;\n /** Custom loading fallback component */\n loadingFallback?: React.ComponentType;\n /** Custom header component */\n customHeader?: ReactNode;\n /** Custom footer component */\n customFooter?: ReactNode;\n /** Whether to show event validation errors (default: true) */\n showValidationErrors?: boolean;\n /** Custom loading message */\n loadingMessage?: string;\n}\n\n// === HEADER COMPONENT ===\n\nexport interface PublicPageHeaderProps {\n /** The event data for this public page */\n event?: Event;\n /** The event code for this public page */\n eventCode: string;\n /** Optional page title */\n title?: string;\n /** Optional page description */\n description?: string;\n /** Whether to show the event logo (default: true) */\n showEventLogo?: boolean;\n /** Whether to show the app logo (default: true) */\n showAppLogo?: boolean;\n /** Custom CSS classes for the header */\n className?: string;\n /** Custom content to display in the header */\n children?: ReactNode;\n /** Custom event logo component */\n customEventLogo?: ReactNode;\n}\n\nexport function PublicPageHeader({\n event,\n eventCode,\n title,\n description,\n showEventLogo = true,\n showAppLogo = true,\n className = '',\n children,\n customEventLogo\n}: PublicPageHeaderProps) {\n const { appName } = useAppConfig();\n\n return (\n <header className={cn(\n \"w-full px-[max(0rem,calc((100vw-var(--app-width))/2-0.5rem))] grid grid-cols-[auto_1fr_auto] place-items-center gap-2\",\n className\n )}>\n {/* App Logo */}\n {showAppLogo && appName && (\n <img\n className=\"ml-4 max-w-36 object-contain row-span-2\"\n src={`/${appName.toLowerCase()}_logo_wide.svg`}\n alt={appName}\n />\n )}\n\n {/* Event Information */}\n {event && (\n <>\n <h1>{event.event_name}</h1>\n {/* Event Logo */}\n {showEventLogo && event && (\n <>\n {customEventLogo || (\n <FileDisplay\n table_name=\"event\"\n record_id={event.event_id}\n organisation_id={event.organisation_id}\n category={FileCategory.EVENT_LOGOS}\n displayOnly={true}\n showFallback={true}\n fallbackSize=\"md\"\n className=\"mr-4 max-w-36 row-span-2\"\n generateFallbackText={(fileName) => {\n if (!event.event_name) return 'EV';\n return event.event_name\n .split(/[\\s\\-_]+/)\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3);\n }}\n />\n )}\n </>\n )}\n {event.event_venue && (\n <h4>{event.event_venue}</h4>\n )}\n </>\n )}\n\n {/* Page Title and Description */}\n {title && (\n <>\n <h1>{title}</h1>\n {description && (\n <p className=\"text-lg text-sec-600 max-w-3xl mx-auto\">\n {description}\n </p>\n )}\n </>\n )}\n\n {/* Custom Content */}\n {children && <>{children}</>}\n </header>\n );\n}\n\n// === FOOTER COMPONENT ===\n\nexport interface PublicPageFooterProps {\n /** The event data for this public page */\n event: Event;\n /** Company or organization name */\n companyName?: string;\n /** Current year or custom year for copyright */\n year?: number;\n /** Optional array of navigation links to display */\n links?: Array<{\n label: string;\n href: string;\n }>;\n /** Optional CSS class name */\n className?: string;\n /** Logo image URL */\n logo?: string;\n /** Copyright text */\n copyright?: string;\n /** Footer content - children to render inside footer */\n children?: React.ReactNode;\n}\n\nexport function PublicPageFooter({\n event,\n companyName = 'Solvera Solutions Pty Ltd',\n year = new Date().getFullYear(),\n links,\n className = '',\n logo,\n copyright,\n children\n}: PublicPageFooterProps) {\n const copyrightText = copyright || `© Copyright 2022–${year} all rights reserved, ${companyName}.`;\n\n return (\n <footer className={cn('mt-8 py-6 flex justify-center', className)}>\n <section className='px-4 w-[min(var(--app-width),100%)] mx-auto text-center'>\n {logo && (\n <img src={logo} alt=\"Logo\" className=\"h-8 w-auto\" />\n )}\n\n {children && <>{children}</>}\n\n <span className=\"text-muted-foreground\">\n {copyrightText}\n </span>\n\n {links && links.length > 0 && (\n <ul className=\"flex gap-4 mt-2 md:mt-0\">\n {links.map((link, index) => (\n <li key={index}>\n <a href={link.href} className=\"text-muted-foreground hover:text-foreground\">\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n )}\n </section>\n </footer>\n );\n}\n\n/**\n * Layout component for public pages that don't require authentication\n * \n * This component provides a consistent structure for public event pages\n * with event-specific branding, error handling, and loading states.\n * \n * Automatically applies event colors from the event's event_colours field\n * when an event is provided, ensuring consistent theming across public pages.\n * \n * @param props - Layout configuration and content\n * @returns React element with complete public page layout\n */\nexport function PublicPageLayout({\n eventCode,\n children,\n event = null,\n isLoading = false,\n error = null,\n refetch,\n showFooter = true,\n className = '',\n errorFallback: ErrorFallback,\n loadingFallback: LoadingFallback,\n customHeader,\n customFooter,\n showValidationErrors = true,\n loadingMessage\n}: PublicPageLayoutProps) {\n // Apply event theme colors automatically when event is available\n // This works in public page context without requiring EventProvider\n useEventTheme(event);\n\n // Default refetch function\n const handleRefetch = refetch || (async () => {});\n\n // Handle loading state\n if (isLoading) {\n if (LoadingFallback) {\n return <LoadingFallback />;\n }\n return (\n <div className=\"min-h-screen bg-background flex items-center justify-center\">\n <div className=\"max-w-md mx-auto text-center px-4\">\n <LoadingSpinner size=\"lg\" className=\"mx-auto mb-4\" />\n {loadingMessage && (\n <p className=\"text-sec-600\">{loadingMessage}</p>\n )}\n </div>\n </div>\n );\n }\n\n // Handle error state\n if (error && showValidationErrors) {\n if (ErrorFallback) {\n return <ErrorFallback error={error} retry={handleRefetch} />;\n }\n return (\n <main className=\"flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n\n <h1>Event Not Found</h1>\n <p>\n The event code \"{eventCode}\" is invalid or the event is not available for public viewing.\n </p>\n <Button onClick={handleRefetch}>Try Again</Button>\n\n </main>\n );\n }\n\n // Handle missing event\n if (!event && showValidationErrors) {\n return (\n <main className=\"flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n\n <h1>Event Not Available</h1>\n <p>\n This event is not available for public viewing.\n </p>\n {handleRefetch && <Button onClick={handleRefetch}>Try Again</Button>}\n\n </main>\n );\n }\n\n // At this point, if showValidationErrors is true, event must exist\n // If showValidationErrors is false, we allow rendering without event\n // But footer requires event, so only show it if event exists\n return (\n <ErrorBoundary componentName=\"PublicPageLayout\">\n <>\n {/* Header */}\n {customHeader || (\n <PublicPageHeader \n event={event || undefined}\n eventCode={eventCode}\n />\n )}\n\n {/* Main Content */}\n <main className=\"px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n {children}\n </main>\n\n {/* Footer - only show if event exists */}\n {showFooter && event && (\n customFooter || <PublicPageFooter event={event} />\n )}\n </>\n </ErrorBoundary>\n );\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,YAAY,WAAW;AAgOf,cA0CM,YA1CN;AAlMR,IAAM,eAAqB;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,OAAO;AAAA,IACP,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,CAAC,eAAe,gBAAgB,IAAU,eAAS,YAAY;AACrE,UAAM,CAAC,QAAQ,SAAS,IAAU,eAAS,KAAK;AAChD,UAAM,CAAC,eAAe,gBAAgB,IAAU,eAAS,EAAE;AAC3D,UAAM,CAAC,cAAc,eAAe,IAAU,eAAS,KAAK;AAE5D,UAAM,WAAiB,aAAyB,IAAI;AACpD,UAAM,iBAAuB,aAAyB,IAAI;AAC1D,UAAM,eAAqB,aAAwB,IAAI;AAGvD,UAAM,QAAQ,oBAAoB,SAAY,kBAAkB;AAGhE,UAAM,EAAE,aAAa,WAAW,OAAO,mBAAmB,eAAe,iBAAiB,IACxF,uBAAuB,QAAQ,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGH,IAAM,gBAAU,MAAM;AACpB,UAAI,YAAY,SAAS,KAAK,gBAAgB,MAAM,KAAK,GAAG;AAC1D,kBAAU,IAAI;AAAA,MAChB,WAAW,YAAY,WAAW,KAAK,CAAC,MAAM,KAAK,GAAG;AACpD,kBAAU,KAAK;AAAA,MACjB;AAAA,IACF,GAAG,CAAC,aAAa,cAAc,KAAK,CAAC;AAGrC,UAAM,oBAA0B;AAAA,MAC9B,CAAC,MAA2C;AAC1C,cAAM,WAAW,EAAE,OAAO;AAC1B,YAAI,oBAAoB,QAAW;AACjC,2BAAiB,QAAQ;AAAA,QAC3B;AACA,wBAAgB,QAAQ;AACxB,yBAAiB,EAAE;AACnB,YAAI,CAAC,SAAS,KAAK,GAAG;AACpB,qBAAW,IAAI;AACf,2BAAiB;AAAA,QACnB;AAAA,MACF;AAAA,MACA,CAAC,iBAAiB,eAAe,UAAU,gBAAgB;AAAA,IAC7D;AAGA,UAAM,sBAA4B;AAAA,MAChC,OAAO,YAAoB;AACzB,kBAAU,KAAK;AACf,yBAAiB,EAAE;AACnB,cAAM,UAAU,MAAM,cAAc,OAAO;AAC3C,YAAI,SAAS;AAEX,gBAAM,eAAe,QAAQ,gBAAgB;AAC7C,cAAI,oBAAoB,QAAW;AACjC,6BAAiB,YAAY;AAAA,UAC/B;AACA,0BAAgB,YAAY;AAC5B,qBAAW,OAAO;AAAA,QACpB;AACA,iBAAS,SAAS,KAAK;AAAA,MACzB;AAAA,MACA,CAAC,eAAe,UAAU,eAAe,eAAe;AAAA,IAC1D;AAGA,UAAM,gBAAsB;AAAA,MAC1B,CAAC,MAA6C;AAC5C,YAAI,CAAC,UAAU,YAAY,WAAW,GAAG;AACvC,cAAI,EAAE,QAAQ,UAAU;AACtB,sBAAU,KAAK;AACf,qBAAS,SAAS,KAAK;AAAA,UACzB;AACA;AAAA,QACF;AAEA,gBAAQ,EAAE,KAAK;AAAA,UACb,KAAK;AACH,cAAE,eAAe;AACjB,6BAAiB,CAAC,SAAU,OAAO,YAAY,SAAS,IAAI,OAAO,IAAI,IAAK;AAC5E;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,6BAAiB,CAAC,SAAU,OAAO,IAAI,OAAO,IAAI,EAAG;AACrD;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,gBAAI,iBAAiB,KAAK,gBAAgB,YAAY,QAAQ;AAC5D,kCAAoB,YAAY,aAAa,EAAE,QAAQ;AAAA,YACzD;AACA;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,sBAAU,KAAK;AACf,6BAAiB,EAAE;AACnB,qBAAS,SAAS,KAAK;AACvB;AAAA,UACF,KAAK;AACH,sBAAU,KAAK;AACf,6BAAiB,EAAE;AACnB;AAAA,QACJ;AAAA,MACF;AAAA,MACA,CAAC,QAAQ,aAAa,eAAe,mBAAmB;AAAA,IAC1D;AAGA,UAAM,cAAoB,kBAAY,MAAM;AAC1C,sBAAgB,IAAI;AACpB,UAAI,YAAY,SAAS,KAAK,MAAM,KAAK,GAAG;AAC1C,kBAAU,IAAI;AAAA,MAChB;AAAA,IACF,GAAG,CAAC,aAAa,KAAK,CAAC;AAGvB,UAAM,aAAmB;AAAA,MACvB,CAAC,MAA0C;AAEzC,mBAAW,MAAM;AACf,cAAI,CAAC,aAAa,SAAS,SAAS,SAAS,aAAa,GAAG;AAC3D,4BAAgB,KAAK;AACrB,sBAAU,KAAK;AACf,6BAAiB,EAAE;AAAA,UACrB;AAAA,QACF,GAAG,GAAG;AAAA,MACR;AAAA,MACA,CAAC;AAAA,IACH;AAGA,IAAM,gBAAU,MAAM;AACpB,YAAM,qBAAqB,CAAC,UAAsB;AAChD,YAAI,aAAa,WAAW,CAAC,aAAa,QAAQ,SAAS,MAAM,MAAc,GAAG;AAChF,oBAAU,KAAK;AACf,2BAAiB,EAAE;AAAA,QACrB;AAAA,MACF;AAEA,UAAI,QAAQ;AACV,iBAAS,iBAAiB,aAAa,kBAAkB;AACzD,eAAO,MAAM;AACX,mBAAS,oBAAoB,aAAa,kBAAkB;AAAA,QAC9D;AAAA,MACF;AAAA,IACF,GAAG,CAAC,MAAM,CAAC;AAGX,UAAM,gBAAsB,YAAM;AAKlC,IAAM,gBAAU,MAAM;AACpB,UAAI,iBAAiB,GAAG;AACtB,cAAM,eAAe,SAAS;AAAA,UAC5B,GAAG,aAAa,SAAS,aAAa;AAAA,QACxC;AACA,YAAI,gBAAgB,OAAO,aAAa,mBAAmB,YAAY;AACrE,uBAAa,eAAe,EAAE,OAAO,WAAW,UAAU,SAAS,CAAC;AAAA,QACtE;AAAA,MACF;AAAA,IACF,GAAG,CAAC,eAAe,aAAa,CAAC;AAGjC,IAAM,0BAAoB,KAAK,MAAM,SAAS,OAA2B;AAEzE,UAAM,WAAW,SAAS,CAAC,CAAC;AAE5B,WACE,qBAAC,UAAK,KAAK,cAAc,WAAW,GAAG,mBAAmB,SAAS,GACjE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,MAAK;AAAA,UACL;AAAA,UACA,UAAU;AAAA,UACV,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA,MAAK;AAAA,UACL,iBAAe;AAAA,UACf,qBAAkB;AAAA,UAClB,iBAAe;AAAA,UACf,iBAAc;AAAA,UACd,yBACE,iBAAiB,IAAI,GAAG,aAAa,SAAS,aAAa,KAAK;AAAA,UAEjE,GAAG;AAAA;AAAA,MACN;AAAA,MACC,aACC,oBAAC,OAAE,WAAU,iEACX,8BAAC,kBAAe,MAAK,MAAK,GAC5B;AAAA,MAGD,UAAU,YAAY,SAAS,KAC9B;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,IAAI;AAAA,UACJ,MAAK;AAAA,UACL,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,eAAY;AAAA,UAEX,sBAAY,IAAI,CAAC,YAAY,UAC5B,qBAAO,gBAAN,EACC;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI,GAAG,aAAa,SAAS,KAAK;AAAA,gBAClC,MAAK;AAAA,gBACL,iBAAe,kBAAkB;AAAA,gBACjC,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,kBAAkB,SAAS;AAAA,kBAC3B;AAAA,gBACF;AAAA,gBACA,SAAS,MAAM,oBAAoB,WAAW,QAAQ;AAAA,gBACtD,cAAc,MAAM,iBAAiB,KAAK;AAAA,gBAC1C,eAAa,sBAAsB,KAAK;AAAA,gBAEvC,qBAAW,uBAAuB,aAAa,WAAW;AAAA;AAAA,YAC7D;AAAA,YACC,WAAW,uBAAuB,kBACjC,oBAAC,QAAG,WAAU,0CACX,qBAAW,sBAAsB,gBACpC;AAAA,eArBiB,WAAW,QAuBhC,CACD;AAAA;AAAA,MACH;AAAA,MAGD,qBACC,oBAAC,OAAE,WAAU,iCAAgC,MAAK,SAC/C,4BAAkB,SACrB;AAAA,OAEJ;AAAA,EAEJ;AACF;AAEA,aAAa,cAAc;;;AC/P3B,YAAYA,YAAW;AACvB,YAAY,oBAAoB;AA+D5B,qBAAAC,WAaM,OAAAC,MAZJ,QAAAC,aADF;AA5DJ,IAAM,kBAAkB,MAAc;AACpC,SAAO;AACT;AAsCA,IAAM,QAAc,kBAGlB,CAAC;AAAA,EACD;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAG,QAAQ;AACT,QAAM,WAAW,CAAC,CAAC;AACnB,QAAM,iBAAiB,cAAc,CAAC;AAEtC,SACE,gBAAAA,MAAAF,WAAA,EACE;AAAA,oBAAAE;AAAA,MAAgB;AAAA,MAAf;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ;AAAA,QACF;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,UACA,YACC,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,cAAW;AAAA,cACX,WAAW;AAAA,gBACT;AAAA,gBACA,yBAAyB;AAAA,cAC3B;AAAA,cAEC,+BAAqB;AAAA;AAAA,UACxB;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEC,kBACC,gBAAAA,KAAC,OAAE,WAAW,GAAG,yBAAyB,mBAAmB,GAC1D,sBACH;AAAA,IAGD,YACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,aAAU;AAAA,QACV,WAAW,GAAG,oBAAoB,cAAc;AAAA,QAE/C;AAAA;AAAA,IACH;AAAA,KAEJ;AAEJ,CAAC;AAED,MAAM,cAA6B,oBAAK;;;ACrFpC,gBAAAE,YAAA;AAFJ,SAAS,SAAS,EAAE,WAAW,UAAU,WAAW,OAAO,MAAM,OAAO,KAAK,GAAG,MAAM,GAA6D;AACjJ,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA;AAAA,QAET;AAAA;AAAA,QAGA;AAAA,UACE,gBAAgB,YAAY,aAAa,CAAC;AAAA,UAC1C,qDAAqD,YAAY,iBAAiB;AAAA,QACpF;AAAA;AAAA,QAGA;AAAA,UACE,kCAAkC,SAAS;AAAA,UAC3C,kCAAkC,SAAS;AAAA,UAC3C,qCAAqC,SAAS;AAAA,QAChD;AAAA,QAEA;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,cAAc;;;AC3HvB,SAAgB,YAAAC,WAAU,aAAAC,YAAwB,UAAAC,SAAQ,YAAY,eAAe;AACrF,SAAS,UAAU,oBAAoB;;;ACQvC,SAAS,YAAAC,WAAU,aAAAC,YAAW,eAAAC,cAAa,UAAAC,eAAc;AAMzD,IAAM,MAAM,aAAa,YAAY;AA+B9B,SAAS,WACd,eACA,SACkB;AAClB,QAAM,EAAE,iBAAiB,UAAU,WAAW,KAAK,IAAI;AAEvD,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAwB,IAAI;AAClD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAkB,KAAK;AACzD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,qBAAqBC,QAAsB,IAAI;AAErD,QAAM,UAAUC,aAAY,YAAY;AACtC,QAAI,CAAC,eAAe;AAClB,aAAO,IAAI;AACX,mBAAa,KAAK;AAClB,eAAS,IAAI;AACb;AAAA,IACF;AAGA,QAAI,aAAc,OAAO,mBAAmB,YAAY,cAAc,IAAK;AACzE;AAAA,IACF;AAEA,iBAAa,IAAI;AACjB,aAAS,IAAI;AACb,uBAAmB,UAAU,cAAc;AAE3C,QAAI;AACF,UAAI,eAA8B;AAElC,UAAI,cAAc,WAAW;AAE3B,uBAAe,aAAa,UAAU,cAAc,WAAW,IAAI;AAAA,MACrE,OAAO;AAEL,cAAM,kBAAkB,MAAM,aAAa,UAAU,cAAc,WAAW;AAAA,UAC5E,SAAS;AAAA,UACT,OAAO;AAAA,UACP,WAAW;AAAA,QACb,CAAC;AACD,uBAAe,iBAAiB,OAAO;AAAA,MACzC;AAEA,aAAO,YAAY;AACnB,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,YAAMC,SAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,6BAA6B;AAClF,eAASA,MAAK;AACd,aAAO,IAAI;AACX,UAAI,MAAM,yBAAyBA,MAAK;AAAA,IAC1C,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,eAAe,UAAU,iBAAiB,WAAW,GAAG,CAAC;AAE7D,QAAM,QAAQD,aAAY,MAAM;AAC9B,WAAO,IAAI;AACX,aAAS,IAAI;AACb,iBAAa,KAAK;AAClB,uBAAmB,UAAU;AAAA,EAC/B,GAAG,CAAC,CAAC;AAGL,EAAAE,WAAU,MAAM;AACd,QAAI,UAAU;AAEZ,UAAI,mBAAmB,YAAY,eAAe,IAAI;AACpD,eAAO,IAAI;AACX,iBAAS,IAAI;AAAA,MACf;AAEA,UAAI,iBAAiB,CAAC,OAAO,CAAC,WAAW;AACvC,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,IAAI,UAAU,SAAS,KAAK,SAAS,CAAC;AAEzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AD+Fa,SAiLC,YAAAC,WAjLD,OAAAC,MAgBL,QAAAC,aAhBK;AAlNb,IAAM,sBAAsB;AAAA,EAC1B,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AACT;AAKA,IAAM,sBAAsB;AAK5B,SAAS,mBAAmB,OAAiD,MAAc;AACzF,QAAM,YAAY,oBAAoB,IAAI;AAC1C,SAAO,GAAG,mBAAmB,IAAI,SAAS,GAAG,KAAK;AACpD;AAKA,SAAS,4BAA4B,UAA2B;AAC9D,MAAI,CAAC,SAAU,QAAO;AAGtB,QAAM,WAAW,SAAS,QAAQ,aAAa,EAAE;AACjD,QAAM,QAAQ,SAAS,MAAM,UAAU;AAEvC,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,MACJ,IAAI,UAAQ,KAAK,OAAO,CAAC,EAAE,YAAY,CAAC,EACxC,KAAK,EAAE,EACP,UAAU,GAAG,CAAC;AACnB;AAyEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,eAAe;AACjB,GAA4B;AAC1B,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAS,KAAK;AAClD,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAA8B,IAAI,IAAI,QAAQ,CAAC;AAC/F,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,KAAK;AAC9D,QAAM,oBAAoBC,QAAwB,CAAC,CAAC;AAGpD,QAAM,uBAAuB,QAAQ,MAAM;AACzC,QAAI,aAAc,QAAO;AAEzB,UAAM,aAAa,sBAAsB,eAAe,eAAe;AACvE,WAAO,qBAAqB,UAAU;AAAA,EACxC,GAAG,CAAC,cAAc,oBAAoB,eAAe,oBAAoB,CAAC;AAG1E,QAAM,kBAAkB,QAAQ,MAAM;AACpC,WAAO,mBAAmB,YAAY;AAAA,EACxC,GAAG,CAAC,YAAY,CAAC;AAIjB,EAAAC,WAAU,MAAM;AACd,UAAM,aAAa,eAAe,IAAI,OAAK,EAAE,EAAE,EAAE,KAAK,GAAG;AACzD,UAAM,UAAU,kBAAkB,QAAQ,IAAI,OAAK,EAAE,EAAE,EAAE,KAAK,GAAG;AAEjE,QAAI,eAAe,SAAS;AAC1B,wBAAkB,UAAU;AAE5B,0BAAoB,IAAI,IAAI,QAAQ,CAAC;AAAA,IACvC,OAAO;AAEL,0BAAoB,IAAI,IAAI,QAAQ,CAAC;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,gBAAgB,QAAQ,CAAC;AAE7B,QAAM,oBAAoB,MAAM;AAC9B,wBAAoB,IAAI;AAAA,EAC1B;AAEA,QAAM,sBAAsB,YAAY;AACtC,wBAAoB,KAAK;AACzB,QAAI,UAAU;AACZ,YAAM,SAAS;AAAA,IACjB;AACA,kBAAc,KAAK;AAAA,EACrB;AAEA,QAAM,mBAAmB,MAAM;AAC7B,kBAAc,IAAI;AAAA,EACpB;AAEA,QAAM,cAAc,CAAC,aAAqB;AACxC,QAAI,SAAS,WAAW,QAAQ,EAAG,QAAO;AAC1C,QAAI,SAAS,WAAW,QAAQ,EAAG,QAAO;AAC1C,QAAI,SAAS,WAAW,QAAQ,EAAG,QAAO;AAC1C,QAAI,SAAS,SAAS,KAAK,EAAG,QAAO;AACrC,QAAI,SAAS,SAAS,MAAM,EAAG,QAAO;AACtC,QAAI,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,aAAa,EAAG,QAAO;AAC3E,QAAI,SAAS,SAAS,YAAY,KAAK,SAAS,SAAS,cAAc,EAAG,QAAO;AACjF,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,CAAC,UAAkB;AACxC,QAAI,UAAU,EAAG,QAAO;AACxB,UAAM,IAAI;AACV,UAAM,QAAQ,CAAC,SAAS,MAAM,MAAM,IAAI;AACxC,UAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,WAAO,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC;AAAA,EACxE;AAGA,MAAI,OAAO;AACT,QAAI,gBAAgB;AAClB,aAAO,gBAAAJ,KAAC,kBAAe,OAAc,OAAO,YAAY;AAAA,IAC1D;AAGA,QAAI,cAAc;AAChB,aACE,gBAAAA,KAAC,YAAO,WAAsB,OAAM,oBAClC,0BAAAA,KAAC,OAAE,WAAW,iBACX,gCACH,GACF;AAAA,IAEJ;AAEA,WACE,gBAAAC,MAAC,YAAO,WAAsB,OAAM,SAClC;AAAA,sBAAAA,MAAC,OAAE,WAAW,mBAAmB,gBAAgB,IAAI,GAAG;AAAA;AAAA,QACjC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,SAC5E;AAAA,MACC,cACC,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACV,cAAW;AAAA,UACZ;AAAA;AAAA,MAED;AAAA,OAEJ;AAAA,EAEJ;AAIA,MAAI,cAAc,KAAK,CAAC,WAAW;AAEjC,QAAI,cAAc;AAChB,aACE,gBAAAC,MAAC,YAAO,WAAsB,OAAM,WAClC;AAAA,wBAAAD,KAAC,OAAE,WAAW,iBACX,gCACH;AAAA,QACC;AAAA,SACH;AAAA,IAEJ;AAEA,WACE,gBAAAC,MAAC,YAAO,WAAW,gCAAgC,SAAS,IAC1D;AAAA,sBAAAD,KAAC,OAAE,4BAAc;AAAA,MAChB;AAAA,OACH;AAAA,EAEJ;AAGA,MAAI,aAAa,gBAAgB,cAAc,GAAG;AAChD,WACE,gBAAAC,MAAC,YAAO,WAAsB,OAAM,cAClC;AAAA,sBAAAD,KAAC,OAAE,WAAW,iBACX,gCACH;AAAA,MACC;AAAA,OACH;AAAA,EAEJ;AAEA,MAAI,WAAW;AACb,QAAI,kBAAkB;AACpB,aAAO,gBAAAA,KAAC,oBAAiB;AAAA,IAC3B;AACA,WACE,gBAAAA,KAAC,YAAO,WAAsB,OAAM,WAClC,0BAAAA,KAAC,OAAE,WAAU,wCACX,0BAAAA,KAAC,kBAAe,GAClB,GACF;AAAA,EAEJ;AAGA,OAAK,YAAY,gBAAgB,eAAe;AAC9C,UAAM,UAAU,cAAc,cAAc,UAAU,WAAW,QAAQ;AAIzE,QAAI,eAAe,WAAW,CAAC,cAAc,CAAC,gBAAgB;AAE5D,UAAI,cAAc,cAAc;AAC9B,eACE,gBAAAA,KAAC,YAAO,WAAsB,OAAO,cAAc,cAAc,YAAY,QAC3E,0BAAAA,KAAC,OAAE,WAAW,iBACX,gCACH,GACF;AAAA,MAEJ;AAGA,UAAI,CAAC,SAAS;AACZ,eACE,gBAAAA,KAAC,YAAO,WAAW,aAAa,mBAAmB,OAAM,WACvD,0BAAAA,KAAC,OAAE,WAAW,iBACZ,0BAAAA,KAAC,kBAAe,GAClB,GACF;AAAA,MAEJ;AAEA,aACE,gBAAAA,KAAC,YAAO,WAAW,aAAa,IAC9B,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,cAAc,cAAc,YAAY;AAAA,UAC7C,WAAW,gBAAgB;AAAA,UAC3B,SAAS;AAAA;AAAA,MACX,GACF;AAAA,IAEJ;AAIA,QAAI,eAAe,CAAC,WAAW,WAAW,iBAAiB,CAAC,YAAY;AACtE,YAAM,WAAW,cAAc,eAAe,YAAY;AAC1D,YAAM,YAAY,QAAQ,QAAQ;AAElC,aACE,gBAAAC,MAAC,YAAO,WACN;AAAA,wBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,cAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,8BAAAD,KAAC,YAAS,WAAU,mBAAkB,eAAY,QAAO;AAAA,cACzD,gBAAAA,KAAC,UAAK,WAAU,+BACb,oBACH;AAAA,cACA,gBAAAA,KAAC,gBAAa,WAAU,mBAAkB,eAAY,QAAO;AAAA;AAAA;AAAA,QAC/D;AAAA,QACC,gBACC,gBAAAC,MAAC,gBACC;AAAA,0BAAAD,KAAC,OAAG,oBAAS;AAAA,UACZ,cAAc,cAAc,YAC3B,gBAAAC,MAAC,OAAG;AAAA,2BAAe,cAAc,cAAc,QAAQ;AAAA,YAAE;AAAA,YAAI,cAAc,cAAc;AAAA,aAAS;AAAA,WAEtG;AAAA,SAEJ;AAAA,IAEJ;AAIA,QAAI,eAAe,iBAAiB,CAAC,WAAW,cAAc,CAAC,UAAU;AACvE,aACE,gBAAAD,KAAC,YAAO,WAAsB,OAAO,cAAc,cAAc,YAAY,QAC3E,0BAAAA,KAAC,OAAE,WAAW,iBACX,gCACH,GACF;AAAA,IAEJ;AAEA,WACE,gBAAAA,KAAC,YAAO,WAAW,YAAY,SAAS,IACrC,qBAAW,WAAW,CAAC,aACtB,gBAAAC,MAAAF,WAAA,EACE;AAAA,sBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,cAAc,cAAc,YAAY;AAAA,UAC7C,WAAW,gBAAgB;AAAA,UAC3B,SAAS;AAAA;AAAA,MACX;AAAA,MACC,cACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,wBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YACV,OAAM;AAAA,YACN,cAAW;AAAA,YACZ;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA,KAAC,UAAO,MAAM,kBAAkB,cAAc,qBAC5C,0BAAAC,MAAC,iBAAc,MAAK,MAClB;AAAA,0BAAAD,KAAC,gBACC,0BAAAA,KAAC,eAAY,4BAAc,GAC7B;AAAA,UACA,gBAAAA,KAAC,cACC,0BAAAA,KAAC,OAAE,sFAAwE,GAC7E;AAAA,UACA,gBAAAC,MAAC,gBACC;AAAA,4BAAAD,KAAC,UAAO,SAAQ,WAAU,SAAS,MAAM,oBAAoB,KAAK,GAAG,oBAErE;AAAA,YACA,gBAAAA,KAAC,UAAO,SAAQ,eAAc,SAAS,qBAAqB,oBAE5D;AAAA,aACF;AAAA,WACF,GACF;AAAA,SACF;AAAA,MAED;AAAA,MACA,gBACC,gBAAAC,MAAC,gBACC;AAAA,wBAAAD,KAAC,OAAG,wBAAc,cAAc,YAAY,gBAAe;AAAA,SACzD,cAAc,cAAc,YAAY,cAAc,cAAc,aACpE,gBAAAC,MAAC,OACE;AAAA,wBAAc,cAAc,YAAY,eAAe,cAAc,cAAc,QAAQ;AAAA,UAC3F,cAAc,cAAc,YAAY,cAAc,cAAc,YAAY;AAAA,UAChF,cAAc,cAAc;AAAA,WAC/B;AAAA,SAEJ;AAAA,OAEJ,IACE,WAAW,cAAc;AAAA;AAAA,MAE3B,gBAAAA,MAAAF,WAAA,EACE;AAAA,wBAAAC,KAAC,OAAE,WAAW,iBAAiB,OAAO,cAAc,cAAc,YAAY,QAC3E,gCACH;AAAA,QACC;AAAA,QACA,gBACC,gBAAAC,MAAC,gBACC;AAAA,0BAAAD,KAAC,OAAG,wBAAc,cAAc,YAAY,gBAAe;AAAA,WACzD,cAAc,cAAc,YAAY,cAAc,cAAc,aACpE,gBAAAC,MAAC,OACE;AAAA,0BAAc,cAAc,YAAY,eAAe,cAAc,cAAc,QAAQ;AAAA,YAC3F,cAAc,cAAc,YAAY,cAAc,cAAc,YAAY;AAAA,YAChF,cAAc,cAAc;AAAA,aAC/B;AAAA,WAEJ;AAAA,SAEJ;AAAA,QAEA,gBAAAA,MAAAF,WAAA,EACE;AAAA,sBAAAE,MAAC,OAAE,WAAU,8EACX;AAAA,wBAAAD,KAAC,UAAK,WAAU,YACb,sBAAY,cAAc,cAAc,YAAY,EAAE,GACzD;AAAA,QACC,cACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,0BAAAC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACV,OAAM;AAAA,cACN,cAAW;AAAA,cACZ;AAAA;AAAA,UAED;AAAA,UACA,gBAAAA,KAAC,UAAO,MAAM,kBAAkB,cAAc,qBAC5C,0BAAAC,MAAC,iBAAc,MAAK,MAClB;AAAA,4BAAAD,KAAC,gBACC,0BAAAA,KAAC,eAAY,4BAAc,GAC7B;AAAA,YACA,gBAAAA,KAAC,cACC,0BAAAA,KAAC,OAAE,sFAAwE,GAC7E;AAAA,YACA,gBAAAC,MAAC,gBACC;AAAA,8BAAAD,KAAC,UAAO,SAAQ,WAAU,SAAS,MAAM,oBAAoB,KAAK,GAAG,oBAErE;AAAA,cACA,gBAAAA,KAAC,UAAO,SAAQ,eAAc,SAAS,qBAAqB,oBAE5D;AAAA,eACF;AAAA,aACF,GACF;AAAA,WACF;AAAA,SAEJ;AAAA,MACC;AAAA,MACA,gBACC,gBAAAC,MAAC,gBACC;AAAA,wBAAAD,KAAC,OAAG,wBAAc,cAAc,YAAY,gBAAe;AAAA,SACzD,cAAc,cAAc,YAAY,cAAc,cAAc,aACpE,gBAAAC,MAAC,OACE;AAAA,wBAAc,cAAc,YAAY,eAAe,cAAc,cAAc,QAAQ;AAAA,UAC3F,cAAc,cAAc,YAAY,cAAc,cAAc,YAAY;AAAA,UAChF,cAAc,cAAc;AAAA,WAC/B;AAAA,SAEJ;AAAA,OAEJ,GAEJ;AAAA,EAEJ;AAGA,SACE,gBAAAA,MAAC,YAAO,WAAW,aAAa,SAAS,IACtC;AAAA,mBAAe,IAAI,CAAC,YAAY;AAC/B,YAAM,UAAU,QAAQ,cAAc,UAAU,WAAW,QAAQ;AACnE,YAAMI,WAAU,iBAAiB,IAAI,QAAQ,EAAE,KAAK;AACpD,YAAM,cAAc,CAAC,WAAWA;AAEhC,aACE,gBAAAJ,MAAC,YAAwB,WAAU,8EAChC;AAAA,mBAAWI,WACV,gBAAAL;AAAA,UAAC;AAAA;AAAA,YACC,KAAKK;AAAA,YACL,KAAK,QAAQ,cAAc,YAAY;AAAA,YACvC,WAAW,gBAAgB;AAAA,YAC3B,SAAS;AAAA;AAAA,QACX,IAEA,gBAAAL,KAAC,UAAK,WAAU,YACb,sBAAY,QAAQ,cAAc,YAAY,EAAE,GACnD;AAAA,QAED,gBACC,gBAAAC,MAAC,gBAAW,WAAU,kBACpB;AAAA,0BAAAD,KAAC,OAAE,WAAU,qCACV,kBAAQ,cAAc,YAAY,gBACrC;AAAA,WACE,QAAQ,cAAc,YAAY,QAAQ,cAAc,YAAY,QAAQ,cAAc,aAC1F,gBAAAC,MAAC,OAAE,WAAU,wBACV;AAAA,oBAAQ,cAAc,YAAY,eAAe,QAAQ,cAAc,QAAQ;AAAA,YAC/E,QAAQ,cAAc,YAAY,QAAQ,cAAc,YAAY;AAAA,YACpE,QAAQ,cAAc;AAAA,aACrB,QAAQ,cAAc,YAAY,QAAQ,cAAc,aAAa,QAAQ,cAAc,YAAY;AAAA,YACxG,QAAQ,cAAc;AAAA,aACzB;AAAA,WAEJ;AAAA,QAEF,gBAAAA,MAAC,OAAE,WAAU,+BACV;AAAA,yBACC,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,QAAQ;AAAA,cACd,UAAU,QAAQ,cAAc,YAAY;AAAA,cAC5C,WAAU;AAAA,cACV,OAAM;AAAA,cACP;AAAA;AAAA,UAED;AAAA,UAED,cAAc,YACb,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,OAAM;AAAA,cACN,cAAW;AAAA,cACZ;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,WAnDW,QAAQ,EAoDrB;AAAA,IAEJ,CAAC;AAAA,IACA;AAAA,KACH;AAEJ;AAMA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,aAAa;AAAA,EACb,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,oBAAoB,WAAW,iBAAiB;AACtD,QAAM,WAAW,mBAAmB,YAAY;AAEhD,MAAI,CAAC,UAAU;AAEb,QAAI,cAAc;AAChB,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,UACX,OAAO;AAAA,UACP,SAAS;AAAA,UACT,eAAe;AAAA,UACf,gBAAgB,CAAC;AAAA,UACjB,UAAU,oBAAI,IAAI;AAAA,UAClB,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAGA,WACE,gBAAAA,KAAC,YAAO,WAAsB,OAAM,SAClC,0BAAAA,KAAC,OAAE,WAAW,mBAAmB,gBAAgB,IAAI,GAAG,6DAExD,GACF;AAAA,EAEJ;AAEA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,SAAS;AAAA,EACb;AAGA,MAAI,OAAO;AACT,WAAO,MAAM,qBAAqB,uBAAuB;AAAA,MACvD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,MAAM;AAAA,MACb,YAAY,MAAM;AAAA,IACpB,CAAC;AAAA,EACH;AAGA,QAAM,eAAe,YAAY;AAAA,EAEjC;AAGA,MAAI,qBAAqB;AACzB,MAAI,eAAe;AACnB,MAAI,sBAAsB;AAC1B,MAAI,iBAAiB;AAErB,MAAI,eAAe,CAAC,YAAY,eAAe,SAAS,GAAG;AAEzD,UAAM,aAAa,eAAe;AAAA,MAAO,OACvC,EAAE,cAAc,UAAU,WAAW,QAAQ;AAAA,IAC/C;AACA,UAAM,aAAa,WAAW,SAAS,IAAI,WAAW,CAAC,IAAI,eAAe,CAAC;AAC3E,yBAAqB;AACrB,0BAAsB,CAAC,UAAU;AACjC,qBAAiB;AAGjB,mBAAe,SAAS,IAAI,WAAW,EAAE,KAAK;AAAA,EAChD;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,eAAe;AAAA,MACf,gBAAgB;AAAA,MAChB;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,aAAa,eAAe;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAMA,SAAS,yBAAyB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,aAAa;AAAA,EACb,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,EAAE,SAAS,IAAI,eAAe;AAEpC,MAAI,CAAC,UAAU;AACb,WACE,gBAAAA,KAAC,YAAO,WAAsB,OAAM,SAClC,0BAAAA,KAAC,OAAE,WAAW,mBAAmB,gBAAgB,IAAI,GAAG,oEAExD,GACF;AAAA,EAEJ;AAEA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,SAAS;AAAA,EACb;AAGA,QAAM,CAAC,0BAA0B,2BAA2B,IAAIE,UAA+B,IAAI;AAGnG,QAAM,4BAA4B,2BAA2B,SAAS,IAAI,yBAAyB,EAAE,IAAI;AACzG,QAAM,yBAAyB;AAAA,IAC7B,4BAA4B,CAAC,4BAA4B,2BAA2B;AAAA,IACpF;AAAA,MACE;AAAA,MACA;AAAA,MACA,UAAU,CAAC,6BAA6B,CAAC,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,QAAM,qBAAqB,6BAA6B,uBAAuB;AAG/E,EAAAE,WAAU,MAAM;AACd,QAAI,eAAe,CAAC,YAAY,eAAe,SAAS,GAAG;AAEzD,YAAM,aAAa,eAAe;AAAA,QAAO,OACvC,EAAE,cAAc,UAAU,WAAW,QAAQ;AAAA,MAC/C;AACA,YAAM,aAAa,WAAW,SAAS,IAAI,WAAW,CAAC,IAAI,eAAe,CAAC;AAC3E,kCAA4B,UAAU;AAAA,IAExC,OAAO;AAEL,kCAA4B,IAAI;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,aAAa,UAAU,gBAAgB,QAAQ,CAAC;AAGpD,QAAM,eAAe,YAAY;AAAA,EAEjC;AAGA,MAAI,qBAAqB;AACzB,MAAI,eAAe;AACnB,MAAI,sBAAsB;AAC1B,MAAI,iBAAiB;AACrB,MAAI,iBAAiB;AACrB,MAAI,aAAa;AAEjB,MAAI,eAAe,CAAC,UAAU;AAE5B,yBAAqB;AACrB,mBAAe;AACf,0BAAsB,2BAA2B,CAAC,wBAAwB,IAAI,CAAC;AAC/E,qBAAiB,2BAA2B,IAAI;AAEhD,QAAI,CAAC,2BAA2B;AAC9B,uBAAiB,aAAa,uBAAuB;AACrD,mBAAa,SAAS,uBAAuB;AAAA,IAC/C;AAAA,EACF;AAEA,SACE,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,MACX,OAAO;AAAA,MACP,SAAS;AAAA,MACT,eAAe;AAAA,MACf,gBAAgB;AAAA,MAChB;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,aAAa,eAAe;AAAA,MACtC,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAoBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,aAAa;AAAA,EACb,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AAEnB,QAAM,eAAe,gBAAgB;AAGrC,MAAI,cAAc;AAChB,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,EAEJ;AAIA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;;;AEl9BA,SAAS,YAAAM,WAAU,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,WAAAC,gBAAe;AAalE,IAAMC,OAAM,aAAa,kBAAkB;AAO3C,IAAM,oBAAoB;AAAA,EACxB,eAAe,oBAAI,IAAuF;AAAA,EAE1G,UAAU,KAAa,UAA8B;AACnD,QAAI,QAAQ,KAAK,cAAc,IAAI,GAAG;AACtC,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,WAAW,oBAAI,IAAI,GAAG,YAAY,KAAK;AACjD,WAAK,cAAc,IAAI,KAAK,KAAK;AAAA,IACnC;AAEA,UAAM,UAAU,IAAI,QAAQ;AAE5B,QAAI,CAAC,MAAM,YAAY;AACrB,YAAM,aAAa,YAAY,MAAM;AACnC,eAAO,UAAU,QAAQ,CAAC,OAAO,GAAG,CAAC;AAAA,MACvC,GAAG,KAAK,KAAK,GAAI;AAAA,IACnB;AAEA,WAAO,MAAM;AACX,WAAK,YAAY,KAAK,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,YAAY,KAAa,UAA8B;AACrD,UAAM,QAAQ,KAAK,cAAc,IAAI,GAAG;AACxC,QAAI,CAAC,MAAO;AAEZ,UAAM,UAAU,OAAO,QAAQ;AAE/B,QAAI,MAAM,UAAU,SAAS,GAAG;AAC9B,UAAI,MAAM,YAAY;AACpB,sBAAc,MAAM,UAAU;AAAA,MAChC;AACA,WAAK,cAAc,OAAO,GAAG;AAAA,IAC/B;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,UAA0B;AACzD,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,UAAUC,SAAQ,MAAM,2BAA2B,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAE9E,QAAM,aAAaC,aAAY,OAAO,SAA4B,SAAiD;AACjH,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,SAAS,MAAM,wBAAwB,UAAU,SAAS,IAAI;AACpE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,mBAAmBA,aAAY,OAAO,YAAoB,WAAmB,oBAA2D;AAC5I,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,iBAAiB,YAAY,WAAW,eAAe;AAAA,IAC9E,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,aAAaA,aAAY,OAAO,YAAoB,WAAmB,oBAAoD;AAC/H,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,WAAW,YAAY,WAAW,eAAe;AAAA,IACxE,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAMC,gBAAeD,aAAY,OAAO,YAAoB,WAAmB,iBAAyB,eAAgD;AACtJ,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,aAAa,YAAY,WAAW,iBAAiB,UAAU;AAAA,IACtF,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,sBAAsBA,aAAY,OAAO,IAAY,YAAmE;AAC5H,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,oBAAoB,IAAI,OAAO;AAAA,IACtD,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,sBAAsBA,aAAY,OAAO,YAAoB,WAAmB,iBAAyB,gBAA4C;AACzJ,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,oBAAoB,YAAY,WAAW,iBAAiB,WAAW;AAAA,IAC9F,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,qBAAqBA,aAAY,OAAO,YAAoB,WAAmB,oBAAsD;AACzI,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,mBAAmB,YAAY,WAAW,eAAe;AAAA,IAChF,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO,CAAC;AAAA,IACV,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,eAAeA,aAAY,OAAO,YAAoB,WAAmB,oBAA6C;AAC1H,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,aAAa,YAAY,WAAW,eAAe;AAAA,IAC1E,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,uBAAuBA,aAAY,OAAO,IAAY,oBAA2D;AACrH,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,qBAAqB,IAAI,eAAe;AAAA,IAC/D,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,qBAAqBA,aAAY,OACrC,YACA,WACA,UACA,oBAC6B;AAC7B,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,aAAO,MAAM,QAAQ,mBAAmB,YAAY,WAAW,UAAU,eAAe;AAAA,IAC1F,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,aAAO,CAAC;AAAA,IACV,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,aAAaA,aAAY,MAAM;AACnC,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAAC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,0BACd,UACA,YACA,WACA,iBACA;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB,QAAQ;AAE7B,QAAM,CAAC,SAAS,UAAU,IAAIH,UAAwB,IAAI;AAC1D,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAA+B,IAAI;AAC7E,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAA0B,CAAC,CAAC;AACxE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAiB,CAAC;AACpD,QAAM,yBAAyBI,QAA4B,IAAI;AAE/D,QAAM,oBAAoBF,aAAY,YAAY;AAChD,UAAM,YAAY,MAAM,iBAAiB,YAAY,WAAW,eAAe;AAC/E,qBAAiB,SAAS;AAC1B,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,YAAY,WAAW,eAAe,CAAC;AAE7D,QAAM,cAAcA,aAAY,YAAY;AAC1C,UAAM,MAAM,MAAM,WAAW,YAAY,WAAW,eAAe;AACnE,eAAW,GAAG;AACd,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,YAAY,WAAW,eAAe,CAAC;AAEvD,QAAM,qBAAqBA,aAAY,YAAY;AACjD,UAAM,aAAa,MAAM,mBAAmB,YAAY,WAAW,eAAe;AAClF,sBAAkB,UAAU;AAC5B,WAAO;AAAA,EACT,GAAG,CAAC,oBAAoB,YAAY,WAAW,eAAe,CAAC;AAE/D,QAAM,gBAAgBA,aAAY,YAAY;AAC5C,UAAM,QAAQ,MAAM,aAAa,YAAY,WAAW,eAAe;AACvE,iBAAa,KAAK;AAClB,WAAO;AAAA,EACT,GAAG,CAAC,cAAc,YAAY,WAAW,eAAe,CAAC;AAEzD,QAAM,aAAaA,aAAY,OAAO,gBAA0B;AAC9D,UAAM,UAAU,MAAM,oBAAoB,YAAY,WAAW,iBAAiB,WAAW;AAC7F,QAAI,SAAS;AACX,uBAAiB,IAAI;AACrB,iBAAW,IAAI;AACf,YAAM,cAAc;AAAA,IACtB;AACA,WAAO;AAAA,EACT,GAAG,CAAC,qBAAqB,YAAY,WAAW,iBAAiB,aAAa,CAAC;AAG/E,EAAAG,WAAU,MAAM;AACd,QAAI,uBAAuB,SAAS;AAClC,6BAAuB,QAAQ;AAC/B,6BAAuB,UAAU;AAAA,IACnC;AAEA,QAAI,CAAC,iBAAiB,cAAc,WAAW;AAE7C;AAAA,IACF;AAGA,UAAM,MAAM,GAAG,cAAc,UAAU,IAAI,cAAc,SAAS,IAAI,eAAe;AACrF,2BAAuB,UAAU,kBAAkB,UAAU,KAAK,MAAM;AACtE,kBAAY;AAAA,IACd,CAAC;AAED,WAAO,MAAM;AACX,UAAI,uBAAuB,SAAS;AAClC,+BAAuB,QAAQ;AAC/B,+BAAuB,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,eAAe,CAAC;AAEhD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,qBACd,UACA,iBACA,gBACA;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB,QAAQ;AAE7B,QAAM,CAAC,eAAe,gBAAgB,IAAIL,UAA+B,IAAI;AAC7E,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAwB,IAAI;AAE1D,QAAM,oBAAoBE,aAAY,YAAY;AAChD,QAAI,CAAC,mBAAmB,CAAC,gBAAgB;AACvC,uBAAiB,IAAI;AACrB,iBAAW,IAAI;AACf,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,MAAM,qBAAqB,iBAAiB,cAAc;AAC5E,qBAAiB,SAAS;AAC1B,WAAO;AAAA,EACT,GAAG,CAAC,sBAAsB,iBAAiB,cAAc,CAAC;AAE1D,EAAAG,WAAU,MAAM;AACd,sBAAkB;AAAA,EACpB,GAAG,CAAC,iBAAiB,CAAC;AAGtB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,gBAAgB;AACzD,iBAAW,IAAI;AACf;AAAA,IACF;AAEA,UAAM,UAAU,YAAY;AAC1B,YAAM,UAAU,2BAA2B,QAAQ;AACnD,YAAM,MAAM,MAAM,QAAQ;AAAA,QACxB,cAAc;AAAA,QACd,cAAc;AAAA,QACd;AAAA,MACF;AACA,iBAAW,GAAG;AAAA,IAChB;AAEA,YAAQ;AAAA,EACV,GAAG,CAAC,eAAe,iBAAiB,gBAAgB,QAAQ,CAAC;AAE7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAcO,SAAS,mBACd,UACA,YACA,WACA,UACA,iBACA;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB,QAAQ;AAE7B,QAAM,CAAC,gBAAgB,iBAAiB,IAAIL,UAA0B,CAAC,CAAC;AACxE,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA8B,oBAAI,IAAI,CAAC;AAEvE,QAAM,YAAYE,aAAY,YAAY;AACxC,QAAI,CAAC,YAAY,CAAC,iBAAiB;AACjC,wBAAkB,CAAC,CAAC;AACpB,kBAAY,oBAAI,IAAI,CAAC;AACrB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,QAAQ,MAAM,mBAAmB,YAAY,WAAW,UAAU,eAAe;AACvF,sBAAkB,KAAK;AAGvB,UAAM,SAAS,MAAM,sBAAsB,UAAU,OAAO;AAAA,MACpD,SAAS;AAAA,MACT,OAAO;AAAA,MACP,WAAW;AAAA,IACb,CAAC;AAEP,gBAAY,MAAM;AAClB,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,WAAW,UAAU,iBAAiB,UAAU,kBAAkB,CAAC;AAEnF,EAAAG,WAAU,MAAM;AACd,cAAU;AAAA,EACZ,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjaA,YAAYC,YAAW;AA+Gb,gBAAAC,YAAA;AArGV,IAAM,cAAc;AAAA,EAClB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AACT;AA2BA,IAAM,SAAe;AAAA,EACnB,CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,GAAG;AAAA,EACL,GAAG,QAAQ;AACT,UAAM,CAAC,YAAY,aAAa,IAAU,gBAAS,KAAK;AACxD,UAAM,EAAE,SAAS,IAAI,eAAe;AAIpC,UAAM,iBAAiB,QAAQ,UAAU,mBAAmB,QAAQ;AACpE,UAAM,EAAE,eAAe,SAAS,WAAW,WAAW,cAAc,IAAI;AAAA,MACtE,YAAa,CAAC;AAAA;AAAA,MACd,iBAAiB,SAAU;AAAA,MAC3B,iBAAiB,kBAAmB;AAAA,IACtC;AAGA,UAAM,eAAe,cAAc,aAAa,mBAAmB,YAAY;AAC/E,UAAM,YAAY,kBAAkB,aAAa,CAAC;AAClD,UAAM,eAAe,OAAO,CAAC;AAG7B,UAAM,eAAe,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,cAAc,cAAe,kBAAkB,CAAC,aAAa,CAAC;AAGvH,UAAM,cAAc,SAAS,OACzB,0CACA,IAAI,YAAY,IAAI,CAAC;AAGzB,UAAM,kBAAkB;AAGxB,UAAM,eAAe;AAGrB,UAAM,mBAAmB,GAAG,aAAa,SAAS;AAGlD,UAAM,mBAAyB,mBAAY,MAAM;AAC/C,oBAAc,IAAI;AAAA,IACpB,GAAG,CAAC,CAAC;AAGL,IAAM,iBAAU,MAAM;AACpB,UAAI,KAAK;AACP,sBAAc,KAAK;AAAA,MACrB;AAAA,IACF,GAAG,CAAC,GAAG,CAAC;AAER,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,QACV,GAAG;AAAA,QAEH,yBACC,gBAAAA,KAAC,gBAAW,WAAW,iBAAiB,cAAY,OAAO,UACxD,oBACH,IACE;AAAA;AAAA,UAEF,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,aAAa;AAAA,cACb,cAAc;AAAA,cACd,cAAc;AAAA,cACd,WAAW,GAAG,cAAc,SAAS;AAAA;AAAA,UACvC;AAAA,YACE,aAAa;AAAA;AAAA,UAEf,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAK,OAAO;AAAA,cACZ,WAAW;AAAA,cACX,SAAS;AAAA;AAAA,UACX;AAAA,YACE;AAAA;AAAA,UAEF,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,KAAK,OAAO;AAAA,cACZ,WAAW;AAAA,cACX,SAAS;AAAA;AAAA,UACX;AAAA;AAAA;AAAA,UAGA,gBAAAA,KAAC,gBAAW,WAAW,iBAAiB,cAAY,OAAO,UACxD,oBACH;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AACF;AAEA,OAAO,cAAc;;;ACsEb,gBAAAC,YAAA;AA1MR,IAAM,cAAc;AAAA,EAClB,OAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AACF;AAOA,IAAM,SAAS,CAAC,QAAQ,OAAO,KAAK;AAMpC,IAAM,SAAS,CAAC,SAAS,WAAW,MAAM;AAO1C,SAAS,oBAAoB,OAAc,OAAc,OAAsB;AAC7E,QAAM,MAAM,YAAY,KAAK;AAC7B,QAAM,QAAkB,CAAC;AAEzB,MAAI,UAAU,SAAS;AAErB,UAAM,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,EAAE;AAAA,EACjE,WAAW,UAAU,WAAW;AAE9B,UAAM,KAAK,uCAAuC,WAAW,KAAK,IAAI,IAAI,MAAM,IAAI,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ,KAAK,IAAI,IAAI,WAAW,EAAE;AAAA,EACxJ,WAAW,UAAU,QAAQ;AAE3B,UAAM;AAAA,MACJ,MAAM,KAAK,IAAI,IAAI,EAAE;AAAA,MACrB;AAAA,MACA,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,MACzB,QAAQ,KAAK,IAAI,IAAI,IAAI;AAAA,MACzB;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,IAClC;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,GAAG;AACvB;AAmDA,SAAS,yBAAuD;AAC9D,QAAM,iBAAiB,CAAC;AAExB,aAAW,SAAS,QAAQ;AAC1B,eAAW,SAAS,QAAQ;AAC1B,iBAAW,SAAS,OAAO,KAAK,WAAW,GAAc;AACvD,cAAM,UAAU,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK;AAC1C,uBAAe,OAAO,IAAI,oBAAoB,OAAO,OAAO,KAAK;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAGA,IAAM,oBAAoB,uBAAuB;AAkBjD,SAAS,gBAAgB,UAAwB,qBAA6B;AAC5E,QAAM,cAAc;AACpB,SAAO,GAAG,WAAW,IAAI,kBAAkB,OAAO,CAAC;AACrD;AA0BA,SAAS,MAAM,EAAE,WAAW,UAAU,qBAAqB,KAAK,GAAG,MAAM,GAAsD;AAC3H,QAAM,gBAAgB,QAAQ,WAAW,OAAO;AAEhD,MAAI,eAAe;AAGjB,UAAM,iBAAiB,gBAAgB,OAAO;AAE9C,UAAM,mBAAmB,eAAe,MAAM,wBAAwB;AACtE,UAAM,mBAAmB,mBAAmB,iBAAiB,CAAC,IAAI;AAGlE,UAAM,wBAAwB,eAC3B,QAAQ,0BAA0B,EAAE,EACpC,QAAQ,uBAAuB,EAAE,EACjC,QAAQ,QAAQ,GAAG,EACnB,KAAK;AAIR,UAAM,gBAAgB,GAAG,uBAAuB,SAAS;AACzD,UAAM,eAAe,GAAG,aAAa,sBAAsB,gBAAgB,GAAG,KAAK;AAEnF,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,QACV,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,gBAAgB,OAAO,GAAG,SAAS;AAAA,MAChD,GAAG;AAAA;AAAA,EACN;AAEN;AAEA,MAAM,cAAc;;;ACjOpB,YAAYC,YAAW;AACvB,YAAY,qBAAqB;AAmD7B,gBAAAC,YAAA;AAzBJ,IAAM,SAAe,kBAGnB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC,WAAW;AAAA;AAAA,MAET;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IACJ;AAAA,IAEA,0BAAAA;AAAA,MAAiB;AAAA,MAAhB;AAAA,QACC,WAAW;AAAA;AAAA,UAET;AAAA;AAAA,UAEA;AAAA;AAAA,UAEA;AAAA;AAAA,UAEA;AAAA,UACA;AAAA,QACF;AAAA;AAAA,IACF;AAAA;AACF,CACD;AAED,OAAO,cAA8B,qBAAK;;;ACjF1C,YAAYC,YAAW;AACvB,YAAY,mBAAmB;AA4B3B,gBAAAC,YAAA;AALJ,IAAM,OAAa,kBAGjB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAA,KAAe,oBAAd,EAAmB,SAAO,MAAE,GAAG,OAC9B,0BAAAA,KAAC,aAAQ,KAAU,WAChB,UACH,GACF,CACD;AAED,KAAK,cAA4B,mBAAK,eAAe;AAqBrD,IAAM,WAAiB,kBAGrB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAA,KAAe,oBAAd,EAAmB,SAAO,MAAE,GAAG,OAC9B,0BAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IAEC;AAAA;AACH,GACF,CACD;AAED,SAAS,cAA4B,mBAAK,eAAe;AAgCzD,IAAM,cAAoB,kBAGxB,CAAC,EAAE,WAAW,SAAS,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ;AAC3D,SACE,gBAAAA,KAAe,uBAAd,EAAsB,SAAO,MAAE,GAAG,OACjC,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH,GACF;AAEJ,CAAC;AAED,YAAY,cAA4B,sBAAQ,eAAe;AAoB/D,IAAM,cAAoB,kBAGxB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAA,KAAe,uBAAd,EAAsB,SAAO,MAAE,GAAG,OACjC,0BAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IAEC;AAAA;AACH,GACF,CACD;AAED,YAAY,cAA4B,sBAAQ,eAAe;;;ACrK/D,YAAYC,YAAW;AACvB;AAAA,EACE;AAAA,EAEA;AAAA,OAIK;AACP,SAAS,YAAY;AAmMR,qBAAAC,WAAA,OAAAC,MAiHO,QAAAC,aAjHP;AA5Ib,IAAM,cAAc,CAAK,KAAsC,UAAoB;AACjF,MAAI,CAAC,KAAK;AACR;AAAA,EACF;AACA,MAAI,OAAO,QAAQ,YAAY;AAC7B,QAAI,KAAK;AACT;AAAA,EACF;AACA,EAAC,IAAyC,UAAU;AACtD;AAyDA,IAAM,WAAiB;AAAA,EACrB,CAAC,EAAE,WAAW,YAAY,MAAM,YAAY,QAAQ,OAAO,iBAAiB,eAAe,yBAAyB,UAAU,GAAG,MAAM,GAAG,QAAQ;AAChJ,UAAM,WAAiB,cAAgC,IAAI;AAC3D,UAAM,kBAAwB;AAAA,MAC5B,CAAC,SAAkC;AACjC,iBAAS,UAAU;AACnB,YAAI,CAAC,KAAK;AACR;AAAA,QACF;AACA,YAAI,OAAO,QAAQ,YAAY;AAC7B,cAAI,IAAI;AAAA,QACV,OAAO;AACL,UAAC,IAAwD,UAAU;AAAA,QACrE;AAAA,MACF;AAAA,MACA,CAAC,GAAG;AAAA,IACN;AAGA,UAAM,eAAqB,cAA+B,IAAI;AAE9D,UAAM,WAAY,MAAc;AAEhC,UAAM,oBAAoB,oBAAoB;AAG9C,UAAM,CAAC,eAAe,gBAAgB,IAAU,gBAAe,MAAM;AACnE,YAAM,MAAM,oBAAI,KAAK;AACrB,aAAO,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,CAAC;AAAA,IACtD,CAAC;AAID,UAAM,QAAc,eAAQ,MAAM;AAChC,YAAM,aAAa,oBAAoB,kBAAkB;AACzD,UAAI,CAAC,YAAY;AACf,cAAM,MAAM,oBAAI,KAAK;AACrB,eAAO,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,CAAC;AAAA,MACtD;AAEA,YAAM,aAAa,IAAI,KAAK,WAAW,YAAY,GAAG,WAAW,SAAS,GAAG,CAAC;AAC9E,aAAO;AAAA,IACT,GAAG,CAAC,mBAAmB,iBAAiB,aAAa,CAAC;AAGtD,UAAM,oBAA0B,mBAAY,CAAC,aAAmB;AAC9D,UAAI,CAAC,mBAAmB;AACtB,yBAAiB,QAAQ;AAAA,MAC3B;AACA,gCAA0B,QAAQ;AAAA,IACpC,GAAG,CAAC,mBAAmB,uBAAuB,CAAC;AAG/C,UAAM,2BAAiC,mBAAY,CAAC,aAAmB;AACrE,wBAAkB,QAAQ;AAAA,IAC5B,GAAG,CAAC,iBAAiB,CAAC;AAKtB,UAAM,aAAmB,YAAK,CAAC,EAAE,UAAU,SAAS,kBAAkB,GAAG,UAAU,MAAiB;AAClG,YAAM;AAAA,QACJ,WAAW;AAAA,QACX,OAAO;AAAA,QACP,UAAU;AAAA,QACV,GAAG;AAAA,MACL,IAAI;AAEJ,mBAAa,UAAU;AAAA,QACrB,WAAW;AAAA,QACX,OAAO;AAAA,QACP,SAAS;AAAA,QACT;AAAA,MACF;AACA,aAAO,gBAAAD,KAAAD,WAAA,EAAG,UAAS;AAAA,IACrB,CAAC;AACD,eAAW,cAAc;AAGzB,UAAM,eAAqB,YAAK,CAAC,EAAE,SAAS,MAAmB;AAC7D,aAAO,gBAAAC,KAAAD,WAAA,EAAG,UAAS;AAAA,IACrB,CAAC;AACD,iBAAa,cAAc;AAE3B,UAAM,kBAAwB,kBAA6C,CAACG,QAAO,iBAAiB;AAClG,aAAO,gBAAAF,KAAC,WAAM,KAAK,cAAe,GAAGE,QAAO;AAAA,IAC9C,CAAC;AACD,oBAAgB,cAAc;AAG9B,UAAM,cAAoB,YAAK,CAAC,EAAE,eAAe,cAAc,WAAAC,YAAW,SAAS,MAAkB;AACnG,YAAM,EAAE,YAAY,YAAAC,aAAY,QAAQ,YAAAC,aAAY,eAAe,WAAW,UAAU,IAAI,aAAa;AACzG,YAAM,UAAU,WAAW,cAAc,cAAc,MAAM,CAAC,CAAC;AAC/D,YAAM,UAAUD,aAAY;AAE5B,YAAM,gBAAsB,gBAAS,QAAQ,QAAQ;AACrD,YAAM,iBAAiB,cAAc,UAAU,CAAC,UAAe;AAC7D,YAAI,CAAO,sBAAe,KAAK,EAAG,QAAO;AACzC,cAAM,YAAY,MAAM;AACxB,eAAQ,OAAO,cAAc,cAAc,UAAU,gBAAgB,eACnE,MAAM,SAAS;AAAA,MACnB,CAAC;AAED,aACE,gBAAAJ,KAAAD,WAAA,EACG,wBAAc,IAAI,CAAC,OAAO,UAAU;AACnC,YAAU,sBAAe,KAAK,KAAM,MAAM,MAAc,gBAAgB,gBAAgB;AACtF,iBAAO;AAAA,QACT;AAEA,YAAI,UAAU,kBAAwB,sBAAe,KAAK,GAAG;AAC3D,gBAAM,iBAAiB;AACvB,gBAAM,iBAAiB,iBAAiB,KAAK,UAAU;AACvD,gBAAM,kBAAkB,iBAAiB,aAAa,UAAU;AAEhE,gBAAM,EAAE,UAAU,mBAAmB,WAAW,oBAAoB,OAAO,gBAAgB,GAAG,cAAc,IAC1G,eAAe;AAEjB,gBAAM,kBAAkB;AAAA,YACtB;AAAA,YACA,iBAAiB,iBAAiB,YAAY;AAAA,YAC9CI;AAAA,YACA;AAAA,UACF;AAEA,gBAAM,cAAc;AAAA,YAClB,GAAI,iBAAiB,iBAAiB,SAAS,CAAC,IAAI,CAAC;AAAA,YACrD,GAAI,kBAAkB,CAAC;AAAA,UACzB;AAEA,gBAAM,aAA0D;AAAA,YAC9D,GAAI,kBAAkB,iBAAiB,YAAY,gBAAgB,YAAY,CAAC;AAAA,YAChF,GAAG;AAAA,YACH,WAAW;AAAA,YACX,GAAI,OAAO,KAAK,WAAW,EAAE,SAAS,EAAE,OAAO,YAAY,IAAI,CAAC;AAAA,UAClE;AAEA,cAAI,QAAS,WAAuC,WAAW,MAAM,QAAW;AAC9E,YAAC,WAAuC,WAAW,IAAI;AAAA,UACzD;AAEA,gBAAM,kBAAkB,kBAAkB,iBAAiB;AAC3D,gBAAM,iBAAiB,kBACnB,CAAC,SAAkC;AACjC,gBAAI,gBAAgB;AAClB,8BAAgB,IAAI;AAAA,YACtB;AACA,gBAAI,iBAAiB,SAAS;AAC5B,0BAAY,gBAAgB,SAA+C,IAAI;AAAA,YACjF;AAAA,UACF,IACA;AAEJ,gBAAM,sBAAsB,CAAC,UAA+C;AAC1E,kBAAM,eAAe;AACrB,gBAAI,CAAC,cAAe;AACpB,sBAAU,aAAa;AAAA,UACzB;AAEA,gBAAM,kBAAkB,CAAC,UAA+C;AACtE,kBAAM,eAAe;AACrB,gBAAI,CAAC,UAAW;AAChB,sBAAU,SAAS;AAAA,UACrB;AAEA,gBAAM,mBAAmB;AAGzB,gBAAM,YACJ,kBAAkB,iBAAiB,MAC/B,CAAC,SAAkC;AACjC,gBAAI,gBAAgB;AAClB,6BAAe,IAAI;AAAA,YACrB;AACA,wBAAY,iBAAiB,KAAuD,IAAI;AAAA,UAC1F,IACA;AAEN,iBAAa;AAAA,YACX;AAAA,YACA;AAAA,cACE,KAAK,MAAM,OAAO,cAAc,YAAY;AAAA,cAC5C,GAAG;AAAA,cACH,GAAI,YAAY,EAAE,KAAK,UAAU,IAAI,CAAC;AAAA,YACxC;AAAA,YACA,gBAAAF,MAAAF,WAAA,EACE;AAAA,8BAAAC,KAAC,aAAQ,WAAU,YACjB,0BAAAC,MAAC,SAAI,WAAU,mDACb;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAW;AAAA,sBACT;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACAK,aAAY;AAAA,oBACd;AAAA,oBACA,UAAU,gBAAgB,SAAY;AAAA,oBACtC,iBAAe,gBAAgB,SAAY;AAAA,oBAC3C,cAAY,gBAAgB,OAAO,cAAc,aAAa,IAAI;AAAA,oBAClE,SAAS;AAAA,oBACT,UAAU,CAAC;AAAA,oBAEV,oBAAU,gBAAAL,KAAC,WAAQ,aAAY,QAAO,WAAU,UAAS,UAAU,CAAC,eAAe,IAAK,gBAAAA,KAAC,UAAK,oBAAC;AAAA;AAAA,gBAClG;AAAA,gBACA,gBAAAA,KAAC,UAAK,WAAU,uBAAuB,mBAAQ;AAAA,gBAC/C,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAW;AAAA,sBACT;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACAK,aAAY;AAAA,oBACd;AAAA,oBACA,UAAU,YAAY,SAAY;AAAA,oBAClC,iBAAe,YAAY,SAAY;AAAA,oBACvC,cAAY,YAAY,OAAO,UAAU,SAAS,IAAI;AAAA,oBACtD,SAAS;AAAA,oBACT,UAAU,CAAC;AAAA,oBAEV,oBAAU,gBAAAL,KAAC,WAAQ,aAAY,SAAQ,WAAU,UAAS,UAAU,CAAC,WAAW,IAAK,gBAAAA,KAAC,UAAK,oBAAC;AAAA;AAAA,gBAC/F;AAAA,iBACF,GACF;AAAA,cACC;AAAA,eACH;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,MACT,CAAC,GACH;AAAA,IAEJ,CAAC;AACD,gBAAY,cAAc;AAG1B,UAAM,iBAAuB,YAAK,CAAC,EAAE,WAAAG,YAAW,UAAU,GAAGD,OAAM,MAAqB;AACtF,aACE,gBAAAF,KAAC,WACC,0BAAAA,KAAC,QAAG,WAAW,GAAG,wBAAwBG,UAAS,GAAI,GAAGD,QACvD,UACH,GACF;AAAA,IAEJ,CAAC;AACD,mBAAe,cAAc;AAG7B,UAAM,oBAA0B,eAAQ,OAAO;AAAA,MAC7C,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,WAAW;AAAA;AAAA,MAEX,UAAU;AAAA;AAAA,MAEV,GAAI,cAAc,CAAC;AAAA,IACrB,IAAI,CAAC,YAAY,YAAY,cAAc,aAAa,cAAc,CAAC;AAEvE,WACE,gBAAAF;AAAA,MAAC;AAAA;AAAA,QACE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QACxB,QAAQ,UAAU;AAAA,QAClB,gBAAgB;AAAA,QACf,GAAI;AAAA,QAGL;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf;AAAA,QACA,YAAY;AAAA;AAAA,UAEV,QAAQ;AAAA;AAAA,UACR,OAAO;AAAA;AAAA,UACP,eAAe;AAAA;AAAA,UACf,eAAe;AAAA,UACf,KAAK;AAAA;AAAA,UAEL,iBAAiB;AAAA,YACf;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,aAAa;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA;AAAA,UAEA,YAAY;AAAA;AAAA;AAAA,UAEZ,UAAU;AAAA;AAAA,UACV,SAAS;AAAA;AAAA,UAET,MAAM;AAAA;AAAA,UAEN,KAAK;AAAA;AAAA;AAAA,UAEL,YAAY;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA;AAAA,UAEA,WAAW;AAAA;AAAA,UAEX,UAAU;AAAA;AAAA,UAEV,OAAO;AAAA;AAAA,UAEP,SAAS;AAAA;AAAA,UAET,UAAU;AAAA;AAAA,UAEV,cAAc;AAAA;AAAA,UAEd,QAAQ;AAAA,UACR,GAAG;AAAA,QACL;AAAA,QACA,YAAY;AAAA;AAAA,IACd;AAAA,EAEJ;AACF;AAEA,SAAS,cAAc;;;AClbvB,YAAYM,YAAW;AACvB,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAkBhB,gBAAAC,OAkMQ,QAAAC,aAlMR;AAdF,IAAM,gBAAgC;AAUtC,IAAM,gBAAsB,kBAG1B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,eAAY;AAAA,IACZ,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,cAAc,cAA8B,yBAAS;AAmBrD,IAAM,QAAc,kBAGlB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ;AAClC,SACE,gBAAAA;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,eAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AACD,MAAM,cAA8B,qBAAK;AAezC,IAAM,cAAoB,kBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,eAAY;AAAA,IACZ,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,YAAY,cAA8B,uBAAO;AAejD,IAAM,aAAmB,kBAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,eAAY;AAAA,IACZ,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA,eAAY;AAAA,IACX,GAAG;AAAA,IAEJ,0BAAAA,MAAC,KAAE,WAAU,UAAS;AAAA;AACxB,CACD;AACD,WAAW,cAA8B,sBAAM;AAe/C,IAAM,aAAmB,kBAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,eAAY;AAAA,IACZ,WAAW,GAAG,yBAAyB,SAAS;AAAA,IAC/C,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAA8B,sBAAM;AAe/C,IAAM,mBAAyB,kBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,eAAY;AAAA,IACZ,WAAW,GAAG,sBAAsB,SAAS;AAAA,IAC5C,GAAG;AAAA;AACN,CACD;AACD,iBAAiB,cAA8B,4BAAY;AAyBpD,SAAS,UAAU;AACxB,QAAM,EAAE,OAAO,IAAI,SAAS;AAE5B,SACE,gBAAAC,MAAC,iBAAc,eAAY,kBACzB;AAAA,oBAAAD,MAAC,iBAAc;AAAA,IACd,OAAO,IAAI,CAAC,UAAwB;AAEnC,YAAM,EAAE,IAAI,OAAO,aAAa,QAAQ,SAAS,UAAU,GAAG,WAAW,IAAI;AAE7E,aACE,gBAAAC,MAAC,SAAgB,GAAG,YAAY,UAC7B;AAAA,iBAAS,gBAAAD,MAAC,cAAY,iBAAM;AAAA,QAC5B,eAAe,gBAAAA,MAAC,oBAAkB,uBAAY;AAAA,QAC9C,UAAU;AAAA,QACX,gBAAAA,MAAC,cAAW,SAAS,SAAS;AAAA,WAJpB,EAKZ;AAAA,IAEJ,CAAC;AAAA,KACH;AAEJ;;;AC7OA,SAAS,SAAS,cAA4F,gBAAgB,kBAA8F;AAC5N,SAAS,mBAAmB;AAuFtB,SAgMM,YAAAE,WAhMN,OAAAC,OAoKE,QAAAC,aApKF;AApBC,SAAS,KAAqD;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,UAAU,QAAsB;AAAA,IACpC,UAAU,SAAS,YAAY,MAAM,IAAI;AAAA,IACzC;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,eAAe,QAAQ,aAAa,UAAU,OAAO;AAE3D,SACE,gBAAAD,MAAC,gBAAc,GAAG,SAChB,0BAAAA,MAAC,UAAK,UAAU,cAAc,WAAW,GAAG,aAAa,SAAS,GAC/D,iBAAO,aAAa,aAAa,SAAS,OAAO,IAAI,UACxD,GACF;AAEJ;AA4IO,SAAS,UAGd;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AACF,GAAwC;AACtC,QAAM,EAAE,QAAQ,IAAI,eAA6B;AAEjD,SACE,gBAAAC,MAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GACtC;AAAA,aACC,gBAAAA,MAAC,SAAM,SAAS,MACb;AAAA;AAAA,MACA,YAAY,YACX,gBAAAD,MAAC,UAAK,WAAU,yBAAwB,cAAW,YAAW,eAE9D;AAAA,OAEJ;AAAA,IAGF,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,QAAQ,CAAC,UAAU;AACjB,gBAAM,EAAE,OAAO,WAAW,IAAI;AAC9B,gBAAM,aAAa,WAAW;AAG9B,gBAAM,eAAe,cAAc,OAAO,eAAe,YAAY,aAAa,aAC9E,OAAO,WAAW,OAAO,IACzB;AAEJ,cAAI,QAAQ;AACV,mBAAO,OAAO,KAAK;AAAA,UACrB;AAEA,iBACE,gBAAAC,MAAAF,WAAA,EACE;AAAA,4BAAAC;AAAA,cAAC;AAAA;AAAA,gBACE,GAAG;AAAA,gBACJ,IAAI;AAAA,gBACJ;AAAA,gBACA;AAAA,gBACA,eAAa;AAAA,gBACb,WAAW;AAAA,kBACT;AAAA,kBACA,cAAc;AAAA,gBAChB;AAAA,gBACC,GAAG;AAAA;AAAA,YACN;AAAA,YACC,gBACC,gBAAAA,MAAC,OAAE,WAAU,oBAAmB,MAAK,SAClC,wBACH;AAAA,aAEJ;AAAA,QAEJ;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;ACtRA,OAAOE,UAAS,YAAAC,WAAU,eAAAC,cAAa,WAAAC,gBAAe;AAsGhD,SACE,OAAAC,OADF,QAAAC,aAAA;AArDC,IAAM,YAAYC,OAAM,KAAqB,CAAC;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,EAAE,OAAO,IAAI,UAAU,GAAG,CAAC;AACpE,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAGtD,QAAM,cAAcC,SAAQ,MAAM;AAChC,WAAO,SAAS,MAAM,SAAS,KAAK,SAAS,SAAS,SAAS;AAAA,EACjE,GAAG,CAAC,SAAS,OAAO,SAAS,QAAQ,CAAC;AAGtC,QAAM,oBAAoB,CAAC,MAA2C;AACpE,gBAAY,WAAS,EAAE,GAAG,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,EAC1D;AAEA,QAAM,uBAAuB,CAAC,MAA2C;AACvE,gBAAY,WAAS,EAAE,GAAG,MAAM,UAAU,EAAE,OAAO,MAAM,EAAE;AAAA,EAC7D;AAEA,QAAM,eAAeC,aAAY,OAAO,MAAuB;AAC7D,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,QAAI,CAAC,eAAe,UAAW;AAC/B,QAAI;AACF,YAAM,SAAS,QAAQ;AACvB,kBAAY;AAAA,IACd,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,gBAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,YAAY,CAAC;AAAA,IAChE;AAAA,EACF,GAAG,CAAC,UAAU,aAAa,WAAW,UAAU,WAAW,OAAO,CAAC;AAEnE,QAAM,oBAAoB,MAAM;AAC9B,eAAW;AAAA,EACb;AAEA,QAAM,eAAeD,SAAQ,MAAM,UAAU,UAAU,cAAc,OAAO,KAAK,YAAY,CAAC,OAAO,OAAO,CAAC;AAC7G,QAAM,kBAAkBA,SAAQ,MAAM,YAAY,uCAAuC,CAAC,QAAQ,CAAC;AAEnG,SACE,gBAAAJ,MAAC,QAAK,WAAW,GAAG,2BAA2B,SAAS,GAChD,0BAAAC,MAAC,UAAK,UAAU,cAAc,eAAY,cAChD;AAAA,oBAAAA,MAAC,cAAW,WAAU,aACpB;AAAA,sBAAAD,MAAC,aAAU,WAAU,wBAAwB,wBAAa;AAAA,MAC1D,gBAAAA,MAAC,mBAAgB,WAAU,eACxB,2BACH;AAAA,OACF;AAAA,IAEE,gBAAAC,MAAC,eAAY,WAAU,aACpB;AAAA,eACC,gBAAAD,MAAC,SAAM,SAAQ,eAAc,MAAK,SAAQ,aAAU,aAClD,0BAAAA,MAAC,oBAAkB,iBAAM,GAC3B;AAAA,MAGA,gBAAAA,MAAC,SAAM,SAAQ,SAAQ,mBAAK;AAAA,MAC5B,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,aAAY;AAAA,UACZ,OAAO,SAAS;AAAA,UAChB,UAAU;AAAA,UACV,UAAQ;AAAA,UACR,UAAU;AAAA;AAAA,MACZ;AAAA,MAGA,gBAAAA,MAAC,SAAM,SAAQ,YAAW,sBAAQ;AAAA,MAClC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,aAAY;AAAA,UACZ,OAAO,SAAS;AAAA,UAChB,UAAU;AAAA,UACV,UAAQ;AAAA,UACR,UAAU;AAAA;AAAA,MACZ;AAAA,OAEJ;AAAA,IACA,gBAAAC,MAAC,cAAW,WAAU,2BACpB;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,UAAU,aAAa,CAAC;AAAA,UAEvB,sBAAY,kBAAkB;AAAA;AAAA,MACjC;AAAA,MACC,eACC,WACE,gBAAAA,MAAC,SAAI,WAAU,6CACb,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAU;AAAA,UACX;AAAA;AAAA,MAED,GACF,IAEA,gBAAAC,MAAC,OAAE,WAAU,qCAAoC;AAAA;AAAA,QACxB;AAAA,QACvB,gBAAAD,MAAC,OAAE,MAAK,WAAU,WAAU,gCAA+B,qBAE3D;AAAA,SACF;AAAA,OAGN;AAAA,KACF,GACF;AAEJ,CAAC;;;ACtLD,SAAS,WAAW,aAAa,MAAM,YAAAM,WAAU,YAAY;AAG7D,SAAS,aAAAC,YAAW,WAAAC,UAAS,UAAAC,eAAc;AAiMrC,SACE,OAAAC,OADF,QAAAC,aAAA;AA5JC,SAAS,cAAc;AAAA,EAC5B,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B,GAAuB;AACrB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,UAAU;AAKd,QAAM,oBAAoB,CAAC,YAAoB;AAC7C,UAAM,QAAQ,OAAO,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,OAAO;AAEjE,QAAI,OAAO;AACT,uBAAiB,KAAK;AACtB,UAAI,eAAe;AACjB,sBAAc,KAAK;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,MAAM;AACxB,kBAAc;AAAA,EAChB;AAGA,QAAM,cAAc,CAAC,UAA0B;AAC7C,QAAI,CAAC,MAAM,WAAY,QAAO;AAE9B,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,IAAI,QAAQ,CAAC;AACvE,UAAM,YAAY,IAAI,KAAK,MAAM,UAAU;AAE3C,WAAO,aAAa;AAAA,EACtB;AAGA,QAAM,kBAAkB,CAAC,eAA+B;AACtD,UAAM,OAAO,IAAI,KAAK,UAAU;AAChC,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,WAAW,IAAI,KAAK,KAAK;AAC/B,aAAS,QAAQ,SAAS,QAAQ,IAAI,CAAC;AAGvC,UAAM,gBAAgB,CAAC,MAAY;AACjC,YAAM,aAAa,IAAI,KAAK,CAAC;AAC7B,iBAAW,SAAS,GAAG,GAAG,GAAG,CAAC;AAC9B,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,cAAc,IAAI;AACzC,UAAM,kBAAkB,cAAc,KAAK;AAC3C,UAAM,qBAAqB,cAAc,QAAQ;AAGjD,QAAI,eAAe,QAAQ,MAAM,gBAAgB,QAAQ,GAAG;AAC1D,aAAO;AAAA,IACT,WAAW,eAAe,QAAQ,MAAM,mBAAmB,QAAQ,GAAG;AACpE,aAAO;AAAA,IACT,OAAO;AACL,aAAO,KAAK,mBAAmB;AAAA,IACjC;AAAA,EACF;AAGA,QAAM,eAAeH,SAAQ,MAAM;AACjC,UAAM,UAAU,CAAC,MAAc,EAAE,aAAa,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,OAAO;AACxF,WAAO,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;AAAA,EAC3D,GAAG,CAAC,MAAM,CAAC;AAMX,QAAM,sBAAsBC,QAAO,OAAO,MAAM;AAChD,QAAM,yBAAyBA,QAAO,eAAe,QAAQ;AAC7D,QAAM,qBAAqBA,QAAO,KAAK;AAEvC,EAAAF,WAAU,MAAM;AAEd,UAAM,sBAAsB,OAAO,WAAW,oBAAoB;AAClE,UAAM,uBAAuB,eAAe,aAAa,uBAAuB;AAEhF,QAAI,qBAAqB;AACvB,0BAAoB,UAAU,OAAO;AAErC,UAAI,OAAO,SAAS,GAAG;AACrB,2BAAmB,UAAU;AAAA,MAC/B;AAAA,IACF;AACA,QAAI,sBAAsB;AACxB,6BAAuB,UAAU,eAAe;AAEhD,UAAI,eAAe;AACjB,2BAAmB,UAAU;AAAA,MAC/B;AAAA,IACF;AAQA,QAAI,CAAC,iBAAiB,OAAO,SAAS,KAAK,CAAC,aAAa,uBAAuB,CAAC,mBAAmB,SAAS;AAG3G,yBAAmB,UAAU;AAC7B,sBAAgB;AAAA,IAClB;AAEA,aAAS,kBAAkB;AACzB,YAAM,QAAQ,oBAAI,KAAK;AACvB,YAAM,eAAe,IAAI,KAAK,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,EAAE,QAAQ;AAG9F,YAAM,OAAO,CAAC,GAAG,MAAM,EACpB,OAAO,OAAK,EAAE,cAAc,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,KAAK,YAAY,EAC5E,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAoB,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAoB,EAAE,QAAQ,CAAC,EAAE,CAAC;AAE5G,UAAI,MAAM;AACR,yBAAiB,IAAI;AACrB,YAAI,cAAe,eAAc,IAAI;AAAA,MACvC,OAAO;AAEL,cAAM,iBAAiB,CAAC,GAAG,MAAM,EAC9B,OAAO,OAAK;AACX,cAAI,CAAC,EAAE,WAAY,QAAO;AAC1B,gBAAM,YAAY,IAAI,KAAK,EAAE,UAAU;AACvC,gBAAM,mBAAmB,IAAI,KAAK,UAAU,YAAY,GAAG,UAAU,SAAS,GAAG,UAAU,QAAQ,CAAC,EAAE,QAAQ;AAC9G,iBAAO,mBAAmB;AAAA,QAC5B,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAoB,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAoB,EAAE,QAAQ,CAAC,EAAE,CAAC;AAE5G,YAAI,gBAAgB;AAClB,2BAAiB,cAAc;AAC/B,cAAI,cAAe,eAAc,cAAc;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,eAAe,UAAU,WAAW,kBAAkB,aAAa,CAAC;AAGvF,MAAI,WAAW;AACb,WACE,gBAAAI,MAAC,SAAI,WAAW,2BAA2B,SAAS,IAClD;AAAA,sBAAAD,MAAC,kBAAe,MAAK,MAAK;AAAA,MAC1B,gBAAAA,MAAC,UAAK,WAAU,iCAAgC,+BAAiB;AAAA,OACnE;AAAA,EAEJ;AAGA,MAAI,OAAO;AACT,WACE,gBAAAA,MAAC,SAAI,WACH,0BAAAC,MAAC,SAAM,SAAQ,eACb;AAAA,sBAAAD,MAAC,QAAK,WAAU,UAAS;AAAA,MACzB,gBAAAC,MAAC,oBAAiB,WAAU,qCAC1B;AAAA,wBAAAD,MAAC,UAAM,gBAAM,SAAQ;AAAA,QACpB,mBACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YAEV;AAAA,8BAAAD,MAAC,aAAU,WAAU,eAAc;AAAA,cAAE;AAAA;AAAA;AAAA,QAEvC;AAAA,SAEJ;AAAA,OACF,GACF;AAAA,EAEJ;AAGA,MAAI,OAAO,WAAW,GAAG;AACvB,QAAI,qBAAqB;AACvB,aACE,gBAAAA,MAAC,SAAI,WACH,0BAAAC,MAAC,SAAM,SAAQ,UACb;AAAA,wBAAAD,MAAC,eAAY,WAAU,uBAAsB;AAAA,QAC7C,gBAAAC,MAAC,oBAAiB,WAAU,qCAC1B;AAAA,0BAAAD,MAAC,UAAK,kCAAoB;AAAA,UACzB,mBACC,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cAEV;AAAA,gCAAAD,MAAC,aAAU,WAAU,eAAc;AAAA,gBAAE;AAAA;AAAA;AAAA,UAEvC;AAAA,WAEJ;AAAA,SACF,GACF;AAAA,IAEJ;AACA,WAAO;AAAA,EACT;AAGA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,gBAAiB,cAAc,YAAY,cAAc,KAAM;AAAA,MACtE,eAAe;AAAA,MACf;AAAA,MAEA;AAAA,wBAAAD,MAAC,iBAAc,WAAU,aAAY,SAAQ,WAC3C,0BAAAA,MAAC,eAAY,aACV,2BACC,gBAAAC,MAAC,SAAI,WAAU,2BACb;AAAA,0BAAAD,MAACE,WAAA,EAAS,WAAU,wBAAuB;AAAA,UAC3C,gBAAAF,MAAC,UAAK,WAAU,YAAY,wBAAc,YAAW;AAAA,UACpD,cAAc,cACb,gBAAAC,MAAC,UAAK,WAAU,+CAA8C;AAAA;AAAA,YAC1D,gBAAgB,cAAc,UAAU;AAAA,YAAE;AAAA,aAC9C;AAAA,WAEJ,GAEJ,GACF;AAAA,QACA,gBAAAD,MAAC,iBACE,uBACE,IAAI,CAAC,UAAU;AACd,gBAAM,SAAS,YAAY,KAAK;AAChC,gBAAM,aAAa,kBAAkB,cAAc,aAAa,MAAM,YAAY,cAAc,OAAO,MAAM;AAE7G,iBACE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,MAAM,YAAY,MAAM;AAAA,cAC/B,WAAU;AAAA,cAEV,0BAAAC,MAAC,SAAI,WAAU,kCACZ;AAAA,0CAA0B,UACzB,gBAAAD,MAAC,QAAK,WAAU,uBAAsB;AAAA,gBAExC,gBAAAC,MAAC,SAAI,WAAU,UACb;AAAA,kCAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,oCAAAD,MAAC,UAAK,WAAW,aAAa,kBAAkB,IAC7C,gBAAM,YACT;AAAA,oBACC,cACC,gBAAAA,MAAC,UAAK,WAAU,2DAA0D,qBAE1E;AAAA,qBAEJ;AAAA,kBACC,oBAAoB,MAAM,cACzB,gBAAAC,MAAC,SAAI,WAAU,yDACb;AAAA,oCAAAD,MAACE,WAAA,EAAS,WAAU,UAAS;AAAA,oBAC7B,gBAAAF,MAAC,UAAM,0BAAgB,MAAM,UAAU,GAAE;AAAA,oBACxC,0BAA0B,UACzB,gBAAAA,MAAC,UAAK,WAAU,4BAA2B,oBAE3C;AAAA,qBAEJ;AAAA,kBAED,oBAAoB,MAAM,eACzB,gBAAAC,MAAC,SAAI,WAAU,iCAAgC;AAAA;AAAA,oBACzC,MAAM;AAAA,qBACZ;AAAA,mBAEJ;AAAA,iBACF;AAAA;AAAA,YApCK,MAAM,YAAY,MAAM;AAAA,UAqC/B;AAAA,QAEJ,CAAC,GACL;AAAA;AAAA;AAAA,EACF;AAEJ;;;AC5WA,SAAgB,YAAAE,WAAU,eAAAC,cAAa,WAAAC,gBAAe;AAKtD,SAAS,aAAAC,YAAW,eAAAC,cAAa,WAAW,cAAc;AAkHpD,SACE,OAAAC,OADF,QAAAC,aAAA;AA9EC,SAAS,qBAAqB;AAAA,EACnC,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,6BAA6B;AAAA,EAC7B,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AACb,GAA8B;AAC5B,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAwB,IAAI;AAElE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB;AAMrB,QAAM,2BAA2BC,aAAY,OAAO,UAAkB;AACpE,QAAI,YAAY,UAAW;AAE3B,mBAAe,IAAI;AACnB,iBAAa,IAAI;AAEjB,QAAI;AAEF,UAAI,CAAC,2BAA2B,KAAK,GAAG;AACtC,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAEA,YAAM,mBAAmB,KAAK;AAE9B,YAAM,kBAAkB,cAAc,KAAK,SAAO,IAAI,OAAO,KAAK;AAClE,UAAI,mBAAmB,sBAAsB;AAC3C,6BAAqB,eAAe;AAAA,MACtC;AAAA,IAEF,SAAS,OAAO;AACd,aAAO,MAAM,wBAAwB,kCAAkC,KAAK;AAC5E,qBAAe,iBAAiB,QAAQ,MAAM,UAAU,+BAA+B;AAAA,IACzF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAcA,aAAY,YAAY;AAC1C,iBAAa,IAAI;AACjB,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,qBAAqB;AAAA,IAC7B,SAAS,OAAO;AACd,aAAO,MAAM,wBAAwB,oCAAoC,KAAK;AAC9E,qBAAe,iCAAiC;AAAA,IAClD,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,oBAAoB,CAAC;AAGzB,MAAI,YAAY;AACd,WACE,gBAAAF,MAAC,SAAI,WAAW,2BAA2B,SAAS,IAClD;AAAA,sBAAAD,MAAC,kBAAe,MAAK,MAAK;AAAA,MAC1B,gBAAAA,MAAC,UAAK,WAAU,iCACb,oBAAU,eAAe,4BAC5B;AAAA,OACF;AAAA,EAEJ;AAGA,MAAI,UAAU;AACZ,WACE,gBAAAC,MAAC,SAAI,WAAW,aAAa,SAAS,IACpC;AAAA,sBAAAA,MAAC,SAAM,SAAQ,eACb;AAAA,wBAAAD,MAACI,cAAA,EAAY,WAAU,UAAS;AAAA,QAChC,gBAAAH,MAAC,oBAAiB;AAAA;AAAA,UACe,SAAS;AAAA,WAC1C;AAAA,SACF;AAAA,MACC,mBACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAU;AAAA,UAEV;AAAA,4BAAAD,MAACK,YAAA,EAAU,WAAW,eAAe,YAAY,iBAAiB,EAAE,IAAI;AAAA,YAAE;AAAA;AAAA;AAAA,MAE5E;AAAA,OAEJ;AAAA,EAEJ;AAGA,MAAI,cAAc,WAAW,GAAG;AAC9B,QAAI,4BAA4B;AAC9B,aACE,gBAAAJ,MAAC,SAAI,WAAW,aAAa,SAAS,IACpC;AAAA,wBAAAA,MAAC,SACC;AAAA,0BAAAD,MAAC,aAAU,WAAU,UAAS;AAAA,UAC9B,gBAAAA,MAAC,oBAAiB,2GAElB;AAAA,WACF;AAAA,QACC,mBACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAU;AAAA,YAEV;AAAA,8BAAAD,MAACK,YAAA,EAAU,WAAW,eAAe,YAAY,iBAAiB,EAAE,IAAI;AAAA,cAAE;AAAA;AAAA;AAAA,QAE5E;AAAA,SAEJ;AAAA,IAEJ;AACA,WAAO;AAAA,EACT;AAGA,QAAM,qBAAqB,eACzB,gBAAAJ,MAAC,SAAM,SAAQ,eAAc,WAAU,QACrC;AAAA,oBAAAD,MAACI,cAAA,EAAY,WAAU,UAAS;AAAA,IAChC,gBAAAJ,MAAC,oBAAkB,uBAAY;AAAA,KACjC;AAIF,QAAM,mBAAmB,YAAY;AAGrC,QAAM,cAAcM,SAAQ,MAAM;AAChC,WAAO,sBAAsB,MAAM;AAAA,EACrC,GAAG,CAAC,sBAAsB,EAAE,CAAC;AAE7B,SACE,gBAAAL,MAAC,SAAI,WACH;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,eAAe;AAAA,QACf,UAAU;AAAA,QAEV;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAQ;AAAA,cAER,0BAAAA,MAAC,eAAY,aACV,kCACC,gBAAAC,MAAC,SAAI,WAAU,2BACZ;AAAA,4BACC,gBAAAD,MAAC,kBAAe,MAAK,MAAK,IAE1B,gBAAAA,MAAC,aAAU,WAAU,wBAAuB;AAAA,gBAE9C,gBAAAA,MAAC,UAAK,WAAU,YAAY,+BAAqB,cAAa;AAAA,iBAChE,GAEJ;AAAA;AAAA,UACF;AAAA,UACA,gBAAAA,MAAC,iBACE,wBAAc,IAAI,CAAC,QAAQ;AAC1B,kBAAM,WAAW,YAAY,IAAI,EAAE;AACnC,kBAAM,YAAY,2BAA2B,IAAI,EAAE;AAEnD,mBACE,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO,IAAI;AAAA,gBACX,UAAU,CAAC;AAAA,gBACX,WAAW,CAAC,YAAY,eAAe;AAAA,gBAEvC,0BAAAC,MAAC,SAAI,WAAU,4CACb;AAAA,kCAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,oCAAAD,MAAC,aAAU,WAAU,UAAS;AAAA,oBAC9B,gBAAAC,MAAC,SAAI,WAAU,iBACb;AAAA,sCAAAD,MAAC,UAAK,WAAU,eAAe,cAAI,cAAa;AAAA,sBAC/C,CAAC,WAAW,IAAI,eACf,gBAAAA,MAAC,UAAK,WAAU,mDACb,cAAI,aACP;AAAA,uBAEJ;AAAA,qBACF;AAAA,kBACC,YACC,gBAAAC,MAAC,SAAI,WAAU,gCACb;AAAA,oCAAAD,MAAC,UAAO,WAAU,gCAA+B;AAAA,oBACjD,gBAAAA,MAAC,UAAK,WAAU,4CACb,oBAAU,QAAQ,KAAK,GAAG,KAAK,WAClC;AAAA,qBACF;AAAA,mBAEJ;AAAA;AAAA,cAzBK,IAAI;AAAA,YA0BX;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA;AAAA,IACF;AAAA,IACC,sBACC,gBAAAA,MAAC,SAAI,WAAU,QACZ,8BACH;AAAA,KAEJ;AAEJ;;;AChOA,SAAgB,YAAAO,iBAAgB;AAyDxB,gBAAAC,OAIF,QAAAC,cAJE;AApCD,SAAS,mBAAmB,EAAE,UAAU,UAAU,GAA4B;AACnF,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAS,EAAE;AACjD,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAS,EAAE;AACzD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AAEtD,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,aAAS,IAAI;AAEb,QAAI,YAAY,SAAS,GAAG;AAC1B,eAAS,yCAAyC;AAClD;AAAA,IACF;AACA,QAAI,gBAAgB,iBAAiB;AACnC,eAAS,yBAAyB;AAClC;AAAA,IACF;AAEA,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,EAAE,aAAa,gBAAgB,CAAC;AAC9D,UAAI,UAAU,OAAO,OAAO;AAC1B,iBAAS,OAAO,MAAM,WAAW,4BAA4B;AAAA,MAC/D;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,WAAW,eAAe,QAAQ,MAAM,IAAI,MAAM,8BAA8B;AACtF,eAAS,SAAS,OAAO;AAAA,IAC3B,UAAE;AACA,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,SACE,gBAAAD,OAAC,UAAK,UAAU,cAAc,WAAW,GAAG,aAAa,SAAS,GAC/D;AAAA,aACC,gBAAAD,MAAC,SAAI,MAAK,SACP,iBACH;AAAA,IAEF,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD,MAAC,SAAM,SAAQ,gBAAe,0BAAY;AAAA,MAC1C,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,UAC9C,UAAQ;AAAA,UACR,UAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD,MAAC,SAAM,SAAQ,oBAAmB,8BAAgB;AAAA,MAClD,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,mBAAmB,EAAE,OAAO,KAAK;AAAA,UAClD,UAAQ;AAAA,UACR,UAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,UAAU,gBAAgB,CAAC,eAAe,CAAC;AAAA,QAE1C,yBAAe,gBAAgB;AAAA;AAAA,IAClC;AAAA,KACF;AAEJ;;;ACxFA,OAAOG,WAAS,eAAAC,cAAa,WAAAC,UAAS,YAAAC,kBAAgB;AAEtD,SAAS,aAAa,QAAQ,gBAAgB;AA6DpC,SAEI,OAAAC,OAFJ,QAAAC,cAAA;AA/BH,IAAM,WAAWC,QAAM,KAAoB,SAASC,UAAS;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAAG;AACD,QAAM,CAAC,sBAAsB,qBAAqB,IAAIC,WAAS,KAAK;AAEpE,QAAM,WAAWC,SAAQ,MAAM;AAC7B,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe,gBAAgB,KAAK,eAAe,aAAa,KAAK,OAAO,MAAM,GAAG,EAAE,CAAC;AAAA,MAC1G,WAAW,KAAK,eAAe;AAAA,MAC/B,UAAU,KAAK,eAAe,gBAAgB,KAAK,eAAe,aAAa,KAAK,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY;AAAA,IAC1H;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,gBAAgBC,aAAY,YAAY;AAC5C,QAAI,UAAW,OAAM,UAAU;AAAA,EACjC,GAAG,CAAC,SAAS,CAAC;AAEd,MAAI,CAAC,QAAQ,CAAC,UAAU;AACtB,WAAO;AAAA,EACT;AAEA,SACE,gBAAAL,OAAC,UAAO,MAAM,sBAAsB,cAAc,uBAChD;AAAA,oBAAAA,OAAC,UAAO,WACN;AAAA,sBAAAD,MAAC,iBAAc,SAAO,MACpB,0BAAAC,OAAC,UAAO,SAAQ,WAAU,WAAU,2BAA0B,cAAY,SAAS,aAChF;AAAA,sBACC,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,KAAK,SAAS;AAAA,YACd,KAAK,SAAS;AAAA,YACd,UAAU,SAAS;AAAA,YACnB,WAAU;AAAA;AAAA,QACZ;AAAA,QAEF,gBAAAA,MAAC,UAAM,mBAAS,aAAY;AAAA,QAC5B,gBAAAA,MAAC,eAAY,WAAU,UAAS;AAAA,SAClC,GACF;AAAA,MACA,gBAAAC,OAAC,iBACC;AAAA,wBAAAD,MAAC,eAAY,WAAU,eACrB,0BAAAC,OAAC,SAAI,WAAU,2BACb;AAAA,0BAAAD,MAAC,OAAE,WAAU,eAAe,mBAAS,aAAY;AAAA,UACjD,gBAAAA,MAAC,OAAE,WAAU,yBAAyB,mBAAS,OAAM;AAAA,WACvD,GACF;AAAA,QACA,gBAAAA,MAAC,mBAAgB;AAAA,QACjB,gBAAAA,MAAC,iBAAc,SAAO,MACpB,0BAAAC,OAAC,cAAW,OAAM,mBAChB;AAAA,0BAAAD,MAAC,YAAS,WAAU,eAAc;AAAA,UAClC,gBAAAA,MAAC,UAAK,6BAAe;AAAA,WACvB,GACF;AAAA,QACA,gBAAAC,OAAC,cAAW,OAAM,YAAW,SAAS,eACpC;AAAA,0BAAAD,MAAC,UAAO,WAAU,eAAc;AAAA,UAChC,gBAAAA,MAAC,UAAK,sBAAQ;AAAA,WAChB;AAAA,SACF;AAAA,OACF;AAAA,IAEA,gBAAAA,MAAC,iBAAc;AAAA,IACf,gBAAAC,OAAC,iBAAc,WACb;AAAA,sBAAAD,MAAC,gBACC,0BAAAA,MAAC,eAAY,6BAAe,GAC9B;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,OAAO,EAAE,aAAa,gBAAgB,MAAM;AACpD,gBAAI,kBAAkB;AACpB,oBAAM,EAAE,MAAM,IAAI,MAAM,iBAAiB,aAAa,eAAe;AACrE,kBAAI,CAAC,OAAO;AACV,sCAAsB,KAAK;AAAA,cAC7B;AACA,qBAAO,EAAE,MAAM;AAAA,YACjB;AACA,mBAAO,CAAC;AAAA,UACV;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ,CAAC;AAEM,IAAM,kBAAkBE,QAAM,KAAK,SAASK,mBAAkB;AACnE,SACE,gBAAAN,OAAC,SAAI,WAAU,mCACb;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAQ;AAAA,QACR,WAAU;AAAA,QAEV;AAAA,0BAAAD,MAAC,SAAI,WAAU,+CAA8C;AAAA,UAC7D,gBAAAA,MAAC,UAAK,WAAU,0BAAyB,wBAAU;AAAA,UACnD,gBAAAA,MAAC,eAAY,WAAU,iCAAgC;AAAA;AAAA;AAAA,IACzD;AAAA,IACA,gBAAAA,MAAC,SAAI,MAAK,UAAS,cAAW,qBAAoB,aAAU,UAAS,WAAU,+CAA8C;AAAA,KAC/H;AAEJ,CAAC;AAOA,SAAiC,UAAU;;;ACnD5C,YAAYQ,aAAW;AACvB,SAAe,eAAAC,oBAAmB;AAs5BtB,SAOE,OAAAC,OAPF,QAAAC,cAAA;AAtpBL,IAAM,iBAAuB,mBAGlC,CAAC;AAAA,EACD;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,kBAAkB;AAAA;AAAA,EAElB,aAAa;AAAA,EACb,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB,GAAG;AACL,GAAG,QAAQ;AACT,QAAM,CAAC,eAAe,gBAAgB,IAAU,iBAAsB,oBAAI,IAAI,CAAC;AAC/E,QAAM,YAAkB,eAA0B,IAAI;AAGtD,MAAI,cAAc;AAClB,MAAI;AACF,kBAAc,eAAe;AAAA,EAC/B,SAAS,OAAO;AAEd,WAAO,KAAK,kBAAkB,+DAA+D;AAAA,EAC/F;AAGA,MAAI,cAAc;AAClB,MAAI;AACF,kBAAc,QAAQ;AAAA,EACxB,SAAS,OAAO;AAEd,WAAO,KAAK,kBAAkB,sDAAsD;AAAA,EACtF;AAIA,QAAM,kBAAkB,aAAa;AACrC,QAAM,eAAe,mBAAmB;AACxC,QAAM,gBAAgB,aAAa,iBAAiB;AAGpD,QAAM,kBAAkB,aAAa,mBAAmB,aAAa,sBAAsB,KAAK,OAAO;AAMvG,QAAM,EAAE,SAAS,IAAI,eAAe,CAAC;AACrC,QAAM,EAAE,qBAAqB,IAAI,eAAe,CAAC;AACjD,QAAM,EAAE,eAAe,WAAW,cAAc,OAAO,WAAW,IAAI,iBAAiB;AAAA,IACrF,UAAU,mBAAmB,OAAQ,YAAY;AAAA;AAAA,IACjD,wBAAwB,mBAAmB,OAAQ,sBAAsB,MAAM;AAAA,IAC/E,iBAAiB,mBAAmB,OAAQ,eAAe,YAAY;AAAA,EACzE,CAAC;AAID,QAAM,CAAC,eAAe,gBAAgB,IAAU,iBAA6B,MAAS;AACtF,EAAM,kBAAU,MAAM;AAMpB,QACE,CAAC,gBACD,CAAC,eAAe,SAChB,sBAAsB,MACtB,aAAa,WACb,aAAa,MAAM,MACnB,CAAC,eACD;AAGA,UAAI,CAAC,YAAY,QAAQ,CAAC,YAAY,SAAS;AAC7C;AAAA,MACF;AACA,YAAMC,UAAS,YAAY,KAAK;AAChC,YAAM,UAAU,YAAY;AAC5B,aAAO,mBAAgB,EAAE,KAAK,CAAC,EAAE,kBAAkB,MAAM;AACvD,0BAAkB;AAAA,UAChB,QAAAA;AAAA,UACA;AAAA,QACF,CAAC,EAAE,KAAK,CAAC,WAAW;AAClB,cAAI,QAAQ,OAAO;AACjB,6BAAiB,OAAO,KAAK;AAAA,UAC/B;AAAA,QACF,CAAC,EAAE,MAAM,CAAC,UAAU;AAAA,QAEpB,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,cAAc,eAAe,OAAO,sBAAsB,IAAI,aAAa,SAAS,aAAa,MAAM,IAAI,aAAa,CAAC;AAO7H,QAAM,iBAAuB,gBAAQ,MAAM;AAEzC,QAAI,eAAe,gBAAgB;AACjC,aAAO;AAAA,IACT;AAKA,QAAI,sBAAsB,IAAI;AAC5B,YAAM,gBAAgB;AAAA,QACpB,gBAAgB,qBAAqB;AAAA,QACrC,SAAS,eAAe,YAAY;AAAA,QACpC,OAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,sBAAsB,IAAI,eAAe,UAAU,aAAa,CAAC;AAOpF,QAAM,WAAW,iBACb,GAAG,eAAe,kBAAkB,EAAE,IAAI,eAAe,WAAW,EAAE,IAAI,eAAe,SAAS,EAAE,KACpG;AAEJ,QAAM,cAAoB,gBAAQ,MAAM;AACtC,QAAI,gBAAgB,gBAAgB;AAClC,aAAO;AAAA,QACL,gBAAgB,eAAe;AAAA,QAC/B,SAAS,eAAe;AAAA,QACxB,OAAO,eAAe;AAAA,MACxB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,UAAU,cAAc,CAAC;AAI7B,QAAM,SAAU,aAAa,MAAM,MAAM;AAMzC,QAAM,EAAE,aAAa,eAAe,kBAAkB,WAAW,oBAAoB,OAAO,iBAAiB,IAAI;AAAA,IAC/G,mBAAoB,OAAe;AAAA;AAAA,IACnC,mBAAmB,SAAY,YAAY;AAAA;AAAA,IAC3C,mBAAmB,SAAY,YAAY;AAAA;AAAA,IAC3C,mBAAmB,SAAY,YAAY;AAAA;AAAA,EAC7C;AAOA,QAAM,2BAAiC,eAAyB,CAAC,CAAC;AAElE,QAAM,gBAAsB,gBAAQ,MAAM;AAGxC,QAAI,oBAAoB,SAAS,MAAM,SAAS,GAAG;AAEjD,YAAM,gBAAgB,SAAS,CAAC,GAAG,OAAO,UAAQ,CAAC,KAAK,MAAM,MAAM;AACpE,+BAAyB,UAAU;AAEnC,aAAO;AAAA,IACT;AAQE,UAAM,oBAAoB,mBAAmB,sBAAsB;AAInE,UAAM,sBAAsB,oBAAoB,SAAY,OAAO,CAAC;AAKpE,UAAM,kBAAkB,qBAAqB;AAI7C,UAAM,qBAAqB,gBAAiB,CAAC;AAC7C,UAAM,wBAAwB,cAAc,mBAAmB,CAAC;AAMhE,QAAI,SAAS,MAAM,SAAS,KAAK,sBAAsB,IAAI;AAKzD,YAAM,gBAAgB,SAAS,CAAC,GAAG,OAAO,UAAQ,CAAC,KAAK,MAAM,MAAM;AAEpE,+BAAyB,UAAU;AACnC,aAAO;AAAA,IACT;AAGA,QAAI,CAAC,eAAe,CAAC,eAAgB,sBAAsB,CAAC,uBAAwB;AAIlF,aAAO,CAAC;AAAA,IACV;AAQA,QAAI,oBAAoB;AAGtB,UAAI,yBAAyB,QAAQ,SAAS,GAAG;AAC/C,eAAO,yBAAyB;AAAA,MAClC;AAIA,UAAI,SAAS,MAAM,SAAS,KAAK,YAAY,gBAAgB;AAG3D,gBAAQ,SAAS,CAAC,GAAG,OAAO,UAAQ,CAAC,KAAK,MAAM,MAAM;AAAA,MACxD;AAEA,aAAO,CAAC;AAAA,IACV;AAIA,QAAI,kBAAkB;AACpB,aAAO,KAAK,kBAAkB,0DAA0D;AAAA,QACtF,kBAAkB,kBAAkB;AAAA,MACtC,CAAC;AACD,aAAO,CAAC;AAAA,IACV;AAWA,QAAI,CAAC,iBAAiB,OAAO,KAAK,aAAa,EAAE,WAAW,GAAG;AAG7D,UAAI,YAAY,kBAAkB,SAAS,MAAM,SAAS,GAAG;AAG3D,gBAAQ,SAAS,CAAC,GAAG,OAAO,UAAQ,CAAC,KAAK,MAAM,MAAM;AAAA,MACxD;AAGA,UAAI,YAAY,gBAAgB;AAC9B,eAAO,KAAK,kBAAkB,mEAAmE;AAAA,UAC/F,mBAAmB;AAAA,UACnB,gBAAgB,YAAY;AAAA,UAC5B,SAAS,YAAY;AAAA,UACrB,OAAO,YAAY;AAAA,QACrB,CAAC;AAAA,MACH;AACA,aAAO,CAAC;AAAA,IACV;AAIF,UAAM,oBAAoB,CAAC,SAAiC;AAC1D,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,QAAQ,OAAO,EAAE;AAC/D,aAAO,QAAQ;AAAA,IACjB;AAGA,UAAM,oBAAoB,CAAC,SAAkC;AAI3D,UAAI,KAAK,eAAe,KAAK,YAAY,SAAS,KAAK,CAAC,KAAK,MAAM;AAEjE,cAAM,cAAc,KAAK,YACtB,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,IAAI,OAAK,CAAe;AAE3B,YAAI,YAAY,SAAS,GAAG;AAC1B,gBAAM,gBAAgB,iBAAiB,WAAW;AAClD,cAAI,CAAC,eAAe;AAClB,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAGA,UAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AACvC,cAAM,UAAU,KAAK,MAAM,KAAK,UAAQ;AACtC,cAAI,OAAO,SAAS,SAAU,QAAO;AAGrC,kBAAQ,KAAK,YAAY,GAAG;AAAA,YAC1B,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY;AAAA,YACrB,KAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY,cAAc,YAAY;AAAA,YAC/C,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY,gBAAgB,YAAY;AAAA,YACjD;AAEE,qBACE,YAAY,qBAAqB,QACjC,YAAY,iBAAiB,QAC7B,YAAY;AAAA,UAElB;AAAA,QACF,CAAC;AACD,YAAI,CAAC,SAAS;AACZ,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,UAAI,KAAK,aAAa;AACpB,YAAI,OAAO,KAAK,gBAAgB,UAAU;AAExC,gBAAM,cAAc,KAAK,YAAY,YAAY;AACjD,gBAAM,gBAAgB,YAAY;AAGlC,cAAI,YAAY,cAAc;AAAA,UAE9B,OAAO;AAGL,kBAAM,oBAAqD;AAAA,cACzD,UAAU;AAAA,cACV,eAAe;AAAA,cACf,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AACA,kBAAM,kBAAkB,gBAAiB,kBAAkB,aAAa,KAAK,WAAY;AAGzF,kBAAM,iBAAkD;AAAA,cACtD,QAAQ;AAAA,cACR,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO;AAAA,cACP,OAAO;AAAA,YACT;AACA,kBAAM,gBAAgB,eAAe,WAAW,KAAK;AACrD,kBAAM,YAAY,kBAAkB,eAAe,eAAe,KAAK,IAAI;AAE3E,gBAAI,YAAY,eAAe;AAC7B,qBAAO;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAKA,UAAI,KAAK,MAAM;AACb,cAAM,SAAS,KAAK,UAAU,kBAAkB,KAAK,IAAI;AACzD,YAAI,QAAQ;AAEV,gBAAM,iBAA6B,aAAa,MAAM;AAItD,gBAAMC,gBAAe,cAAc,GAAG,MAAM;AAC5C,gBAAM,oBAAoB,cAAc,cAAc,MAAM;AAC5D,gBAAM,qBAAqBA,iBAAgB;AAE3C,cAAI,CAAC,oBAAoB;AACvB,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAGA,UAAM,aAAa,CAAC,SAAgD;AAElE,UAAI,KAAK,MAAM,OAAQ,QAAO;AAG9B,UAAI,CAAC,kBAAkB,IAAI,EAAG,QAAO;AAGrC,UAAI;AACJ,UAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,2BAAmB,KAAK,SACrB,IAAI,WAAS,WAAW,KAAK,CAAC,EAC9B,OAAO,CAAC,UAAmC,UAAU,IAAI;AAG5D,YAAI,iBAAiB,WAAW,KAAK,CAAC,KAAK,MAAM;AAC/C,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU;AAAA,MACZ;AAAA,IACF;AAIA,UAAM,YAAY,SAAS,CAAC,GACzB,IAAI,UAAQ,WAAW,IAAI,CAAC,EAC5B,OAAO,CAAC,SAAiC,SAAS,IAAI;AAGzD,6BAAyB,UAAU;AAEnC,WAAO;AAAA,EACT,GAAG;AAAA,IACD;AAAA,IACA;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,sBAAsB;AAAA,EACxB,CAAC;AAOD,QAAM,4BAA4B,CAAC,OAA4B,SAAyB;AACtF,YAAQ,MAAM,KAAK;AAAA,MACjB,KAAK;AAAA,MACL,KAAK;AACH,cAAM,eAAe;AACrB,YAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,yBAAe,KAAK,EAAE;AAAA,QACxB,WAAW,KAAK,MAAM;AACpB,uBAAa,IAAI;AAAA,QACnB;AACA;AAAA,MACF,KAAK;AACH,YAAI,cAAc,IAAI,KAAK,EAAE,GAAG;AAC9B,yBAAe,KAAK,EAAE;AAAA,QACxB;AACA;AAAA,IACJ;AAAA,EACF;AAGA,QAAM,iBAAiB,CAAC,WAAmB;AACzC,UAAM,cAAc,IAAI,IAAI,aAAa;AACzC,QAAI,YAAY,IAAI,MAAM,GAAG;AAC3B,kBAAY,OAAO,MAAM;AAAA,IAC3B,OAAO;AACL,kBAAY,IAAI,MAAM;AAAA,IACxB;AACA,qBAAiB,WAAW;AAAA,EAC9B;AAGA,QAAM,kBAAkB,CAAC,SAAyB;AAGhD,QAAI,UAAU;AAAA,IAEd;AAGA,QAAI,CAAC,aAAa;AAEhB,UAAI,YAAY;AACd,mBAAW,IAAI;AAAA,MACjB,WAAW,KAAK,MAAM;AACpB,eAAO,SAAS,OAAO,KAAK;AAAA,MAC9B;AACA;AAAA,IACF;AAIA,UAAM,gBAAgB,cAAc,KAAK,cAAY,SAAS,OAAO,KAAK,EAAE;AAG5E,QAAI,CAAC,eAAe;AAClB,aAAO,KAAK,kBAAkB,+CAA+C;AAAA,QAC3E,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,MACb,CAAC;AACD;AAAA,IACF;AAIA,QAAI,gBAAgB;AAMpB,QAAI,KAAK,eAAe,KAAK,YAAY,SAAS,KAAK,eAAe,oBAAoB,iBAAiB,OAAO,KAAK,aAAa,EAAE,SAAS,GAAG;AAEhJ,YAAM,cAAc,KAAK,YACtB,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,IAAI,OAAK,CAAe;AAE3B,UAAI,YAAY,SAAS,GAAG;AAC1B,wBAAgB,iBAAiB,WAAW;AAAA,MAC9C;AAAA,IACF;AAGA,QAAI,CAAC,iBAAiB,aAAa;AAEjC,UAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AACvC,wBAAgB,KAAK,MAAM,KAAK,UAAQ;AACtC,cAAI,OAAO,SAAS,SAAU,QAAO;AAGrC,kBAAQ,KAAK,YAAY,GAAG;AAAA,YAC1B,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY;AAAA,YACrB,KAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY,cAAc,YAAY;AAAA,YAC/C,KAAK;AAAA,YACL,KAAK;AACH,qBAAO,YAAY,gBAAgB,YAAY;AAAA,YACjD;AAEE,qBACE,YAAY,qBAAqB,QACjC,YAAY,iBAAiB,QAC7B,YAAY;AAAA,UAElB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAKA,QAAI,CAAC,kBAAkB,CAAC,iBAAiB,OAAO,KAAK,aAAa,EAAE,WAAW,MAAM,eAAe;AAGlG,sBAAgB;AAAA,IAClB;AAEA,QAAI,CAAC,eAAe;AAElB,UAAI,0BAA0B;AAC5B,iCAAyB,IAAI;AAAA,MAC/B;AAEA,UAAI,YAAY;AACd,eAAO,MAAM,kBAAkB,gGAAgG;AAAA,UAC7H,QAAQ,KAAK;AAAA,UACb,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,aAAa,KAAK;AAAA,UAClB,OAAO,KAAK;AAAA,UACZ,aAAa,KAAK;AAAA,UAClB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAED,YAAI,uBAAuB;AACzB,gCAAsB,MAAM,0BAA0B;AAAA,QACxD;AAAA,MACF;AAEA;AAAA,IACF;AAEA,QAAI,YAAY;AACd,iBAAW,IAAI;AAAA,IACjB,WAAW,KAAK,MAAM;AAEpB,aAAO,SAAS,OAAO,KAAK;AAAA,IAC9B;AAAA,EACF;AAGA,QAAM,eAAe,CAAC,SAAkC;AACtD,QAAI,gBAAgB,KAAK,KAAM,QAAO;AACtC,QAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,aAAO,KAAK,SAAS,KAAK,WAAS,aAAa,KAAK,CAAC;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAGA,QAAM,yBAAyB,CAAC,WAAmB;AACjD,UAAM,OAAO,cAAc,KAAK,OAAK,EAAE,OAAO,MAAM;AACpD,QAAI,MAAM;AACR,sBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAGA,QAAM,yBAAyB,CAAC,MAAsB,QAAgB,MAAM;AAC1E,UAAM,cAAc,KAAK,YAAY,KAAK,SAAS,SAAS;AAC5D,UAAM,aAAa,cAAc,IAAI,KAAK,EAAE;AAC5C,UAAM,eAAe,aAAa,IAAI;AAEtC,WACE,gBAAAH,MAAC,QAAG,MAAK,QACN,wBACC,gBAAAC,OAAC,SACC;AAAA,sBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,eAAe,KAAK,EAAE;AAAA,UACrC,WAAW,CAAC,MAAM,0BAA0B,GAAG,IAAI;AAAA,UACnD,iBAAe;AAAA,UACf,iBAAe,WAAW,KAAK,EAAE;AAAA,UACjC,gBAAc,eAAe,SAAS;AAAA,UAEtC;AAAA,4BAAAD,MAAC,UAAM,eAAK,OAAM;AAAA,YAClB,gBAAAA,MAACI,cAAA,EAAY,eAAY,QAAO;AAAA;AAAA;AAAA,MAClC;AAAA,MAEC,cAAc,KAAK,YAClB,gBAAAJ;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,WAAW,KAAK,EAAE;AAAA,UACtB,MAAK;AAAA,UACL,cAAY,GAAG,KAAK,KAAK;AAAA,UAExB,eAAK,SAAS,IAAI,WACjB,gBAAAA,MAAO,kBAAN,EACE,iCAAuB,OAAO,QAAQ,CAAC,KADrB,MAAM,EAE3B,CACD;AAAA;AAAA,MACH;AAAA,OAEJ,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,KAAK,QAAQ;AAAA,QACnB,SAAS,CAAC,MAAM;AACd,cAAI,cAAc,KAAK,MAAM;AAC3B,cAAE,eAAe;AACjB,uBAAW,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,QACA,WAAW,CAAC,MAAM,0BAA0B,GAAG,IAAI;AAAA,QACnD,MAAK;AAAA,QACL,gBAAc,eAAe,SAAS;AAAA,QAErC,eAAK;AAAA;AAAA,IACR,GAEJ;AAAA,EAEJ;AAGA,MAAI,SAAS,YAAY;AACvB,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,eAAe;AAAA,QACf;AAAA,QACA,eAAY;AAAA,QAEZ;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL;AAAA,cACA,cAAY;AAAA,cACZ,eAAY;AAAA,cAEZ,0BAAAA,MAAC,eAAY,aAAa,YAAY;AAAA;AAAA,UACxC;AAAA,UACA,gBAAAA,MAAC,iBACE,wBAAc,IAAI,CAAC,SAAS;AAC3B,kBAAM,WAAW,aAAa,IAAI;AAClC,mBACE,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO,KAAK;AAAA,gBACZ,UAAU,CAAC,KAAK;AAAA,gBAChB,eAAa,wBAAwB,KAAK,EAAE;AAAA,gBAE3C,eAAK;AAAA;AAAA,cALD,KAAK;AAAA,YAMZ;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAGA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,cAAY;AAAA,MACX,GAAG;AAAA,MAEJ,0BAAAA,MAAC,QAAG,MAAK,WACN,wBAAc,IAAI,UACjB,gBAAAA,MAAO,kBAAN,EACE,iCAAuB,MAAM,CAAC,KADZ,KAAK,EAE1B,CACD,GACH;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,eAAe,cAAc;;;ACjmC7B,SAAS,YAAY;AAgLf,gBAAAK,OAwEE,QAAAC,cAxEF;AA1BC,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,WAAW,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AACF,GAAgB;AAEd,QAAM,kCAAkC,MAAM;AAC5C,UAAM,EAAE,eAAe,eAAe,IAAI,iBAAiB;AAE3D,QAAI,CAAC,kBAAkB,CAAC,iBAAiB,cAAc,WAAW,GAAG;AACnE,aAAO;AAAA,IACT;AACA,WACE,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,aAAY;AAAA,QACZ,WAAU;AAAA,QACV,eAAY;AAAA,QACZ,SAAS;AAAA;AAAA,IACX;AAAA,EAEJ;AAEA,SACE,gBAAAA,MAAC,YAAO,WAAW;AAAA,IACjB;AAAA,IACA;AAAA,EACF,GAAG,MAAK,UACN,0BAAAC,OAAC,SAAI,WAAU,8EAEV;AAAA,WACC,WACE,gBAAAD,MAAC,QAAK,IAAI,UAAU,WAAU,sDAC3B,gBACH,IAEA,OAEA,UACF,WACE,gBAAAA,MAAC,QAAK,IAAI,UAAU,WAAU,sDAC5B,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK,WAAW;AAAA,QAChB,WAAU;AAAA;AAAA,IACZ,GACF,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK,WAAW;AAAA,QAChB,WAAU;AAAA;AAAA,IACZ,IAGF,WACE,gBAAAA,MAAC,QAAK,IAAI,UAAU,WAAU,sDAC5B,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAI;AAAA,QACJ,KAAK,WAAW;AAAA,QAChB,WAAU;AAAA;AAAA,IACZ,GACF,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAI;AAAA,QACJ,KAAK,WAAW;AAAA,QAChB,WAAU;AAAA;AAAA,IACZ;AAAA,IAKH,YAAY,SAAS,SAAS,KAC7B,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,YAAW;AAAA,QACX,WAAU;AAAA,QACV,kBAAkB;AAAA;AAAA,IACpB;AAAA,IAKJ,gBAAAC,OAAC,SAAI,WAAU,mCAEZ;AAAA,wBACC,gBAAAD,MAAC,mCAAgC,IAC/B;AAAA,MAGH,oBACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAY;AAAA,UACZ,WAAU;AAAA,UACV,eAAY;AAAA;AAAA,MACd,IACE;AAAA,MAGH;AAAA,MAGA,iBACC,WACE,WAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,QAAQ;AAAA,UACd;AAAA,UACA;AAAA,UACA,WAAU;AAAA;AAAA,MACZ;AAAA,OAGN;AAAA,KAEF,GACF;AAEJ;;;AChSA,OAAOE,aAAW;AA4EZ,SAMI,YAAAC,WAJA,OAAAC,OAFJ,QAAAC,cAAA;AAfN,IAAM,kBAAyC,CAAC;AAAA,EAC9C,cAAc;AAAA,EACd,QAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC9B;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,gBAAgB,aAAa,4BAAoB,IAAI,yBAAyB,WAAW;AAE/F,SACE,gBAAAD,MAAC,YAAO,WAAW,GAAG,oEAAoE,SAAS,GAEjG,0BAAAC,OAAC,aAAQ,WAAU,2DAChB;AAAA,YACC,gBAAAD,MAAC,SAAI,KAAK,MAAM,KAAI,QAAO,WAAU,cAAa;AAAA,IAGnD,YACC,gBAAAA,MAAAD,WAAA,EACG,UACH;AAAA,IAGF,gBAAAC,MAAC,UAAK,WAAU,yBACb,yBACH;AAAA,IAEC,SAAS,MAAM,SAAS,KACvB,gBAAAA,MAAC,QAAG,WAAU,2BACX,gBAAM,IAAI,CAAC,MAAM,UAChB,gBAAAA,MAAC,QACC,0BAAAA,MAAC,OAAE,MAAM,KAAK,MAAM,WAAU,+CAC3B,eAAK,OACR,KAHO,KAIT,CACD,GACH;AAAA,KAEJ,GACF;AAEJ;AAEA,gBAAgB,cAAc;AAEvB,IAAM,SAASE,QAAM,KAAK,eAAe;AAChD,OAAO,cAAc;;;ACjGrB,SAAgB,YAAAC,YAAU,aAAAC,YAAW,WAAAC,gBAA4B;AACjE,SAAS,QAAQ,aAAa,mBAAmB;AAuvBzC,SA8CK,YAAAC,WA7CH,OAAAC,OADF,QAAAC,cAAA;AA1uBR,IAAM,wBAAwB,CAAC;AAC/B,IAAM,0BAA0B,CAAC;AAsO1B,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB;AAAA,EACA,gBAAgB;AAAA;AAAA,EAEhB,aAAa;AAAA,EACb,yBAAyB;AAAA,EACzB;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA;AAAA,EAEA,mBAAmB;AAAA,EACnB,cAAc,CAAC;AAAA,EACf,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,EAAE,MAAM,SAAS,gBAAgB,UAAU,OAAO,cAAc,uBAAuB,IAAI,eAAe;AAChH,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,IAAI,iBAAiB;AAIrB,QAAM,EAAE,cAAc,sBAAsB,WAAW,YAAY,IAAI,QAAQ;AAI/E,QAAM,CAAC,oBAAoB,qBAAqB,IAAIC,WAAkB,KAAK;AAC3E,QAAM,CAAC,4BAA4B,6BAA6B,IAAIA,WAAkB,KAAK;AAE3F,EAAAC,WAAU,MAAM;AACd,UAAM,wBAAwB,YAAY;AACxC,UAAI,CAAC,MAAM,IAAI;AACb,8BAAsB,KAAK;AAC3B,sCAA8B,KAAK;AACnC;AAAA,MACF;AAGA,UAAI,sBAAsB;AACxB,sCAA8B,KAAK;AACnC;AAAA,MACF;AAEA,oCAA8B,IAAI;AAClC,UAAI;AACF,cAAM,mBAAmB,MAAM,aAAmB,KAAK,EAAE;AACzD,8BAAsB,gBAAgB;AAAA,MACxC,SAAS,OAAO;AACd,eAAO,MAAM,iBAAiB,8CAA8C,EAAE,QAAQ,MAAM,IAAI,MAAM,CAAC;AACvG,8BAAsB,KAAK;AAAA,MAC7B,UAAE;AACA,sCAA8B,KAAK;AAAA,MACrC;AAAA,IACF;AAEA,0BAAsB;AAAA,EACxB,GAAG,CAAC,MAAM,IAAI,oBAAoB,CAAC;AAGnC,QAAMC,gBAAe,wBAAwB;AAC7C,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,YAAY;AAG7B,gBAAc;AAGd,MAAI,gBAA6C;AACjD,MAAI;AACF,UAAM,gBAAgB,UAAU;AAChC,oBAAgB,cAAc;AAAA,EAChC,SAAS,OAAO;AAAA,EAEhB;AAGA,QAAM,EAAE,eAAe,WAAW,aAAa,IAAI,iBAAiB;AAAA,IAClE,UAAU,YAAY;AAAA,IACtB,wBAAwB,sBAAsB,MAAM;AAAA,IACpD,iBAAiB,eAAe,YAAY;AAAA,EAC9C,CAAC;AAID,QAAM,gBAAgB,gBAAgB,eAAe;AAMrD,QAAM,aAAa,eAAe,kBAAkB,sBAAsB,MAAM;AAChF,QAAM,eAAe,eAAe,WAAW,eAAe,YAAY;AAC1E,QAAM,aAAa,eAAe,SAAS,iBAAiB;AAE5D,QAAM,QAAQC,SAAe,MAAM;AACjC,UAAM,WAAkB,CAAC;AACzB,QAAI,YAAY;AACd,eAAS,iBAAiB;AAAA,IAC5B;AACA,QAAI,cAAc;AAChB,eAAS,UAAU;AAAA,IACrB;AACA,QAAI,YAAY;AACd,eAAS,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,cAAc,UAAU,CAAC;AAGzC,QAAM,kBAAoCA,SAAQ,MAAM;AAAA,IACtD,EAAE,IAAI,QAAQ,OAAO,QAAQ,MAAM,KAAK,MAAM,OAAO;AAAA,IACrD,EAAE,IAAI,aAAa,OAAO,aAAa,MAAM,cAAc,MAAM,kBAAkB;AAAA,IACnF,EAAE,IAAI,YAAY,OAAO,YAAY,MAAM,aAAa,MAAM,WAAW;AAAA,IACzE,EAAE,IAAI,eAAe,OAAO,eAAe,MAAM,gBAAgB,MAAM,YAAY;AAAA,IACnF,EAAE,IAAI,uBAAuB,OAAO,sBAAsB,MAAM,wBAAwB,MAAM,QAAQ;AAAA,EACxG,GAAG,CAAC,CAAC;AAGL,QAAM,gBAAgBA,SAAQ,MAAM,YAAY,iBAAiB,CAAC,QAAQ,CAAC;AAG3E,QAAM,yBAAyBA,SAAQ,MAAM;AAC3C,UAAM,cAAc,SAAS;AAC7B,WAAO,iBAAiB,WAAW,KAAK;AAAA,EAC1C,GAAG,CAAC,SAAS,UAAU,kBAAkB,iBAAiB,CAAC;AAK3D,QAAM,gBAAgBA,SAAQ,MAAM;AAClC,UAAM,cAAc,SAAS;AAE7B,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,cAAc,WAAW;AAAA,IAClC;AAEA,UAAM,eAAe,YAAY,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAGnE,WAAO,aAAa,CAAC,KAAK;AAAA,EAC5B,GAAG,CAAC,SAAS,UAAU,aAAa,CAAC;AAGrC,QAAM,oBAAoBA,SAAoB,MAAM;AAGlD,QAAI,CAAC,sBAAsB,CAAC,eAAe;AACzC,aAAO;AAAA,IACT;AACA,UAAM,mBAAmB,GAAG,sBAAsB,SAAS,aAAa;AACxE,WAAO;AAAA,EACT,GAAG,CAAC,oBAAoB,wBAAwB,aAAa,CAAC;AAW9D,QAAM,wBAAwB,sBAAsB,CAAC,CAAC,qBAAqB,CAAC,CAAC;AAC7E,QAAM,EAAE,KAAK,aAAa,WAAW,sBAAsB,OAAO,gBAAgB,IAAI;AAAA,IACpF,MAAM,MAAM;AAAA,IACZ;AAAA,IACA,wBAAwB,oBAAqB;AAAA,IAC7C,wBAAwB,gBAAgB;AAAA,IACxC;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AAKA,QAAM,MAAMD,gBAAe,OAAO;AAClC,QAAM,gBAAgB,qBAAqB,MAAM;AAGjD,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,oBAAoB;AACvB;AAAA,IACF;AAKA,QAAI,sBAAsB;AACxB;AAAA,IACF;AAIA,QAAI,cAAc,CAACC,iBAAgB,CAAC,KAAK;AACvC,aAAO,MAAM,iBAAiB,qFAAqF;AAAA,QACjH,UAAU;AAAA,QACV,WAAW;AAAA,QACX,QAAQ,MAAM;AAAA,QACd,cAAcA;AAAA,QACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAED,UAAI,uBAAuB;AACzB,8BAAsB,eAAe,sBAAsB;AAAA,MAC7D;AAAA,IACF;AAGA,QAAI,CAACA,iBAAgB,CAAC,OAAO,oBAAoB;AAC/C,yBAAmB,eAAe,sBAAsB;AAAA,IAC1D;AAAA,EACF,GAAG,CAAC,oBAAoB,KAAK,sBAAsBA,eAAc,eAAe,wBAAwB,MAAM,IAAI,YAAY,UAAU,oBAAoB,qBAAqB,CAAC;AAIlL,QAAM,CAAC,mBAAmB,oBAAoB,IAAIF,WAA2B,aAAa;AAE1F,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AAEhB,UAAM,cAAc,YAAY;AAG9B,UAAI,CAAC,MAAM,IAAI;AAEb,YAAI,WAAW;AACb,+BAAqB,aAAa;AAAA,QACpC;AACA;AAAA,MACF;AAIA,YAAM,eAAe;AAMrB,YAAM,WAAW,aAAa,SAAS;AAIvC,YAAM,yBAAyB,aAAa;AAC5C,YAAM,UAAU,CAAC,CAAC,MAAM;AAKxB,UAAI,CAAC,SAAS;AAEZ,YAAI,WAAW;AACb,+BAAqB,aAAa;AAAA,QACpC;AACA;AAAA,MACF;AAKA,UAAI,CAAC,wBAAwB;AAC3B,YAAI,WAAW;AAGb,+BAAqB,aAAa;AAAA,QACpC;AACA;AAAA,MACF;AAIA,UAAI;AACF,cAAM,EAAE,cAAc,uBAAuB,IAAI,MAAM,OAAO,mBAAgB;AAC9E,cAAM,UAAU,MAAM,uBAAuB,KAAK,EAAE;AAEpD,YAAI,SAAS;AAEX,cAAI,WAAW;AACb,iCAAqB,aAAa;AAAA,UACpC;AACA;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AAGd,YAAI,SAAS,OAAO,UAAU,YAAY,UAAU,SAAS,MAAM,SAAS,wBAAwB;AAAA,QAGpG,OAAO;AAEL,gBAAM;AAAA,QACR;AAAA,MACF;AAMA,UAAI;AACF,cAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,mBAAgB;AAI1D,cAAM,kBAAyB;AAAA,UAC7B,gBAAgB,aAAa;AAAA,UAC7B,SAAS,aAAa;AAAA,UACtB,OAAO,aAAa,SAAS,iBAAiB;AAAA;AAAA,QAChD;AAEA,cAAM,gBAAgB,MAAM,iBAAiB;AAAA,UAC3C,QAAQ,KAAK;AAAA,UACb,OAAO;AAAA,QACT,CAAC;AAGD,cAAM,WAAW,cAAc,IAAI,CAAC,SAAS;AAC3C,cAAI,CAAC,KAAK,KAAM,QAAO,EAAE,MAAM,WAAW,KAAK;AAI/C,gBAAM,SAAS,cAAc,KAAK,IAAI,MAAM,KAAK,SAAS,MAAM,cAAc,KAAK,KAAK,MAAM,CAAC,MAAM;AACrG,gBAAM,aAAa,iBAAiB,KAAK,IAAI,KAAK;AAClD,gBAAM,iBAA6B,WAAW,SAAS,GAAG,IACrD,aACA,SAAS,GAAG,UAAU,SAAS,MAAM,KAAK;AAG/C,gBAAM,YAAY,cAAc,GAAG,MAAM,QAAQ,cAAc,cAAc,MAAM;AAEnF,iBAAO,EAAE,MAAM,UAAU;AAAA,QAC3B,CAAC;AAED,YAAI,CAAC,UAAW;AAEhB,cAAM,kBAAkB,SACrB,OAAO,CAAC,EAAE,UAAU,MAAM,SAAS,EACnC,IAAI,CAAC,EAAE,KAAK,MAAM,IAAI;AAKzB,6BAAqB,eAAe;AAAA,MACtC,SAAS,OAAO;AAGd,eAAO,MAAM,iBAAiB,0DAA0D,EAAE,QAAQ,MAAM,IAAI,MAAM,CAAC;AACnH,YAAI,WAAW;AACb,+BAAqB,aAAa;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAEA,gBAAY;AAEZ,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,eAAe,eAAe,kBAAkB,mBAAmB,KAAK,MAAM,IAAI,OAAO,cAAc,cAAc,eAAe,OAAO,sBAAsB,EAAE,CAAC;AAIxK,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,oBAAoB,YAAY,WAAW,EAAG;AAEnD,QAAI,YAAY;AAEhB,UAAM,mBAAmB,YAAY;AACnC,YAAM,cAAc,SAAS;AAC7B,YAAM,eAAe,YAAY,KAAK,WAAS,MAAM,SAAS,WAAW;AAEzE,UAAI,CAAC,cAAc;AAEjB,YAAI,YAAY;AACd,iBAAO,MAAM,iBAAiB,2DAA2D;AAAA,YACvF,OAAO;AAAA,YACP,QAAQ,MAAM;AAAA,YACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AAED,cAAI,4BAA4B;AAC9B,uCAA2B,aAAa,kCAAkC;AAAA,UAC5E;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,YAAY;AAGhB,UAAI,aAAa,UAAU,aAAa,eAAe,aAAa,YAAY,SAAS,GAAG;AAG1F,YAAI;AACF,gBAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,mBAAgB;AAC3D,gBAAM,oBAAoB,MAAM,kBAAkB;AAAA,YAChD,QAAQ,MAAM,MAAM;AAAA,YACpB;AAAA,YACA,YAAY,aAAa,YAAY,CAAC;AAAA,YACtC,QAAQ,aAAa;AAAA,UACvB,CAAC;AACD,cAAI,CAAC,UAAW;AAChB,sBAAY;AAAA,QACd,SAAS,OAAO;AACd,iBAAO,MAAM,iBAAiB,mCAAmC,EAAE,OAAO,aAAa,QAAQ,aAAa,QAAQ,MAAM,CAAC;AAC3H,cAAI,CAAC,UAAW;AAChB,sBAAY;AAAA,QACd;AAAA,MACF;AAGA,UAAI,aAAa,aAAa,SAAS,aAAa,MAAM,SAAS,KAAK,MAAM,IAAI;AAChF,cAAM,EAAE,gBAAAG,gBAAe,IAAI,MAAM,OAAO,mCAA8C;AAItF,oBAAY;AAAA,MACd;AAEA,UAAI,CAAC,UAAW;AAEhB,UAAI,CAAC,WAAW;AAEd,YAAI,qBAAqB;AACvB,8BAAoB,aAAa,0BAA0B;AAAA,QAC7D;AAEA,YAAI,YAAY;AACd,iBAAO,MAAM,iBAAiB,sFAAsF;AAAA,YAClH,OAAO;AAAA,YACP,QAAQ,MAAM;AAAA,YACd,aAAa,aAAa;AAAA,YAC1B,OAAO,aAAa;AAAA,YACpB,aAAa,aAAa;AAAA,YAC1B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AAED,cAAI,4BAA4B;AAC9B,uCAA2B,aAAa,0BAA0B;AAAA,UACpE;AAAA,QACF;AAGA,iBAAS,eAAe,EAAE,SAAS,KAAK,CAAC;AACzC;AAAA,MACF;AAAA,IACF;AAEA,qBAAiB;AAEjB,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,kBAAkB,aAAa,SAAS,UAAU,YAAY,MAAM,IAAI,eAAe,OAAO,UAAU,UAAU,qBAAqB,0BAA0B,CAAC;AAEtK,QAAM,gBAAgB,YAAY;AAChC,UAAM,QAAQ;AAAA,EAChB;AAEA,QAAM,uBAAuB,OAAO,aAAqB,oBAA4B;AAEnF,UAAM,SAAS,MAAM,eAAe,WAAW;AAC/C,QAAI,QAAQ,OAAO;AAEjB,aAAO,MAAM,iBAAiB,6BAA6B,EAAE,OAAO,OAAO,MAAM,QAAQ,CAAC;AAE1F,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS,OAAO,MAAM;AAAA,UACtB,MAAM,OAAO,MAAM,QAAQ;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,WAAO,CAAC;AAAA,EACV;AAkBA,MAAI,MAAM,MAAM,uBAAuB,CAACF,iBAAgB,CAAC,8BAA8B,CAAC,eAAe,CAAC,wBAAwB;AAC9H,WACE,gBAAAJ,MAAC,SAAI,WAAU,iDACb,0BAAAC,OAAC,SAAI,WAAU,eACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,2EAA0E;AAAA,MACzF,gBAAAA,MAAC,OAAE,WAAU,gBAAe,6CAA+B;AAAA,OAC7D,GACF;AAAA,EAEJ;AAUA,MAAI,sBAAsB,sBAAsB;AAC9C,WACE,gBAAAA,MAAC,SAAI,WAAU,iDACb,0BAAAC,OAAC,SAAI,WAAU,eACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,2EAA0E;AAAA,MACzF,gBAAAA,MAAC,OAAE,WAAU,gBAAe,qCAAuB;AAAA,OACrD,GACF;AAAA,EAEJ;AAIA,MAAI,sBAAsB,mBAAmB,CAACI,eAAc;AAC1D,WACE,gBAAAJ,MAAC,SAAI,WAAU,iDACb,0BAAAC,OAAC,SAAI,WAAU,eACb;AAAA,sBAAAD,MAAC,QAAG,WAAU,2CAA0C,8BAAgB;AAAA,MACxE,gBAAAA,MAAC,OAAE,WAAU,qBAAqB,0BAAgB,SAAQ;AAAA,MAC1D,gBAAAA,MAAC,UAAO,SAAS,MAAM,SAAS,GAAG,GAAG,qBAAO;AAAA,OAC/C,GACF;AAAA,EAEJ;AAIA,MAAI,sBAAsB,kBAAkB,SAAS,CAAC,8BAA8B,CAACI,eAAc;AAEjG,QAAI,0BAA0B,wBAAwB;AACpD,aAAO,gBAAAJ,MAAAD,WAAA,EAAG,kCAAuB;AAAA,IACnC;AAEA,QAAI,oBAAoB;AACtB,aAAO,gBAAAC,MAAAD,WAAA,EAAG,8BAAmB;AAAA,IAC/B;AAEA,WACE,gBAAAC,MAAC,SAAI,WAAU,iDACb,0BAAAC,OAAC,SAAI,WAAU,eACb;AAAA,sBAAAD,MAAC,QAAG,WAAU,2CAA0C,2BAAa;AAAA,MACrE,gBAAAA,MAAC,OAAE,WAAU,qBAAoB,4DAEjC;AAAA,MACA,gBAAAC,OAAC,SAAI,WAAU,6BACb;AAAA,wBAAAD,MAAC,UAAO,SAAS,MAAM,SAAS,GAAG,GAAG,qBAAO;AAAA,QAC7C,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,SAAS,YAAY;AACnB,oBAAM,cAAc;AACpB,uBAAS,QAAQ;AAAA,YACnB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,SACF;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE,gBAAAC,OAAAF,WAAA,EACE;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,cAAc;AAAA,QACpB,SAAS,CAAC,aAAa,IAAI,QAAQ,YAAY,CAAC,mBAAmB;AAAA,QACnE,SAAS,GAAG,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV;AAAA,QACA,WAAW;AAAA,QACX,kBAAkB;AAAA,QAClB,aAAa,OAAO,SAAS;AAAA,QAC7B,YAAY,CAAC,SAAS;AACpB,cAAI,KAAK,MAAM;AACb,qBAAS,KAAK,IAAI;AAAA,UACpB;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,mBAAmB;AAAA;AAAA,IAChC;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,oDACd,0BAAAA,MAAC,UAAO,GACV;AAAA,IACA,gBAAAA,MAAC,UAAO;AAAA,KACV;AAEJ;;;AC30BA,SAAgB,aAAAO,YAAW,YAAAC,YAAU,cAAAC,mBAAkB;AACvD,SAAS,eAAAC,cAAa,eAAAC,oBAAmB;AAwOrC,SACE,OAAAC,OADF,QAAAC,cAAA;AA9LG,IAAM,gBAA8C,CAAC;AAAA,EAC1D,UAAU;AAAA,EACV,wBAAwB;AAAA,EACxB,mBAAmB;AACrB,MAAM;AACJ,QAAM,EAAE,QAAQ,iBAAiB,WAAW,WAAW,MAAM,SAAS,IAAI,eAAe;AAEzF,QAAM,WAAWC,aAAY;AAC7B,QAAM,WAAWC,aAAY;AAC7B,QAAM,CAAC,aAAa,cAAc,IAAIC,WAAS,KAAK;AACpD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAwB,IAAI;AAClE,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,WAAS,KAAK;AAI9D,QAAM,sBAAsBC,YAAW,mBAAmB;AAC1D,QAAM,eAAe,qBAAqB,gBAAgB;AAI1D,EAAAC,WAAU,MAAM;AACd,iBAAa;AAAA,EACf,GAAG,CAAC,CAAC;AAIL,EAAAA,WAAU,MAAM;AACd,UAAM,gBAAgB,SAAS,aAAa,YAAY,SAAS,SAAS,WAAW,QAAQ;AAC7F,QAAI,eAAe;AACjB,mBAAa;AAAA,IACf;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,CAAC;AAItB,EAAAA,WAAU,MAAM;AACd,UAAM,eAAe,YAAY;AAC/B,UAAI;AACF,cAAM,gBAAgB,OAAO,SAAS,aAAa,YAAY,OAAO,SAAS,SAAS,WAAW,QAAQ;AAC3G,YAAI,iBAAiB,cAAc;AACjC,gBAAM,aAAa,sBAAsB;AAAA,QAC3C;AAAA,MACF,SAAS,OAAO;AAAA,MAEhB;AAAA,IACF;AAGA,UAAM,YAAY,WAAW,MAAM;AACjC,mBAAa;AAAA,IACf,GAAG,GAAG;AAEN,WAAO,MAAM,aAAa,SAAS;AAAA,EACrC,GAAG,CAAC,YAAY,CAAC;AAGjB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,oBAAoB,CAAC,mBAAmB,aAAa,CAAC,QAAQ,CAAC,UAAU;AAC5E;AAAA,IACF;AAEA,UAAM,cAAc,YAAY;AAC9B,0BAAoB,IAAI;AACxB,qBAAe,IAAI;AAEnB,UAAI;AACF,cAAM,SAAS,KAAK;AACpB,eAAO,MAAM,iBAAiB,mCAAmC,EAAE,SAAS,OAAO,CAAC;AAGpF,cAAM,kBAAkB,MAAM,aAAa,MAAM;AAEjD,YAAI,iBAAiB;AACnB,iBAAO,MAAM,iBAAiB,sCAAsC;AACpE,8BAAoB,KAAK;AACzB,mBAAS,uBAAuB,EAAE,SAAS,KAAK,CAAC;AACjD;AAAA,QACF;AAGA,cAAM,EAAE,MAAM,SAAS,OAAO,SAAS,IAAI,MAAM,SAC9C,KAAK,WAAW,EAChB,OAAO,qBAAqB,EAC5B,GAAG,QAAQ,OAAO,EAClB,GAAG,aAAa,IAAI,EACpB,OAAO;AAEV,YAAI,YAAY,CAAC,SAAS;AACxB,iBAAO,MAAM,iBAAiB,kBAAkB,EAAE,SAAS,OAAO,SAAS,CAAC;AAC5E,yBAAe,gBAAgB,OAAO,yDAAyD;AAC/F,8BAAoB,KAAK;AACzB;AAAA,QACF;AAGA,cAAM,EAAE,MAAM,WAAW,OAAO,WAAW,IAAI,MAAM,SAClD,KAAK,gBAAgB,EACrB,OAAO,eAAe,EACtB,GAAG,UAAU,QAAQ,EAAE;AAE1B,YAAI,cAAc,CAAC,aAAa,UAAU,WAAW,GAAG;AACtD,yBAAe,wCAAwC,OAAO,uHAAuH;AACrL,8BAAoB,KAAK;AACzB;AAAA,QACF;AAGA,cAAM,EAAE,MAAM,OAAO,IAAI,MAAM,SAC5B,KAAK,yBAAyB,EAC9B,OAAO,iBAAiB,EACxB,GAAG,WAAW,MAAM,EACpB,GAAG,UAAU,QAAQ,EACrB,GAAG,cAAc,IAAI,EACrB,MAAM,CAAC,EACP,YAAY;AAEf,cAAM,iBAAiB,QAAQ;AAE/B,YAAI,CAAC,gBAAgB;AACnB,yBAAe,wCAAwC,OAAO,gFAAgF;AAC9I,8BAAoB,KAAK;AACzB;AAAA,QACF;AAIA,YAAI,eAAe;AACnB,mBAAW,QAAQ,WAAW;AAC5B,gBAAM,EAAE,MAAM,eAAe,OAAO,UAAU,IAAI,MAAM,SACrD,IAAI,oCAAoC;AAAA,YACvC,WAAW;AAAA,YACX,cAAc,aAAa,KAAK,SAAS;AAAA;AAAA,YACzC,mBAAmB;AAAA,YACnB,YAAY;AAAA,YACZ,UAAU,QAAQ;AAAA,YAClB,WAAW,KAAK;AAAA;AAAA,UAClB,CAAC;AAEH,cAAI,CAAC,aAAa,kBAAkB,MAAM;AACxC,2BAAe;AACf;AAAA,UACF;AAAA,QACF;AAEA,YAAI,cAAc;AAChB,8BAAoB,KAAK;AACzB,mBAAS,uBAAuB,EAAE,SAAS,KAAK,CAAC;AACjD;AAAA,QACF;AAGA,uBAAe,wCAAwC,OAAO,qIAAqI;AACnM,4BAAoB,KAAK;AAAA,MAC3B,SAAS,OAAO;AACd,eAAO,MAAM,iBAAiB,8BAA8B,KAAK;AACjE,uBAAe,yFAAyF;AACxG,4BAAoB,KAAK;AAAA,MAC3B;AAAA,IACF;AAEA,gBAAY;AAAA,EACd,GAAG,CAAC,iBAAiB,WAAW,MAAM,UAAU,SAAS,kBAAkB,UAAU,qBAAqB,CAAC;AAE3G,QAAM,eAAe,OAAO,SAA8C;AACxE,mBAAe,IAAI;AACnB,mBAAe,IAAI;AAEnB,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,OAAO,KAAK,OAAO,KAAK,QAAQ;AAExD,UAAI,OAAO;AAET,cAAM;AAAA,MACR;AAIA,UAAI,CAAC,kBAAkB;AACrB,YAAI;AACF,mBAAS,uBAAuB,EAAE,SAAS,KAAK,CAAC;AAAA,QACnD,SAAS,UAAU;AACjB,iBAAO,MAAM,iBAAiB,mCAAmC,QAAQ;AAAA,QAC3E;AAAA,MACF;AAAA,IACF,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,SACE,gBAAAL,OAAC,UAAK,WAAU,+EAA8E,cAAY,GAAG,OAAO,eAClH;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,IAAI,QAAQ,YAAY,CAAC;AAAA,QAC9B,KAAK,GAAG,OAAO;AAAA,QACf,WAAU;AAAA;AAAA,IACZ;AAAA,IAEE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAAU,WAAU;AAAA,QACnB,UAAU;AAAA,QACV;AAAA,QACA,WAAW;AAAA,QACX,SAAS,CAAC,UAAU;AAElB,iBAAO,MAAM,iBAAiB,gBAAgB,KAAK;AAAA,QACrD;AAAA;AAAA,IACF;AAAA,KACE,MAAM;AACN,YAAM,SAAS,CAAC,EAAE,cAChB,UAAU,SAAS,6BAA6B,wBAAwB,KAAK,UAAU,OAAO;AAEhG,aAAO,aAAa,CAAC,SACnB,gBAAAA,MAAC,QAAG,WAAU,qCAAqC,oBAAU,SAAQ,IACnE;AAAA,IACN,GAAG;AAAA,IACF,eACC,gBAAAA,MAAC,QAAG,WAAU,qCACX,uBACH;AAAA,IAED,oBACC,gBAAAA,MAAC,QAAG,WAAU,0CAAyC,qCAEvD;AAAA,KAEN;AAEJ;;;ACnVI,SASE,OAAAO,OATF,QAAAC,cAAA;AALG,IAAM,2BAAoE,CAAC;AAAA,EAChF,UAAU;AAAA,EACV;AACF,MAAM;AACJ,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAY;AAAA,MAEZ;AAAA,wBAAAD,MAAC,kBAAe,MAAK,MAAK;AAAA,QAC1B,gBAAAA,MAAC,SAAI,WAAU,wBACZ,mBACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACEA,SAAgB,WAAAE,WAAS,aAAAC,aAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AAC5D,SAAS,UAAU,UAAAC,eAAc;AAwLtB,gBAAAC,OAuFH,QAAAC,cAvFG;AA1HJ,SAAS,eAAe;AAAA,EAC7B,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAAwB;AACtB,QAAM,EAAE,iBAAiB,UAAU,IAAI,eAAe;AAItD,QAAM,gBAAgB,UAAU;AAChC,QAAM,gBAAgB,eAAe,cAAc,gBAAgB;AACnE,QAAM,SAAS,eAAgB,cAAc,UAAU,CAAC,IAAK,CAAC;AAC9D,QAAM,eAAe,eAAgB,cAAc,aAAa,QAAS;AAEzE,QAAM,qBAAqB,sBAAsB;AAGjD,sBAAoB,EAAE,SAAS,MAAM,eAAe,IAAK,CAAC;AAG1D,QAAM,sBAAsBC,QAAO,KAAK;AACxC,QAAM,CAAC,gBAAgB,iBAAiB,IAAIC,WAAS,KAAK;AAC1D,QAAM,0BAA0BD,QAAO,KAAK;AAG5C,EAAAE,YAAU,MAAM;AACd,QAAI,iBAAiB;AACnB,0BAAoB,UAAU;AAC9B,wBAAkB,KAAK;AACvB,8BAAwB,UAAU;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAIpB,EAAAA,YAAU,MAAM;AACd,QAAI,OAAO,aAAa,YAAa;AAErC,QAAI,YAAkD;AACtD,QAAI,YAAY,SAAS;AAEzB,UAAM,yBAAyB,MAAM;AACnC,YAAM,eAAe,CAAC,SAAS;AAG/B,UAAI,gBAAgB,WAAW;AAE7B,YAAI,CAAC,mBAAmB,oBAAoB,SAAS;AACnD,kCAAwB,UAAU;AAClC,4BAAkB,KAAK;AAGvB,cAAI,WAAW;AACb,yBAAa,SAAS;AAAA,UACxB;AAGA,sBAAY,WAAW,MAAM;AAE3B,oCAAwB,UAAU;AAElC,8BAAkB,CAAC,SAAS;AAG1B,qBAAO;AAAA,YACT,CAAC;AAAA,UACH,GAAG,GAAI;AAAA,QACT;AAAA,MACF,WAAW,CAAC,cAAc;AAExB,gCAAwB,UAAU;AAClC,YAAI,WAAW;AACb,uBAAa,SAAS;AACtB,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,kBAAY,CAAC;AAAA,IACf;AAGA,QAAI,CAAC,SAAS,UAAU,CAAC,mBAAmB,oBAAoB,SAAS;AACvE,8BAAwB,UAAU;AAClC,wBAAkB,KAAK;AACvB,kBAAY,WAAW,MAAM;AAC3B,gCAAwB,UAAU;AAAA,MACpC,GAAG,GAAI;AAAA,IACT;AAEA,aAAS,iBAAiB,oBAAoB,sBAAsB;AACpE,WAAO,MAAM;AACX,eAAS,oBAAoB,oBAAoB,sBAAsB;AACvE,UAAI,WAAW;AACb,qBAAa,SAAS;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,EAAAA,YAAU,MAAM;AACd,QAAI,iBAAiB;AACnB,wBAAkB,KAAK;AACvB,8BAAwB,UAAU;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAEpB,QAAM,qBAAqBC,UAAQ,MAAM;AACvC,WAAO,mBAAmB,eACxB,CAAC,mBAAmB,uBACpB,CAAC,mBAAmB,oBACpB,CAAC,mBAAmB;AAAA,EACxB,GAAG;AAAA,IACD,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,EACrB,CAAC;AAGD,MAAI,oBAAoB;AACtB,WAAO,gBAAAL,MAAC,4BAAyB;AAAA,EACnC;AAIA,MAAI,gBAAgB,cAAc;AAChC,WAAO,gBAAAA,MAACM,SAAA,EAAO;AAAA,EACjB;AAIA,MAAI,aAAa,CAAC,mBAAmB,aAAa;AAChD,WAAO,mBACL,gBAAAN,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,UAAU,YAAY,UAAU,QAAQ,QAAQ,GAC7F,0BAAAA,MAAC,kBAAe,GAClB;AAAA,EAEJ;AAUA,MAAI,CAAC,iBAAiB;AAEpB,QAAI,mBAAmB,eAAe,mBAAmB,kBAAkB;AACzE,aAAO,KAAK,kBAAkB,oDAAoD;AAAA,QAChF,UAAU,mBAAmB;AAAA,QAC7B,OAAO,mBAAmB,kBAAkB;AAAA,MAC9C,CAAC;AACD,aAAO,gBAAAA,MAAC,YAAS,IAAI,WAAW,SAAO,MAAC;AAAA,IAC1C;AAGA,QAAI,CAAC,oBAAoB,SAAS;AAChC,aAAO,gBAAAA,MAAC,YAAS,IAAI,WAAW,SAAO,MAAC;AAAA,IAC1C;AAIA,UAAM,eAAe,OAAO,aAAa,eAAe,CAAC,SAAS;AAClE,QAAI,wBAAwB,WAAY,gBAAgB,oBAAoB,WAAW,WAAY;AACjG,aAAO,mBACL,gBAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,UAAU,YAAY,UAAU,QAAQ,QAAQ,GAC7F,0BAAAA,MAAC,kBAAe,GAClB;AAAA,IAEJ;AAGA,QAAI,gBAAgB;AAClB,aAAO,gBAAAA,MAAC,YAAS,IAAI,WAAW,SAAO,MAAC;AAAA,IAC1C;AAIA,QAAI,WAAW;AACb,aAAO,mBACL,gBAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,UAAU,YAAY,UAAU,QAAQ,QAAQ,GAC7F,0BAAAA,MAAC,kBAAe,GAClB;AAAA,IAEJ;AAGA,WAAO,gBAAAA,MAAC,YAAS,IAAI,WAAW,SAAO,MAAC;AAAA,EAC1C;AAGA,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAAA,MAACM,SAAA,EAAO;AAAA,EACjB;AASA,MAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,WAAO,oBACL,gBAAAN,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,UAAU,YAAY,UAAU,WAAW,SAAS,SAAS,OAAO,GACjH,0BAAAC,OAAC,SAAM,SAAQ,eAAc,WAAU,YACrC;AAAA,sBAAAD,MAAC,cAAW,iCAAmB;AAAA,MAC/B,gBAAAA,MAAC,oBAAiB,qHAElB;AAAA,OACF,GACF;AAAA,EAEJ;AASA,MAAI,CAAC,eAAe;AAElB,WAAO,gBAAAA,MAACM,SAAA,EAAO;AAAA,EACjB;AAGA,SAAO,gBAAAN,MAACM,SAAA,EAAO;AACjB;;;ACrWA,SAAgB,YAAAC,YAAU,eAAAC,eAAa,UAAAC,SAAQ,aAAAC,aAAW,WAAAC,iBAAe;AA2c7D,SAgBI,YAAAC,WAhBJ,OAAAC,OAgBI,QAAAC,cAhBJ;AAnaL,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,UAAU,KAAK,OAAO;AAAA;AAAA,EACtB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,CAAC,YAAY,aAAa,IAAIC,WAAS,KAAK;AAClD,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAuC,oBAAI,IAAI,CAAC;AACxF,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAwB,UAAU,IAAI;AAChF,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,WAAS,CAAC,MAAM;AAChE,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAwB,IAAI;AAChE,QAAM,eAAeC,QAAyB,IAAI;AAClD,QAAM,EAAE,YAAY,WAAW,MAAM,IAAI,iBAAiB,QAAQ;AAGlE,EAAAC,YAAU,MAAM;AACd,QAAI,QAAQ;AAEV,uBAAiB,MAAM;AACvB,0BAAoB,KAAK;AACzB,oBAAc,IAAI;AAClB;AAAA,IACF;AAGA,UAAM,eAAe,YAAY;AAC/B,0BAAoB,IAAI;AACxB,oBAAc,IAAI;AAElB,UAAI;AACF,cAAM,UAAU,kBAAkB;AAClC,YAAI,CAAC,SAAS;AACZ,gBAAM,WAAW;AACjB,wBAAc,QAAQ;AACtB,8BAAoB,KAAK;AACzB;AAAA,QACF;AAEA,cAAM,aAAa,MAAM,SAAS,UAAU,OAAO;AACnD,YAAI,CAAC,YAAY;AACf,gBAAM,WAAW,0CAA0C,OAAO;AAClE,wBAAc,QAAQ;AACtB,8BAAoB,KAAK;AACzB;AAAA,QACF;AAEA,yBAAiB,UAAU;AAC3B,4BAAoB,KAAK;AAAA,MAC3B,SAAS,KAAK;AACZ,cAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,sBAAc,YAAY;AAC1B,4BAAoB,KAAK;AAAA,MAC3B;AAAA,IACF;AAEA,iBAAa;AAAA,EACf,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAGrB,QAAM,cAAcC,UAAQ,MAAM;AAChC,WAAO,aAAa,OAAO,KAAK,MAAM,KAAK,aAAa,OAAO,CAAC,EAAE;AAAA,MAAK,WACrE,MAAM,SAAS,WAAW,eAAe,MAAM,SAAS,WAAW;AAAA,IACrE;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,aAAaA,UAAQ,MAAM;AAC/B,WAAO,YAAY,eAAe,oBAAoB,CAAC;AAAA,EACzD,GAAG,CAAC,UAAU,aAAa,kBAAkB,aAAa,CAAC;AAG3D,QAAM,kBAAkBC,cAAY,CAAC,SAAuC;AAC1E,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAI,CAAC,KAAK,KAAK,WAAW,QAAQ,GAAG;AACnC,gBAAQ,IAAI;AACZ;AAAA,MACF;AAEA,YAAM,SAAS,IAAI,WAAW;AAC9B,aAAO,SAAS,CAAC,MAAM;AACrB,gBAAQ,EAAE,QAAQ,UAAoB,IAAI;AAAA,MAC5C;AACA,aAAO,UAAU,MAAM,QAAQ,IAAI;AACnC,aAAO,cAAc,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAGL,QAAM,eAAeA,cAAY,CAAC,SAA8B;AAE9D,QAAI,KAAK,OAAO,SAAS;AACvB,aAAO,SAAS,KAAK,IAAI,6BAA6B,KAAK,MAAM,UAAU,OAAO,IAAI,CAAC;AAAA,IACzF;AAGA,QAAI,WAAW,OAAO;AACpB,YAAM,gBAAgB,OAAO,MAAM,GAAG,EAAE,IAAI,UAAQ,KAAK,KAAK,CAAC;AAC/D,YAAM,gBAAgB,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AACpE,YAAM,eAAe,KAAK;AAE1B,YAAM,aAAa,cAAc,KAAK,cAAY;AAChD,YAAI,SAAS,WAAW,GAAG,GAAG;AAE5B,iBAAO,aAAa;AAAA,QACtB,WAAW,SAAS,SAAS,IAAI,GAAG;AAElC,gBAAM,WAAW,SAAS,MAAM,GAAG,EAAE,CAAC;AACtC,iBAAO,aAAa,WAAW,WAAW,GAAG;AAAA,QAC/C,OAAO;AAEL,iBAAO,aAAa;AAAA,QACtB;AAAA,MACF,CAAC;AAED,UAAI,CAAC,YAAY;AACf,eAAO,SAAS,KAAK,IAAI,0CAA0C,MAAM;AAAA,MAC3E;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,QAAM,mBAAmBA,cAAY,OAAO,UAA2B;AACrE,QAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAElC,UAAM,YAAY,MAAM,KAAK,KAAK;AAGlC,UAAM,mBAA6B,CAAC;AACpC,UAAM,aAAqB,CAAC;AAE5B,eAAW,QAAQ,WAAW;AAC5B,YAAMC,SAAQ,aAAa,IAAI;AAC/B,UAAIA,QAAO;AACT,yBAAiB,KAAKA,MAAK;AAC3B,wBAAgBA,QAAO,IAAI;AAAA,MAC7B,OAAO;AACL,mBAAW,KAAK,IAAI;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,IACF;AAGA,UAAM,kBAAkB,oBAAI,IAA6B;AAEzD,eAAW,QAAQ,YAAY;AAC7B,YAAM,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC;AACtD,YAAM,UAAU,cAAe,MAAM,gBAAgB,IAAI,KAAM,SAAY;AAE3E,YAAM,WAA2B;AAAA,QAC/B,QAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,YAAY;AAAA,QACZ,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,MACV;AAEA,sBAAgB,IAAI,QAAQ;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,oBAAgB,eAAe;AAG/B,eAAW,CAAC,QAAQ,WAAW,KAAK,gBAAgB,QAAQ,GAAG;AAC7D,YAAM,EAAE,KAAK,IAAI;AAGjB,sBAAgB,UAAQ;AACtB,cAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,cAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,YAAI,OAAO;AACT,kBAAQ,IAAI,QAAQ;AAAA,YAClB,GAAG;AAAA,YACH,UAAU;AAAA,cACR,GAAG,MAAM;AAAA,cACT,QAAQ;AAAA,YACV;AAAA,UACF,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT,CAAC;AAED,UAAI;AAEF,cAAM,mBAAmB,YAAY,MAAM;AACzC,0BAAgB,UAAQ;AACtB,kBAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,kBAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,gBAAI,SAAS,MAAM,SAAS,WAAW,aAAa;AAClD,oBAAM,oBAAoB,KAAK;AAAA,gBAC7B,MAAM,SAAS,aAAa;AAAA,gBAC5B;AAAA,cACF;AACA,oBAAM,cAA8B;AAAA,gBAClC,GAAG,MAAM;AAAA,gBACT,YAAY;AAAA,gBACZ,QAAQ,KAAK,MAAO,oBAAoB,MAAO,KAAK,IAAI;AAAA,cAC1D;AACA,2BAAa,WAAW;AACxB,sBAAQ,IAAI,QAAQ;AAAA,gBAClB,GAAG;AAAA,gBACH,UAAU;AAAA,cACZ,CAAC;AAAA,YACH;AACA,mBAAO;AAAA,UACT,CAAC;AAAA,QACH,GAAG,GAAG;AAIN,YAAI,CAAC,eAAe;AAClB,gBAAM,WAAW,cAAc;AAC/B,gBAAM,IAAI,MAAM,QAAQ;AAAA,QAC1B;AAEA,cAAM,SAAS,MAAM,WAAW;AAAA,UAC9B;AAAA,UACA;AAAA,UACA,iBAAiB,mBAAmB;AAAA,UACpC;AAAA;AAAA,UACA,QAAQ,gBAAgB,YAAY,aAAa,IAAI,YAAY,EAAE;AAAA,UACnE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,WAAW;AAAA,QACb,GAAG,IAAI;AAEP,sBAAc,gBAAgB;AAE9B,YAAI,QAAQ;AAEV,0BAAgB,UAAQ;AACtB,kBAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,kBAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,gBAAI,OAAO;AACT,sBAAQ,IAAI,QAAQ;AAAA,gBAClB,GAAG;AAAA,gBACH,UAAU;AAAA,kBACR,GAAG,MAAM;AAAA,kBACT,QAAQ;AAAA,kBACR,YAAY;AAAA,kBACZ,QAAQ,KAAK;AAAA,gBACf;AAAA,gBACA;AAAA,cACF,CAAC;AAAA,YACH;AACA,mBAAO;AAAA,UACT,CAAC;AAED,gBAAM,gBAAgC;AAAA,YACpC,QAAQ,KAAK;AAAA,YACb,OAAO,KAAK;AAAA,YACZ,YAAY;AAAA,YACZ,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,UACV;AACA,uBAAa,aAAa;AAC1B,4BAAkB,MAAM;AAAA,QAI1B,OAAO;AAEL,0BAAgB,UAAQ;AACtB,kBAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,kBAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,gBAAI,OAAO;AACT,sBAAQ,IAAI,QAAQ;AAAA,gBAClB,GAAG;AAAA,gBACH,UAAU;AAAA,kBACR,GAAG,MAAM;AAAA,kBACT,QAAQ;AAAA,kBACR,OAAO;AAAA,gBACT;AAAA,cACF,CAAC;AAAA,YACH;AACA,mBAAO;AAAA,UACT,CAAC;AAED,gBAAM,gBAAgC;AAAA,YACpC,QAAQ;AAAA,YACR,OAAO,KAAK;AAAA,YACZ,YAAY;AAAA,YACZ,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,OAAO;AAAA,UACT;AACA,uBAAa,aAAa;AAC1B,0BAAgB,iBAAiB,IAAI;AAAA,QACvC;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAE1D,wBAAgB,UAAQ;AACtB,gBAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,gBAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,cAAI,OAAO;AACT,oBAAQ,IAAI,QAAQ;AAAA,cAClB,GAAG;AAAA,cACH,UAAU;AAAA,gBACR,GAAG,MAAM;AAAA,gBACT,QAAQ;AAAA,gBACR,OAAO;AAAA,cACT;AAAA,YACF,CAAC;AAAA,UACH;AACA,iBAAO;AAAA,QACT,CAAC;AAED,cAAM,gBAAgC;AAAA,UACpC,QAAQ;AAAA,UACR,OAAO,KAAK;AAAA,UACZ,YAAY;AAAA,UACZ,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AACA,qBAAa,aAAa;AAC1B,wBAAgB,cAAc,IAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,YAAY,YAAY,WAAW,iBAAiB,eAAe,UAAU,QAAQ,UAAU,SAAS,iBAAiB,eAAe,YAAY,cAAc,iBAAiB,aAAa,UAAU,CAAC;AAE/M,QAAM,iBAAiBD,cAAY,CAAC,MAAuB;AACzD,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,QAAI,CAAC,YAAY;AACf,oBAAc,IAAI;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,kBAAkBA,cAAY,CAAC,MAAuB;AAC1D,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,kBAAc,KAAK;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA,cAAY,CAAC,MAAuB;AACrD,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,kBAAc,KAAK;AAEnB,QAAI,WAAY;AAEhB,UAAM,QAAQ,EAAE,aAAa;AAC7B,qBAAiB,KAAK;AAAA,EACxB,GAAG,CAAC,YAAY,gBAAgB,CAAC;AAEjC,QAAM,wBAAwBA,cAAY,CAAC,MAA2C;AACpF,qBAAiB,EAAE,OAAO,KAAK;AAE/B,QAAI,EAAE,QAAQ;AACZ,QAAE,OAAO,QAAQ;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,cAAcA,cAAY,MAAM;AACpC,QAAI,CAAC,cAAc,aAAa,SAAS;AACvC,mBAAa,QAAQ,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,iBAAiB,CAAC,UAA0B;AAChD,QAAI,UAAU,EAAG,QAAO;AACxB,UAAM,IAAI;AACV,UAAM,QAAQ,CAAC,SAAS,MAAM,MAAM,IAAI;AACxC,UAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,WAAO,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC;AAAA,EACxE;AAEA,QAAM,cAAc,aAAa,+BAA+B;AAChE,QAAM,kBAAkB,aAAa,kCAAkC;AAEvE,SACE,gBAAAL,OAAC,SAAI,WAAW,aAAa,SAAS,IACpC;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU,aAAa,KAAK;AAAA,QAC5B,cAAW;AAAA,QACX,iBAAe;AAAA,QACf,WAAW,gFAAgF,WAAW,IAAI,eAAe;AAAA,QACzH,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,SAAS,CAAC,aAAa,cAAc;AAAA,QACrC,WAAW,CAAC,aAAa,CAAC,MAAM;AAC9B,cAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,cAAE,eAAe;AACjB,wBAAY;AAAA,UACd;AAAA,QACF,IAAI;AAAA,QAEH;AAAA,sBACC,gBAAAA,OAAC,SAAI,WAAU,aACb;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,MAAK;AAAA,gBACL;AAAA,gBACA;AAAA,gBACA,UAAU;AAAA,gBACV,WAAU;AAAA,gBACV,UAAU;AAAA,gBACV,eAAY;AAAA;AAAA,YACd;AAAA,YACA,gBAAAA,MAAC,SAAI,WAAU,gBACZ,6BACC,mCACE,aACF,uBAEA,gBAAAC,OAAAF,WAAA,EACE;AAAA,8BAAAC,MAAC,UAAK,WAAU,eAAc,6BAAe;AAAA,cAC5C;AAAA,cAAI;AAAA,eACP,GAEJ;AAAA,YACA,gBAAAC,OAAC,SAAI,WAAU,wBACZ;AAAA,eAAC,oBAAoB,WAAW,SAAS,qBAAqB,MAAM;AAAA,cACpE,CAAC,oBAAoB,WAAW,qBAAgB,KAAK,MAAM,UAAU,OAAO,IAAI,CAAC;AAAA,cACjF,CAAC,oBAAoB,YAAY;AAAA,eACpC;AAAA,aACF;AAAA,UAGD,eAAe,CAAC,gBACf,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,aAAU;AAAA,cACV,cAAW;AAAA,cAEX,0BAAAA,MAAC,SAAI,WAAU,+DAA8D,eAAY,QAAO;AAAA;AAAA,UAClG;AAAA;AAAA;AAAA,IAEJ;AAAA,IAGC,gBAAgB,aAAa,OAAO,KACnC,gBAAAA,MAAC,SAAI,WAAU,aACZ,gBAAM,KAAK,aAAa,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,WAAW,MAAM;AACjE,YAAM,EAAE,MAAM,UAAU,SAAS,OAAO,IAAI;AAC5C,YAAM,UAAU,SAAS,WAAW;AACpC,YAAM,cAAc,SAAS,WAAW;AACxC,YAAMQ,eAAc,SAAS,WAAW,eAAe,SAAS,WAAW;AAE3E,aACE,gBAAAP;AAAA,QAAC;AAAA;AAAA,UAEC,WAAW,qDACT,UACI,6BACA,cACA,qCACA,0BACN;AAAA,UAGA;AAAA,4BAAAD,MAAC,SAAI,WAAU,iBACZ,oBACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,KAAK,KAAK;AAAA,gBACV,WAAU;AAAA;AAAA,YACZ,IAEA,gBAAAA,MAAC,SAAI,WAAU,iEACb,0BAAAA,MAAC,UAAK,WAAU,YAAW,uBAAE,GAC/B,GAEJ;AAAA,YAGA,gBAAAC,OAAC,SAAI,WAAU,kBACb;AAAA,8BAAAD,MAAC,SAAI,WAAU,qCACZ,eAAK,MACR;AAAA,cACA,gBAAAC,OAAC,SAAI,WAAU,wBACZ;AAAA,+BAAe,KAAK,IAAI;AAAA,gBACxB,eAAe,UAAU;AAAA,gBACzB,WAAW,SAAS,SAAS,WAAM,SAAS,KAAK;AAAA,iBACpD;AAAA,cAGC,iBAAiBO,gBAAe,YAC/B,gBAAAP,OAAC,SAAI,WAAU,QACb;AAAA,gCAAAD,MAAC,SAAI,WAAU,sCACb,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,gDACT,UAAU,eAAe,aAC3B;AAAA,oBACA,OAAO,EAAE,OAAO,GAAG,SAAS,UAAU,IAAI;AAAA;AAAA,gBAC5C,GACF;AAAA,gBACCQ,gBACC,gBAAAP,OAAC,SAAI,WAAU,6BACZ;AAAA,2BAAS;AAAA,kBAAW;AAAA,kBAAK,eAAe,SAAS,MAAM;AAAA,kBAAE;AAAA,kBAAI,eAAe,SAAS,KAAK;AAAA,mBAC7F;AAAA,iBAEJ;AAAA,eAEJ;AAAA,YAGA,gBAAAA,OAAC,SAAI,WAAU,iBACZ;AAAA,6BACC,gBAAAD,MAAC,UAAK,WAAU,4BAA2B,oBAAC;AAAA,cAE7C,WACC,gBAAAA,MAAC,UAAK,WAAU,wBAAuB,oBAAC;AAAA,cAEzCQ,gBACC,gBAAAR;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,eAAY;AAAA;AAAA,cACb;AAAA,eAEL;AAAA;AAAA;AAAA,QAvEK;AAAA,MAwEP;AAAA,IAEJ,CAAC,GACH;AAAA,IAGD,cACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,aAAU;AAAA,QAET;AAAA;AAAA,IACH;AAAA,IAED,SACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,aAAU;AAAA,QAET;AAAA;AAAA,IACH;AAAA,KAEJ;AAEJ;;;AChhBA,YAAYS,aAAW;AAwBrB,gBAAAC,aAAA;AAJF,IAAM,QAAc,mBAGlB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,MAAM,cAAc;AAEpB,IAAM,cAAoB,mBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA,MAAC,WAAM,KAAU,WAAW,GAAG,mBAAmB,SAAS,GAAI,GAAG,OAAO,CAC1E;AACD,YAAY,cAAc;AAE1B,IAAM,YAAkB,mBAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,8BAA8B,SAAS;AAAA,IACpD,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAExB,IAAM,cAAoB,mBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,YAAY,cAAc;AAE1B,IAAM,WAAiB,mBAGrB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,SAAS,cAAc;AAEvB,IAAM,YAAkB,mBAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAExB,IAAM,YAAkB,mBAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kDAAkD,SAAS;AAAA,IACxE,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAExB,IAAM,eAAqB,mBAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,sCAAsC,SAAS;AAAA,IAC5D,GAAG;AAAA;AACN,CACD;AACD,aAAa,cAAc;;;AC3DnB,SAaI,YAAAC,YAbJ,OAAAC,OASA,QAAAC,cATA;AApBD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,EAAE,QAAQ,IAAI,aAAa;AAEjC,SACE,gBAAAA,OAAC,YAAO,WAAW;AAAA,IACjB;AAAA,IACA;AAAA,EACF,GAEG;AAAA,mBAAe,WACd,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,KAAK,IAAI,QAAQ,YAAY,CAAC;AAAA,QAC9B,KAAK;AAAA;AAAA,IACP;AAAA,IAID,SACC,gBAAAC,OAAAF,YAAA,EACE;AAAA,sBAAAC,MAAC,QAAI,gBAAM,YAAW;AAAA,MAErB,iBAAiB,SAChB,gBAAAA,MAAAD,YAAA,EACG,6BACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,YAAW;AAAA,UACX,WAAW,MAAM;AAAA,UACjB,iBAAiB,MAAM;AAAA,UACvB;AAAA,UACA,aAAa;AAAA,UACb,cAAc;AAAA,UACd,cAAa;AAAA,UACb,WAAU;AAAA,UACV,sBAAsB,CAAC,aAAa;AAClC,gBAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,mBAAO,MAAM,WACV,MAAM,UAAU,EAChB,IAAI,UAAQ,KAAK,OAAO,CAAC,EAAE,YAAY,CAAC,EACxC,KAAK,EAAE,EACP,UAAU,GAAG,CAAC;AAAA,UACnB;AAAA;AAAA,MACF,GAEJ;AAAA,MAED,MAAM,eACL,gBAAAA,MAAC,QAAI,gBAAM,aAAY;AAAA,OAE3B;AAAA,IAID,SACC,gBAAAC,OAAAF,YAAA,EACE;AAAA,sBAAAC,MAAC,QAAI,iBAAM;AAAA,MACV,eACC,gBAAAA,MAAC,OAAE,WAAU,0CACV,uBACH;AAAA,OAEJ;AAAA,IAID,YAAY,gBAAAA,MAAAD,YAAA,EAAG,UAAS;AAAA,KAC3B;AAEJ;AA0BO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA,cAAc;AAAA,EACd,QAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC9B;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,gBAAgB,aAAa,4BAAoB,IAAI,yBAAyB,WAAW;AAE/F,SACE,gBAAAC,MAAC,YAAO,WAAW,GAAG,iCAAiC,SAAS,GAC9D,0BAAAC,OAAC,aAAQ,WAAU,2DAChB;AAAA,YACC,gBAAAD,MAAC,SAAI,KAAK,MAAM,KAAI,QAAO,WAAU,cAAa;AAAA,IAGnD,YAAY,gBAAAA,MAAAD,YAAA,EAAG,UAAS;AAAA,IAEzB,gBAAAC,MAAC,UAAK,WAAU,yBACb,yBACH;AAAA,IAEC,SAAS,MAAM,SAAS,KACvB,gBAAAA,MAAC,QAAG,WAAU,2BACX,gBAAM,IAAI,CAAC,MAAM,UAChB,gBAAAA,MAAC,QACC,0BAAAA,MAAC,OAAE,MAAM,KAAK,MAAM,WAAU,+CAC3B,eAAK,OACR,KAHO,KAIT,CACD,GACH;AAAA,KAEJ,GACF;AAEJ;AAcO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR;AAAA,EACA,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA,EACvB;AACF,GAA0B;AAGxB,gBAAc,KAAK;AAGnB,QAAM,gBAAgB,YAAY,YAAY;AAAA,EAAC;AAG/C,MAAI,WAAW;AACb,QAAI,iBAAiB;AACnB,aAAO,gBAAAA,MAAC,mBAAgB;AAAA,IAC1B;AACA,WACE,gBAAAA,MAAC,SAAI,WAAU,+DACb,0BAAAC,OAAC,SAAI,WAAU,qCACb;AAAA,sBAAAD,MAAC,kBAAe,MAAK,MAAK,WAAU,gBAAe;AAAA,MAClD,kBACC,gBAAAA,MAAC,OAAE,WAAU,gBAAgB,0BAAe;AAAA,OAEhD,GACF;AAAA,EAEJ;AAGA,MAAI,SAAS,sBAAsB;AACjC,QAAI,eAAe;AACjB,aAAO,gBAAAA,MAAC,iBAAc,OAAc,OAAO,eAAe;AAAA,IAC5D;AACA,WACE,gBAAAC,OAAC,UAAK,WAAU,8FAEZ;AAAA,sBAAAD,MAAC,QAAG,6BAAe;AAAA,MACnB,gBAAAC,OAAC,OAAE;AAAA;AAAA,QACgB;AAAA,QAAU;AAAA,SAC7B;AAAA,MACA,gBAAAD,MAAC,UAAO,SAAS,eAAe,uBAAS;AAAA,OAE7C;AAAA,EAEJ;AAGA,MAAI,CAAC,SAAS,sBAAsB;AAClC,WACE,gBAAAC,OAAC,UAAK,WAAU,8FAEZ;AAAA,sBAAAD,MAAC,QAAG,iCAAmB;AAAA,MACvB,gBAAAA,MAAC,OAAE,6DAEH;AAAA,MACC,iBAAiB,gBAAAA,MAAC,UAAO,SAAS,eAAe,uBAAS;AAAA,OAE/D;AAAA,EAEJ;AAKA,SACE,gBAAAA,MAAC,iBAAc,eAAc,oBAC3B,0BAAAC,OAAAF,YAAA,EAEG;AAAA,oBACC,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,SAAS;AAAA,QAChB;AAAA;AAAA,IACF;AAAA,IAIF,gBAAAA,MAAC,UAAK,WAAU,oDACb,UACH;AAAA,IAGC,cAAc,UACb,gBAAgB,gBAAAA,MAAC,oBAAiB,OAAc;AAAA,KAEpD,GACF;AAEJ;","names":["React","Fragment","jsx","jsxs","jsx","useState","useEffect","useRef","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","error","useEffect","Fragment","jsx","jsxs","useState","useRef","useEffect","fileUrl","useState","useCallback","useEffect","useRef","useMemo","log","useState","useMemo","useCallback","getSignedUrl","useRef","useEffect","React","jsx","jsx","jsx","React","jsx","React","jsx","React","Fragment","jsx","jsxs","props","className","components","classNames","React","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useCallback","useMemo","jsx","jsxs","React","useState","useMemo","useCallback","Calendar","useEffect","useMemo","useRef","jsx","jsxs","Calendar","useState","useCallback","useMemo","RefreshCw","AlertCircle","jsx","jsxs","useState","useCallback","AlertCircle","RefreshCw","useMemo","useState","jsx","jsxs","useState","React","useCallback","useMemo","useState","jsx","jsxs","React","UserMenu","useState","useMemo","useCallback","UserMenuLoading","React","ChevronDown","jsx","jsxs","userId","isSuperAdmin","ChevronDown","jsx","jsxs","React","Fragment","jsx","jsxs","React","useState","useEffect","useMemo","Fragment","jsx","jsxs","useState","useEffect","isSuperAdmin","useMemo","useUnifiedAuth","useEffect","useState","useContext","useNavigate","useLocation","jsx","jsxs","useNavigate","useLocation","useState","useContext","useEffect","jsx","jsxs","useMemo","useEffect","useRef","useState","Outlet","jsx","jsxs","useRef","useState","useEffect","useMemo","Outlet","useState","useCallback","useRef","useEffect","useMemo","Fragment","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","error","isUploading","React","jsx","Fragment","jsx","jsxs"]}
|