{"version":3,"file":"index.cjs","names":["useNativeCapabilities","useBottomNavHidden","SidebarProvider","Sidebar","SidebarHeader","SidebarContent","SidebarFooter","SidebarInset","RefreshCw","getServerSnapshot","SYSTEM_NAVIGATION_ITEMS","ContactRound","Repeat","Bell","Box","Boxes","Briefcase","Calendar","ShoppingCart","CircleUser","MessageCircle","Compass","Mail","File","FileText","FileVideo","Folder","FolderOpen","Settings","Globe","GraduationCap","Heart","House","Image","ListMusic","Search","MessageSquare","MessageCircleHeart","PackageOpen","Puzzle","Star","Store","LayoutGrid","User","UserCog","Users","normalizeSlug","shellEn","useSidebar","useShellTranslation","useHaptics","useBottomNavHidden","React","Ellipsis","MobileBottomSheet","useShellTranslation","useShellTranslation","Collapsible","SidebarMenuItem","CollapsibleTrigger","SidebarMenuButton","ChevronRight","CollapsibleContent","SidebarMenuSub","normalizeSlug","useShellTranslation","SidebarMenu","SidebarGroupLabel","normalizeSlug","SidebarMenuItem","SidebarMenuButton","useLanguagesApi","useActiveLocale","storeKeys","SUPPORTED_LANGUAGES","resolveLocale","useActiveLocale","useSidebar","useRepUser","useHaptics","useShellTranslation","useNativeCapabilities","useHapticCallback","MobileBottomSheet","ChevronLeft","Check","Smartphone","Globe","ChevronRight","Moon","Sun","LogOut","useSidebar","useShellTranslation","normalizeSlug","IconButton","ChevronLeft","ScreenHeaderMobileActionsSlot","Menu","useActiveLocale","useIsMobile","useShellTranslation","Button","Globe","MobileActionSheet","Popover","PopoverTrigger","PopoverContent","Check","matchSlugPrefix","useSidebar","usePortalTenantClient","CartButton","useFluidContext","useStore","useAccount","CartScript","CartWidget","Building2","cn","Skeleton","useStore","useShellTranslation","FallbackCard","Compass","Button","useShellTranslation","alertWidgetPropertySchema","announcementWidgetPropertySchema","bulletListWidgetPropertySchema","calendarWidgetPropertySchema","cardWidgetPropertySchema","carouselWidgetPropertySchema","catchUpWidgetPropertySchema","chartWidgetPropertySchema","containerWidgetPropertySchema","embedWidgetPropertySchema","imageWidgetPropertySchema","layoutWidgetPropertySchema","linkWidgetPropertySchema","listWidgetPropertySchema","mySiteWidgetPropertySchema","nestedWidgetPropertySchema","pointsWidgetPropertySchema","quickLinksWidgetPropertySchema","quickShareWidgetPropertySchema","quoteWidgetPropertySchema","recentActivityWidgetPropertySchema","separatorWidgetPropertySchema","shopWidgetPropertySchema","spacerWidgetPropertySchema","tableWidgetPropertySchema","textWidgetPropertySchema","toDoWidgetPropertySchema","videoWidgetPropertySchema","useRegistry","isDefaultWidgetComponent","DataAwareWidget","useShellTranslation","ProfileScreen","OrdersScreen","SubscriptionsScreen","MessagingScreen","ContactsScreen","ShopScreen","CustomersScreen","ShareablesScreen","MySiteScreen","ActivityScreen","OPT_IN_SYSTEM_SCREEN_SLUGS","findSystemSlugByPrefix","useAccount","useOptionalStore","deniesRepSurfaces","slugifyName","isRepOnlySlug","Suspense","isSystemNavigationItem","CoreScreenPlaceholder","ShellTranslationContext","shellEn","FallbackCard","TriangleAlert","Button","Component","deleteDatabase","useShellTranslation","Moon","Sun","SidebarMenu","SidebarMenuItem","SidebarMenuButton","LogOut","isRepOnlySlug","useIsMobile","useSidebar","useScreenHeaderSlotRefs","PanelLeft","useShellTranslation","useOptionalScreenAreaFullscreenCoordinator","useScreenAreaFullscreenSnapshot","matchSlugPrefix","normalizeSlug","normalizeSlug","useIsMobile","useBottomNavHidden","Toaster","useFluidApp","useAccount","getDefaultThemeDefinition","resolveTheme","deniesRepSurfaces","collectNavSlugs","extractSlugFromPathname","internalSlugFromHref","matchSlugPrefix","RepUserProvider","AppNavigationProvider","WidgetInteractionProvider","BottomNavVisibilityProvider","ScreenHeaderProvider","ScreenAreaFullscreenProvider","useOptionalStore","getFluidNativeBridge","Component","FluidProvider","StrictMode","useAppDefinitionApi","useCompanyScopedQueryKey","APP_DATA_QUERY_KEY","fetchRawManifest","transformManifestToRepAppData","useAppDefinitionApi","useCompanyScopedQueryKey","useThemeContext","useAccount","hasMemberPermission","memberTypeSlug","memberTypeName","canAccessRepSurfaces","useLegacyPortalTenantClient","deleteDatabase","now","daysFromNow","now","now","hoursAgo","now","daysAgo","z","useShellTranslation","useAccount","deniesRepSurfaces","getSystemNavigationBySection","Popover","PopoverTrigger","Button","LayoutGrid","PopoverContent"],"sources":["../src/types/page-template.ts","../src/registries/page-template-registry.ts","../src/core/resolve-pages.ts","../src/providers/PageTemplateProvider.tsx","../../react/src/shell/use-suppress-initial-iframe-focus-scroll.ts","../../react/src/shell/use-scroll-restoration.ts","../../react/src/shell/use-pull-to-refresh.ts","../../react/src/shell/AppShellLayout.tsx","../../react/src/shell/ThemeModeContext.tsx","../../core/src/navigation/default-navigation.ts","../../react/src/components/RepIcon.tsx","../../core/src/navigation/navigation-storage.ts","../../core/src/navigation/navigation-utils.ts","../../core/src/navigation/translate-nav-label.ts","../src/shell/SdkBottomNav.tsx","../../react/src/shell/AppShellSkeleton.tsx","../src/shell/AppShellLoading.tsx","../src/shell/CollapsibleNavItem.tsx","../src/shell/SdkNavigation.tsx","../src/hooks/use-enabled-languages.ts","../src/shell/use-mobile-languages.ts","../src/shell/SdkMobileProfileMenu.tsx","../src/shell/SdkHeader.tsx","../src/shell/LanguageSelector.tsx","../src/shell/PortalCart.tsx","../../../company-switcher/ui/src/components/CompanyImage.tsx","../../../company-switcher/ui/src/components/CompanyItem.tsx","../../../company-switcher/ui/src/components/CompanySwitcherSkeleton.tsx","../src/shell/SdkCompanySwitcher.tsx","../src/shell/go-back-or-home.ts","../src/screens/ScreenNotFound.tsx","../src/screens/AccessDeniedScreen.tsx","../src/core/default-property-schema-registry.ts","../src/utils/warn-unknown-widget-props.ts","../src/shell/BuilderScreenView.tsx","../../core/src/member-type-content.ts","../src/shell/system-screen-map.ts","../src/shell/PageRouter.tsx","../src/shell/AppShellErrorBoundary.tsx","../src/shell/native-theme-bridge.ts","../src/shell/native-ready-bridge.ts","../src/utils/reset-fairshare-sdk.ts","../src/hooks/use-logout.ts","../src/shell/SdkLogoutButton.tsx","../src/navigation/filter-nav-items.ts","../../react/src/shell/ScreenTransition.tsx","../../react/src/shell/ScreenHeader.tsx","../src/shell/TranslatedScreenHeader.tsx","../src/shell/mobile-back-target.ts","../src/shell/AppShell.tsx","../../core/src/pwa/build-tenant-web-manifest.ts","../src/pwa/rasterize-letter-avatar.ts","../src/pwa/inject-tenant-manifest.ts","../src/pwa/pwa-icon-cache.ts","../src/pwa/PwaManifestInjector.tsx","../src/pwa/register-portal-service-worker.ts","../src/pwa/detect-pwa-display-mode.ts","../src/pwa/ensure-standalone-viewport-fit.ts","../src/pwa/PortalPwa.tsx","../src/config/env.ts","../src/config/defaults.ts","../src/entry/create-portal.tsx","../src/hooks/use-fluid-profile.ts","../src/hooks/use-app-definition.ts","../src/hooks/use-fluid-theme.ts","../src/pwa/use-pwa-display-mode.ts","../src/hooks/use-member-type.ts","../src/hooks/use-company-switch.ts","../src/hooks/demo-data/calendar-events.ts","../src/hooks/use-calendar-events.ts","../src/hooks/demo-data/todos.ts","../src/hooks/use-todos.ts","../src/hooks/hook-types.ts","../src/hooks/demo-data/activities.ts","../src/hooks/use-activities.ts","../src/hooks/demo-data/catchups.ts","../src/hooks/use-catchups.ts","../src/hooks/demo-data/mysite.ts","../src/hooks/use-mysite.ts","../src/hooks/demo-data/conversations.ts","../src/hooks/use-conversations.ts","../src/types/screen-types.ts","../src/hooks/demo-data/contacts.ts","../src/hooks/use-contacts.ts","../../../platform/auth/src/types.ts","../../../platform/auth/src/company-switch.ts","../src/screens/core-page-ids.ts","../src/screens/index.ts","../src/shell/QuickLinksDropdown.tsx","../src/scaffold/manifest.ts"],"sourcesContent":["import type { WidgetSchema } from \"./widget-schema\";\n\n/**\n * Category for organizing page templates in the registry\n */\nexport interface PageCategory {\n  /** Unique identifier for the category */\n  readonly id: string;\n  /** Display label */\n  label: string;\n  /** Icon identifier (e.g., lucide icon name) */\n  icon?: string;\n}\n\n/**\n * A reusable page template that can be shared across multiple navigations\n */\nexport interface PageTemplate {\n  /** Unique identifier for the template */\n  readonly id: string;\n  /** URL-friendly slug */\n  slug: string;\n  /** Display name */\n  name: string;\n  /** Description of the template's purpose */\n  description?: string;\n  /** Category ID for organization */\n  category: string;\n  /** Tags for filtering and search */\n  tags?: readonly string[];\n  /** The widget tree that defines the page content */\n  component_tree: readonly WidgetSchema[];\n  /** Semantic version of the template */\n  version: string;\n  /** Whether this is a core feature that cannot be removed */\n  isCore?: boolean;\n  /** Default prop values that can be customized */\n  defaultProps?: Readonly<Record<string, unknown>>;\n  /** Thumbnail image URL for UI display */\n  thumbnail?: string;\n}\n\n/**\n * Reference to a shared page template within a navigation\n */\nexport interface PageReference {\n  /** ID of the page template being referenced */\n  page_template_id: string;\n  /** Screen ID to assign to this page in the navigation */\n  screen_id: number;\n  /** Optional prop overrides (only prop values, not widget structure) */\n  overrides?: readonly PageOverride[];\n}\n\n/**\n * Override for a specific widget's props within a page template\n */\nexport interface PageOverride {\n  /** ID of the widget to override (must match WidgetSchema.id in the template) */\n  readonly widget_id: string;\n  /** Props to override (merged with original props) */\n  props: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Built-in page category IDs\n */\nexport const PAGE_CATEGORIES = {\n  CORE: \"core\",\n  COMMERCE: \"commerce\",\n  COMMUNICATION: \"communication\",\n  DATA: \"data\",\n  CUSTOM: \"custom\",\n} as const;\n\nexport type PageCategoryId =\n  (typeof PAGE_CATEGORIES)[keyof typeof PAGE_CATEGORIES];\n","import type {\n  PageTemplate,\n  PageCategory,\n  PageCategoryId,\n} from \"../types/page-template\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\n\n/**\n * Registry for managing reusable page templates.\n *\n * The registry provides a central store for page templates that can be\n * shared across multiple navigations. Core pages (like Messaging, Contacts)\n * are pre-registered and cannot be removed.\n *\n * @example\n * ```ts\n * // Register a custom page template\n * PageTemplateRegistry.register({\n *   id: 'custom-dashboard',\n *   slug: 'dashboard',\n *   name: 'Custom Dashboard',\n *   category: 'custom',\n *   version: '1.0.0',\n *   component_tree: [{ type: 'TextWidget', props: { text: 'Hello' } }],\n * });\n *\n * // Get a template by ID\n * const template = PageTemplateRegistry.get('custom-dashboard');\n *\n * // List all templates in a category\n * const corePages = PageTemplateRegistry.getByCategory('core');\n * ```\n */\nclass PageTemplateRegistryImpl {\n  private templates = new Map<string, PageTemplate>();\n  private categories: PageCategory[] = [];\n\n  constructor() {\n    // Initialize default categories\n    this.categories = [\n      { id: PAGE_CATEGORIES.CORE, label: \"Core Features\", icon: \"star\" },\n      {\n        id: PAGE_CATEGORIES.COMMERCE,\n        label: \"Commerce\",\n        icon: \"shopping-cart\",\n      },\n      {\n        id: PAGE_CATEGORIES.COMMUNICATION,\n        label: \"Communication\",\n        icon: \"message-circle\",\n      },\n      {\n        id: PAGE_CATEGORIES.DATA,\n        label: \"Data & Analytics\",\n        icon: \"bar-chart\",\n      },\n      { id: PAGE_CATEGORIES.CUSTOM, label: \"Custom\", icon: \"puzzle\" },\n    ];\n  }\n\n  /**\n   * Register a new page template.\n   * @throws Error if a template with the same ID already exists\n   */\n  register(template: PageTemplate): void {\n    if (this.templates.has(template.id)) {\n      throw new Error(\n        `Page template with ID \"${template.id}\" is already registered`,\n      );\n    }\n    this.templates.set(template.id, template);\n  }\n\n  /**\n   * Unregister a page template by ID.\n   * Core templates cannot be unregistered.\n   * @returns true if the template was removed, false if it didn't exist or is a core template\n   */\n  unregister(id: string): boolean {\n    const template = this.templates.get(id);\n    if (!template) {\n      return false;\n    }\n    if (template.isCore) {\n      console.warn(\n        `Cannot unregister core page template \"${id}\". Core templates are required.`,\n      );\n      return false;\n    }\n    return this.templates.delete(id);\n  }\n\n  /**\n   * Get a page template by ID.\n   */\n  get(id: string): PageTemplate | undefined {\n    return this.templates.get(id);\n  }\n\n  /**\n   * Get all page templates in a specific category.\n   */\n  getByCategory(category: PageCategoryId | string): PageTemplate[] {\n    return Array.from(this.templates.values()).filter(\n      (t) => t.category === category,\n    );\n  }\n\n  /**\n   * List all registered page templates.\n   */\n  listAll(): PageTemplate[] {\n    return Array.from(this.templates.values());\n  }\n\n  /**\n   * List all core page templates (isCore: true).\n   */\n  listCore(): PageTemplate[] {\n    return Array.from(this.templates.values()).filter((t) => t.isCore);\n  }\n\n  /**\n   * List all non-core page templates.\n   */\n  listOptional(): PageTemplate[] {\n    return Array.from(this.templates.values()).filter((t) => !t.isCore);\n  }\n\n  /**\n   * List all registered categories.\n   */\n  listCategories(): PageCategory[] {\n    return [...this.categories];\n  }\n\n  /**\n   * Add a custom category.\n   */\n  addCategory(category: PageCategory): void {\n    if (this.categories.some((c) => c.id === category.id)) {\n      console.warn(`Category with ID \"${category.id}\" already exists`);\n      return;\n    }\n    this.categories.push(category);\n  }\n\n  /**\n   * Check if a template exists by ID.\n   */\n  has(id: string): boolean {\n    return this.templates.has(id);\n  }\n\n  /**\n   * Get the count of registered templates.\n   */\n  get size(): number {\n    return this.templates.size;\n  }\n\n  /**\n   * Clear all non-core templates.\n   * Useful for testing or resetting the registry.\n   */\n  clearNonCore(): void {\n    for (const [id, template] of this.templates) {\n      if (!template.isCore) {\n        this.templates.delete(id);\n      }\n    }\n  }\n}\n\n/**\n * Global page template registry singleton.\n *\n * This registry is automatically populated with core page templates\n * (Messaging, Contacts) when the SDK is imported.\n */\nexport const PageTemplateRegistry: PageTemplateRegistryImpl =\n  new PageTemplateRegistryImpl();\n","import type { Navigation, ScreenDefinition, WidgetSchema } from \"../types\";\nimport type {\n  PageReference,\n  PageOverride,\n  PageTemplate,\n} from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\n\n/**\n * Apply prop overrides to widgets in a component tree.\n * Recursively walks widget.props.children so overrides targeting\n * nested widgets (inside LayoutWidget, ContainerWidget, etc.) are applied.\n *\n * @param componentTree - The original component tree from the page template\n * @param overrides - Array of widget-specific prop overrides\n * @returns A new component tree with overrides applied\n */\nfunction applyOverrides(\n  componentTree: readonly WidgetSchema[],\n  overrides: readonly PageOverride[],\n): WidgetSchema[] {\n  if (!overrides.length) {\n    // Return a mutable copy to satisfy ScreenDefinition.component_tree type\n    return [...componentTree];\n  }\n\n  // Build a map of widget_id -> override for O(1) lookup (built once, shared across recursion)\n  const overrideMap = new Map(overrides.map((o) => [o.widget_id, o.props]));\n\n  return componentTree.map((widget) =>\n    applyWidgetOverrides(widget, overrideMap),\n  );\n}\n\n/**\n * Recursively apply overrides to a widget and its children.\n * Only clones widgets that actually change (have an override or contain children that might).\n */\nfunction applyWidgetOverrides(\n  widget: WidgetSchema,\n  overrideMap: ReadonlyMap<string, Record<string, unknown>>,\n): WidgetSchema {\n  const override = widget.id ? overrideMap.get(widget.id) : undefined;\n  const children = widget.props.children;\n\n  // Recurse into children if they exist (LayoutWidget, ContainerWidget)\n  const hasChildren = Array.isArray(children) && children.length > 0;\n\n  if (!override && !hasChildren) {\n    return widget;\n  }\n\n  const newProps = override\n    ? { ...widget.props, ...override }\n    : { ...widget.props };\n\n  if (hasChildren) {\n    newProps.children = (children as readonly WidgetSchema[]).map((child) =>\n      applyWidgetOverrides(child, overrideMap),\n    );\n  }\n\n  return { ...widget, props: newProps };\n}\n\n/**\n * Resolve a page reference to a screen definition.\n *\n * @param ref - The page reference from navigation\n * @returns A ScreenDefinition or undefined if the template doesn't exist\n */\nfunction resolvePageReference(\n  ref: Readonly<PageReference>,\n): ScreenDefinition | undefined {\n  const template = PageTemplateRegistry.get(ref.page_template_id);\n  if (!template) {\n    console.warn(\n      `Page template \"${ref.page_template_id}\" not found in registry`,\n    );\n    return undefined;\n  }\n\n  // Apply any overrides to the component tree\n  // Spread to create mutable array for ScreenDefinition.component_tree\n  const componentTree = ref.overrides\n    ? applyOverrides(template.component_tree, ref.overrides)\n    : [...template.component_tree];\n\n  return {\n    id: ref.screen_id,\n    slug: template.slug,\n    name: template.name,\n    component_tree: componentTree,\n  };\n}\n\n/**\n * Resolve all page references and local screens into a unified screen list.\n *\n * This function merges:\n * 1. Screen definitions from page_refs (shared templates)\n * 2. Local screen definitions (for backwards compatibility and custom screens)\n *\n * When a screen_id appears in both page_refs and screens, the local screen\n * takes precedence (allows local overrides of template pages).\n *\n * @param navigation - The navigation configuration\n * @returns A unified array of ScreenDefinition objects\n *\n * @example\n * ```ts\n * const navigation: Navigation = {\n *   definition_id: 1,\n *   id: 1,\n *   name: \"Main Nav\",\n *   navigation_items: [...],\n *   screens: [\n *     // Local custom screen\n *     { id: 1, slug: \"home\", name: \"Home\", component_tree: [...] }\n *   ],\n *   page_refs: [\n *     // Reference to shared messaging template\n *     { page_template_id: \"core-messaging\", screen_id: 2 }\n *   ],\n * };\n *\n * const allScreens = resolveNavigationPages(navigation);\n * // Returns: [home screen, messaging screen from template]\n * ```\n */\nexport function resolveNavigationPages(\n  navigation: Readonly<Navigation>,\n): ScreenDefinition[] {\n  // Start with local screens (these take precedence)\n  const localScreenIds = new Set(navigation.screens.map((s) => s.id));\n  const result: ScreenDefinition[] = [...navigation.screens];\n\n  // Resolve page references (skip if local screen already exists with same ID)\n  if (navigation.page_refs) {\n    for (const ref of navigation.page_refs) {\n      if (localScreenIds.has(ref.screen_id)) {\n        // Local screen takes precedence\n        continue;\n      }\n\n      const screen = resolvePageReference(ref);\n      if (screen) {\n        result.push(screen);\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Get all available page templates for use in navigation.\n *\n * @returns Array of page templates from the registry\n */\nexport function getAvailablePageTemplates(): PageTemplate[] {\n  return PageTemplateRegistry.listAll();\n}\n\n/**\n * Get core page templates that are required for basic functionality.\n *\n * @returns Array of core page templates\n */\nexport function getCorePageTemplates(): PageTemplate[] {\n  return PageTemplateRegistry.listCore();\n}\n\n/**\n * Get optional page templates that can be added to navigation.\n *\n * @returns Array of optional (non-core) page templates\n */\nexport function getOptionalPageTemplates(): PageTemplate[] {\n  return PageTemplateRegistry.listOptional();\n}\n\n/**\n * Check if a navigation has all required core pages.\n *\n * @param navigation - The navigation to check\n * @returns Object with validation result and missing page IDs\n */\nexport function validateNavigationPages(navigation: Readonly<Navigation>): {\n  readonly valid: boolean;\n  readonly missingCorePages: readonly string[];\n} {\n  const corePages = PageTemplateRegistry.listCore();\n  const referencedTemplateIds = new Set(\n    navigation.page_refs?.map((ref) => ref.page_template_id) ?? [],\n  );\n\n  // Check which core pages are referenced\n  const missingCorePages = corePages\n    .filter((page) => !referencedTemplateIds.has(page.id))\n    .map((page) => page.id);\n\n  return {\n    valid: missingCorePages.length === 0,\n    missingCorePages,\n  };\n}\n","import React, {\n  createContext,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n} from \"react\";\nimport type { PageTemplate } from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { resolveNavigationPages } from \"../core/resolve-pages\";\nimport type { Navigation, ScreenDefinition } from \"../types\";\n\n/** Stable empty array for the default `templates` prop (avoids new reference each render) */\nconst EMPTY_TEMPLATES: readonly PageTemplate[] = [];\n\n/**\n * Context value for page template resolution.\n * All properties are readonly since context values should not be mutated by consumers.\n */\ninterface PageTemplateContextValue {\n  /**\n   * Resolve a navigation's page_refs and screens into a unified screen list\n   */\n  readonly resolvePages: (navigation: Navigation) => ScreenDefinition[];\n  /**\n   * Get all available page templates\n   */\n  readonly listTemplates: () => PageTemplate[];\n  /**\n   * Get a specific template by ID\n   */\n  readonly getTemplate: (id: string) => PageTemplate | undefined;\n  /**\n   * Check if a template exists\n   */\n  readonly hasTemplate: (id: string) => boolean;\n}\n\nconst PageTemplateContext = createContext<PageTemplateContextValue | null>(\n  null,\n);\n\n/**\n * Props for PageTemplateProvider\n */\ninterface PageTemplateProviderProps {\n  children: React.ReactNode;\n  /**\n   * Additional custom page templates to register.\n   * These are registered when the provider mounts and unregistered when it unmounts.\n   */\n  templates?: readonly PageTemplate[];\n}\n\n/**\n * Provider for page template resolution.\n *\n * This provider:\n * 1. Registers any custom templates passed via props\n * 2. Provides methods for resolving navigation pages\n * 3. Cleans up custom templates on unmount\n *\n * @example\n * ```tsx\n * // With custom templates\n * const customTemplates: PageTemplate[] = [\n *   {\n *     id: 'custom-dashboard',\n *     slug: 'dashboard',\n *     name: 'Dashboard',\n *     category: 'custom',\n *     version: '1.0.0',\n *     component_tree: [{ type: 'TextWidget', props: { text: 'Custom Dashboard' } }],\n *   },\n * ];\n *\n * <PageTemplateProvider templates={customTemplates}>\n *   <App />\n * </PageTemplateProvider>\n *\n * // Without custom templates (uses only core templates)\n * <PageTemplateProvider>\n *   <App />\n * </PageTemplateProvider>\n * ```\n */\nexport function PageTemplateProvider({\n  children,\n  templates = EMPTY_TEMPLATES,\n}: PageTemplateProviderProps): React.JSX.Element {\n  // Track which templates we registered so we can clean them up\n  const registeredIds = useRef<string[]>([]);\n\n  // Derive a stable primitive key from template IDs\n  // (rerender-dependencies rule: use primitive dependencies in effects)\n  const templateKey = templates.map((t) => t.id).join(\",\");\n\n  // Register custom templates when template IDs change\n  useEffect(() => {\n    const registered: string[] = [];\n\n    for (const template of templates) {\n      if (!PageTemplateRegistry.has(template.id)) {\n        try {\n          PageTemplateRegistry.register(template);\n          registered.push(template.id);\n        } catch (error) {\n          console.warn(\n            `Failed to register page template \"${template.id}\":`,\n            error,\n          );\n        }\n      }\n    }\n\n    registeredIds.current = registered;\n\n    // Cleanup when template IDs change or on unmount\n    return () => {\n      for (const id of registeredIds.current) {\n        PageTemplateRegistry.unregister(id);\n      }\n      registeredIds.current = [];\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [templateKey]);\n\n  // Memoize context value to prevent unnecessary re-renders\n  // Use `satisfies` to validate shape at compile time while preserving inference\n  const contextValue = useMemo(\n    () =>\n      ({\n        resolvePages: resolveNavigationPages,\n        listTemplates: () => PageTemplateRegistry.listAll(),\n        getTemplate: (id: string) => PageTemplateRegistry.get(id),\n        hasTemplate: (id: string) => PageTemplateRegistry.has(id),\n      }) satisfies PageTemplateContextValue,\n    [],\n  );\n\n  return (\n    <PageTemplateContext.Provider value={contextValue}>\n      {children}\n    </PageTemplateContext.Provider>\n  );\n}\n\n/**\n * Hook to access page template functionality.\n *\n * @throws Error if used outside of PageTemplateProvider\n *\n * @example\n * ```tsx\n * function NavigationRenderer({ navigation }: { navigation: Navigation }) {\n *   const { resolvePages } = usePageTemplates();\n *   const screens = resolvePages(navigation);\n *\n *   return (\n *     <div>\n *       {screens.map((screen) => (\n *         <Screen key={screen.id} definition={screen} />\n *       ))}\n *     </div>\n *   );\n * }\n * ```\n */\nexport function usePageTemplates(): PageTemplateContextValue {\n  const context = useContext(PageTemplateContext);\n  if (!context) {\n    throw new Error(\n      \"usePageTemplates must be used within a PageTemplateProvider\",\n    );\n  }\n  return context;\n}\n\n/**\n * Hook to resolve navigation pages directly.\n * Convenience wrapper around usePageTemplates().resolvePages.\n *\n * @param navigation - The navigation to resolve\n * @returns Array of resolved screen definitions\n */\nexport function useResolvedPages(navigation: Navigation): ScreenDefinition[] {\n  const { resolvePages } = usePageTemplates();\n  return useMemo(() => resolvePages(navigation), [resolvePages, navigation]);\n}\n","import { useEffect, type RefObject } from \"react\";\n\n/**\n * Iframes embed opaque third-party content that can call `.focus()` on its\n * internal elements during load — video players, calendar pickers, form\n * inputs, search boxes. The browser then scrolls the nearest scrolling\n * ancestor to bring the focused iframe into view, yanking the viewport to a\n * widget the user didn't ask for.\n *\n * Suppress that scroll on the given scroll container until the user has\n * explicitly interacted with the page; afterwards, focus-scrolls are\n * treated as user-initiated and left alone. The container's `scrollTop` at\n * effect setup is captured and restored, so any pre-effect scroll position\n * (e.g. from future hash-anchor restoration) is preserved.\n */\nexport function useSuppressInitialIframeFocusScroll(\n  ref: RefObject<HTMLElement | null>,\n): void {\n  useEffect(() => {\n    const el = ref.current;\n    if (!el) return;\n\n    const initialScrollTop = el.scrollTop;\n    let userInteracted = false;\n\n    const handleFocusIn = (event: FocusEvent) => {\n      if (userInteracted) return;\n      if (!(event.target instanceof HTMLIFrameElement)) return;\n      requestAnimationFrame(() => {\n        if (!userInteracted) el.scrollTop = initialScrollTop;\n      });\n    };\n\n    const markInteracted = () => {\n      userInteracted = true;\n    };\n\n    el.addEventListener(\"focusin\", handleFocusIn);\n    window.addEventListener(\"pointerdown\", markInteracted, { once: true });\n    window.addEventListener(\"keydown\", markInteracted, { once: true });\n    window.addEventListener(\"wheel\", markInteracted, {\n      once: true,\n      passive: true,\n    });\n\n    return () => {\n      el.removeEventListener(\"focusin\", handleFocusIn);\n      window.removeEventListener(\"pointerdown\", markInteracted);\n      window.removeEventListener(\"keydown\", markInteracted);\n      window.removeEventListener(\"wheel\", markInteracted);\n    };\n  }, [ref]);\n}\n","import { useLayoutEffect, useRef, type RefObject } from \"react\";\n\n/**\n * Remembers the scroll position of the shell's screen area per route and\n * restores it when the user navigates back — so returning to a scrolled list\n * lands where they left off instead of at the top, the way a native stack does.\n *\n * Positions are recorded continuously on scroll (keyed by the active slug) so\n * the outgoing position is already captured by the time the route changes.\n * Restoring an unvisited route scrolls to the top.\n */\nexport function useScrollRestoration(\n  scrollRef: RefObject<HTMLElement | null>,\n  currentSlug: string,\n): void {\n  const positionsRef = useRef<Map<string, number>>(new Map());\n  const activeSlugRef = useRef(currentSlug);\n  const previousSlugRef = useRef<string | null>(null);\n\n  // Keep a ref to the active slug so the scroll listener records under the\n  // route that's actually on screen, not a stale closure value.\n  activeSlugRef.current = currentSlug;\n\n  // Record scroll position as the user scrolls the current route.\n  useLayoutEffect(() => {\n    const el = scrollRef.current;\n    if (!el) return;\n\n    // Record synchronously on every scroll (last write wins) rather than\n    // throttling through an animation frame: a throttle would both save under\n    // the wrong slug if navigation landed before the frame ran, and drop every\n    // offset after the first in a fast burst. A Map.set per scroll event is\n    // cheap, and reading scrollTop in a passive listener forces no reflow.\n    const onScroll = (): void => {\n      positionsRef.current.set(activeSlugRef.current, el.scrollTop);\n    };\n\n    el.addEventListener(\"scroll\", onScroll, { passive: true });\n    return () => el.removeEventListener(\"scroll\", onScroll);\n  }, [scrollRef]);\n\n  // Restore on route change.\n  useLayoutEffect(() => {\n    const el = scrollRef.current;\n    if (!el || previousSlugRef.current === currentSlug) return;\n    previousSlugRef.current = currentSlug;\n    el.scrollTop = positionsRef.current.get(currentSlug) ?? 0;\n  }, [currentSlug, scrollRef]);\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, type RefObject } from \"react\";\nimport { useNativeCapabilities } from \"@fluid-app/portal-core/native-capabilities-api-context\";\n\nconst DEFAULT_THRESHOLD = 64;\nconst DEFAULT_MAX_PULL = 96;\n/** Fraction of finger travel translated into visual pull (rubber-band feel). */\nconst RESISTANCE = 0.5;\n/** Keep the spinner visible at least this long so a fast refetch doesn't flash. */\nconst MIN_SPINNER_MS = 400;\n/**\n * Finger travel (px) required before we commit to a direction. Below this the\n * gesture is ambiguous, so we neither translate nor preventDefault — letting a\n * clearly-horizontal drag (carousel, table) keep its native scroll.\n */\nconst DIRECTION_LOCK_SLOP = 8;\n\nexport interface UsePullToRefreshOptions {\n  /** The scrollable element the gesture is attached to. */\n  scrollRef: RefObject<HTMLElement | null>;\n  /**\n   * Called when the user pulls past the threshold. May return a promise; the\n   * spinner stays up until it settles.\n   */\n  onRefresh?: (() => Promise<void> | void) | undefined;\n  /** Disable the gesture entirely (defaults to enabled when `onRefresh` is set). */\n  enabled?: boolean;\n  /** Pull distance (px) required to trigger a refresh. */\n  threshold?: number;\n  /** Maximum visual pull distance (px). */\n  maxPull?: number;\n}\n\nexport interface PullToRefreshState {\n  /** Pixels to translate the content / position the indicator (0 when idle). */\n  offset: number;\n  /** True while `onRefresh` is in flight. */\n  isRefreshing: boolean;\n  /** True while a pull gesture is actively in progress (disable CSS transition). */\n  isActive: boolean;\n  /** 0..1 fraction of the trigger threshold currently reached. */\n  progress: number;\n}\n\n/**\n * Touch-driven pull-to-refresh for a scroll container. Engages only when the\n * container is scrolled to the top and the user drags downward, so it never\n * competes with normal scrolling. Mouse/trackpad input never fires touch\n * events, so this is inherently a mobile/touch-only affordance.\n */\nexport function usePullToRefresh({\n  scrollRef,\n  onRefresh,\n  enabled = true,\n  threshold = DEFAULT_THRESHOLD,\n  maxPull = DEFAULT_MAX_PULL,\n}: UsePullToRefreshOptions): PullToRefreshState {\n  const [offset, setOffset] = useState(0);\n  const [isRefreshing, setIsRefreshing] = useState(false);\n  const [isActive, setIsActive] = useState(false);\n\n  // Native haptics on the mobile shell; a safe no-op on plain web.\n  const native = useNativeCapabilities();\n\n  // Values read inside native event handlers are mirrored in refs so the\n  // listeners can stay bound across renders without going stale.\n  const offsetRef = useRef(0);\n  const startXRef = useRef(0);\n  const startYRef = useRef<number | null>(null);\n  // Identifier of the finger that started the pull, so unrelated touches\n  // (a second finger lifting) can't complete or cancel the gesture.\n  const touchIdRef = useRef<number | null>(null);\n  const pullingRef = useRef(false);\n  const refreshingRef = useRef(false);\n  const armedRef = useRef(false);\n  const resetTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const onRefreshRef = useRef(onRefresh);\n  const nativeRef = useRef(native);\n\n  useEffect(() => {\n    onRefreshRef.current = onRefresh;\n  }, [onRefresh]);\n\n  useEffect(() => {\n    nativeRef.current = native;\n  }, [native]);\n\n  useEffect(() => {\n    const el = scrollRef.current;\n    if (!el || !enabled || !onRefresh) return;\n\n    const setOffsetBoth = (value: number) => {\n      offsetRef.current = value;\n      setOffset(value);\n    };\n\n    const findTouch = (list: TouchList, id: number): Touch | null => {\n      for (let i = 0; i < list.length; i += 1) {\n        const touch = list.item(i);\n        if (touch && touch.identifier === id) return touch;\n      }\n      return null;\n    };\n\n    // Pull-to-refresh must yield to any nested scroller the finger is over.\n    // Walk from the touch target up to the scroll container: if any element in\n    // that chain is scrolled down, the user is scrolling *that* element back up,\n    // not pulling to refresh. A non-zero scrollTop is itself proof the element\n    // is a scrolled scroll-container, so no overflow/style probing is needed\n    // (and this stays correct in jsdom, where computed styles aren't applied).\n    const scrollChainAtTop = (target: EventTarget | null): boolean => {\n      let node: Element | null = target instanceof Element ? target : null;\n      while (node) {\n        if (node.scrollTop > 0) return false;\n        if (node === el) break;\n        node = node.parentElement;\n      }\n      return true;\n    };\n\n    const endGesture = () => {\n      pullingRef.current = false;\n      armedRef.current = false;\n      startYRef.current = null;\n      touchIdRef.current = null;\n      setIsActive(false);\n    };\n\n    const triggerRefresh = () => {\n      refreshingRef.current = true;\n      setIsRefreshing(true);\n      setOffsetBoth(threshold);\n      nativeRef.current.haptic(\"light\");\n      const start = Date.now();\n      void Promise.resolve()\n        .then(() => onRefreshRef.current?.())\n        .catch(() => {\n          // Surface nothing here; the underlying queries own error state.\n        })\n        .finally(() => {\n          const wait = Math.max(0, MIN_SPINNER_MS - (Date.now() - start));\n          resetTimerRef.current = setTimeout(() => {\n            refreshingRef.current = false;\n            setIsRefreshing(false);\n            setOffsetBoth(0);\n          }, wait);\n        });\n    };\n\n    const handleTouchStart = (e: TouchEvent) => {\n      // Ignore additional fingers while a gesture is already tracked, and never\n      // engage when the finger is over a nested scroller that isn't at its top.\n      if (\n        refreshingRef.current ||\n        touchIdRef.current !== null ||\n        !scrollChainAtTop(e.target)\n      ) {\n        return;\n      }\n      const touch = e.changedTouches[0];\n      if (!touch) return;\n      touchIdRef.current = touch.identifier;\n      startXRef.current = touch.clientX;\n      startYRef.current = touch.clientY;\n      pullingRef.current = false;\n    };\n\n    const handleTouchMove = (e: TouchEvent) => {\n      if (\n        refreshingRef.current ||\n        touchIdRef.current === null ||\n        startYRef.current === null\n      ) {\n        return;\n      }\n      const touch = findTouch(e.touches, touchIdRef.current);\n      if (!touch) return;\n      const dy = touch.clientY - startYRef.current;\n      const dx = touch.clientX - startXRef.current;\n\n      if (!pullingRef.current) {\n        // Wait for a decisive drag before locking a direction, so a nearly\n        // horizontal (or barely-vertical diagonal) swipe never gets captured.\n        if (Math.max(Math.abs(dx), Math.abs(dy)) < DIRECTION_LOCK_SLOP) return;\n        // Only lock to pull-to-refresh for a clearly downward drag at the top;\n        // otherwise release the touch so native scrolling proceeds.\n        if (\n          dy <= 0 ||\n          Math.abs(dx) > Math.abs(dy) ||\n          !scrollChainAtTop(e.target)\n        ) {\n          endGesture();\n          return;\n        }\n        pullingRef.current = true;\n        setIsActive(true);\n      } else if (dy <= 0 || !scrollChainAtTop(e.target)) {\n        // A committed pull dragged back to/above the top: cancel it.\n        endGesture();\n        setOffsetBoth(0);\n        return;\n      }\n      // Suppress native scroll/overscroll while we own the gesture.\n      e.preventDefault();\n      const next = Math.min(dy * RESISTANCE, maxPull);\n      // Fire a single \"release to refresh\" cue the moment we cross the\n      // threshold; re-arm only after the user pulls back below it.\n      if (next >= threshold && !armedRef.current) {\n        armedRef.current = true;\n        nativeRef.current.haptic(\"selection\");\n      } else if (next < threshold && armedRef.current) {\n        armedRef.current = false;\n      }\n      setOffsetBoth(next);\n    };\n\n    /** Is `e` the finger that started the active pull? */\n    const isTrackedTouch = (e: TouchEvent): boolean =>\n      touchIdRef.current !== null &&\n      findTouch(e.changedTouches, touchIdRef.current) !== null;\n\n    const handleTouchEnd = (e: TouchEvent) => {\n      if (!isTrackedTouch(e)) return;\n      const shouldRefresh =\n        pullingRef.current && offsetRef.current >= threshold;\n      endGesture();\n      if (shouldRefresh) {\n        triggerRefresh();\n      } else {\n        setOffsetBoth(0);\n      }\n    };\n\n    // A cancelled touch (interrupted by the system) is never a deliberate\n    // release, so it resets without ever triggering a refresh.\n    const handleTouchCancel = (e: TouchEvent) => {\n      if (!isTrackedTouch(e)) return;\n      endGesture();\n      setOffsetBoth(0);\n    };\n\n    el.addEventListener(\"touchstart\", handleTouchStart, { passive: true });\n    el.addEventListener(\"touchmove\", handleTouchMove, { passive: false });\n    el.addEventListener(\"touchend\", handleTouchEnd, { passive: true });\n    el.addEventListener(\"touchcancel\", handleTouchCancel, { passive: true });\n\n    return () => {\n      el.removeEventListener(\"touchstart\", handleTouchStart);\n      el.removeEventListener(\"touchmove\", handleTouchMove);\n      el.removeEventListener(\"touchend\", handleTouchEnd);\n      el.removeEventListener(\"touchcancel\", handleTouchCancel);\n      if (resetTimerRef.current) clearTimeout(resetTimerRef.current);\n    };\n  }, [scrollRef, enabled, onRefresh, threshold, maxPull]);\n\n  return {\n    offset,\n    isRefreshing,\n    isActive,\n    progress: Math.min(offset / threshold, 1),\n  };\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { useLayoutEffect, useRef } from \"react\";\nimport { RefreshCw } from \"lucide-react\";\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarHeader,\n  SidebarInset,\n  SidebarProvider,\n} from \"./sidebar\";\nimport { useSuppressInitialIframeFocusScroll } from \"./use-suppress-initial-iframe-focus-scroll\";\nimport { useScrollRestoration } from \"./use-scroll-restoration\";\nimport { useBottomNavHidden } from \"./BottomNavVisibilityContext\";\nimport { usePullToRefresh } from \"./use-pull-to-refresh\";\n\nexport interface AppShellLayoutProps {\n  /** Navigation content rendered inside the sidebar's scrollable area */\n  sidebarContent: React.ReactNode;\n  /** Header content rendered above the main content area */\n  headerContent: React.ReactNode;\n  /** Main page content */\n  children: React.ReactNode;\n  /** Optional slot at the top of the sidebar (e.g. logo, search) */\n  sidebarHeader?: React.ReactNode;\n  /** Optional slot at the bottom of the sidebar (e.g. user info) */\n  sidebarFooter?: React.ReactNode;\n  /** Content rendered after SidebarInset (e.g. MobileBottomNav) */\n  afterContent?: React.ReactNode;\n  /** Enable bottom nav mode (hides sidebar on mobile, adds bottom padding) */\n  useBottomNav?: boolean;\n  /** Active route slug — enables per-route scroll restoration when provided. */\n  currentSlug?: string;\n  /**\n   * Pull-to-refresh handler for the screen content area. When provided, a\n   * touch-driven pull-down gesture on the scroll container invokes this and\n   * shows a spinner until it settles. Omit to disable the gesture.\n   */\n  onRefresh?: (() => Promise<void> | void) | undefined;\n}\n\n/**\n * Pure visual frame that replicates the RepApp layout:\n * - 13rem collapsible sidebar\n * - 52px header area\n * - rounded-xl bg-background shadow-lg content area with bg-muted gutters\n *\n * This component handles zero business logic — it simply provides the visual shell.\n */\nexport function AppShellLayout({\n  sidebarContent,\n  headerContent,\n  children,\n  sidebarHeader,\n  sidebarFooter,\n  afterContent,\n  useBottomNav = false,\n  currentSlug,\n  onRefresh,\n}: AppShellLayoutProps): React.JSX.Element {\n  const screenContentRef = useRef<HTMLDivElement>(null);\n  const bottomNavHidden = useBottomNavHidden();\n\n  useScrollRestoration(screenContentRef, currentSlug ?? \"\");\n  const {\n    offset: pullOffset,\n    isRefreshing,\n    isActive: isPulling,\n    progress: pullProgress,\n  } = usePullToRefresh({\n    scrollRef: screenContentRef,\n    onRefresh,\n    enabled: onRefresh != null,\n  });\n\n  // Reserve space for the fixed bottom nav on mobile. When a drill-down surface\n  // hides the nav (e.g. an open conversation), drop the padding entirely so the\n  // now full-screen surface owns its bottom edge — including the safe-area\n  // inset (e.g. the messaging composer already pads for the home indicator).\n  // Padding it here too would double the inset. Animated to match the nav's\n  // slide, so content and chrome move together.\n  const mobileBottomPadding = useBottomNav\n    ? bottomNavHidden\n      ? \"max-md:pb-0\"\n      : \"max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\"\n    : \"\";\n\n  // Publish the screen content slot's measured pixel height as\n  // `--portal-fullscreen-embed-height` so descendants (e.g. EmbedWidget in\n  // inline + Full Screen mode) can anchor against the visible portal screen\n  // area instead of the browser viewport. Mirrors the admin builder's\n  // ScreenContentSlot in `packages/portal/builder/src/components/core/RepApp.tsx`.\n  useLayoutEffect(() => {\n    const el = screenContentRef.current;\n    if (!el) return;\n    const update = () => {\n      el.style.setProperty(\n        \"--portal-fullscreen-embed-height\",\n        `${el.clientHeight}px`,\n      );\n    };\n    update();\n    const obs = new ResizeObserver(update);\n    obs.observe(el);\n    return () => obs.disconnect();\n  }, []);\n\n  useSuppressInitialIframeFocusScroll(screenContentRef);\n\n  return (\n    <SidebarProvider useBottomNav={useBottomNav}>\n      <div className=\"bg-muted relative flex h-[var(--fluid-portal-viewport-height,100dvh)] max-h-[var(--fluid-portal-viewport-height,100dvh)] w-full overflow-hidden\">\n        {/* Navigation Sidebar */}\n        <Sidebar collapsible=\"icon\">\n          {sidebarHeader && <SidebarHeader>{sidebarHeader}</SidebarHeader>}\n          <SidebarContent className=\"p-4\">{sidebarContent}</SidebarContent>\n          {sidebarFooter && <SidebarFooter>{sidebarFooter}</SidebarFooter>}\n        </Sidebar>\n\n        {/* Main Content Area */}\n        <SidebarInset className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n          {/* Header */}\n          {headerContent}\n\n          {/* Screen Content */}\n          <div\n            className={`bg-muted relative min-h-0 flex-1 overflow-hidden transition-[padding] duration-300 ease-out motion-reduce:transition-none md:pt-4 md:pr-4 md:pb-4 md:pl-2 ${mobileBottomPadding}`}\n          >\n            {/* Pull-to-refresh indicator */}\n            {onRefresh != null && (pullOffset > 0 || isRefreshing) && (\n              <div\n                aria-hidden\n                className=\"pointer-events-none absolute inset-x-0 top-0 z-10 flex justify-center\"\n                style={{\n                  transform: `translateY(${pullOffset - 40}px)`,\n                  opacity: isRefreshing ? 1 : pullProgress,\n                  transition: isPulling\n                    ? \"none\"\n                    : \"transform 200ms ease-out, opacity 200ms ease-out\",\n                }}\n              >\n                <div className=\"ring-foreground/5 bg-background text-muted-foreground flex size-8 items-center justify-center rounded-full shadow-sm ring-1\">\n                  <RefreshCw\n                    className={`size-4 ${isRefreshing ? \"animate-spin\" : \"\"}`}\n                    style={\n                      isRefreshing\n                        ? undefined\n                        : { transform: `rotate(${pullProgress * 270}deg)` }\n                    }\n                  />\n                </div>\n              </div>\n            )}\n            <div\n              ref={screenContentRef}\n              data-fluid-portal-screen-area=\"\"\n              tabIndex={-1}\n              className=\"ring-foreground/5 scrollbar-none bg-background text-foreground h-full overflow-x-hidden overflow-y-auto rounded-xl shadow-sm ring-1 max-md:rounded-b-none max-md:shadow-none max-md:ring-0\"\n              style={{\n                transform:\n                  pullOffset > 0 ? `translateY(${pullOffset}px)` : undefined,\n                transition: isPulling ? \"none\" : \"transform 200ms ease-out\",\n              }}\n            >\n              {children}\n            </div>\n          </div>\n        </SidebarInset>\n\n        {/* After content (e.g. MobileBottomNav) */}\n        {afterContent}\n      </div>\n    </SidebarProvider>\n  );\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport {\n  createContext,\n  type ReactNode,\n  use,\n  useCallback,\n  useMemo,\n  useSyncExternalStore,\n} from \"react\";\n\nexport type ThemeMode = \"auto\" | \"light\" | \"dark\";\n\nexport type DisplayMode = \"light\" | \"dark\";\n\nexport interface ThemeModeContextValue {\n  mode: ThemeMode;\n  displayMode: DisplayMode;\n  setMode: (mode: ThemeMode) => void;\n  autoModeEnabled: boolean;\n  cycleMode: () => void;\n  dataAttribute: string | undefined;\n}\n\nconst ThemeModeContext = createContext<ThemeModeContextValue | null>(null);\n\nconst darkMediaQuery =\n  typeof window !== \"undefined\"\n    ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n    : null;\n\nfunction subscribeToPrefersColorScheme(callback: () => void) {\n  darkMediaQuery?.addEventListener(\"change\", callback);\n  return () => darkMediaQuery?.removeEventListener(\"change\", callback);\n}\n\nfunction getSystemPrefersDark(): boolean {\n  return darkMediaQuery?.matches ?? false;\n}\n\nfunction getServerSnapshot(): boolean {\n  return false;\n}\n\ninterface ThemeModeProviderProps {\n  children: ReactNode;\n  mode: ThemeMode;\n  onModeChange: (mode: ThemeMode) => void;\n  /** When false, auto mode is skipped in the cycle (light↔dark only). Default true. */\n  autoModeEnabled?: boolean;\n}\n\nexport function ThemeModeProvider({\n  children,\n  mode,\n  onModeChange,\n  autoModeEnabled = true,\n}: ThemeModeProviderProps): React.JSX.Element {\n  const systemPrefersDark = useSyncExternalStore(\n    subscribeToPrefersColorScheme,\n    getSystemPrefersDark,\n    getServerSnapshot,\n  );\n\n  const systemMode: DisplayMode = systemPrefersDark ? \"dark\" : \"light\";\n\n  const displayMode: DisplayMode = mode === \"auto\" ? systemMode : mode;\n\n  const cycleMode = useCallback(() => {\n    if (autoModeEnabled) {\n      // Toggle displayed mode. If target matches system preference, use \"auto\".\n      const target: DisplayMode = displayMode === \"light\" ? \"dark\" : \"light\";\n      onModeChange(target === systemMode ? \"auto\" : target);\n    } else {\n      // light ↔ dark\n      onModeChange(mode === \"light\" ? \"dark\" : \"light\");\n    }\n  }, [mode, displayMode, systemMode, onModeChange, autoModeEnabled]);\n\n  const dataAttribute = getThemeModeAttribute(mode);\n\n  const value = useMemo(\n    () => ({\n      mode,\n      displayMode,\n      setMode: onModeChange,\n      autoModeEnabled,\n      cycleMode,\n      dataAttribute,\n    }),\n    [\n      mode,\n      displayMode,\n      onModeChange,\n      autoModeEnabled,\n      cycleMode,\n      dataAttribute,\n    ],\n  );\n\n  return (\n    <ThemeModeContext.Provider value={value}>\n      {children}\n    </ThemeModeContext.Provider>\n  );\n}\n\n/** Access the current theme mode, setter, and cycle helper. Must be used within a `ThemeModeProvider`. */\nexport function useThemeMode(): ThemeModeContextValue {\n  const ctx = use(ThemeModeContext);\n  if (!ctx) {\n    throw new Error(\"useThemeMode must be used within a ThemeModeProvider\");\n  }\n  return ctx;\n}\n\n/** Maps a ThemeMode to the value for `data-theme-mode`. Returns undefined for \"auto\". */\nexport function getThemeModeAttribute(mode: ThemeMode): string | undefined {\n  return mode === \"auto\" ? undefined : mode;\n}\n","import {\n  SYSTEM_NAVIGATION_ITEMS,\n  type SystemNavigationSlug,\n} from \"./system-navigation-items\";\nimport type { NavigationItem } from \"../types/navigation\";\n\n/**\n * Build a NavigationItem from a system navigation slug.\n * Icons and labels come from SYSTEM_NAVIGATION_ITEMS (single source of truth).\n */\nfunction systemNavItem(slug: SystemNavigationSlug): NavigationItem {\n  const item = SYSTEM_NAVIGATION_ITEMS[slug];\n  return {\n    slug: item.slug,\n    label: item.label,\n    icon: item.icon,\n    children: [],\n  };\n}\n\nfunction sectionHeader(label: string): NavigationItem {\n  return { label, children: [] };\n}\n\n/**\n * Returns the default navigation items for a portal app when no\n * API data is available. All icons/labels derive from\n * SYSTEM_NAVIGATION_ITEMS so they can never drift.\n */\nexport function getDefaultNavigation(): NavigationItem[] {\n  return [\n    sectionHeader(\"We Commerce\"),\n    systemNavItem(\"shop\"),\n    systemNavItem(\"messages\"),\n    systemNavItem(\"contacts\"),\n    systemNavItem(\"profile\"),\n    systemNavItem(\"orders\"),\n    systemNavItem(\"subscriptions\"),\n    sectionHeader(\"Marketing Assets\"),\n    systemNavItem(\"share/products\"),\n  ];\n}\n","import type React from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport {\n  Bell,\n  Box,\n  Boxes,\n  Briefcase,\n  Calendar,\n  CircleUser,\n  Compass,\n  ContactRound,\n  File,\n  FileText,\n  FileVideo,\n  Folder,\n  FolderOpen,\n  Globe,\n  GraduationCap,\n  Heart,\n  House,\n  Image,\n  LayoutGrid,\n  ListMusic,\n  Mail,\n  MessageCircle,\n  MessageCircleHeart,\n  MessageSquare,\n  PackageOpen,\n  Puzzle,\n  Repeat,\n  Search,\n  Settings,\n  ShoppingCart,\n  Star,\n  Store,\n  User,\n  UserCog,\n  Users,\n} from \"lucide-react\";\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n  \"address-card\": ContactRound,\n  \"arrows-repeat\": Repeat,\n  bell: Bell,\n  box: Box,\n  \"boxes-stacked\": Boxes,\n  briefcase: Briefcase,\n  calendar: Calendar,\n  \"cart-shopping\": ShoppingCart,\n  \"circle-user\": CircleUser,\n  comment: MessageCircle,\n  compass: Compass,\n  envelope: Mail,\n  file: File,\n  \"file-lines\": FileText,\n  \"file-video\": FileVideo,\n  folder: Folder,\n  \"folder-open\": FolderOpen,\n  gear: Settings,\n  globe: Globe,\n  \"graduation-cap\": GraduationCap,\n  heart: Heart,\n  house: House,\n  image: Image,\n  \"list-music\": ListMusic,\n  \"magnifying-glass\": Search,\n  message: MessageSquare,\n  // The widget CLI scaffolds these two, so an authored widget lands on a real\n  // icon instead of the generic fallback.\n  \"message-circle-heart\": MessageCircleHeart,\n  \"package-open\": PackageOpen,\n  \"puzzle-piece\": Puzzle,\n  star: Star,\n  store: Store,\n  \"table-cells-large\": LayoutGrid,\n  user: User,\n  \"user-gear\": UserCog,\n  users: Users,\n};\n\ninterface RepIconProps {\n  name: string;\n  className?: string;\n}\n\nexport function RepIcon({ name, className }: RepIconProps): React.JSX.Element {\n  const Icon = ICON_MAP[name] ?? File;\n  return <Icon className={className} />;\n}\n","/**\n * Utility functions for managing navigation state in localStorage\n */\n\nconst STORAGE_PREFIX = \"portal-app-last-tab\";\n\n/**\n * Gets the localStorage key for a specific app and top-level section\n */\nfunction getStorageKey(appDefinitionId: number, topLevelSlug: string): string {\n  return `${STORAGE_PREFIX}-${appDefinitionId}-${topLevelSlug}`;\n}\n\n/**\n * Retrieves the last visited tab slug for a given section\n */\nexport function getLastVisitedTab(\n  appDefinitionId: number,\n  topLevelSlug: string,\n): string | null {\n  if (typeof window === \"undefined\") return null;\n\n  try {\n    const key = getStorageKey(appDefinitionId, topLevelSlug);\n    return localStorage.getItem(key);\n  } catch (error) {\n    console.warn(\"Failed to read from localStorage:\", error);\n    return null;\n  }\n}\n\n/**\n * Stores the last visited tab slug for a given section\n */\nexport function setLastVisitedTab(\n  appDefinitionId: number,\n  topLevelSlug: string,\n  tabSlug: string,\n): void {\n  if (typeof window === \"undefined\") return;\n\n  try {\n    const key = getStorageKey(appDefinitionId, topLevelSlug);\n    localStorage.setItem(key, tabSlug);\n  } catch (error) {\n    console.warn(\"Failed to write to localStorage:\", error);\n  }\n}\n\n/**\n * Clears the last visited tab for a given section\n */\nexport function clearLastVisitedTab(\n  appDefinitionId: number,\n  topLevelSlug: string,\n): void {\n  if (typeof window === \"undefined\") return;\n\n  try {\n    const key = getStorageKey(appDefinitionId, topLevelSlug);\n    localStorage.removeItem(key);\n  } catch (error) {\n    console.warn(\"Failed to remove from localStorage:\", error);\n  }\n}\n","import type { NavigationItem } from \"../types/navigation\";\nimport { normalizeSlug } from \"./system-navigation-items\";\nimport { getLastVisitedTab } from \"./navigation-storage\";\n\n/**\n * True when `normalizedRoute` is the section's slug or a descendant of it, so a\n * tab stays selected while drilling into its sub-routes (e.g. `shop` stays\n * active on a product detail at `shop/123`). The trailing \"/\" keeps the match\n * on a path boundary so `shop` does not match an unrelated `shopping` route.\n */\nfunction routeMatchesSection(\n  normalizedRoute: string,\n  slug: string | undefined,\n): boolean {\n  const normalizedSlug = normalizeSlug(slug);\n  if (!normalizedSlug) return false;\n  return (\n    normalizedRoute === normalizedSlug ||\n    normalizedRoute.startsWith(`${normalizedSlug}/`)\n  );\n}\n\n/**\n * Helper function to determine if the current route is within a top-level section\n */\nexport function isInSection(\n  topLevelItem: NavigationItem,\n  currentRoute: string,\n): boolean {\n  const normalizedCurrentRoute = normalizeSlug(currentRoute);\n\n  if (topLevelItem.children && topLevelItem.children.length > 0) {\n    return topLevelItem.children.some((child: NavigationItem) =>\n      routeMatchesSection(normalizedCurrentRoute, child.slug),\n    );\n  }\n\n  return routeMatchesSection(normalizedCurrentRoute, topLevelItem.slug);\n}\n\n/**\n * Get the target slug when clicking a top-level navigation item\n */\nexport function getNavigationTarget(\n  item: NavigationItem,\n  appDefinitionId: number,\n): string | null {\n  // If it has children, it's always a section parent — navigate to a child\n  if (item.children && item.children.length > 0) {\n    // Try to get the last visited tab from localStorage (only if parent has a slug for the key)\n    if (item.slug) {\n      const lastVisitedSlug = getLastVisitedTab(appDefinitionId, item.slug);\n\n      // If we have a last visited tab and it exists in the children, use it\n      if (lastVisitedSlug) {\n        const normalizedLastVisited = normalizeSlug(lastVisitedSlug);\n        const childExists = item.children.some((child: NavigationItem) => {\n          const normalizedChildSlug = normalizeSlug(child.slug);\n          return normalizedChildSlug === normalizedLastVisited;\n        });\n        if (childExists) {\n          return normalizedLastVisited;\n        }\n      }\n    }\n\n    // Default to the first child's slug\n    const firstChild = item.children[0];\n    if (firstChild?.slug) {\n      return normalizeSlug(firstChild.slug);\n    }\n\n    return null;\n  }\n\n  // If it's a leaf node with a screen, return its slug directly (normalized)\n  if (item.screen_id && item.slug) {\n    return normalizeSlug(item.slug);\n  }\n\n  // If it's a leaf node with just a slug (system nav items like account, messages, etc.)\n  if (item.slug) {\n    return normalizeSlug(item.slug);\n  }\n\n  return null;\n}\n","import type { TranslationApi } from \"@fluid-app/i18n/translation-api\";\nimport type { ShellDict } from \"../shell-translation-dictionary\";\nimport { shellEn } from \"../shell-translation-dictionary\";\n\n/**\n * Derive a shell translation key from a navigation slug.\n *\n * Converts slugs like \"app-download\" → \"nav_label_app_download\"\n * and \"share/media\" → \"nav_label_share_media\".\n */\nfunction slugToTranslationKey(slug: string): string {\n  return `nav_label_${slug.replace(/-/g, \"_\").replace(/\\//g, \"_\")}`;\n}\n\n/**\n * Derive a shell translation key from a section header label.\n *\n * Converts labels like \"We Commerce\" → \"nav_section_we_commerce\"\n * and \"Marketing Assets\" → \"nav_section_marketing_assets\".\n */\nfunction sectionToTranslationKey(label: string): string {\n  return `nav_section_${label.toLowerCase().replace(/\\s+/g, \"_\")}`;\n}\n\n/**\n * Check whether a builder has customized the label by comparing it against the\n * English default. If the fallback label differs from the English dictionary\n * value, the builder intentionally renamed the nav item and we should honour\n * their custom label rather than overriding it with a translation.\n */\nfunction isCustomLabel(key: string, fallbackLabel: string): boolean {\n  const englishDefault = (shellEn as Record<string, string>)[key];\n  return englishDefault !== undefined && fallbackLabel !== englishDefault;\n}\n\n/**\n * Translate a navigation item label using the shell translation dictionary.\n *\n * Looks up `nav_label_<normalized_slug>` in the dictionary. Falls back to the\n * raw `label` when:\n * - the slug is absent or has no matching translation key\n * - the builder has customised the label (differs from the English default)\n */\nexport function translateNavLabel(\n  api: TranslationApi<ShellDict>,\n  slug: string | undefined,\n  fallbackLabel: string,\n): string {\n  if (!slug) return fallbackLabel;\n  const t = api.t as (key: string) => string;\n  const slugKey = slugToTranslationKey(slug);\n\n  if (!isCustomLabel(slugKey, fallbackLabel)) {\n    const translated = t(slugKey);\n    if (translated !== slugKey) return translated;\n  }\n\n  // Slug didn't match (e.g. account has slug \"profile\" but label \"Account\").\n  // Try a key derived from the label itself before falling back to raw English.\n  const labelKey = `nav_label_${fallbackLabel.toLowerCase().replace(/[-\\s]+/g, \"_\")}`;\n  if (labelKey !== slugKey) {\n    const translated = t(labelKey);\n    if (translated !== labelKey) return translated;\n  }\n\n  return fallbackLabel;\n}\n\n/**\n * Translate a sidebar section header label using the shell translation dictionary.\n *\n * Looks up `nav_section_<normalized_label>` in the dictionary. Falls back to the\n * raw `label` when no matching translation key exists or when the builder has\n * customised the section name.\n */\nexport function translateSectionLabel(\n  api: TranslationApi<ShellDict>,\n  label: string,\n): string {\n  const key = sectionToTranslationKey(label);\n  // If the builder renamed the section, honour their custom label\n  if (isCustomLabel(key, label)) return label;\n  const translated = (api.t as (key: string) => string)(key);\n  return translated === key ? label : translated;\n}\n","import * as React from \"react\";\nimport { Ellipsis } from \"lucide-react\";\nimport { MobileBottomSheet } from \"@fluid-app/ui-components/components/MobileBottomSheet\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n  isInSection,\n  getNavigationTarget,\n} from \"@fluid-app/portal-core/navigation/utils\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { useHaptics } from \"@fluid-app/portal-react/shell/use-haptics\";\nimport { useBottomNavHidden } from \"@fluid-app/portal-react/shell/BottomNavVisibilityContext\";\nimport { translateNavLabel } from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport type { NavigationItem } from \"../types/navigation\";\n\ninterface SdkBottomNavProps {\n  navItems: NavigationItem[];\n  currentSlug: string;\n  onNavigate: (slug: string) => void;\n  appDefinitionId?: number;\n  maxVisibleItems?: number;\n}\n\nexport function SdkBottomNav({\n  navItems,\n  currentSlug,\n  onNavigate,\n  appDefinitionId = 0,\n  maxVisibleItems = 6,\n}: SdkBottomNavProps): React.JSX.Element | null {\n  const { isMobile, useBottomNav } = useSidebar();\n  const shellApi = useShellTranslation();\n  const { t } = shellApi;\n  const haptics = useHaptics();\n  // Drill-down surfaces (e.g. an open conversation) hide the nav for a native\n  // full-screen feel. Kept mounted so it can slide/fade rather than pop out.\n  const hidden = useBottomNavHidden();\n  const [moreOpen, setMoreOpen] = React.useState(false);\n\n  if (!isMobile || !useBottomNav) return null;\n\n  const navigableItems = navItems\n    .filter((item) => !item.parent_id)\n    .filter((item) => item.slug || (item.children && item.children.length > 0));\n\n  const hasOverflow = navigableItems.length > maxVisibleItems;\n  const visibleItems = hasOverflow\n    ? navigableItems.slice(0, maxVisibleItems - 1)\n    : navigableItems;\n  const overflowItems = hasOverflow\n    ? navigableItems.slice(maxVisibleItems - 1)\n    : [];\n\n  // The \"More\" tab counts as active when any overflow item is in section.\n  const overflowIsActive = overflowItems.some((item) =>\n    isInSection(item, currentSlug),\n  );\n\n  const handleItemClick = (item: NavigationItem) => {\n    const target = getNavigationTarget(item, appDefinitionId);\n    if (target) {\n      haptics.tap();\n      onNavigate(target);\n    }\n    setMoreOpen(false);\n  };\n\n  const handleMoreClick = () => {\n    haptics.tap();\n    setMoreOpen(true);\n  };\n\n  return (\n    <>\n      <nav\n        data-fluid-bottom-nav=\"\"\n        data-hidden={hidden ? \"\" : undefined}\n        aria-hidden={hidden || undefined}\n        inert={hidden}\n        className={`border-border bg-sidebar fixed right-0 bottom-0 left-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] items-start justify-around border-t pb-[env(safe-area-inset-bottom)] transition-[transform,opacity] duration-300 ease-out motion-reduce:transition-none ${\n          hidden\n            ? \"pointer-events-none translate-y-full opacity-0\"\n            : \"translate-y-0 opacity-100\"\n        }`}\n      >\n        {visibleItems.map((item) => {\n          const isActive = isInSection(item, currentSlug);\n          return (\n            <button\n              key={item.id ?? item.slug ?? item.label}\n              type=\"button\"\n              onClick={() => handleItemClick(item)}\n              aria-current={isActive ? \"page\" : undefined}\n              className={`flex h-14 flex-1 touch-manipulation flex-col items-center justify-center gap-0.5 pt-2 pb-1 text-[10px] font-medium transition-[color,transform] duration-150 active:scale-95 ${\n                isActive ? \"text-primary\" : \"text-muted-foreground\"\n              }`}\n            >\n              <RepIcon name={item.icon || \"file\"} className=\"size-5\" />\n              <span className=\"max-w-[72px] truncate\">\n                {translateNavLabel(shellApi, item.slug, item.label)}\n              </span>\n            </button>\n          );\n        })}\n\n        {hasOverflow && (\n          <button\n            type=\"button\"\n            onClick={handleMoreClick}\n            aria-current={overflowIsActive ? \"page\" : undefined}\n            className={`flex h-14 flex-1 touch-manipulation flex-col items-center justify-center gap-0.5 pt-2 pb-1 text-[10px] font-medium transition-[color,transform] duration-150 active:scale-95 ${\n              overflowIsActive ? \"text-primary\" : \"text-muted-foreground\"\n            }`}\n          >\n            <Ellipsis className=\"size-5\" />\n            <span>{t(\"nav_more\")}</span>\n          </button>\n        )}\n      </nav>\n\n      <MobileBottomSheet\n        open={moreOpen}\n        onOpenChange={setMoreOpen}\n        title={t(\"nav_more\")}\n        surface=\"sidebar\"\n      >\n        {overflowItems.map((item) => {\n          const isActive = isInSection(item, currentSlug);\n          return (\n            <button\n              key={item.id ?? item.slug ?? item.label}\n              type=\"button\"\n              onClick={() => handleItemClick(item)}\n              className={`flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors ${\n                isActive\n                  ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n                  : \"text-sidebar-foreground hover:bg-sidebar-accent\"\n              }`}\n            >\n              <RepIcon name={item.icon || \"file\"} className=\"size-5\" />\n              <span>{translateNavLabel(shellApi, item.slug, item.label)}</span>\n            </button>\n          );\n        })}\n      </MobileBottomSheet>\n    </>\n  );\n}\n","/**\n * A silhouette of the portal shell — a header bar, a few content placeholders,\n * and a bottom-nav strip — shown while the app is loading instead of a bare\n * spinner. Rendering the *shape* of the app (not a spinner on blank) makes the\n * cold start read as \"the app is already here, filling in\" rather than \"a web\n * page is loading.\"\n *\n * Uses only base semantic tokens (`bg-muted`, `bg-background`, `border-border`)\n * which are defined at `:root` before the brand theme loads, so it renders\n * correctly even during the very first paint. Safe-area insets are honored so\n * the silhouette lines up with the real header/nav it stands in for.\n *\n * `variant=\"content\"` omits the header/nav chrome for use inside a screen\n * container (e.g. a route Suspense fallback) where the shell is already\n * painted around it.\n *\n * `label` is an optional translated loading string rendered visually hidden for\n * assistive tech. Taken as a prop (rather than read from a translation hook)\n * so this foundational component stays free of provider assumptions and renders\n * in any context, translated where the caller has a `t()`.\n */\nexport function AppShellSkeleton({\n  variant = \"full\",\n  label,\n}: {\n  variant?: \"full\" | \"content\";\n  label?: string;\n}): React.JSX.Element {\n  const srLabel = label ? <span className=\"sr-only\">{label}</span> : null;\n\n  // portal-react is a foundational layer that deliberately doesn't depend on\n  // ui-primitives, so this reuses the shadcn Skeleton primitive's style rather\n  // than importing the component. Tinted off the foreground instead of bg-muted\n  // because the container below is muted, matching the loaded shell.\n  const block =\n    \"bg-foreground/5 animate-pulse rounded-md motion-reduce:animate-none\";\n\n  const content = (\n    <div className=\"flex flex-1 flex-col gap-4 px-4 py-5\" aria-hidden>\n      <div className={`${block} h-7 w-40`} />\n      <div className={`${block} h-32 w-full`} />\n      <div className={`${block} h-24 w-full`} />\n      <div className={`${block} h-24 w-full`} />\n    </div>\n  );\n\n  if (variant === \"content\") {\n    return (\n      <div\n        className=\"flex h-full w-full flex-col\"\n        role=\"status\"\n        aria-busy=\"true\"\n      >\n        {srLabel}\n        {content}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      className=\"bg-muted flex h-[var(--fluid-portal-viewport-height,100dvh)] w-full flex-col\"\n      role=\"status\"\n      aria-busy=\"true\"\n    >\n      {srLabel}\n      <div className=\"border-border flex items-center justify-between border-b px-4 pt-[calc(env(safe-area-inset-top)+0.75rem)] pb-3\">\n        <div className={`${block} h-5 w-28`} />\n        <div className={`${block} size-8 rounded-full`} />\n      </div>\n\n      {content}\n\n      <div className=\"border-border flex items-start justify-around border-t px-2 pt-2 pb-[calc(env(safe-area-inset-bottom)+0.5rem)]\">\n        {Array.from({ length: 5 }).map((_, index) => (\n          <div\n            key={index}\n            className=\"flex flex-1 flex-col items-center gap-1.5 py-1\"\n          >\n            <div className={`${block} size-5`} />\n            <div className={`${block} h-2 w-10`} />\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n","import { AppShellSkeleton } from \"@fluid-app/portal-react/shell/AppShellSkeleton\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\n\n/**\n * Shown while AppShell fetches app data for the first time. Renders a\n * silhouette of the shell (header + content + bottom nav) rather than a\n * spinner on blank, so the cold start reads as the app filling in. The\n * skeleton relies only on base semantic tokens, which resolve before the\n * brand theme loads. Passes the translated loading label for assistive tech.\n */\nexport function AppShellLoading(): React.JSX.Element {\n  const { t } = useShellTranslation();\n  return <AppShellSkeleton label={t(\"loading\")} />;\n}\n","import { useEffect, useState } from \"react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { ChevronRight } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport {\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarMenuSub,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n  Collapsible,\n  CollapsibleTrigger,\n  CollapsibleContent,\n} from \"@fluid-app/ui-primitives\";\nimport { translateNavLabel } from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport type { NavigationItem } from \"../types/navigation\";\n\nexport interface CollapsibleNavItemProps {\n  item: NavigationItem;\n  isActive: boolean;\n  currentSlug: string;\n  onNavigate: (slug: string) => void;\n}\n\nexport function CollapsibleNavItem({\n  item,\n  isActive,\n  currentSlug,\n  onNavigate,\n}: CollapsibleNavItemProps): React.JSX.Element {\n  const [open, setOpen] = useState(isActive);\n  const shellApi = useShellTranslation();\n\n  useEffect(() => {\n    if (isActive) setOpen(true);\n  }, [isActive]);\n\n  return (\n    <Collapsible\n      open={open}\n      onOpenChange={setOpen}\n      asChild\n      className=\"group/collapsible\"\n    >\n      <SidebarMenuItem>\n        <CollapsibleTrigger asChild>\n          <SidebarMenuButton>\n            <RepIcon name={item.icon || \"file\"} />\n            <span className=\"truncate\">\n              {translateNavLabel(shellApi, item.slug, item.label)}\n            </span>\n            <ChevronRight className=\"ml-auto size-3 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n          </SidebarMenuButton>\n        </CollapsibleTrigger>\n        <CollapsibleContent>\n          <SidebarMenuSub>\n            {item.children.map((child) => {\n              const childSlug = normalizeSlug(child.slug);\n              const childIsActive = normalizeSlug(currentSlug) === childSlug;\n\n              return (\n                <SidebarMenuItem key={child.slug || child.label}>\n                  <SidebarMenuButton\n                    isActive={childIsActive}\n                    onClick={() => onNavigate(childSlug)}\n                  >\n                    <RepIcon name={child.icon || \"file\"} className=\"size-3\" />\n                    <span>\n                      {translateNavLabel(shellApi, child.slug, child.label)}\n                    </span>\n                  </SidebarMenuButton>\n                </SidebarMenuItem>\n              );\n            })}\n          </SidebarMenuSub>\n        </CollapsibleContent>\n      </SidebarMenuItem>\n    </Collapsible>\n  );\n}\n","import {\n  SidebarGroupLabel,\n  SidebarMenu,\n  SidebarMenuItem,\n  SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { isInSection } from \"@fluid-app/portal-core/navigation/utils\";\nimport {\n  translateNavLabel,\n  translateSectionLabel,\n} from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { CollapsibleNavItem } from \"./CollapsibleNavItem\";\n\nexport interface SdkNavigationProps {\n  navItems: NavigationItem[];\n  currentSlug: string;\n  onNavigate: (slug: string) => void;\n}\n\nexport function SdkNavigation({\n  navItems,\n  currentSlug,\n  onNavigate,\n}: SdkNavigationProps): React.JSX.Element {\n  const shellApi = useShellTranslation();\n\n  return (\n    <SidebarMenu>\n      {navItems.map((item, index) => {\n        // Skip items without slug AND without label\n        if (!item.slug && !item.label) return null;\n\n        const isActive = isInSection(item, currentSlug);\n        const hasChildren = item.children?.length > 0;\n\n        // Items with children — collapsible\n        if (hasChildren) {\n          return (\n            <CollapsibleNavItem\n              key={item.slug || item.label}\n              item={item}\n              isActive={isActive}\n              currentSlug={currentSlug}\n              onNavigate={onNavigate}\n            />\n          );\n        }\n\n        // Items without a slug are section headers\n        if (!item.slug) {\n          return (\n            <SidebarGroupLabel key={item.id ?? `section-${index}`}>\n              {translateSectionLabel(shellApi, item.label)}\n            </SidebarGroupLabel>\n          );\n        }\n\n        // Leaf item — no children\n        const itemSlug = normalizeSlug(item.slug);\n\n        return (\n          <SidebarMenuItem key={item.id ?? itemSlug}>\n            <SidebarMenuButton\n              isActive={isActive}\n              onClick={() => onNavigate(itemSlug)}\n            >\n              <RepIcon name={item.icon || \"file\"} />\n              <span className=\"truncate\">\n                {translateNavLabel(shellApi, item.slug, item.label)}\n              </span>\n            </SidebarMenuButton>\n          </SidebarMenuItem>\n        );\n      })}\n    </SidebarMenu>\n  );\n}\n","import { useEffect, useMemo } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useActiveLocale } from \"@fluid-app/i18n/locale-context\";\nimport { useLanguagesApi } from \"@fluid-app/store-core/languages-api-context\";\nimport { storeKeys } from \"../account/query-keys\";\nimport {\n  resolveLocale,\n  SUPPORTED_LANGUAGES,\n  type SupportedLanguage,\n} from \"./use-portal-active-locale\";\n\nexport interface UseEnabledLanguagesResult {\n  /** What the language pickers should offer. */\n  readonly languages: SupportedLanguage[];\n  /** ISO codes the company has actually enabled; empty while unknown. */\n  readonly enabledCodes: ReadonlySet<string>;\n}\n\n/**\n * The company's enabled languages, plus the reconcile step that the\n * optimistic locale cannot do for itself.\n *\n * `getOptimisticLocale()` seeds `LocaleProvider` synchronously, before any\n * request — so it resolves against all 35 languages the SDK ships, not the\n * handful the company enabled. A browser set to Japanese visiting a portal\n * that offers only English and Spanish therefore lands on `ja`, and nothing\n * ever corrected it: `setLocale` had exactly two callers, both of them a\n * user picking from the menu.\n *\n * The symptom is visible in the picker itself — it lists only the enabled\n * languages, so `languages.find((l) => l.iso === locale)` misses and the\n * trigger falls back to rendering the raw code (\"ja\") instead of a language\n * name.\n *\n * `resolveLocale(supportedCodes)` was written for exactly this and had no\n * callers; it takes the supported set as a parameter precisely so it can be\n * re-run once the company's set is known. This is that call.\n */\nexport function useEnabledLanguages(): UseEnabledLanguagesResult {\n  const languagesApi = useLanguagesApi();\n  const { locale, setLocale } = useActiveLocale();\n\n  const { data } = useQuery({\n    queryKey: storeKeys.languages(),\n    queryFn: () => languagesApi.listLanguages({ limit: 100 }),\n    staleTime: 5 * 60 * 1000,\n  });\n\n  const enabledCodes = useMemo(\n    () => new Set((data?.languages ?? []).map((l) => l.code)),\n    [data],\n  );\n\n  const companyReturnedLanguages = (data?.languages.length ?? 0) > 0;\n\n  // Fall back to the full supported list if the company-languages request\n  // hasn't returned (loading), failed, or came back empty. If the company\n  // returned only codes this SDK cannot render, offer the SDK default instead\n  // of treating that known result as an unknown set and over-offering.\n  const languages = useMemo(() => {\n    const filtered = SUPPORTED_LANGUAGES.filter((l) => enabledCodes.has(l.iso));\n    if (filtered.length > 0) return filtered;\n    return companyReturnedLanguages\n      ? SUPPORTED_LANGUAGES.slice(0, 1)\n      : SUPPORTED_LANGUAGES;\n  }, [companyReturnedLanguages, enabledCodes]);\n\n  useEffect(() => {\n    // Unknown set — loading, failed, or empty. Leave the locale alone\n    // rather than forcing a switch on incomplete information, matching the\n    // over-offer fallback above.\n    if (enabledCodes.size === 0) return;\n    const selectableCodes = languages.map((language) => language.iso);\n    if (selectableCodes.includes(locale)) return;\n\n    const next = resolveLocale(selectableCodes);\n    if (next !== locale) setLocale(next);\n  }, [enabledCodes, languages, locale, setLocale]);\n\n  return { languages, enabledCodes };\n}\n","import { useActiveLocale } from \"@fluid-app/i18n/locale-context\";\nimport { useEnabledLanguages } from \"../hooks/use-enabled-languages\";\n\nexport interface MobileLanguageOption {\n  readonly iso: string;\n  readonly name: string;\n}\n\nexport interface UseMobileLanguagesResult {\n  readonly languages: readonly MobileLanguageOption[];\n  readonly locale: string;\n  readonly setLocale: (iso: string) => void;\n  readonly currentName: string;\n}\n\n/**\n * Resolve the language options to offer in the mobile switcher: the company's\n * enabled languages, falling back to the full supported set if that request\n * hasn't returned, failed, or came back empty (better to over-offer than to\n * strand the user with no way to switch).\n */\nexport function useMobileLanguages(): UseMobileLanguagesResult {\n  const { locale, setLocale } = useActiveLocale();\n  const { languages } = useEnabledLanguages();\n  const current = languages.find((l) => l.iso === locale);\n\n  return { languages, locale, setLocale, currentName: current?.name ?? locale };\n}\n","import { useState, useCallback } from \"react\";\nimport {\n  Moon,\n  Sun,\n  LogOut,\n  Smartphone,\n  Globe,\n  Check,\n  ChevronRight,\n  ChevronLeft,\n} from \"lucide-react\";\nimport { MobileBottomSheet } from \"@fluid-app/ui-components/components/MobileBottomSheet\";\nimport { useMobileLanguages } from \"./use-mobile-languages\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useRepUser } from \"@fluid-app/portal-widgets/contexts\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport {\n  useHaptics,\n  useHapticCallback,\n} from \"@fluid-app/portal-react/shell/use-haptics\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { useNativeCapabilities } from \"@fluid-app/portal-core/native-capabilities-api-context\";\n\nexport interface SdkMobileProfileMenuProps {\n  onNavigate: (slug: string) => void;\n  onLogout?: () => void;\n}\n\nfunction getInitials(name: string | null | undefined): string {\n  if (!name) return \"U\";\n  const parts = name.trim().split(/\\s+/);\n  if (parts.length >= 2) {\n    return (\n      (parts[0]?.[0] ?? \"\") + (parts[parts.length - 1]?.[0] ?? \"\")\n    ).toUpperCase();\n  }\n  return (name[0] ?? \"U\").toUpperCase();\n}\n\nexport function SdkMobileProfileMenu({\n  onNavigate,\n  onLogout,\n}: SdkMobileProfileMenuProps): React.JSX.Element | null {\n  const { isMobile, useBottomNav } = useSidebar();\n  const [isOpen, setIsOpen] = useState(false);\n  // Which view the sheet shows: the main profile menu or the language list\n  // (an inline drill-down within the same sheet — no second sheet).\n  const [view, setView] = useState<\"main\" | \"language\">(\"main\");\n  const user = useRepUser();\n  const themeMode = useThemeMode();\n  const languages = useMobileLanguages();\n  const haptics = useHaptics();\n  const { t } = useShellTranslation();\n  const nativeCapabilities = useNativeCapabilities();\n\n  const handleNavigate = useCallback(\n    (slug: string) => {\n      setIsOpen(false);\n      onNavigate(slug);\n    },\n    [onNavigate],\n  );\n\n  const handleOpenChange = useCallback((open: boolean) => {\n    setIsOpen(open);\n    // Always reset to the main view when the sheet closes.\n    if (!open) setView(\"main\");\n  }, []);\n\n  // Haptics on every interaction, wired via useHapticCallback so intent lives\n  // at the call site instead of sprinkled inside handler bodies. Snap-point\n  // haptics are handled app-wide by PortalSheetHapticsProvider.\n  const handleOpenMenu = useHapticCallback(\"tap\", () => setIsOpen(true));\n  const handleShowLanguages = useHapticCallback(\"tap\", () =>\n    setView(\"language\"),\n  );\n  const handleBackToMain = useHapticCallback(\"tap\", () => setView(\"main\"));\n  const handleAppDownload = useHapticCallback(\"tap\", () =>\n    handleNavigate(\"app-download\"),\n  );\n  const handleCycleTheme = useHapticCallback(\"select\", themeMode.cycleMode);\n  const handleLogout = useHapticCallback(\"tap\", onLogout);\n\n  if (!isMobile || !useBottomNav) return null;\n\n  const initials = getInitials(user?.name);\n\n  return (\n    <>\n      <button\n        type=\"button\"\n        onClick={handleOpenMenu}\n        className=\"bg-background text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex shrink-0 items-center justify-center rounded-full p-1\"\n        aria-label={t(\"profile_open_menu\")}\n      >\n        {user?.imageUrl ? (\n          <img\n            src={user.imageUrl}\n            alt={user.name ?? t(\"profile_user_fallback\")}\n            className=\"size-8 rounded-full object-cover\"\n          />\n        ) : (\n          <span className=\"flex size-8 items-center justify-center text-xs font-medium\">\n            {initials}\n          </span>\n        )}\n      </button>\n\n      <MobileBottomSheet\n        open={isOpen}\n        onOpenChange={handleOpenChange}\n        surface=\"sidebar\"\n        title={\n          view === \"language\" ? (\n            <button\n              type=\"button\"\n              onClick={handleBackToMain}\n              className=\"text-foreground -ml-1 flex items-center gap-1\"\n              aria-label={t(\"nav_back\")}\n            >\n              <ChevronLeft className=\"size-5\" />\n              <span>{t(\"language_select\")}</span>\n            </button>\n          ) : (\n            t(\"profile_title\")\n          )\n        }\n      >\n        {view === \"language\" ? (\n          <div className=\"flex flex-col pb-2\">\n            {languages.languages.map((lang) => {\n              const isActive = lang.iso === languages.locale;\n              return (\n                <button\n                  key={lang.iso}\n                  type=\"button\"\n                  onClick={() => {\n                    haptics.select();\n                    languages.setLocale(lang.iso);\n                    setView(\"main\");\n                  }}\n                  className=\"hover:bg-sidebar-accent flex w-full items-center justify-between gap-3 rounded-lg px-3 py-3.5 text-left\"\n                >\n                  <span\n                    className={\n                      isActive\n                        ? \"text-foreground text-base font-semibold\"\n                        : \"text-foreground text-base\"\n                    }\n                  >\n                    {lang.name}\n                  </span>\n                  {isActive && (\n                    <Check className=\"text-primary size-5 shrink-0\" />\n                  )}\n                </button>\n              );\n            })}\n          </div>\n        ) : (\n          <>\n            {user && (\n              <div className=\"border-border flex items-center gap-3 border-b px-3 py-4\">\n                {user.imageUrl ? (\n                  <img\n                    src={user.imageUrl}\n                    alt={user.name ?? t(\"profile_user_fallback\")}\n                    className=\"size-10 rounded-full object-cover\"\n                  />\n                ) : (\n                  <span className=\"bg-muted flex size-10 items-center justify-center rounded-full text-sm font-medium\">\n                    {initials}\n                  </span>\n                )}\n                <div className=\"min-w-0 flex-1\">\n                  {user.name && (\n                    <p className=\"text-foreground truncate text-sm font-semibold\">\n                      {user.name}\n                    </p>\n                  )}\n                  {user.email && (\n                    <p className=\"text-muted-foreground truncate text-xs\">\n                      {user.email}\n                    </p>\n                  )}\n                </div>\n              </div>\n            )}\n\n            {!nativeCapabilities.isNativeApp && (\n              <div className=\"border-border border-b py-2\">\n                <button\n                  type=\"button\"\n                  onClick={handleAppDownload}\n                  className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n                >\n                  <Smartphone className=\"size-5\" />\n                  <span>{t(\"profile_app_download\")}</span>\n                </button>\n              </div>\n            )}\n\n            <div className=\"space-y-1 py-2\">\n              <button\n                type=\"button\"\n                onClick={handleShowLanguages}\n                className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n              >\n                <Globe className=\"size-5 shrink-0\" />\n                <span>{t(\"language_select\")}</span>\n                <span className=\"text-muted-foreground ml-auto flex min-w-0 items-center gap-1\">\n                  <span className=\"truncate\">{languages.currentName}</span>\n                  <ChevronRight className=\"size-4 shrink-0\" />\n                </span>\n              </button>\n\n              <button\n                type=\"button\"\n                onClick={handleCycleTheme}\n                className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n              >\n                {themeMode.mode === \"dark\" ? (\n                  <Moon className=\"size-5\" />\n                ) : (\n                  <Sun className=\"size-5\" />\n                )}\n                <span>\n                  {themeMode.mode === \"light\"\n                    ? t(\"theme_light\")\n                    : t(\"theme_dark\")}\n                </span>\n              </button>\n\n              {onLogout && (\n                <button\n                  type=\"button\"\n                  onClick={handleLogout}\n                  className=\"text-destructive hover:bg-sidebar-accent flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n                >\n                  <LogOut className=\"size-5\" />\n                  <span>{t(\"logout\")}</span>\n                </button>\n              )}\n            </div>\n          </>\n        )}\n      </MobileBottomSheet>\n    </>\n  );\n}\n","import { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { ScreenHeaderMobileActionsSlot } from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { IconButton } from \"@fluid-app/ui-primitives\";\nimport { ChevronLeft, Menu } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { translateNavLabel } from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { SdkMobileProfileMenu } from \"./SdkMobileProfileMenu\";\n\nexport interface SdkHeaderProps {\n  mobileTabs?: NavigationItem[];\n  currentSlug: string;\n  /** Current page title, shown on the left of the mobile top bar. */\n  title?: string;\n  /**\n   * When provided, a native back button is shown at the start of the mobile\n   * top bar. Set only on drill-down screens (e.g. a product detail) so tapping\n   * it returns to the parent list.\n   */\n  onBack?: () => void;\n  onNavigate: (slug: string) => void;\n  /**\n   * Navigation for the second-level sub-tabs. Lateral tab switching, so it\n   * should not leave a back-button referrer. Falls back to onNavigate.\n   */\n  onTabNavigate?: (slug: string) => void;\n  onLogout?: () => void;\n  /** Actions that remain available in the mobile header on every route. */\n  persistentActions?: ReactNode;\n}\n\nexport function SdkHeader({\n  mobileTabs,\n  currentSlug,\n  title,\n  onBack,\n  onNavigate,\n  onTabNavigate,\n  onLogout,\n  persistentActions,\n}: SdkHeaderProps): React.JSX.Element | null {\n  const navigateToTab = onTabNavigate ?? onNavigate;\n  const sidebar = useSidebar();\n  const shellApi = useShellTranslation();\n  const { t } = shellApi;\n\n  // Localize the title the same way the desktop header does (translateNavLabel),\n  // so nav-item titles aren't left as raw English on mobile. The \"More\" screen\n  // isn't a tenant nav item, so it has no derived title — fall back to the\n  // localized \"More\" label there.\n  const resolvedTitle = title\n    ? translateNavLabel(shellApi, currentSlug, title)\n    : normalizeSlug(currentSlug) === \"more\"\n      ? t(\"nav_more\")\n      : undefined;\n\n  const isMobileWithBottomNav = sidebar.isMobile && sidebar.useBottomNav;\n  const isMobileWithHamburger = sidebar.isMobile && !sidebar.useBottomNav;\n\n  // Desktop has nothing to render here (theme toggle moved to sidebar footer).\n  // Skip the entire header so we don't reserve a 52px gutter for empty space.\n  if (!isMobileWithBottomNav && !isMobileWithHamburger) {\n    return null;\n  }\n\n  return (\n    <header className=\"bg-sidebar shrink-0 pt-[env(safe-area-inset-top)]\">\n      {isMobileWithBottomNav ? (\n        <div className=\"flex h-[52px] items-center gap-2 px-4\">\n          {onBack ? (\n            <IconButton\n              icon={ChevronLeft}\n              aria-label={t(\"nav_back\")}\n              onClick={onBack}\n              className=\"border-border/60 bg-background/70 -ml-1 flex-none rounded-full border shadow-sm backdrop-blur-md transition-transform active:scale-95 [&_svg]:size-5\"\n            />\n          ) : null}\n          {resolvedTitle ? (\n            <h1 className=\"text-sidebar-foreground min-w-0 flex-1 truncate text-[17px] leading-tight font-semibold tracking-[-0.01em]\">\n              {resolvedTitle}\n            </h1>\n          ) : null}\n          <div className=\"text-muted-foreground ml-auto flex flex-none items-center justify-end gap-2\">\n            <ScreenHeaderMobileActionsSlot />\n            {persistentActions}\n            <SdkMobileProfileMenu onNavigate={onNavigate} onLogout={onLogout} />\n          </div>\n        </div>\n      ) : (\n        <div className=\"flex h-[52px] items-center px-6\">\n          <button\n            type=\"button\"\n            onClick={sidebar.toggleSidebar}\n            className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex shrink-0 items-center justify-center rounded-md p-2\"\n            aria-label={t(\"nav_toggle_sidebar\")}\n          >\n            <Menu className=\"size-5\" />\n          </button>\n        </div>\n      )}\n\n      {/* Mobile child tabs — shown below header when parent has children */}\n      {isMobileWithBottomNav && mobileTabs && mobileTabs.length > 0 && (\n        <nav className=\"scrollbar-none flex items-center gap-1 overflow-x-auto px-4\">\n          {mobileTabs.map((tab) => {\n            const tabSlug = normalizeSlug(tab.slug);\n            if (!tabSlug) return null;\n\n            const isActive = normalizeSlug(currentSlug) === tabSlug;\n\n            return (\n              <button\n                key={tab.id ?? tabSlug}\n                type=\"button\"\n                onClick={() => navigateToTab(tabSlug)}\n                className={`border-b-2 px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${\n                  isActive\n                    ? \"border-primary text-foreground\"\n                    : \"text-muted-foreground hover:border-border hover:text-foreground border-transparent\"\n                }`}\n              >\n                {translateNavLabel(shellApi, tab.slug, tab.label)}\n              </button>\n            );\n          })}\n        </nav>\n      )}\n    </header>\n  );\n}\n","import { useEffect, useState } from \"react\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n  Button,\n} from \"@fluid-app/ui-primitives\";\nimport { Globe, Check } from \"lucide-react\";\nimport { useActiveLocale } from \"@fluid-app/i18n/locale-context\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { useIsMobile } from \"@fluid-app/portal-react/shell/use-mobile\";\nimport { MobileActionSheet } from \"@fluid-app/ui-components/components/MobileActionSheet\";\nimport { useEnabledLanguages } from \"../hooks/use-enabled-languages\";\n\nexport function LanguageSelector(): React.JSX.Element {\n  const [openPresentation, setOpenPresentation] = useState<\n    \"mobile\" | \"desktop\" | null\n  >(null);\n  const { locale, setLocale } = useActiveLocale();\n  const isMobile = useIsMobile();\n  const { t } = useShellTranslation();\n  // Owns the company-languages query, the over-offer fallback, AND the\n  // reconcile that switches away from a locale the company never enabled.\n  const { languages: languagesToRender } = useEnabledLanguages();\n\n  useEffect(() => {\n    setOpenPresentation(null);\n  }, [isMobile]);\n\n  const trigger = (\n    <Button\n      variant=\"ghost\"\n      size=\"sm\"\n      className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shrink-0 gap-1.5\"\n      aria-label={t(\"language_select\")}\n      onClick={isMobile ? () => setOpenPresentation(\"mobile\") : undefined}\n    >\n      <Globe className=\"size-3\" />\n      <span className=\"text-xs uppercase\">{locale.split(\"_\")[0]}</span>\n    </Button>\n  );\n\n  if (isMobile) {\n    return (\n      <>\n        {trigger}\n        <MobileActionSheet\n          open={openPresentation === \"mobile\"}\n          onOpenChange={(nextOpen) =>\n            setOpenPresentation(nextOpen ? \"mobile\" : null)\n          }\n          title={t(\"language_select\")}\n          actions={languagesToRender.map((language) => ({\n            id: language.iso,\n            label: language.name,\n            selected: language.iso === locale,\n            onSelect: () => setLocale(language.iso),\n          }))}\n        />\n      </>\n    );\n  }\n\n  return (\n    <Popover\n      open={openPresentation === \"desktop\"}\n      onOpenChange={(nextOpen) =>\n        setOpenPresentation(nextOpen ? \"desktop\" : null)\n      }\n    >\n      <PopoverTrigger asChild>{trigger}</PopoverTrigger>\n      <PopoverContent\n        align=\"end\"\n        className=\"bg-popover z-50 w-56 rounded-lg p-1 shadow-lg\"\n      >\n        {languagesToRender.map((lang) => (\n          <Button\n            key={lang.iso}\n            variant=\"ghost\"\n            className=\"h-auto w-full justify-between px-3 py-2 text-left text-sm whitespace-normal\"\n            onClick={() => {\n              setLocale(lang.iso);\n              setOpenPresentation(null);\n            }}\n          >\n            <span>{lang.name}</span>\n            {lang.iso === locale && <Check className=\"size-4\" />}\n          </Button>\n        ))}\n      </PopoverContent>\n    </Popover>\n  );\n}\n","import { useCallback } from \"react\";\nimport { CartButton, CartScript, CartWidget } from \"@fluid-app/cart-ui\";\nimport { matchSlugPrefix } from \"@fluid-app/portal-core/navigation/slug-utils\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport * as portalTenant from \"@fluid-app/portal-tenant-api-client/sdk\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { useStore } from \"../hooks/use-store\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\n\nconst SHOP_ROUTE_SLUGS = [\"shop\"];\n\n/**\n * Keep the cart persistent across routes when Shop is in navigation, while\n * preserving route-local cart access for portals that reach Shop another way.\n */\nexport function isPortalCartAvailable(\n  activeSlug: string,\n  navSlugs: readonly string[],\n): boolean {\n  return (\n    navSlugs.includes(\"shop\") ||\n    matchSlugPrefix(activeSlug, SHOP_ROUTE_SLUGS) !== undefined\n  );\n}\n\n/**\n * Extract the cart token (e.g. \"ct_abc123\") from a checkout URL such as\n * https://checkout.fluid.app/checkouts/ct_abc123?fluid_shop=oliabo — the URL\n * the FairShare SDK returns from getCheckoutUrl(). Returns null when the URL\n * has no recognizable token.\n */\nexport function parseCartToken(checkoutUrl: string): string | null {\n  try {\n    // Resolve against the current location so relative checkout paths\n    // (e.g. \"/checkouts/ct_abc123\") parse too — new URL() alone rejects\n    // non-absolute URLs, which would silently skip the claim.\n    const base =\n      typeof window === \"undefined\" ? undefined : window.location.href;\n    const { pathname } = new URL(checkoutUrl, base);\n    return /\\/checkouts\\/([^/?#]+)/.exec(pathname)?.[1] ?? null;\n  } catch {\n    return null;\n  }\n}\n\n// Claiming the cart must never block checkout indefinitely. If the claim\n// hangs (flaky network, no client-side fetch timeout), give up after this\n// bound and proceed to checkout as if the claim failed — best-effort.\nconst CART_CLAIM_TIMEOUT_MS = 3000;\n\n/**\n * Persistent cart trigger for portal headers. Kept separate from the runtime\n * so responsive headers can render exactly one trigger without duplicating\n * the SDK script or cart drawer.\n */\nexport function PortalCartButton({\n  viewport,\n}: {\n  viewport: \"desktop\" | \"mobile\";\n}): React.JSX.Element | null {\n  const { isMobile } = useSidebar();\n  const client = usePortalTenantClient();\n\n  // Claim the FairShare-created (unclaimed) cart for the logged-in member —\n  // rep OR customer — then hand off to the checkout_url the claim returns.\n  //\n  // CartClaimer attaches the member's customer identity for every member (and\n  // buyer_rep only for rep-eligible ones, which drives wholesale pricing), and\n  // the response's checkout_url carries that member's handoff JWT. Navigating\n  // there makes checkout adopt the current member instead of falling back to a\n  // stale per-browser cookie left by a previously logged-in account.\n  //\n  // Best-effort: a failed or slow claim must never block checkout, so fall back\n  // to the token-less SDK URL.\n  const handleCheckout = useCallback(\n    async (checkoutUrl: string) => {\n      const token = parseCartToken(checkoutUrl);\n      let destination = checkoutUrl;\n\n      if (token) {\n        let timeoutId: ReturnType<typeof setTimeout> | undefined;\n        try {\n          const claimed = await Promise.race([\n            portalTenant.cartsClaim({ client, path: { token } }),\n            new Promise<never>((_, reject) => {\n              timeoutId = setTimeout(\n                () => reject(new Error(\"cart claim timed out\")),\n                CART_CLAIM_TIMEOUT_MS,\n              );\n            }),\n          ]);\n          destination = claimed?.checkout_url ?? checkoutUrl;\n        } catch (error) {\n          console.error(\"Failed to claim cart:\", error);\n        } finally {\n          if (timeoutId) clearTimeout(timeoutId);\n        }\n      }\n\n      window.location.assign(destination);\n    },\n    [client],\n  );\n\n  const isVisible = viewport === \"mobile\" ? isMobile : !isMobile;\n  if (!isVisible) return null;\n\n  return <CartButton onCheckout={handleCheckout} />;\n}\n\n/**\n * One cart SDK + drawer instance for the whole portal session. AppShell owns\n * this runtime so route changes never remove the cart or reset its handlers.\n */\nexport function PortalCartRuntime(): React.JSX.Element {\n  const { config } = useFluidContext();\n  const { data: store } = useStore();\n  const { data: account, isPending: accountPending } = useAccount();\n  const subdomain = store?.subdomain;\n  const countryCode = config.countryIso ?? \"US\";\n\n  // Tenant host (e.g. tacobell.portal.fluid.app), SSR-safe. Used to scope\n  // FairShare cookies to this tenant so attribution stays isolated per company.\n  const tenantHost =\n    typeof window !== \"undefined\" ? window.location.hostname : undefined;\n\n  return (\n    <>\n      {\n        // Mount CartScript ONLY when both:\n        // (a) subdomain is known (otherwise data-fluid-shop is empty), and\n        // (b) the customer's account has resolved (so FluidConfigHydrator has\n        //     already merged the real market country into config.countryIso).\n        // ES modules are cached by URL, so mounting with the \"US\" fallback\n        // before account resolution would seed the wrong country permanently.\n        subdomain && !accountPending ? (\n          <CartScript\n            subdomain={subdomain}\n            bffMode\n            scriptSrc={\n              import.meta.env.DEV\n                ? String(\n                    import.meta.env.VITE_FAIRSHARE_SDK_URL ||\n                      \"http://localhost:4444/index.js\",\n                  )\n                : undefined\n            }\n            apiBaseUrl={\n              import.meta.env.DEV\n                ? String(\n                    import.meta.env.VITE_FAIRSHARE_API_BASE_URL ||\n                      \"http://api.fluid.localhost:3000\",\n                  )\n                : undefined\n            }\n            debug={import.meta.env.DEV}\n            country={countryCode}\n            cookieDomain={tenantHost}\n            shareGuid={account?.share_guid ?? undefined}\n          />\n        ) : null\n      }\n      <CartWidget />\n    </>\n  );\n}\n","import { useState } from \"react\";\nimport { Building2 } from \"lucide-react\";\n\nexport function CompanyImage({\n  src,\n  alt,\n  size,\n}: {\n  size: number;\n  src: string;\n  alt: string;\n}) {\n  const [error, setError] = useState(false);\n\n  if (!src || error)\n    return (\n      <Building2\n        style={{ height: size, width: size }}\n        className=\"text-muted-foreground/25\"\n      />\n    );\n\n  return (\n    <img\n      className=\"max-h-8 max-w-8 object-contain\"\n      alt={alt}\n      src={src}\n      width={size}\n      height={size}\n      onError={() => setError(true)}\n    />\n  );\n}\n","import type { Company } from \"@fluid-app/company-switcher-core\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { CompanyImage } from \"./CompanyImage\";\n\nexport function CompanyItem({\n  logo_url,\n  icon_url,\n  name,\n  compact = false,\n}: Omit<Company, \"id\"> & { compact?: boolean }) {\n  const resolvedSrc = icon_url || logo_url || \"\";\n  return (\n    <>\n      <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg\">\n        <CompanyImage alt={name} src={resolvedSrc} size={32} />\n      </div>\n      <div\n        className={cn(\n          \"grid text-left text-sm leading-tight\",\n          compact ? \"flex-shrink-0\" : \"flex-1\",\n        )}\n      >\n        <span className=\"truncate font-semibold\">{name}</span>\n      </div>\n    </>\n  );\n}\n","import { Skeleton } from \"@fluid-app/ui-primitives\";\n\nexport function CompanySwitcherSkeleton({ show }: { show: boolean }) {\n  if (!show) return null;\n\n  return (\n    <div className=\"flex items-center gap-4 p-2\">\n      <Skeleton className=\"size-5 shrink-0 rounded-sm bg-current\" />\n      <Skeleton className=\"h-4 w-36 bg-current\" />\n    </div>\n  );\n}\n","import { useStore } from \"../hooks/use-store\";\nimport {\n  CompanyItem,\n  CompanySwitcherSkeleton,\n} from \"@fluid-app/company-switcher-ui\";\n\n/**\n * Static company display for single-tenant portal.\n * Shows logo + name in the sidebar header. No switching — just branding.\n */\nexport function SdkCompanySwitcher(): React.JSX.Element | null {\n  const { data: store, isLoading } = useStore();\n\n  if (isLoading) {\n    return <CompanySwitcherSkeleton show />;\n  }\n\n  if (!store) {\n    return null;\n  }\n\n  return (\n    <div className=\"flex w-full items-center gap-2 rounded-md p-2\">\n      <CompanyItem\n        logo_url={store.logo_url}\n        icon_url={store.icon_url}\n        name={store.name || store.subdomain}\n      />\n    </div>\n  );\n}\n","/**\n * Navigate one step back in the browser history if anything is on the stack;\n * otherwise navigate to the SPA root. Used by fallback screens (error\n * boundary, 404) to give the user a way out without risking a navigation\n * outside the SPA when no prior history exists.\n */\nexport function goBackOrHome(): void {\n  if (window.history.length > 1) {\n    window.history.back();\n  } else {\n    window.location.assign(\"/\");\n  }\n}\n","import { Button } from \"@fluid-app/ui-primitives\";\nimport { Compass } from \"lucide-react\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { goBackOrHome } from \"../shell/go-back-or-home\";\nimport { FallbackCard } from \"./FallbackCard\";\n\n/**\n * Rendered by `PageRouter` when the current slug doesn't match any custom\n * page, system screen, or builder screen. This is a true \"not found\" — the\n * portal isn't configured to render anything for this path.\n */\nexport function ScreenNotFound({\n  name,\n}: {\n  readonly name?: string;\n}): React.JSX.Element {\n  const { t } = useShellTranslation();\n  return (\n    <FallbackCard\n      icon={<Compass />}\n      title={t(\"not_found_title\")}\n      description={\n        name ? t(\"not_found_named\", { name }) : t(\"not_found_generic\")\n      }\n      actions={\n        <Button variant=\"default\" onClick={goBackOrHome}>\n          {t(\"error_go_back\")}\n        </Button>\n      }\n    />\n  );\n}\n","import { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\n\n/**\n * Shown when a customer attempts to access a rep-only page via direct URL.\n */\nexport function AccessDeniedScreen(): React.JSX.Element {\n  const { t } = useShellTranslation();\n  return (\n    <div className=\"flex min-h-[400px] items-center justify-center\">\n      <div className=\"border-border max-w-sm rounded-lg border border-dashed p-8 text-center\">\n        <h2 className=\"text-foreground text-xl font-semibold\">\n          {t(\"access_denied_title\")}\n        </h2>\n        <p className=\"text-muted-foreground mt-2\">\n          {t(\"access_denied_description\")}\n        </p>\n        <p className=\"text-muted-foreground mt-1 text-sm\">\n          {t(\"access_denied_detail\")}\n        </p>\n      </div>\n    </div>\n  );\n}\n","/**\n * Default property schema registry for SDK apps.\n * Maps widget type names to their editable property schemas from\n * portal-widgets — the same widget set covered by\n * `DEFAULT_SDK_WIDGET_REGISTRY` in `./default-widget-registry`.\n *\n * Used to validate authored widget props at render time (see\n * `warnUnknownWidgetProps` in `../utils/warn-unknown-widget-props`), not for\n * the builder's property-panel UI — that registry\n * (`DEFAULT_PROPERTY_SCHEMAS` in `@fluid-app/portal-builder`) is assembled\n * separately from the same per-widget schema exports and may include\n * builder-only widgets this one doesn't.\n */\n\nimport type { PropertySchemaRegistry } from \"@fluid-app/portal-core/registries\";\nimport {\n  alertWidgetPropertySchema,\n  announcementWidgetPropertySchema,\n  bulletListWidgetPropertySchema,\n  calendarWidgetPropertySchema,\n  cardWidgetPropertySchema,\n  carouselWidgetPropertySchema,\n  catchUpWidgetPropertySchema,\n  chartWidgetPropertySchema,\n  containerWidgetPropertySchema,\n  embedWidgetPropertySchema,\n  imageWidgetPropertySchema,\n  layoutWidgetPropertySchema,\n  linkWidgetPropertySchema,\n  listWidgetPropertySchema,\n  mySiteWidgetPropertySchema,\n  nestedWidgetPropertySchema,\n  pointsWidgetPropertySchema,\n  quickLinksWidgetPropertySchema,\n  quickShareWidgetPropertySchema,\n  quoteWidgetPropertySchema,\n  recentActivityWidgetPropertySchema,\n  separatorWidgetPropertySchema,\n  spacerWidgetPropertySchema,\n  tableWidgetPropertySchema,\n  textWidgetPropertySchema,\n  toDoWidgetPropertySchema,\n  videoWidgetPropertySchema,\n} from \"@fluid-app/portal-widgets/widgets\";\n// ShopWidget is imported via its direct subpath — see default-widget-registry.ts\n// for the --isolatedDeclarations rationale; the same barrel-avoidance applies\n// to its property schema.\nimport { shopWidgetPropertySchema } from \"@fluid-app/portal-widgets/widgets/ShopWidget\";\n\nexport const DEFAULT_PROPERTY_SCHEMA_REGISTRY: PropertySchemaRegistry = {\n  AlertWidget: alertWidgetPropertySchema,\n  AnnouncementWidget: announcementWidgetPropertySchema,\n  BulletListWidget: bulletListWidgetPropertySchema,\n  CalendarWidget: calendarWidgetPropertySchema,\n  CardWidget: cardWidgetPropertySchema,\n  CarouselWidget: carouselWidgetPropertySchema,\n  CatchUpWidget: catchUpWidgetPropertySchema,\n  ChartWidget: chartWidgetPropertySchema,\n  ContainerWidget: containerWidgetPropertySchema,\n  EmbedWidget: embedWidgetPropertySchema,\n  ImageWidget: imageWidgetPropertySchema,\n  LayoutWidget: layoutWidgetPropertySchema,\n  LinkWidget: linkWidgetPropertySchema,\n  ListWidget: listWidgetPropertySchema,\n  MySiteWidget: mySiteWidgetPropertySchema,\n  NestedWidget: nestedWidgetPropertySchema,\n  PointsWidget: pointsWidgetPropertySchema,\n  QuickLinksWidget: quickLinksWidgetPropertySchema,\n  QuickShareWidget: quickShareWidgetPropertySchema,\n  QuoteWidget: quoteWidgetPropertySchema,\n  RecentActivityWidget: recentActivityWidgetPropertySchema,\n  SeparatorWidget: separatorWidgetPropertySchema,\n  ShopWidget: shopWidgetPropertySchema,\n  SpacerWidget: spacerWidgetPropertySchema,\n  TableWidget: tableWidgetPropertySchema,\n  TextWidget: textWidgetPropertySchema,\n  ToDoWidget: toDoWidgetPropertySchema,\n  VideoWidget: videoWidgetPropertySchema,\n};\n","import type {\n  PropertyField,\n  PropertySchemaRegistry,\n  WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\n\n/**\n * Props every widget instance may legitimately receive that are never part\n * of a widget's own editable property schema:\n *  - Standard React/DOM pass-through props (`className`, `style`, `children`,\n *    `id`, `key`).\n *  - Structural identity props the screen-renderer pipeline injects itself\n *    for container widgets so they can support drag/select wiring\n *    (`widgetId`, `widgetPath`) — see `ScreenRenderer.tsx` in\n *    `@fluid-app/portal-widgets/core` and `WidgetContent` in\n *    `@fluid-app/portal-builder/core/widget-rendering`, which both inject\n *    these for the same widget nodes rendered here.\n * Never warn about these even though they never appear in a widget's\n * `fields` list.\n */\nexport const ALWAYS_ALLOWED_WIDGET_PROPS: ReadonlySet<string> = new Set([\n  \"className\",\n  \"style\",\n  \"children\",\n  \"id\",\n  \"key\",\n  \"widgetId\",\n  \"widgetPath\",\n]);\n\n/** Maximum Levenshtein distance for a \"did you mean\" suggestion to be shown. */\nconst MAX_SUGGESTION_DISTANCE = 3;\n\n/**\n * Common authoring aliases → the canonical prop name to suggest. Levenshtein\n * only catches spelling slips; these are *semantic* misses (the motivating\n * incident authored `content` where the schema says `description` — edit\n * distance 9, far beyond any sane typo threshold). A suggestion is only shown\n * when the canonical name actually exists in the widget's schema.\n */\nconst PROP_NAME_SYNONYMS: Readonly<Record<string, string>> = {\n  content: \"description\",\n  text: \"description\",\n  body: \"description\",\n  copy: \"description\",\n  message: \"description\",\n  heading: \"title\",\n  header: \"title\",\n  label: \"title\",\n};\n\n/** `${widgetType}::${propName}` pairs already warned about this session. */\nconst warnedPairs = new Set<string>();\n\n// Vite exposes `import.meta.env.DEV`; other bundlers/runtimes (Next.js, Node,\n// Jest/CJS) don't define it at all. The optional chain means a missing/absent\n// `env` can never throw, so this can never fire outside a Vite dev build —\n// mirrors the existing `import.meta.env?.DEV` check in `FluidProvider.tsx`.\n// Written as a direct property access (no intermediate `as` cast) so it\n// compiles to a literal `import.meta.env` substring: the portal-sdk Jest\n// transform text-replaces exactly that substring with `globalThis.__VITE_ENV__`\n// at test time (see `jest-swc-transform.cjs`), which is how tests toggle\n// dev/prod mode. A cast that splits \"meta\" from \".env\" in the compiled output\n// would slip past that replacement and crash Jest on the raw `import.meta`\n// syntax.\nfunction isDevBuild(): boolean {\n  return import.meta.env?.DEV === true;\n}\n\n/**\n * Levenshtein edit distance between two strings. Small inline helper (no new\n * dependency) — only ever called with short widget-prop-name strings.\n */\nfunction levenshteinDistance(a: string, b: string): number {\n  if (a === b) return 0;\n  if (a.length === 0) return b.length;\n  if (b.length === 0) return a.length;\n\n  let previousRow: number[] = Array.from({ length: b.length + 1 }, (_, j) => j);\n\n  for (let i = 1; i <= a.length; i++) {\n    const currentRow: number[] = [i];\n    for (let j = 1; j <= b.length; j++) {\n      const substitutionCost = a[i - 1] === b[j - 1] ? 0 : 1;\n      // Bounds are guaranteed by the loop ranges; noUncheckedIndexedAccess\n      // still types these as possibly-undefined, so fall back defensively.\n      const deletion = (previousRow[j] ?? Infinity) + 1;\n      const insertion = (currentRow[j - 1] ?? Infinity) + 1;\n      const substitution = (previousRow[j - 1] ?? Infinity) + substitutionCost;\n      currentRow.push(Math.min(deletion, insertion, substitution));\n    }\n    previousRow = currentRow;\n  }\n\n  return previousRow[b.length] ?? Math.max(a.length, b.length);\n}\n\n/**\n * Finds the suggestion for an unknown prop: a known semantic synonym first\n * (see {@link PROP_NAME_SYNONYMS}), then the nearest known key by Levenshtein\n * distance within {@link MAX_SUGGESTION_DISTANCE}.\n */\nfunction findNearestKey(\n  propName: string,\n  candidates: readonly string[],\n): string | undefined {\n  const synonym = PROP_NAME_SYNONYMS[propName.toLowerCase()];\n  if (synonym && candidates.includes(synonym)) return synonym;\n\n  let nearest: string | undefined;\n  let nearestDistance = MAX_SUGGESTION_DISTANCE + 1;\n\n  for (const candidate of candidates) {\n    const distance = levenshteinDistance(propName, candidate);\n    if (distance < nearestDistance) {\n      nearestDistance = distance;\n      nearest = candidate;\n    }\n  }\n\n  return nearestDistance <= MAX_SUGGESTION_DISTANCE ? nearest : undefined;\n}\n\n/**\n * Collects every prop name a widget's property schema actually recognizes as\n * a `widget.props` key:\n *  - `borderRadius` fields are composite — their top-level `key` is a schema\n *    grouping identifier, not a real widget prop, so its four corner keys are\n *    expanded instead (mirrors `extractPropertyValues` in\n *    `@fluid-app/portal-core/registries`).\n *  - `dataSource` fields are excluded entirely. Per the same\n *    `extractPropertyValues` reference, this field type only exists so the\n *    property panel can gate other fields' visibility on whether a data\n *    source is configured — its value is read from `widget.dataSource` (the\n *    top-level, sibling-of-`props` config), never from `widget.props`.\n *    Authoring a literal `props.dataSource` is a real mistake (the config\n *    belongs one level up), so its field `key` must not be treated as an\n *    accepted prop here.\n */\nfunction collectKnownPropKeys(fields: readonly PropertyField[]): string[] {\n  const keys: string[] = [];\n  for (const field of fields) {\n    if (field.type === \"borderRadius\") {\n      keys.push(...Object.values(field.keys));\n    } else if (field.type !== \"dataSource\") {\n      keys.push(field.key);\n    }\n  }\n  return keys;\n}\n\n/**\n * Merges schema field keys with `dataSourceTargetProps` — props a data\n * source may populate (e.g. ListWidget's `items`) that aren't necessarily\n * declared as editable fields — into one deduped list. Used for both the\n * known/unknown check and what's surfaced to the author (the \"Known props:\"\n * list and suggestion candidates), so a typo of a data-source-only prop\n * still gets a correct suggestion and the valid name is actually listed.\n */\nfunction collectAllKnownKeys(schema: WidgetPropertySchema): string[] {\n  const fieldKeys = collectKnownPropKeys(schema.fields);\n  const targetProps = schema.dataSourceTargetProps ?? [];\n  return Array.from(new Set([...fieldKeys, ...targetProps]));\n}\n\nexport interface WarnUnknownWidgetPropsInput {\n  /** The widget's `type` discriminant (e.g. \"TextWidget\"). */\n  readonly widgetType: string;\n  /** The authored props from the widget's JSON node (`widget.props`). */\n  readonly props: Readonly<Record<string, unknown>>;\n  /** Registry of built-in property schemas to validate against. */\n  readonly registry: PropertySchemaRegistry;\n}\n\n/**\n * Dev-only console warning for widget props not declared in the widget's\n * registered property schema. Guards against the class of bug where an\n * authored screen sets a prop the widget doesn't know about (typo'd name,\n * stale field from a prior schema version) — the prop is silently dropped\n * and the widget renders its placeholder defaults with no signal to the\n * author.\n *\n * No-ops entirely outside a Vite dev build (checked first, before any prop\n * iteration, so there's zero overhead in production bundles) and for widget\n * types with no registered schema (custom/company widgets) — there's nothing\n * to validate against, so we skip silently rather than warn.\n *\n * Warns at most once per (widgetType, propName) pair per session.\n */\nexport function warnUnknownWidgetProps({\n  widgetType,\n  props,\n  registry,\n}: WarnUnknownWidgetPropsInput): void {\n  if (!isDevBuild()) return;\n\n  const schema = registry[widgetType];\n  if (!schema) return;\n\n  const knownKeys = collectAllKnownKeys(schema);\n  const knownKeySet = new Set(knownKeys);\n\n  for (const propName of Object.keys(props)) {\n    if (knownKeySet.has(propName)) continue;\n    if (ALWAYS_ALLOWED_WIDGET_PROPS.has(propName)) continue;\n\n    const pairKey = `${widgetType}::${propName}`;\n    if (warnedPairs.has(pairKey)) continue;\n    warnedPairs.add(pairKey);\n\n    const suggestion = findNearestKey(propName, knownKeys);\n    const suggestionText = suggestion ? ` Did you mean \"${suggestion}\"?` : \"\";\n\n    console.warn(\n      `[portal] ${widgetType} received unknown prop \"${propName}\" — not in its schema.${suggestionText} Known props: ${knownKeys.join(\", \")}.`,\n    );\n  }\n}\n\n/**\n * Test-only: clears the per-session (widgetType, propName) dedupe set so\n * \"warns once\" behavior can be verified across multiple test cases.\n */\nexport function resetUnknownWidgetPropWarnings(): void {\n  warnedPairs.clear();\n}\n","/**\n * BuilderScreenView — renders a builder screen's component_tree with\n * DataAwareWidget support for data-bound widgets.\n *\n * Uses the shared ScreenRenderer from portal-widgets under the hood,\n * but wraps data-bound widgets with DataAwareWidget from portal-core.\n */\n\nimport React, { memo } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { ScreenDefinition } from \"@fluid-app/portal-core/types\";\nimport { DataAwareWidget } from \"@fluid-app/portal-react/data-sources/DataAwareWidget\";\nimport { useRegistry } from \"@fluid-app/portal-widgets/contexts\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { DEFAULT_PROPERTY_SCHEMA_REGISTRY } from \"../core/default-property-schema-registry\";\nimport { isDefaultWidgetComponent } from \"../core/default-widget-registry\";\nimport { warnUnknownWidgetProps } from \"../utils/warn-unknown-widget-props\";\n\ninterface WidgetRendererProps {\n  widget: WidgetSchema;\n  index: number;\n}\n\n/**\n * Renders a single widget, wrapping with DataAwareWidget if it has a dataSource.\n */\nfunction WidgetRenderer({ widget, index }: WidgetRendererProps) {\n  const registry = useRegistry();\n  const Component = registry[widget.type];\n\n  if (!Component) {\n    console.warn(\n      `[BuilderScreenView] Widget type \"${String(widget.type)}\" not found in registry`,\n    );\n    return null;\n  }\n\n  // Dev-only: warns once per (widgetType, propName) pair when an authored\n  // screen sets a prop the widget's schema doesn't declare — the prop is\n  // otherwise silently dropped and the widget falls back to its placeholder\n  // defaults with no signal to whoever authored the screen. Checked against\n  // `widget.props` (the authored JSON), not any data-source-merged props\n  // below, since those are only ever populated for keys the schema already\n  // declares. No-ops outside dev builds and for widget types with no\n  // registered schema (custom/company widgets).\n  //\n  // `registry` (from context) is the runtime registry apps can extend or\n  // override — it isn't necessarily `DEFAULT_SDK_WIDGET_REGISTRY`. Only run\n  // the check when `Component` is actually the built-in the schema\n  // describes; otherwise an app-overridden built-in (different prop shape)\n  // would get false positives, and a custom widget reusing a built-in type\n  // name would get validated against the wrong contract.\n  if (isDefaultWidgetComponent(widget.type, Component)) {\n    warnUnknownWidgetProps({\n      widgetType: widget.type,\n      props: widget.props,\n      registry: DEFAULT_PROPERTY_SCHEMA_REGISTRY,\n    });\n  }\n\n  if (widget.dataSource) {\n    return (\n      <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n        <DataAwareWidget widget={widget} Component={Component} />\n      </div>\n    );\n  }\n\n  return (\n    <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n      <Component {...widget.props} />\n    </div>\n  );\n}\n\nexport interface BuilderScreenViewProps {\n  /** The screen definition to render */\n  screen: ScreenDefinition;\n  /** Additional CSS classes for the wrapper div */\n  className?: string;\n}\n\n/**\n * Renders a builder screen's component_tree with full data source support.\n * Widgets with `dataSource` config are automatically wrapped with `DataAwareWidget`\n * which fetches data and merges it with static props before rendering.\n */\nfunction BuilderScreenViewImpl({\n  screen,\n  className,\n}: BuilderScreenViewProps): React.JSX.Element | null {\n  const { t } = useShellTranslation();\n  const widgets = screen.component_tree;\n\n  if (!widgets || widgets.length === 0) {\n    return (\n      <div className={className ?? \"h-full w-full\"}>\n        <div className=\"text-muted-foreground flex h-full items-center justify-center\">\n          <p>{t(\"screen_no_content\")}</p>\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div className={className ?? \"h-full w-full\"}>\n      {widgets.map((widget, index) => {\n        if (!widget) return null;\n        return (\n          <WidgetRenderer\n            key={widget.id ?? index}\n            widget={widget}\n            index={index}\n          />\n        );\n      })}\n    </div>\n  );\n}\n\nexport const BuilderScreenView: React.MemoExoticComponent<\n  typeof BuilderScreenViewImpl\n> = memo(BuilderScreenViewImpl);\n","import type { ComponentType } from \"react\";\n\n/**\n * Per-member-type portal content.\n *\n * Lets a portal serve different screens to different member types — e.g.\n * an `affiliate` sees a different dashboard at the `home` slug than a\n * `customer` does — without forking the whole app. Keyed by the real\n * member-type slug (from `member_type_detail.slug`), then by page slug.\n *\n * Resolution order in the router: a per-type page for the current\n * member's slug wins over the global `customPages` entry for the same\n * slug, which in turn wins over the built-in system screen. A member type\n * with no entry falls through to the global content unchanged.\n */\n\n/** A portal page component, receiving the resolved slug and rest params. */\nexport type CustomPageComponent = ComponentType<{\n  slug?: string;\n  params?: string;\n}>;\n\n/** Page components keyed by navigation slug. */\nexport type CustomPages = Record<string, CustomPageComponent>;\n\n/** Per-member-type page overrides: memberTypeSlug -> (pageSlug -> component). */\nexport type MemberTypeCustomPages = Record<string, CustomPages>;\n\n/**\n * Resolve the page component to render for a given member-type slug and\n * page slug, preferring an exact page match then a base-slug (prefix)\n * match. Returns undefined when the member type has no override for the\n * route, so the caller falls back to global content.\n *\n * Known limitation: `baseSlug` is the caller's navigation-derived base (see\n * PageRouter), so a per-type override registered at a detail *prefix* that is\n * not itself a navigation slug (e.g. `share/product` when the nav only has\n * `share/products`) is only matched on an exact `currentSlug`. Data-driven,\n * prefix-aware matching against the registry's own keys is deferred to the\n * authoring phase; register the exact slug you route to for now.\n */\nexport function resolveMemberTypePage(\n  registry: MemberTypeCustomPages | undefined,\n  memberTypeSlug: string | null,\n  currentSlug: string,\n  baseSlug: string,\n): CustomPageComponent | undefined {\n  if (!registry || !memberTypeSlug) return undefined;\n\n  const pages = registry[memberTypeSlug];\n  if (!pages) return undefined;\n\n  return (\n    pages[currentSlug] ??\n    (baseSlug !== currentSlug ? pages[baseSlug] : undefined)\n  );\n}\n","import { lazy, type ComponentType } from \"react\";\nimport {\n  OPT_IN_SYSTEM_SCREEN_SLUGS,\n  findSystemSlugByPrefix,\n  type SystemScreenSlug,\n} from \"./system-screen-slugs\";\n\nconst ProfileScreen = lazy(() =>\n  import(\"../screens/ProfileScreen\").then((m) => ({\n    default: m.ProfileScreen,\n  })),\n);\nconst OrdersScreen = lazy(() =>\n  import(\"../screens/OrdersScreen\").then((m) => ({\n    default: m.OrdersScreen,\n  })),\n);\nconst SubscriptionsScreen = lazy(() =>\n  import(\"../screens/SubscriptionsScreen\").then((m) => ({\n    default: m.SubscriptionsScreen,\n  })),\n);\nconst MessagingScreen = lazy(() =>\n  import(\"../screens/MessagingScreen\").then((m) => ({\n    default: m.MessagingScreen,\n  })),\n);\nconst ContactsScreen = lazy(() =>\n  import(\"../screens/ContactsScreen\").then((m) => ({\n    default: m.ContactsScreen,\n  })),\n);\nconst ShopScreen = lazy(() =>\n  import(\"../screens/ShopScreen\").then((m) => ({ default: m.ShopScreen })),\n);\nconst CustomersScreen = lazy(() =>\n  import(\"../screens/CustomersScreen\").then((m) => ({\n    default: m.CustomersScreen,\n  })),\n);\nconst ShareablesScreen = lazy(() =>\n  import(\"../screens/ShareablesScreen\").then((m) => ({\n    default: m.ShareablesScreen,\n  })),\n);\nconst MySiteScreen = lazy(() =>\n  import(\"../screens/MySiteScreen\").then((m) => ({\n    default: m.MySiteScreen,\n  })),\n);\nconst AppDownloadScreen = lazy(() =>\n  import(\"../screens/AppDownloadScreen\").then((m) => ({\n    default: m.AppDownloadScreen,\n  })),\n);\nconst ActivityScreen = lazy(() =>\n  import(\"../screens/ActivityScreen\").then((m) => ({\n    default: m.ActivityScreen,\n  })),\n);\n\n// Keyed off the slug list in system-screen-slugs.ts, so a slug added on either\n// side without the other is a type error.\nconst SCREEN_FOR_SLUG: Record<SystemScreenSlug, ComponentType> = {\n  profile: ProfileScreen,\n  // Legacy alias: portals that pre-date the /account → /profile rename may\n  // still have \"account\" persisted in their nav config.\n  account: ProfileScreen,\n  orders: OrdersScreen,\n  subscriptions: SubscriptionsScreen,\n  messages: MessagingScreen,\n  contacts: ContactsScreen,\n  shop: ShopScreen,\n  customers: CustomersScreen,\n  \"my-site\": MySiteScreen,\n  \"share/products\": ShareablesScreen,\n  \"share/product\": ShareablesScreen,\n  \"share/media\": ShareablesScreen,\n  \"share/playlists\": ShareablesScreen,\n  \"share/playlist\": ShareablesScreen,\n  \"share/files\": ShareablesScreen,\n  \"share/pages\": ShareablesScreen,\n  \"share/page\": ShareablesScreen,\n  \"app-download\": AppDownloadScreen,\n  // Deliberately not opt-in and not rep-only: both gates require the slug to be\n  // in the tenant's nav (see PageRouter), which would 404 the Recent Activity\n  // widget's click-through on every portal that has not added an Activity item.\n  // The API scopes activities to the signed-in member, so nothing leaks.\n  activity: ActivityScreen,\n};\n\nexport const SYSTEM_SLUG_SCREEN_MAP: Record<string, ComponentType> =\n  SCREEN_FOR_SLUG;\n\n/**\n * System screens that a portal must opt into by adding them to its active\n * navigation. Every other system screen is reachable by default; these two\n * only render when their nav slug is present.\n */\nexport const OPT_IN_SYSTEM_SCREENS: ReadonlySet<ComponentType> = new Set(\n  [...OPT_IN_SYSTEM_SCREEN_SLUGS].map((slug) => SCREEN_FOR_SLUG[slug]),\n);\n\n/** Prefix-match a slug against screen map keys, longest match first. */\nexport function findScreenByPrefix(slug: string): ComponentType | undefined {\n  const key = findSystemSlugByPrefix(slug);\n  return key ? SCREEN_FOR_SLUG[key] : undefined;\n}\n\n/**\n * Returns true if any nav slug resolves to the given system screen component.\n * Lets detail routes (e.g. `share/product/:id`) render when their listing\n * slug (`share/products`) is in the nav, since both map to the same screen.\n */\nexport function isSystemScreenCoveredByNav(\n  target: ComponentType,\n  navSlugs: readonly string[],\n): boolean {\n  for (const slug of navSlugs) {\n    const navScreen = SYSTEM_SLUG_SCREEN_MAP[slug] ?? findScreenByPrefix(slug);\n    if (navScreen === target) return true;\n  }\n  return false;\n}\n\n/**\n * Whether navigating to `slug` would land on a real screen rather than \"Page\n * Not Found\". Deliberately conservative — it reports *unreachable* only for the\n * one case it can be sure of: an opt-in system screen (contacts, messages) whose\n * nav item is absent (the sole reason PageRouter shows \"Page Not Found\" for an\n * otherwise-valid destination). Non-opt-in system screens, custom / builder\n * screen-picker destinations, and unknown navSlugs (e.g. builder preview) are\n * all treated as reachable, so a valid link is never hidden without cause.\n * Widgets use this to avoid offering a deep-link that dead-ends.\n */\nexport function isSlugReachable(\n  slug: string,\n  navSlugs: readonly string[] | undefined,\n  customPageSlugs?: ReadonlySet<string>,\n): boolean {\n  const baseSlug = slug.split(\"/\")[0] ?? slug;\n  // A custom page at this slug (exact or base) overrides the system screen and\n  // renders regardless of nav — PageRouter resolves customPages (ExactCustomPage\n  // / PrefixCustomPage) before system screens.\n  if (customPageSlugs?.has(slug) || customPageSlugs?.has(baseSlug)) return true;\n  if (navSlugs === undefined) return true;\n  const screen = SYSTEM_SLUG_SCREEN_MAP[baseSlug] ?? findScreenByPrefix(slug);\n  // Only a gated opt-in system screen (contacts, messages) whose nav item is\n  // absent is knowably unreachable. Non-opt-in system screens always render, and\n  // custom / builder screen-picker destinations are routed by PageRouter's\n  // customPages (invisible here) — so treat anything that isn't a gated opt-in\n  // screen as reachable rather than risk hiding a valid link.\n  if (screen === undefined || !OPT_IN_SYSTEM_SCREENS.has(screen)) return true;\n  return isSystemScreenCoveredByNav(screen, navSlugs);\n}\n","import { Suspense, useMemo, type ComponentType } from \"react\";\nimport { AppShellSkeleton } from \"@fluid-app/portal-react/shell/AppShellSkeleton\";\nimport {\n  isSystemNavigationItem,\n  isRepOnlySlug,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { slugifyName } from \"@fluid-app/portal-core/navigation/slug-utils\";\nimport type { NavigationItem, ScreenDefinition } from \"../types/navigation\";\nimport { CoreScreenPlaceholder } from \"../screens/CoreScreenPlaceholder\";\nimport { ScreenNotFound } from \"../screens/ScreenNotFound\";\nimport { AccessDeniedScreen } from \"../screens/AccessDeniedScreen\";\nimport { BuilderScreenView } from \"./BuilderScreenView\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { deniesRepSurfaces } from \"@fluid-app/portal-core/member-permissions\";\nimport {\n  resolveMemberTypePage,\n  type MemberTypeCustomPages,\n} from \"@fluid-app/portal-core/member-type-content\";\nimport {\n  OPT_IN_SYSTEM_SCREENS,\n  SYSTEM_SLUG_SCREEN_MAP,\n  findScreenByPrefix,\n  isSystemScreenCoveredByNav,\n} from \"./system-screen-map\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\n\n// The Activity screen ships dark until QA signs a tenant off: gated on the\n// PORTAL_ACTIVITY_SCREEN company flag, read off the store payload.\nconst FLAG_GATED_SLUG = \"activity\";\n\nfunction isRouteCoveredByNav(\n  currentSlug: string,\n  baseSlug: string,\n  navSlugs: readonly string[] | undefined,\n): boolean {\n  if (navSlugs === undefined) return true;\n  return navSlugs.some(\n    (navSlug) =>\n      navSlug === baseSlug ||\n      currentSlug === navSlug ||\n      currentSlug.startsWith(navSlug + \"/\"),\n  );\n}\n\nexport interface PageRouterProps {\n  currentSlug: string;\n  currentNavItem?: NavigationItem | undefined;\n  customPages?:\n    | Record<string, ComponentType<{ slug?: string; params?: string }>>\n    | undefined;\n  /** Per-member-type page overrides, resolved by the current member's slug. */\n  memberTypeCustomPages?: MemberTypeCustomPages | undefined;\n  /** Builder screen definitions (from fluidos API) */\n  screens?: ScreenDefinition[] | undefined;\n  baseSlug: string;\n  restParams: string;\n  /**\n   * Slugs from the active navigation. When provided, screens listed in\n   * `OPT_IN_SYSTEM_SCREENS` only render if they're\n   * reachable via the nav — matching the implicit gating builder screens\n   * get from being sourced via `appData.screens`. All other system screens\n   * bypass this check. Omit to render system screens unconditionally.\n   */\n  navSlugs?: readonly string[] | undefined;\n}\n\nexport function PageRouter({\n  currentSlug,\n  currentNavItem,\n  customPages,\n  memberTypeCustomPages,\n  screens,\n  baseSlug,\n  restParams,\n  navSlugs,\n}: PageRouterProps): React.JSX.Element {\n  const { data: account } = useAccount();\n  const storeQuery = useOptionalStore();\n  // Rep-only routes are gated on the member type's `rep_eligible` permission\n  // so custom non-rep types are blocked the same as customers.\n  const canRep = !deniesRepSurfaces(account);\n\n  // Build a screen lookup map by ID for O(1) access\n  const screenById = useMemo(() => {\n    if (!screens || screens.length === 0) return undefined;\n    return new Map(screens.map((s) => [s.id, s]));\n  }, [screens]);\n\n  // Build a screen lookup map by slug for fallback resolution. Keys include\n  // both the screen's own `slug` (e.g. `screen-{uuid}` for direct URL access)\n  // and `slugifyName(screen.name)` to match nav-item slugs authored in the\n  // admin builder via `generateSlugFromName(screen.name)` — without this,\n  // the slug fallback never matches because the two formats diverge.\n  const screenBySlug = useMemo(() => {\n    if (!screens || screens.length === 0) return undefined;\n    const map = new Map<string, ScreenDefinition>();\n    for (const s of screens) {\n      if (s.slug) map.set(s.slug, s);\n    }\n    for (const s of screens) {\n      if (!s.name) continue;\n      const nameSlug = slugifyName(s.name);\n      if (nameSlug && !map.has(nameSlug)) map.set(nameSlug, s);\n    }\n    return map;\n  }, [screens]);\n\n  // Resolve builder screen: screen_id first, then slug fallback\n  const builderScreen = useMemo(() => {\n    if (currentNavItem?.screen_id && screenById) {\n      const byId = screenById.get(currentNavItem.screen_id);\n      if (byId) return byId;\n    }\n    if (screenBySlug) {\n      return (\n        screenBySlug.get(currentSlug) ?? screenBySlug.get(baseSlug) ?? undefined\n      );\n    }\n    return undefined;\n  }, [\n    currentNavItem?.screen_id,\n    screenById,\n    screenBySlug,\n    currentSlug,\n    baseSlug,\n  ]);\n\n  const routeCoveredByNav =\n    currentNavItem !== undefined ||\n    isRouteCoveredByNav(currentSlug, baseSlug, navSlugs);\n  const isRepOnlyRoute = isRepOnlySlug(currentSlug);\n\n  // 0. Block customer access to rep-only slugs only when the route is\n  // configured in navigation. Hidden rep-only routes should look like normal\n  // missing pages instead of revealing that a rep-only screen exists.\n  if (!canRep && isRepOnlyRoute && routeCoveredByNav) {\n    return <AccessDeniedScreen />;\n  }\n\n  // 0b. Per-member-type page override — an affiliate/customer/etc. can be\n  //     served a different screen at the same slug. Wins over the global\n  //     customPages and system screens below.\n  //\n  //     Keyed on the REAL member type slug (member_type_detail.slug), never\n  //     the binary fallback: content must not be selected for a member whose\n  //     true type is still unknown (backfill gap / loading), or a custom type\n  //     would be served the generic rep/customer bucket's page. Resolves to\n  //     null in that case and falls through to the global content below.\n  //\n  //     A rep-only route the member cannot access is never served a per-type\n  //     page — it must fall through to the AccessDenied/404 handling so a\n  //     per-type override cannot bypass the rep-only gate.\n  const memberTypeContentSlug = account?.member_type_detail?.slug ?? null;\n  const MemberTypePage =\n    canRep || !isRepOnlyRoute\n      ? resolveMemberTypePage(\n          memberTypeCustomPages,\n          memberTypeContentSlug,\n          currentSlug,\n          baseSlug,\n        )\n      : undefined;\n  if (MemberTypePage) {\n    return <MemberTypePage slug={currentSlug} params={restParams} />;\n  }\n\n  // 1. Custom page match (takes priority over system defaults)\n  const ExactCustomPage = customPages?.[currentSlug];\n  if (ExactCustomPage) {\n    return <ExactCustomPage slug={currentSlug} params={restParams} />;\n  }\n\n  // 2. Prefix custom page match (base slug with rest params)\n  if (baseSlug !== currentSlug) {\n    const PrefixCustomPage = customPages?.[baseSlug];\n    if (PrefixCustomPage) {\n      return <PrefixCustomPage slug={currentSlug} params={restParams} />;\n    }\n  }\n\n  // 3. System navigation item with a dedicated screen component\n  //    First try exact match on baseSlug, then prefix-match currentSlug\n  //    against screen map keys (handles detail routes like \"share/product/123\"\n  //    matching \"share/product\" when the slug isn't a registered nav item).\n  const SystemScreen =\n    SYSTEM_SLUG_SCREEN_MAP[baseSlug] ?? findScreenByPrefix(currentSlug);\n  const systemScreenRequiresNav =\n    SystemScreen !== undefined &&\n    (OPT_IN_SYSTEM_SCREENS.has(SystemScreen) || isRepOnlyRoute);\n  const systemScreenInNav =\n    navSlugs === undefined ||\n    (SystemScreen !== undefined &&\n      (!systemScreenRequiresNav ||\n        routeCoveredByNav ||\n        isSystemScreenCoveredByNav(SystemScreen, navSlugs)));\n  if (SystemScreen && baseSlug === FLAG_GATED_SLUG) {\n    // Held while the store is in flight so a flagged-on portal does not flash\n    // Page Not Found; no store at all (no provider, or the fetch failed) reads\n    // as off.\n    if (storeQuery.isPending && storeQuery.fetchStatus !== \"idle\") {\n      return <AppShellSkeleton variant=\"content\" />;\n    }\n    if (storeQuery.data?.activity_screen_enabled !== true) {\n      return <ScreenNotFound name={currentNavItem?.label ?? currentSlug} />;\n    }\n  }\n  if (SystemScreen && systemScreenInNav) {\n    return (\n      <Suspense fallback={<AppShellSkeleton variant=\"content\" />}>\n        <SystemScreen />\n      </Suspense>\n    );\n  }\n\n  // 4. Recognized system screen gated out by step 3. Treat opt-in and\n  //    rep-only system screens absent from the active nav as missing pages.\n  if (SystemScreen && !systemScreenInNav) {\n    return <ScreenNotFound name={currentNavItem?.label ?? currentSlug} />;\n  }\n\n  // 5. Recognized system slug without an SDK screen mapping yet.\n  if (isSystemNavigationItem(baseSlug)) {\n    return <CoreScreenPlaceholder name={currentNavItem?.label ?? baseSlug} />;\n  }\n\n  // 6. Builder screen (by screen_id or slug match)\n  if (builderScreen) {\n    return <BuilderScreenView screen={builderScreen} />;\n  }\n\n  // 7. True \"not found\" — slug didn't match any custom/system/builder screen\n  return <ScreenNotFound name={currentNavItem?.label ?? currentSlug} />;\n}\n","import { Component, type ErrorInfo, type ReactNode, use } from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { TriangleAlert } from \"lucide-react\";\nimport { ShellTranslationContext } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { shellEn } from \"@fluid-app/portal-core/shell-translation-dictionary\";\nimport { FallbackCard } from \"../screens/FallbackCard\";\nimport { goBackOrHome } from \"./go-back-or-home\";\n\nfunction DefaultErrorFallback({\n  onReset,\n}: {\n  onReset: () => void;\n}): React.JSX.Element {\n  const api = use(ShellTranslationContext);\n  const t = api ? api.t : (key: keyof typeof shellEn) => shellEn[key];\n  return (\n    <FallbackCard\n      icon={<TriangleAlert />}\n      title={t(\"error_title\")}\n      description={t(\"error_description\")}\n      actions={\n        <>\n          <Button variant=\"outline\" onClick={onReset}>\n            {t(\"error_try_again\")}\n          </Button>\n          <Button variant=\"default\" onClick={goBackOrHome}>\n            {t(\"error_go_back\")}\n          </Button>\n        </>\n      }\n    />\n  );\n}\n\nexport interface AppShellErrorBoundaryProps {\n  children: ReactNode;\n  /**\n   * Invoked every time the boundary catches an error. Fires again on each\n   * subsequent crash if `reset()` is called and the underlying issue persists.\n   * When provided, the boundary will not log to `console.error` itself —\n   * forward to your reporter (e.g. Sentry) inside this callback.\n   *\n   * @example\n   * ```tsx\n   * <AppShellErrorBoundary onError={(err, info) => Sentry.captureException(err, { extra: info })}>\n   * ```\n   */\n  onError?: (error: Error, info: ErrorInfo) => void;\n  /** Override the default fallback UI. Receives a reset callback. */\n  fallback?: (props: { error: Error; reset: () => void }) => ReactNode;\n}\n\ninterface State {\n  error: Error | null;\n}\n\nexport class AppShellErrorBoundary extends Component<\n  AppShellErrorBoundaryProps,\n  State\n> {\n  override state: State = { error: null };\n\n  static getDerivedStateFromError(error: Error): State {\n    return { error };\n  }\n\n  override componentDidCatch(error: Error, info: ErrorInfo): void {\n    if (this.props.onError) {\n      try {\n        this.props.onError(error, info);\n      } catch (callbackError) {\n        // A throwing onError (e.g. misconfigured Sentry transport) must not\n        // mask the original crash. Surface both to console as a fallback.\n        console.error(\"[portal] onError handler threw:\", callbackError);\n        console.error(\"[portal] Original screen crash:\", error, info);\n      }\n      return;\n    }\n    console.error(\"[portal] Screen crashed:\", error, info);\n  }\n\n  reset = (): void => {\n    this.setState({ error: null });\n  };\n\n  override render(): ReactNode {\n    const { error } = this.state;\n    if (!error) return this.props.children;\n\n    if (this.props.fallback) {\n      return this.props.fallback({ error, reset: this.reset });\n    }\n\n    return <DefaultErrorFallback onReset={this.reset} />;\n  }\n}\n","import type Color from \"colorjs.io\";\nimport type { ResolvedTheme } from \"@fluid-app/portal-core/theme\";\n\nexport const PORTAL_NATIVE_THEME_MESSAGE_TYPE = \"fluid.portal.theme\";\nexport const PORTAL_NATIVE_THEME_MESSAGE_VERSION = 1;\n\nexport type PortalNativeThemeMode = \"light\" | \"dark\";\n\nexport interface PortalNativeThemeMessage {\n  readonly type: typeof PORTAL_NATIVE_THEME_MESSAGE_TYPE;\n  readonly version: typeof PORTAL_NATIVE_THEME_MESSAGE_VERSION;\n  readonly payload: {\n    readonly themeId: string;\n    readonly mode: PortalNativeThemeMode;\n    readonly colors: {\n      readonly muted: string;\n    };\n  };\n}\n\ninterface ReactNativeWebViewBridge {\n  postMessage: (message: string) => void;\n}\n\ndeclare global {\n  interface Window {\n    ReactNativeWebView?: ReactNativeWebViewBridge;\n  }\n}\n\nexport function colorToSrgbHex(color: Color): string {\n  const srgb = color.to(\"srgb\");\n  srgb.alpha = 1;\n  return srgb.toString({ format: \"hex\" });\n}\n\nexport function createPortalNativeThemeMessage({\n  resolvedTheme,\n  mode,\n}: {\n  readonly resolvedTheme: ResolvedTheme;\n  readonly mode: PortalNativeThemeMode;\n}): PortalNativeThemeMessage {\n  return {\n    type: PORTAL_NATIVE_THEME_MESSAGE_TYPE,\n    version: PORTAL_NATIVE_THEME_MESSAGE_VERSION,\n    payload: {\n      themeId: resolvedTheme.id,\n      mode,\n      colors: {\n        muted: colorToSrgbHex(resolvedTheme[mode].muted.base),\n      },\n    },\n  };\n}\n\nexport function postPortalNativeThemeMessage(\n  message: PortalNativeThemeMessage,\n): void {\n  if (typeof window === \"undefined\") return;\n\n  window.ReactNativeWebView?.postMessage(JSON.stringify(message));\n}\n","export const PORTAL_NATIVE_READY_MESSAGE_TYPE = \"fluid.portal.ready\";\nexport const PORTAL_NATIVE_READY_MESSAGE_VERSION = 1;\n\nexport interface PortalNativeReadyMessage {\n  readonly type: typeof PORTAL_NATIVE_READY_MESSAGE_TYPE;\n  readonly version: typeof PORTAL_NATIVE_READY_MESSAGE_VERSION;\n}\n\nexport function createPortalNativeReadyMessage(): PortalNativeReadyMessage {\n  return {\n    type: PORTAL_NATIVE_READY_MESSAGE_TYPE,\n    version: PORTAL_NATIVE_READY_MESSAGE_VERSION,\n  };\n}\n\n/**\n * Tells the native shell the portal is on screen so it can drop its loading\n * skeleton. Sent once per document, unlike the theme message, which re-fires\n * whenever the theme or colour scheme changes.\n */\nexport function postPortalNativeReadyMessage(): void {\n  if (typeof window === \"undefined\") return;\n\n  window.ReactNativeWebView?.postMessage(\n    JSON.stringify(createPortalNativeReadyMessage()),\n  );\n}\n","/**\n * The FairShare SDK identity cookies that must be dropped when the portal\n * member changes. `fluid_session` maps to the server-side `session_uuid` (the\n * backend inherits a new cart's customer from the most recent cart in the same\n * session — so a stale session re-binds carts to the previous member), and\n * `fluid_authenticated_jwt` (+ its timestamp) is Bearer-synced onto carts. We\n * deliberately do NOT touch `fluid_visitor`, locale, or `fluid_affiliate`\n * (attribution is meant to persist).\n */\nconst SDK_IDENTITY_COOKIES = [\n  \"fluid_session\",\n  \"fluid_authenticated_jwt\",\n  \"fluid_authenticated_at\",\n];\n\n/** SDK localStorage keys tied to the member's cart/identity. */\nconst SDK_IDENTITY_STORAGE = [\"fs_cart\", \"fs_authenticated_user\"];\n\n/**\n * Resets the FairShare SDK's persisted shopping identity so the next portal\n * member starts a clean session (CURRENT-2180).\n *\n * The SDK owns this state (localStorage + cookies), and its own `reset()` is\n * insufficient: it sets identity cookies WITH a `domain=` attribute (via\n * `setCookieOnApexAndSubdomains`, using the tenant host as the cookie domain)\n * but deletes them WITHOUT one, so the domain-scoped cookies survive — which is\n * exactly `fluid_session` / `fluid_authenticated_jwt`. So we call `reset()` for\n * its localStorage + in-memory teardown, then expire the identity cookies here\n * with the matching domain.\n *\n * Called on portal logout and company switch. No-op-safe when the SDK global\n * isn't present (e.g. a page that never mounted the cart script, or SSR).\n */\nexport function resetFairShareSdk(): void {\n  if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n  const sdk = (window as unknown as { FairShareSDK?: { reset?: () => void } })\n    .FairShareSDK;\n\n  if (typeof sdk?.reset === \"function\") {\n    try {\n      sdk.reset();\n    } catch (error) {\n      // Best-effort: never let SDK teardown block the logout/switch flow.\n      console.error(\"[resetFairShareSdk] SDK reset failed:\", error);\n    }\n  }\n\n  // Expire the identity cookies across every domain they could have been set\n  // under. A browser only deletes a cookie when the delete's domain matches how\n  // it was written, and these cookies are written under different scopes:\n  // `fluid_session` under the tenant host (BFF cookieDomain), but\n  // `fluid_authenticated_jwt` can come from a non-BFF login on a broader apex\n  // (e.g. `.fluid.app` / `.portal.fluid.app`). So walk up every parent domain\n  // of the current host (with and without a leading dot) plus host-only.\n  const host = window.location.hostname;\n  const labels = host.split(\".\");\n  const domainVariants = [\"\"]; // host-only (no domain attribute)\n  for (let i = 0; i < labels.length - 1; i++) {\n    const domain = labels.slice(i).join(\".\");\n    domainVariants.push(`; domain=${domain}`, `; domain=.${domain}`);\n  }\n\n  for (const name of SDK_IDENTITY_COOKIES) {\n    for (const domain of domainVariants) {\n      document.cookie = `${name}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT${domain}`;\n    }\n  }\n\n  for (const key of SDK_IDENTITY_STORAGE) {\n    try {\n      window.localStorage.removeItem(key);\n    } catch {\n      // localStorage may be unavailable in some contexts\n    }\n  }\n}\n","/**\n * useLogout Hook\n *\n * Provides a complete logout function that:\n * 1. Clears all client-side state (query cache, IndexedDB, sessionStorage)\n * 2. Navigates to GET /logout — Rails clears the session and redirects to the Hub\n */\n\nimport { useCallback } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\nimport { resetFairShareSdk } from \"../utils/reset-fairshare-sdk\";\n\nexport interface UseLogoutOptions {\n  /** URL to redirect to after logout. Triggers a full page navigation. */\n  redirectUrl?: string;\n  /** Callback invoked after all state is cleared. Ignored when `redirectUrl` is set. */\n  onLogout?: () => void;\n}\n\n/**\n * Hook that returns a `logout` function which clears the server session\n * via `DELETE /logout` and all cached/persisted client state.\n *\n * @example\n * ```tsx\n * const logout = useLogout({ redirectUrl: \"/login\" });\n * <button onClick={logout}>Log out</button>\n * ```\n *\n * @example\n * ```tsx\n * const logout = useLogout({\n *   onLogout: () => navigate(\"/signed-out\"),\n * });\n * ```\n */\nexport function useLogout({\n  redirectUrl,\n  onLogout,\n}: UseLogoutOptions = {}): () => Promise<void> {\n  const queryClient = useQueryClient();\n\n  const logout = useCallback(async () => {\n    // 1. Cancel in-flight requests to prevent cache repopulation\n    await queryClient.cancelQueries();\n\n    // 2. Clear in-memory TanStack Query cache\n    queryClient.clear();\n\n    // 3. Clear IndexedDB persisted query cache\n    try {\n      await deleteDatabase();\n    } catch (error) {\n      // Non-fatal — continue with logout even if IndexedDB cleanup fails\n      console.error(\"[useLogout] Failed to clear IndexedDB cache:\", error);\n    }\n\n    // 4. Clear sessionStorage — intentionally clears all keys because the\n    //    portal app owns the full page (not embedded as a micro-frontend).\n    try {\n      sessionStorage.clear();\n    } catch {\n      // sessionStorage may be unavailable in some contexts\n    }\n\n    // 5. Reset the FairShare SDK's shopping identity (cart, session, auth\n    //    cookies). These live in the SDK's own localStorage/cookies, which the\n    //    steps above don't touch — leaving them lets the next member inherit\n    //    the previous member's cart/customer (CURRENT-2180).\n    resetFairShareSdk();\n\n    // 6. Navigate to the server logout endpoint. Rails clears the session\n    //    cookie and redirects to the Portal Hub company list. A full page\n    //    navigation lets the browser follow the redirect naturally — no\n    //    fetch or JSON parsing needed.\n    if (redirectUrl) {\n      window.location.href = redirectUrl;\n    } else if (onLogout) {\n      onLogout();\n    } else {\n      window.location.href = \"/logout\";\n    }\n  }, [queryClient, redirectUrl, onLogout]);\n\n  return logout;\n}\n","import { useCallback, useState } from \"react\";\nimport { LogOut, Moon, Sun } from \"lucide-react\";\nimport {\n  SidebarMenu,\n  SidebarMenuItem,\n  SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\n\nexport interface SdkLogoutButtonProps {\n  onLogout: () => Promise<void>;\n}\n\n/**\n * Sidebar footer slot. Renders Theme toggle + Log out.\n * Filename is historical — kept to avoid touching the AppShell wiring.\n */\nexport function SdkLogoutButton({\n  onLogout,\n}: SdkLogoutButtonProps): React.JSX.Element {\n  const [isPending, setIsPending] = useState(false);\n  const themeMode = useThemeMode();\n  const { t } = useShellTranslation();\n\n  const handleClick = useCallback(async () => {\n    setIsPending(true);\n    try {\n      await onLogout();\n    } catch (error) {\n      console.error(\"[SdkLogoutButton] Logout failed:\", error);\n    } finally {\n      setIsPending(false);\n    }\n  }, [onLogout]);\n\n  const ThemeIcon = themeMode.displayMode === \"dark\" ? Moon : Sun;\n\n  return (\n    <SidebarMenu>\n      <SidebarMenuItem>\n        <SidebarMenuButton\n          onClick={themeMode.cycleMode}\n          aria-label={t(\"theme_switch\", { mode: themeMode.mode })}\n        >\n          <ThemeIcon className=\"size-4\" />\n          <span>{t(\"theme_label\")}</span>\n        </SidebarMenuButton>\n      </SidebarMenuItem>\n      <SidebarMenuItem>\n        <SidebarMenuButton onClick={handleClick} disabled={isPending}>\n          <LogOut className=\"size-4\" />\n          <span>{isPending ? t(\"logout_pending\") : t(\"logout\")}</span>\n        </SidebarMenuButton>\n      </SidebarMenuItem>\n    </SidebarMenu>\n  );\n}\n","import type { NavigationItem } from \"@fluid-app/portal-core/types\";\nimport {\n  isRepOnlySlug,\n  type SystemNavigationItem,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\n\n/**\n * Filter navigation items by removing rep-only slugs.\n * Handles nested children: rep-only children are removed, and parents\n * with no remaining children are also removed.\n */\nexport function filterRepOnlyNavItems(\n  items: NavigationItem[],\n): NavigationItem[] {\n  const result: NavigationItem[] = [];\n\n  for (const item of items) {\n    // Leaf item with a rep-only slug — skip\n    if (!item.children?.length) {\n      if (isRepOnlySlug(item.slug)) continue;\n      result.push(item);\n      continue;\n    }\n\n    // Parent with a rep-only slug — skip entire group\n    if (isRepOnlySlug(item.slug)) continue;\n\n    // Recursively filter children\n    const filteredChildren = filterRepOnlyNavItems(item.children);\n\n    // Drop parent if all children were removed\n    if (filteredChildren.length === 0) continue;\n\n    result.push({ ...item, children: filteredChildren });\n  }\n\n  return result;\n}\n\n/**\n * Filter system navigation sections by removing rep-only items.\n * Sections with no remaining items are dropped entirely.\n */\nexport function filterRepOnlySections(\n  sections: Record<string, SystemNavigationItem[]>,\n): Record<string, SystemNavigationItem[]> {\n  const filtered: Record<string, SystemNavigationItem[]> = {};\n  for (const [section, items] of Object.entries(sections)) {\n    const allowed = items.filter((item) => !isRepOnlySlug(item.slug));\n    if (allowed.length > 0) filtered[section] = allowed;\n  }\n  return filtered;\n}\n","import { useLayoutEffect, useRef, type ReactNode } from \"react\";\nimport { useIsMobile } from \"./use-mobile\";\n\n// Matches the native sheet easing used elsewhere in the shell so screen\n// pushes/pops feel of a piece with the bottom-sheet motion.\nconst NATIVE_EASING = \"cubic-bezier(0.32, 0.72, 0, 1)\";\nconst SLIDE_DURATION_MS = 300;\n// Tab switches cross-fade quickly rather than sliding — shorter and lighter\n// than a push so lateral moves don't feel like drilling in.\nconst FADE_DURATION_MS = 190;\n\n/**\n * `forward`/`back` are hierarchical pushes/pops (drill in and out) that slide;\n * `lateral` is a switch between top-level tabs, which cross-fades because tabs\n * are peers, not a stack — sliding them would imply a depth change that isn't\n * happening.\n */\nexport type ScreenTransitionDirection = \"forward\" | \"back\" | \"lateral\";\n\nfunction prefersReducedMotion(): boolean {\n  return (\n    typeof window !== \"undefined\" &&\n    typeof window.matchMedia === \"function\" &&\n    window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n  );\n}\n\n/**\n * Animates the active screen in on navigation so it reads like a native app\n * instead of an instant swap. A hierarchical push/pop (`forward`/`back`) slides\n * the content in from the leading edge; a lateral tab switch (`lateral`) does a\n * quick cross-fade instead, since sliding between peer tabs would fake a depth\n * change. Only the content area animates — the header and bottom nav stay put.\n *\n * Driven by the Web Animations API (not CSS) so it's self-contained and works\n * in the portal WebView without depending on package-level keyframes. Animates\n * only on mobile, only on an actual route change, and never when the user\n * prefers reduced motion. Degrades to an instant swap where `element.animate`\n * is unavailable (e.g. jsdom / very old engines).\n */\nexport function ScreenTransition({\n  transitionKey,\n  direction,\n  children,\n}: {\n  /** Changes when the route changes; drives the animation. */\n  transitionKey: string;\n  direction: ScreenTransitionDirection;\n  children: ReactNode;\n}): React.JSX.Element {\n  const ref = useRef<HTMLDivElement>(null);\n  const previousKeyRef = useRef(transitionKey);\n  const isMobile = useIsMobile();\n\n  useLayoutEffect(() => {\n    const node = ref.current;\n    const isFirstRenderForKey = previousKeyRef.current === transitionKey;\n    previousKeyRef.current = transitionKey;\n\n    if (\n      !node ||\n      isFirstRenderForKey ||\n      !isMobile ||\n      prefersReducedMotion() ||\n      typeof node.animate !== \"function\"\n    ) {\n      return;\n    }\n\n    // Lateral tab switch: cross-fade with a whisper of scale, no horizontal\n    // travel, so it reads as \"swapped\" rather than \"pushed.\"\n    if (direction === \"lateral\") {\n      node.animate(\n        [\n          { opacity: 0, transform: \"scale(0.985)\" },\n          { opacity: 1, transform: \"scale(1)\" },\n        ],\n        { duration: FADE_DURATION_MS, easing: \"ease-out\", fill: \"both\" },\n      );\n      return;\n    }\n\n    // Hierarchical push/pop: incoming screen enters from the leading edge\n    // (right on push, left on pop) and settles to rest, with a slight opacity\n    // ramp.\n    const fromX = direction === \"forward\" ? \"100%\" : \"-25%\";\n    node.animate(\n      [\n        { transform: `translate3d(${fromX}, 0, 0)`, opacity: 0.4 },\n        { transform: \"translate3d(0, 0, 0)\", opacity: 1 },\n      ],\n      { duration: SLIDE_DURATION_MS, easing: NATIVE_EASING, fill: \"both\" },\n    );\n  }, [transitionKey, direction, isMobile]);\n\n  return (\n    <div ref={ref} className=\"h-full w-full will-change-transform\">\n      {children}\n    </div>\n  );\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { PanelLeft } from \"lucide-react\";\nimport { useSidebar } from \"./sidebar\";\nimport { useScreenHeaderSlotRefs } from \"./ScreenHeaderContext\";\n\nexport interface ScreenHeaderProps {\n  title?: string;\n  trailingContent?: ReactNode;\n  override?: ScreenHeaderOverride;\n}\n\nexport interface ScreenHeaderOverride {\n  title: string;\n  action: ReactNode;\n}\n\nexport function ScreenHeader({\n  title,\n  trailingContent,\n  override,\n}: ScreenHeaderProps): React.JSX.Element | null {\n  const { toggleSidebar, isMobile } = useSidebar();\n  const { breadcrumbsRef, actionsRef, hasBreadcrumbs } =\n    useScreenHeaderSlotRefs();\n\n  if (!override && !title && !hasBreadcrumbs && !trailingContent) return null;\n\n  const showTrailing = !isMobile && trailingContent;\n\n  return (\n    <div\n      data-fluid-screen-header=\"\"\n      tabIndex={-1}\n      className=\"border-foreground/[0.06] bg-background sticky top-0 z-30 flex flex-row items-center border-b px-4 py-3 max-md:hidden md:px-6\"\n    >\n      {!isMobile && (\n        <>\n          <button\n            type=\"button\"\n            onClick={toggleSidebar}\n            className=\"text-muted-foreground hover:text-foreground -ml-1 inline-flex items-center justify-center rounded-md p-1\"\n            aria-label=\"Toggle Sidebar\"\n          >\n            <PanelLeft className=\"size-4\" />\n          </button>\n          <div className=\"bg-border mx-2 h-4 w-px\" />\n        </>\n      )}\n      <div\n        data-fluid-screen-header-normal-content\n        hidden={override !== undefined}\n        className=\"flex min-w-0 flex-1 items-center\"\n      >\n        <div\n          ref={breadcrumbsRef}\n          className=\"min-w-0 flex-1 empty:hidden [&_[data-slot=breadcrumb-list]]:text-base!\"\n        />\n        {!hasBreadcrumbs && title && (\n          <h1 className=\"text-foreground text-base font-semibold\">{title}</h1>\n        )}\n        <div className=\"ml-auto flex items-center gap-2\">\n          <div\n            ref={actionsRef}\n            className=\"flex items-center gap-2 empty:hidden\"\n          />\n          {showTrailing}\n        </div>\n      </div>\n      {override && (\n        <div\n          data-fluid-screen-header-override-content\n          className=\"flex min-w-0 flex-1 items-center gap-2\"\n        >\n          <h1 className=\"text-foreground min-w-0 truncate text-base font-semibold\">\n            {override.title}\n          </h1>\n          <div className=\"ml-auto flex shrink-0 items-center\">\n            {override.action}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n","import { useLayoutEffect, useRef, type ReactNode } from \"react\";\nimport { translateNavLabel } from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport {\n  ScreenHeader,\n  type ScreenHeaderOverride,\n} from \"@fluid-app/portal-react/shell/ScreenHeader\";\nimport {\n  useOptionalScreenAreaFullscreenCoordinator,\n  useScreenAreaFullscreenSnapshot,\n} from \"./ScreenAreaFullscreenContext\";\n\nfunction FullscreenExitAction({\n  label,\n  onExit,\n  owner,\n}: {\n  readonly label: string;\n  readonly onExit: () => void;\n  readonly owner: symbol;\n}): React.JSX.Element {\n  const buttonRef = useRef<HTMLButtonElement>(null);\n  useLayoutEffect(() => buttonRef.current?.focus(), [owner]);\n\n  return (\n    <button\n      ref={buttonRef}\n      type=\"button\"\n      className=\"fluid-portal-fullscreen-exit\"\n      onClick={onExit}\n    >\n      {label}\n    </button>\n  );\n}\n\n/** Translates the screen title and swaps in trusted fullscreen header chrome. */\nexport function TranslatedScreenHeader({\n  slug,\n  title,\n  trailingContent,\n}: {\n  slug: string | undefined;\n  title: string | undefined;\n  trailingContent: ReactNode;\n}): React.JSX.Element | null {\n  const shellApi = useShellTranslation();\n  const fullscreenCoordinator = useOptionalScreenAreaFullscreenCoordinator();\n  const fullscreen = useScreenAreaFullscreenSnapshot();\n  const translatedTitle = title\n    ? translateNavLabel(shellApi, slug, title)\n    : undefined;\n  const fullscreenOverride: ScreenHeaderOverride | undefined =\n    fullscreen && fullscreenCoordinator\n      ? {\n          title: fullscreen.displayName,\n          action: (\n            <FullscreenExitAction\n              label={shellApi.t(\"fullscreen_exit\")}\n              onExit={() => fullscreenCoordinator.exit()}\n              owner={fullscreen.owner}\n            />\n          ),\n        }\n      : undefined;\n\n  return (\n    <ScreenHeader\n      title={translatedTitle}\n      trailingContent={trailingContent}\n      override={fullscreenOverride}\n    />\n  );\n}\n","import { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { matchSlugPrefix } from \"@fluid-app/portal-core/navigation/slug-utils\";\n\nconst LEGACY_SHAREABLE_PARENT_SLUGS = {\n  \"share/page\": \"share/pages\",\n  \"share/playlist\": \"share/playlists\",\n  \"share/product\": \"share/products\",\n} as const;\n\nexport function resolveMobileBackTarget(\n  currentSlug: string,\n  navSlugs: string[],\n  previousSlug?: string | null,\n): string | undefined {\n  const navMatch = matchSlugPrefix(currentSlug, navSlugs);\n  const normalized = normalizeSlug(currentSlug);\n  const normalizedPrevious = normalizeSlug(previousSlug ?? undefined);\n\n  // Any page reached in-session from another page — a widget button/link, a\n  // list drill-in, a breadcrumb — gets a back button that returns there. This\n  // is what puts a back affordance on every screen you navigate to from a\n  // widget, regardless of whether the destination is a nav item, a \"More\"\n  // overflow page, or a standalone screen.\n  if (normalizedPrevious && normalizedPrevious !== normalized) {\n    return normalizedPrevious;\n  }\n\n  // No in-session referrer (deep link / cold reload): fall back to the\n  // structural parent so nested routes still offer a way up.\n  if (navMatch?.rest) return navMatch.matchedSlug;\n\n  for (const [routePrefix, parentSlug] of Object.entries(\n    LEGACY_SHAREABLE_PARENT_SLUGS,\n  )) {\n    if (\n      normalized.startsWith(routePrefix + \"/\") &&\n      navSlugs.includes(parentSlug)\n    ) {\n      return parentSlug;\n    }\n  }\n\n  return undefined;\n}\n","import {\n  useState,\n  useEffect,\n  useCallback,\n  useMemo,\n  useRef,\n  type ReactNode,\n  type ComponentType,\n  type ErrorInfo,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { AppShellLayout } from \"@fluid-app/portal-react/shell/AppShellLayout\";\nimport {\n  BottomNavVisibilityProvider,\n  useBottomNavHidden,\n} from \"@fluid-app/portal-react/shell/BottomNavVisibilityContext\";\nimport { useIsMobile } from \"@fluid-app/portal-react/shell/use-mobile\";\nimport {\n  ThemeModeProvider,\n  type ThemeMode,\n} from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { getDefaultNavigation } from \"@fluid-app/portal-core/navigation/default-navigation\";\nimport { ScreenHeaderProvider } from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { SdkBottomNav } from \"./SdkBottomNav\";\nimport type {\n  RepAppData,\n  ScreenDefinition,\n} from \"@fluid-app/portal-core/types\";\nimport {\n  applyTheme,\n  getDefaultThemeDefinition,\n  removeAllThemes,\n  resolveTheme,\n} from \"@fluid-app/portal-core/theme\";\nimport { useFluidApp } from \"../hooks/use-fluid-app\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { AppShellLoading } from \"./AppShellLoading\";\nimport { SdkNavigation } from \"./SdkNavigation\";\nimport { SdkHeader } from \"./SdkHeader\";\nimport { LanguageSelector } from \"./LanguageSelector\";\nimport {\n  isPortalCartAvailable,\n  PortalCartButton,\n  PortalCartRuntime,\n} from \"./PortalCart\";\nimport { SdkCompanySwitcher } from \"./SdkCompanySwitcher\";\nimport { PageRouter } from \"./PageRouter\";\nimport { isSlugReachable } from \"./system-screen-map\";\nimport {\n  collectNavSlugs,\n  matchSlugPrefix,\n  extractSlugFromPathname,\n  internalSlugFromHref,\n} from \"@fluid-app/portal-core/navigation/slug-utils\";\nimport { AppNavigationProvider } from \"./AppNavigationContext\";\nimport { AppShellErrorBoundary } from \"./AppShellErrorBoundary\";\nimport type { PortalErrorReporter } from \"../errors/portal-error-reporter\";\nimport {\n  createPortalNativeThemeMessage,\n  postPortalNativeThemeMessage,\n  type PortalNativeThemeMode,\n} from \"./native-theme-bridge\";\nimport { postPortalNativeReadyMessage } from \"./native-ready-bridge\";\n\nimport { useLogout } from \"../hooks/use-logout\";\nimport { SdkLogoutButton } from \"./SdkLogoutButton\";\nimport {\n  RepUserProvider,\n  WidgetInteractionProvider,\n  type WidgetInteractionItem,\n} from \"@fluid-app/portal-widgets/contexts\";\nimport { Toaster } from \"@fluid-app/ui-primitives\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { deniesRepSurfaces } from \"@fluid-app/portal-core/member-permissions\";\nimport type { MemberTypeCustomPages } from \"@fluid-app/portal-core/member-type-content\";\nimport { filterRepOnlyNavItems } from \"../navigation/filter-nav-items\";\nimport { ScreenAreaFullscreenProvider } from \"./ScreenAreaFullscreenContext\";\nimport {\n  ScreenTransition,\n  type ScreenTransitionDirection,\n} from \"@fluid-app/portal-react/shell/ScreenTransition\";\nimport { TranslatedScreenHeader } from \"./TranslatedScreenHeader\";\nimport { resolveMobileBackTarget } from \"./mobile-back-target\";\n\nconst THEME_STORAGE_KEY = \"portal-theme-mode\";\n\n// Maps a ShareableResource.shareable_type discriminator to its detail-screen\n// slug segment. The detail route is `share/<slug>/<id>` (see ShareablesScreen).\n// `Playlist` and `Library` both surface under the playlists slug — fetchResource\n// stamps \"Library\" while the metrics adapters stamp \"Playlist\". `EnrollmentPack`\n// is intentionally absent: there's no in-portal detail screen, so clicks open\n// the pack's public canonical_url in a new tab instead — see handleWidgetItemClick.\nconst SHAREABLE_TYPE_TO_SLUG: Record<string, string> = {\n  Product: \"products\",\n  Medium: \"media\",\n  Page: \"pages\",\n  Playlist: \"playlists\",\n  Library: \"playlists\",\n};\n\nfunction getInitialThemeMode(): ThemeMode {\n  if (typeof window === \"undefined\") return \"light\";\n  const stored = localStorage.getItem(THEME_STORAGE_KEY);\n  if (stored === \"light\" || stored === \"dark\") return stored;\n  return \"light\";\n}\n\n// Seed the history index from the current entry so a reload mid-session keeps\n// popstate direction correct: without this the ref would restart at 0 while the\n// browser entry still carries its real fluidNavIndex, misreading the next Back\n// as a forward.\nfunction getInitialHistoryIndex(): number {\n  if (typeof window === \"undefined\") return 0;\n  const state = window.history.state as { fluidNavIndex?: number } | null;\n  return typeof state?.fluidNavIndex === \"number\" ? state.fluidNavIndex : 0;\n}\n\nfunction findFirstNavigableSlug(items: NavigationItem[]): string {\n  for (const item of items) {\n    if (item.slug) return normalizeSlug(item.slug);\n    for (const child of item.children ?? []) {\n      if (child.slug) return normalizeSlug(child.slug);\n    }\n  }\n  return \"\";\n}\n\n/**\n * Slugs of the top-level nav destinations (the bottom-nav / sidebar tabs). A\n * move between two of these is a lateral tab switch — peers, not a stack — so\n * the screen transition cross-fades instead of sliding. A parent-only tab\n * resolves to the slug it actually lands on: its first navigable child.\n */\nfunction collectTopLevelSlugs(items: NavigationItem[]): string[] {\n  const slugs: string[] = [];\n  for (const item of items) {\n    if (item.slug) {\n      slugs.push(normalizeSlug(item.slug));\n      continue;\n    }\n    const firstChild = item.children.find((child) => child.slug);\n    if (firstChild?.slug) slugs.push(normalizeSlug(firstChild.slug));\n  }\n  return slugs;\n}\n\nfunction findCurrentSection(\n  items: NavigationItem[],\n  slug: string,\n): NavigationItem | undefined {\n  const normalized = normalizeSlug(slug);\n  for (const item of items) {\n    if (normalizeSlug(item.slug) === normalized) return item;\n    if (\n      item.children?.some((child) => normalizeSlug(child.slug) === normalized)\n    ) {\n      return item;\n    }\n  }\n  return undefined;\n}\n\nfunction findNavItem(\n  items: NavigationItem[],\n  slug: string,\n): NavigationItem | undefined {\n  const normalized = normalizeSlug(slug);\n  for (const item of items) {\n    if (normalizeSlug(item.slug) === normalized) return item;\n    for (const child of item.children ?? []) {\n      if (normalizeSlug(child.slug) === normalized) return child;\n    }\n  }\n  return undefined;\n}\n\n/**\n * Toast host. Its own component so it can read bottom nav visibility, which is\n * only available inside that provider.\n */\nfunction PortalToaster(): React.JSX.Element {\n  const isMobileViewport = useIsMobile();\n  const bottomNavHidden = useBottomNavHidden();\n\n  // Both offsets, not just mobileOffset: sonner swaps to that one at 600px\n  // while the bottom nav is still around until 768px, leaving a band uncovered.\n  const offset = useMemo(\n    () =>\n      isMobileViewport && !bottomNavHidden\n        ? { bottom: \"calc(3.5rem + env(safe-area-inset-bottom) + 0.75rem)\" }\n        : undefined,\n    [isMobileViewport, bottomNavHidden],\n  );\n\n  return (\n    // Radix treats a pointerdown outside the sheet as a dismiss, and toasts\n    // render outside it. Without this, dismissing a toast closes the sheet.\n    <div onPointerDown={(e) => e.stopPropagation()}>\n      <Toaster\n        offset={offset}\n        mobileOffset={offset}\n        // One at a time on phones; sonner stacks three by default.\n        visibleToasts={isMobileViewport ? 1 : undefined}\n      />\n    </div>\n  );\n}\n\nexport interface AppShellProps {\n  /** Pre-fetched app data (skips internal useFluidApp call if provided) */\n  appData?: RepAppData;\n  /** Override navigation items (otherwise derived from appData/API) */\n  navigation?: NavigationItem[];\n  /** Custom page components keyed by slug */\n  customPages?: Record<\n    string,\n    ComponentType<{ slug?: string; params?: string }>\n  >;\n  /** Per-member-type page overrides, resolved by the current member's slug. */\n  memberTypeCustomPages?: MemberTypeCustomPages;\n  /** Base path for subpath deployments (e.g. \"/portal\"). Default: \"/\" */\n  basePath?: string;\n  /** Controlled current slug */\n  currentSlug?: string;\n  /** Navigation callback */\n  onNavigate?: (slug: string) => void;\n  /** Custom sidebar header slot */\n  sidebarHeader?: ReactNode;\n  /** Custom sidebar footer slot. When provided, replaces the default logout button. */\n  sidebarFooter?: ReactNode;\n  /**\n   * Callback invoked after the user logs out and all client state has been cleared.\n   * If not provided, a default logout button is still rendered, but no post-logout\n   * action is taken (consumers should pair this with `logoutRedirectUrl`\n   * or provide their own `sidebarFooter`).\n   */\n  onLogout?: () => void;\n  /** URL to redirect to after logout (e.g. \"/login\"). Takes precedence over `onLogout`. */\n  logoutRedirectUrl?: string;\n  /** Optional reporter for screen-level crashes. Falls back to console logging when omitted. */\n  errorReporter?: PortalErrorReporter;\n  /** Render prop or static children for the content area */\n  children?:\n    | ReactNode\n    | ((props: {\n        currentSlug: string;\n        currentNavItem: NavigationItem | undefined;\n      }) => ReactNode);\n}\n\nexport function AppShell({\n  appData: appDataProp,\n  navigation: navigationProp,\n  customPages,\n  memberTypeCustomPages,\n  basePath = \"/\",\n  currentSlug: controlledSlug,\n  onNavigate: onNavigateProp,\n  sidebarHeader,\n  sidebarFooter,\n  onLogout,\n  logoutRedirectUrl,\n  errorReporter,\n  children,\n}: AppShellProps): React.JSX.Element {\n  // Tell the native shell the portal is on screen so it can drop its skeleton.\n  // Once per mount: the theme message re-fires on every theme change, so it\n  // cannot stand in for this.\n  useEffect(() => {\n    postPortalNativeReadyMessage();\n  }, []);\n\n  // Normalize basePath: ensure leading slash, no trailing slash\n  const normalizedBasePath = useMemo(() => {\n    const stripped = basePath.replace(/^\\/|\\/$/g, \"\");\n    return stripped ? `/${stripped}` : \"/\";\n  }, [basePath]);\n\n  // Fetch full app data from the rendered-manifest endpoint\n  // (disabled when appData is provided). The response carries\n  // `definition_id` directly, so no separate definition fetch is needed.\n  const { data: fetchedAppData, isLoading } = useFluidApp({\n    enabled: !appDataProp,\n  });\n  const appData = appDataProp ?? fetchedAppData;\n\n  const { data: account } = useAccount();\n  const repUser = useMemo(\n    () => ({\n      name:\n        account?.first_name && account?.last_name\n          ? `${account.first_name} ${account.last_name}`\n          : null,\n      email: account?.email ?? null,\n      imageUrl: account?.avatar_url ?? null,\n      publicId: account?.public_id,\n    }),\n    [\n      account?.first_name,\n      account?.last_name,\n      account?.email,\n      account?.avatar_url,\n      account?.public_id,\n    ],\n  );\n\n  // Resolve the active theme from app data, falling back to the theme-engine\n  // default when the manifest has no themes. This guarantees CSS variables\n  // are always emitted so the shell renders with proper styling.\n  const activeTheme = useMemo(() => {\n    const themes = appData?.profile?.themes;\n    const activeId = appData?.profile?.activeThemeId;\n    if (themes?.length) {\n      const matched = activeId\n        ? themes.find((t) => t.id === activeId)\n        : undefined;\n      const first = themes[0];\n      if (matched) return matched;\n      if (first) return first;\n    }\n    return getDefaultThemeDefinition();\n  }, [appData?.profile?.themes, appData?.profile?.activeThemeId]);\n\n  // Apply theme CSS via the shared theme pipeline\n  const resolvedTheme = useMemo(() => resolveTheme(activeTheme), [activeTheme]);\n\n  useEffect(() => {\n    applyTheme(resolvedTheme);\n    return () => {\n      removeAllThemes();\n    };\n  }, [resolvedTheme]);\n\n  // Mirror data-theme and data-theme-mode onto <html> so that Radix portals\n  // (rendered at document.body) inherit the correct CSS custom properties.\n  useEffect(() => {\n    const root = document.documentElement;\n    root.setAttribute(\"data-theme\", activeTheme.id);\n    return () => {\n      root.removeAttribute(\"data-theme\");\n    };\n  }, [activeTheme.id]);\n\n  // Resolve navigation items\n  const navItems = useMemo(() => {\n    if (navigationProp) return navigationProp;\n    const profileNav = appData?.profile?.navigation?.navigation_items;\n    if (profileNav && profileNav.length > 0) return profileNav;\n    return getDefaultNavigation();\n  }, [navigationProp, appData?.profile?.navigation?.navigation_items]);\n\n  // Resolve mobile navigation items (fall back to desktop nav)\n  const mobileNavItems = useMemo(() => {\n    const mobileNav = appData?.profile?.mobile_navigation?.navigation_items;\n    if (mobileNav && mobileNav.length > 0) return mobileNav;\n    return navItems;\n  }, [appData?.profile?.mobile_navigation?.navigation_items, navItems]);\n\n  // Gate rep-only nav on the member type's `rep_eligible` permission rather\n  // than the binary customer/rep split, so company-custom member types are\n  // filtered by what they're actually allowed to see.\n  const canRep = !deniesRepSurfaces(account);\n\n  const filteredNavItems = useMemo(\n    () => (canRep ? navItems : filterRepOnlyNavItems(navItems)),\n    [navItems, canRep],\n  );\n\n  const filteredMobileNavItems = useMemo(\n    () => (canRep ? mobileNavItems : filterRepOnlyNavItems(mobileNavItems)),\n    [mobileNavItems, canRep],\n  );\n\n  // Resolve builder screen definitions\n  const screens: ScreenDefinition[] | undefined = appData?.screens;\n\n  // Collect all nav slugs for prefix matching (sorted longest-first)\n  const navSlugs = useMemo(\n    () => collectNavSlugs(filteredNavItems),\n    [filteredNavItems],\n  );\n\n  // Combined desktop + mobile nav slugs for gating system-screen rendering\n  // and prefix-matching; a slug present in either nav counts as \"in nav\".\n  // Re-sort longest-first after merging — `collectNavSlugs` orders each list\n  // individually, but Set insertion order would otherwise let a shorter\n  // desktop prefix (e.g. \"home\") win against a more-specific mobile slug\n  // (e.g. \"home/news\") in `matchSlugPrefix`.\n  const allNavSlugs = useMemo(() => {\n    const mobileSlugs = collectNavSlugs(filteredMobileNavItems);\n    return Array.from(new Set([...navSlugs, ...mobileSlugs])).sort(\n      (a, b) => b.split(\"/\").length - a.split(\"/\").length,\n    );\n  }, [navSlugs, filteredMobileNavItems]);\n\n  // Destinations of the top-level tabs (desktop sidebar + mobile bottom nav).\n  // A navigation whose source and target are both in here is a lateral tab\n  // switch, which the screen transition cross-fades rather than slides.\n  const topLevelSlugs = useMemo(\n    () =>\n      new Set([\n        ...collectTopLevelSlugs(filteredNavItems),\n        ...collectTopLevelSlugs(filteredMobileNavItems),\n      ]),\n    [filteredNavItems, filteredMobileNavItems],\n  );\n\n  // Theme mode state with localStorage persistence\n  const [themeMode, setThemeMode] = useState<ThemeMode>(getInitialThemeMode);\n\n  const handleThemeModeChange = useCallback((mode: ThemeMode) => {\n    setThemeMode(mode);\n    if (typeof window !== \"undefined\") {\n      localStorage.setItem(THEME_STORAGE_KEY, mode);\n    }\n  }, []);\n\n  // Mirror data-theme-mode onto <html> so that Radix portals\n  // (rendered at document.body) inherit the correct CSS custom properties.\n  useEffect(() => {\n    const root = document.documentElement;\n    const mode = themeMode === \"auto\" ? undefined : themeMode;\n    if (mode) {\n      root.setAttribute(\"data-theme-mode\", mode);\n    } else {\n      root.removeAttribute(\"data-theme-mode\");\n    }\n    return () => {\n      root.removeAttribute(\"data-theme-mode\");\n    };\n  }, [themeMode]);\n\n  // Set <meta name=\"theme-color\"> so mobile browser chrome matches the theme\n  useEffect(() => {\n    let meta = document.querySelector<HTMLMetaElement>(\n      'meta[name=\"theme-color\"]',\n    );\n    if (!meta) {\n      meta = document.createElement(\"meta\");\n      meta.name = \"theme-color\";\n      document.head.appendChild(meta);\n    }\n    const metaEl = meta;\n\n    const theme = resolvedTheme;\n    function update(prefersDark: boolean) {\n      const mode: PortalNativeThemeMode =\n        themeMode === \"auto\" ? (prefersDark ? \"dark\" : \"light\") : themeMode;\n      const nativeThemeMessage = createPortalNativeThemeMessage({\n        resolvedTheme: theme,\n        mode,\n      });\n      const mutedColor = nativeThemeMessage.payload.colors.muted;\n      metaEl.content = mutedColor;\n      document.body.style.backgroundColor = mutedColor;\n      postPortalNativeThemeMessage(nativeThemeMessage);\n    }\n\n    const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n    update(mql.matches);\n\n    if (themeMode === \"auto\") {\n      const handler = (e: MediaQueryListEvent) => update(e.matches);\n      mql.addEventListener(\"change\", handler);\n      return () => {\n        mql.removeEventListener(\"change\", handler);\n        metaEl.remove();\n        document.body.style.backgroundColor = \"\";\n      };\n    }\n\n    return () => {\n      metaEl.remove();\n      document.body.style.backgroundColor = \"\";\n    };\n  }, [resolvedTheme, themeMode]);\n\n  // Path-based routing for uncontrolled mode\n  const [pathSlug, setPathSlug] = useState<string>(() => {\n    if (typeof window === \"undefined\") return \"\";\n    return extractSlugFromPathname(\n      window.location.pathname,\n      normalizedBasePath,\n    );\n  });\n\n  const [previousSlug, setPreviousSlug] = useState<string | null>(null);\n\n  // Sync initial path when navItems load — redirect to first nav slug if at root.\n  // Wait for app data to load before redirecting; otherwise the fallback\n  // default navigation can leak its first slug (e.g. \"shop\") into the URL\n  // before the tenant's real navigation arrives.\n  useEffect(() => {\n    if (controlledSlug !== undefined) return;\n    if (typeof window === \"undefined\") return;\n    if (!navigationProp && isLoading && !appData) return;\n\n    const currentPath = extractSlugFromPathname(\n      window.location.pathname,\n      normalizedBasePath,\n    );\n\n    if (!currentPath) {\n      const firstSlug = findFirstNavigableSlug(filteredNavItems);\n      if (firstSlug) {\n        const targetPath =\n          normalizedBasePath === \"/\"\n            ? `/${firstSlug}`\n            : `${normalizedBasePath}/${firstSlug}`;\n        // replaceState to avoid polluting back-button history\n        history.replaceState(null, \"\", targetPath);\n        setPathSlug(firstSlug);\n      }\n    }\n  }, [\n    filteredNavItems,\n    controlledSlug,\n    normalizedBasePath,\n    isLoading,\n    appData,\n    navigationProp,\n  ]);\n\n  // Listen for popstate (browser back/forward)\n  useEffect(() => {\n    if (controlledSlug !== undefined) return;\n\n    const handlePopState = (event: PopStateEvent) => {\n      const slug = extractSlugFromPathname(\n        window.location.pathname,\n        normalizedBasePath,\n      );\n      // Compare the target entry's stamped index to the current one so forward\n      // history traversal slides in from the right, not the left. A traversal\n      // between two top-level tabs cross-fades (lateral) rather than sliding, so\n      // browser back/forward and the native swipe match tab taps.\n      const state = event.state as { fluidNavIndex?: number } | null;\n      const nextIndex =\n        typeof state?.fluidNavIndex === \"number\" ? state.fluidNavIndex : 0;\n      const isTabSwitch =\n        topLevelSlugs.has(normalizeSlug(activeSlugRef.current)) &&\n        topLevelSlugs.has(normalizeSlug(slug));\n      navDirectionRef.current = isTabSwitch\n        ? \"lateral\"\n        : nextIndex < historyIndexRef.current\n          ? \"back\"\n          : \"forward\";\n      historyIndexRef.current = nextIndex;\n      setPreviousSlug(null);\n      setPathSlug(slug);\n    };\n\n    window.addEventListener(\"popstate\", handlePopState);\n    return () => window.removeEventListener(\"popstate\", handlePopState);\n  }, [controlledSlug, normalizedBasePath, topLevelSlugs]);\n\n  // Logout hook — always called (rules of hooks) but only wired to UI below\n  const logout = useLogout({\n    redirectUrl: logoutRedirectUrl,\n    onLogout,\n  });\n\n  const activeSlug = controlledSlug ?? pathSlug;\n  const shoppingEnabled = isPortalCartAvailable(activeSlug, allNavSlugs);\n\n  // Read via ref so handleNavigate stays referentially stable across navigations.\n  const activeSlugRef = useRef(activeSlug);\n  activeSlugRef.current = activeSlug;\n\n  // Direction of the last navigation, driving the screen transition: slide in\n  // from the right on a push, in from the left on a pop, or cross-fade on a\n  // lateral tab switch. A ref because it's read during the render that follows\n  // the slug change, not rendered itself.\n  const navDirectionRef = useRef<ScreenTransitionDirection>(\"forward\");\n\n  // Monotonic index stamped into each history entry so popstate can tell a\n  // back navigation (index decreased) from a forward one (index increased),\n  // instead of assuming every popstate is a back.\n  const historyIndexRef = useRef(getInitialHistoryIndex());\n\n  const navigateToSlug = useCallback(\n    (\n      slug: string,\n      options?: {\n        recordPrevious?: boolean;\n        direction?: \"forward\" | \"back\";\n      },\n    ) => {\n      const current = activeSlugRef.current;\n      // Whether this navigation records the current slug as the in-session\n      // referrer. Drill-ins (widget links, list rows) record it so the header\n      // shows a back button; primary navigation (bottom-nav tabs) and the back\n      // button itself pass false, leaving no referrer behind.\n      const recordPrevious = options?.recordPrevious ?? true;\n      if (slug !== current) {\n        // A switch between two top-level tabs is lateral (cross-fade). A back\n        // navigation (e.g. the mobile header back) passes recordPrevious:false\n        // and pops; anything else is a drill-in that pushes forward. Callers\n        // can override the non-lateral direction — the tab handler forces\n        // forward while clearing the referrer so sub-tab switches don't pop.\n        const isTabSwitch =\n          topLevelSlugs.has(normalizeSlug(current)) &&\n          topLevelSlugs.has(normalizeSlug(slug));\n        navDirectionRef.current = isTabSwitch\n          ? \"lateral\"\n          : (options?.direction ?? (recordPrevious ? \"forward\" : \"back\"));\n      }\n      if (slug !== current && recordPrevious) {\n        setPreviousSlug(current || null);\n      } else if (slug !== current) {\n        setPreviousSlug(null);\n      }\n      if (onNavigateProp) {\n        onNavigateProp(slug);\n        return;\n      }\n      const targetPath =\n        normalizedBasePath === \"/\"\n          ? `/${slug}`\n          : `${normalizedBasePath}/${slug}`;\n      historyIndexRef.current += 1;\n      history.pushState(\n        { fluidNavIndex: historyIndexRef.current },\n        \"\",\n        targetPath,\n      );\n      setPathSlug(slug);\n    },\n    [onNavigateProp, normalizedBasePath, topLevelSlugs],\n  );\n\n  const handleNavigate = useCallback(\n    (slug: string) => {\n      navigateToSlug(slug);\n    },\n    [navigateToSlug],\n  );\n\n  // Tab navigation (bottom-nav tabs and second-level section sub-tabs) is\n  // lateral home-base switching, not a drill-in: it clears the in-session\n  // referrer so the destination never shows a back button, while still sliding\n  // forward like a normal navigation.\n  const handleTabNavigate = useCallback(\n    (slug: string) => {\n      // Clear the referrer explicitly: navigateToSlug only touches it when the\n      // slug changes, so re-tapping the already-active tab would otherwise\n      // leave a stale back arrow from an earlier drill-in.\n      setPreviousSlug(null);\n      navigateToSlug(slug, { recordPrevious: false, direction: \"forward\" });\n    },\n    [navigateToSlug],\n  );\n\n  // Widget links authored as plain URLs may point back into this portal. The\n  // shell owns the URL↔slug mapping, so it answers that question for widgets;\n  // they then route those clicks through handleNavigate instead of letting the\n  // browser load the document, which is what leaves the destination with a\n  // back button.\n  const resolveInternalSlug = useCallback(\n    (href: string) =>\n      typeof window === \"undefined\"\n        ? undefined\n        : internalSlugFromHref(\n            href,\n            normalizedBasePath,\n            window.location.origin,\n          ),\n    [normalizedBasePath],\n  );\n\n  // Whether a slug would render a real screen rather than \"Page Not Found\" for\n  // this portal's nav — opt-in screens (contacts, messages) only render when\n  // their nav item is present. Widgets use this to avoid offering a deep-link\n  // that would dead-end (e.g. a catch-up pointing at a contact on a portal that\n  // hasn't enabled Contacts).\n  const customPageSlugs = useMemo(\n    () => new Set(Object.keys(customPages ?? {})),\n    [customPages],\n  );\n  const canNavigateTo = useCallback(\n    (slug: string) => isSlugReachable(slug, allNavSlugs, customPageSlugs),\n    [allNavSlugs, customPageSlugs],\n  );\n\n  // Pull-to-refresh: refetch every currently-active query. Only the mounted\n  // screen's (plus shared shell) queries are active, so this refreshes the\n  // visible screen's data without touching cached data for other screens.\n  const queryClient = useQueryClient();\n  const handleRefresh = useCallback(\n    () => queryClient.refetchQueries({ type: \"active\" }),\n    [queryClient],\n  );\n\n  // Route widget item clicks (table rows, nested cards, etc.) to the matching\n  // detail screen. Discriminates first on `shareable_type` for content\n  // resources (products, media, pages, libraries), then enrollment packs (no\n  // in-portal detail screen — open the BFF-provided canonical_url in a new\n  // tab, same pattern as shop bundles in shop-app.tsx), then falls back to\n  // subscription/order tokens for the BFF-backed normalized shapes.\n  const handleWidgetItemClick = useCallback(\n    (item: WidgetInteractionItem) => {\n      const subscriptionToken = item.subscription_token;\n      if (typeof subscriptionToken === \"string\" && subscriptionToken) {\n        handleNavigate(`subscriptions/${subscriptionToken}`);\n        return;\n      }\n\n      const shareableType = item.shareable_type;\n      if (typeof shareableType === \"string\") {\n        if (shareableType === \"EnrollmentPack\") {\n          // share_link server-redirects to the same affiliate URL as canonical_url.\n          const canonicalUrl = item.canonical_url;\n          const shareLink = item.share_link;\n          const externalUrl =\n            typeof canonicalUrl === \"string\" && canonicalUrl\n              ? canonicalUrl\n              : typeof shareLink === \"string\" && shareLink\n                ? shareLink\n                : null;\n          if (externalUrl) {\n            window.open(externalUrl, \"_blank\", \"noopener,noreferrer\");\n          }\n          return;\n        }\n        if (item.id != null) {\n          const slug = SHAREABLE_TYPE_TO_SLUG[shareableType];\n          if (slug) {\n            handleNavigate(`share/${slug}/${String(item.id)}`);\n            return;\n          }\n        }\n      }\n\n      const orderToken = item.token;\n      if (typeof orderToken === \"string\" && orderToken) {\n        handleNavigate(`orders/${orderToken}`);\n      }\n    },\n    [handleNavigate],\n  );\n\n  // Resolve sidebar footer: explicit prop wins, otherwise render default logout button\n  const resolvedSidebarFooter = useMemo(\n    () =>\n      sidebarFooter !== undefined ? (\n        sidebarFooter\n      ) : (\n        <SdkLogoutButton onLogout={logout} />\n      ),\n    [sidebarFooter, logout],\n  );\n\n  // Derive base slug and rest params via prefix matching. Use the combined\n  // desktop+mobile slug set so a tap on a mobile-only nav item still resolves\n  // to a registered prefix instead of falling through to the raw URL slug.\n  const slugMatch = useMemo(\n    () => matchSlugPrefix(activeSlug, allNavSlugs),\n    [activeSlug, allNavSlugs],\n  );\n  const baseSlug = slugMatch?.matchedSlug ?? normalizeSlug(activeSlug);\n  const restParams = slugMatch?.rest ?? \"\";\n  const mobileBackTarget = useMemo(\n    () => resolveMobileBackTarget(activeSlug, allNavSlugs, previousSlug),\n    [activeSlug, allNavSlugs, previousSlug],\n  );\n  const handleMobileBack = useCallback(() => {\n    if (!mobileBackTarget) return;\n    navigateToSlug(mobileBackTarget, {\n      recordPrevious: false,\n      direction: \"back\",\n    });\n  }, [mobileBackTarget, navigateToSlug]);\n\n  // Derive mobile sub-tabs for the current section\n  const mobileCurrentSection = findCurrentSection(\n    filteredMobileNavItems,\n    baseSlug,\n  );\n  const mobileSecondLevelTabs = mobileCurrentSection?.children ?? [];\n  const currentNavItem =\n    findNavItem(filteredNavItems, baseSlug) ??\n    findNavItem(filteredMobileNavItems, baseSlug);\n\n  // Resolve screen title from nav label or screen definition name\n  const matchingScreen = screens?.find(\n    (s) => s.id === currentNavItem?.screen_id,\n  );\n  const screenTitle =\n    currentNavItem?.label || matchingScreen?.name || undefined;\n\n  const handleScreenError = useCallback(\n    (error: Error, info: ErrorInfo) => {\n      errorReporter?.(error, {\n        boundary: \"screen\",\n        componentStack: info.componentStack,\n        pathname:\n          typeof window === \"undefined\" ? undefined : window.location.pathname,\n        activeSlug,\n        baseSlug,\n        restParams,\n        screenTitle,\n        navItemSlug: currentNavItem?.slug,\n        screenId: currentNavItem?.screen_id ?? matchingScreen?.id,\n      });\n    },\n    [\n      errorReporter,\n      activeSlug,\n      baseSlug,\n      restParams,\n      screenTitle,\n      currentNavItem?.slug,\n      currentNavItem?.screen_id,\n      matchingScreen?.id,\n    ],\n  );\n\n  // Determine content to render. Wrap in an error boundary keyed on the\n  // active slug so a screen-level crash never takes down the navigation\n  // chrome — and navigating to a different slug auto-recovers the boundary.\n  const rawContent =\n    typeof children === \"function\"\n      ? children({ currentSlug: activeSlug, currentNavItem })\n      : (children ?? (\n          <div className=\"flex h-full flex-col\">\n            <TranslatedScreenHeader\n              slug={currentNavItem?.slug}\n              title={screenTitle}\n              trailingContent={\n                <>\n                  <LanguageSelector />\n                  {shoppingEnabled ? (\n                    <PortalCartButton viewport=\"desktop\" />\n                  ) : null}\n                </>\n              }\n            />\n            <div\n              className=\"relative isolate min-h-0 flex-1\"\n              data-fluid-portal-screen-body=\"\"\n            >\n              <PageRouter\n                currentSlug={activeSlug}\n                currentNavItem={currentNavItem}\n                customPages={customPages}\n                memberTypeCustomPages={memberTypeCustomPages}\n                screens={screens}\n                baseSlug={baseSlug}\n                restParams={restParams}\n                navSlugs={allNavSlugs}\n              />\n            </div>\n          </div>\n        ));\n\n  const content = (\n    <AppShellErrorBoundary\n      key={activeSlug ?? \"\"}\n      onError={errorReporter ? handleScreenError : undefined}\n    >\n      {rawContent}\n    </AppShellErrorBoundary>\n  );\n\n  // Show loading state while app data is being fetched for the first time.\n  // This check is placed after all hooks to satisfy React's rules of hooks.\n  if (isLoading && !appData) {\n    return <AppShellLoading />;\n  }\n\n  return (\n    <RepUserProvider user={repUser}>\n      <ThemeModeProvider\n        mode={themeMode}\n        onModeChange={handleThemeModeChange}\n        autoModeEnabled={false}\n      >\n        <div\n          className=\"font-body\"\n          data-theme={activeTheme.id}\n          data-theme-mode={themeMode === \"auto\" ? undefined : themeMode}\n        >\n          <AppNavigationProvider\n            currentSlug={activeSlug}\n            previousSlug={previousSlug}\n            navItems={filteredNavItems}\n            basePath={normalizedBasePath}\n            navigate={handleNavigate}\n          >\n            <WidgetInteractionProvider\n              onItemClick={handleWidgetItemClick}\n              onNavigate={handleNavigate}\n              resolveInternalSlug={resolveInternalSlug}\n              canNavigateTo={canNavigateTo}\n            >\n              <BottomNavVisibilityProvider>\n                <ScreenHeaderProvider>\n                  <AppShellLayout\n                    sidebarContent={\n                      <SdkNavigation\n                        navItems={filteredNavItems}\n                        currentSlug={activeSlug}\n                        onNavigate={handleNavigate}\n                      />\n                    }\n                    headerContent={\n                      <SdkHeader\n                        mobileTabs={mobileSecondLevelTabs}\n                        currentSlug={activeSlug}\n                        title={screenTitle}\n                        {...(mobileBackTarget !== undefined && {\n                          onBack: handleMobileBack,\n                        })}\n                        onNavigate={handleNavigate}\n                        onTabNavigate={handleTabNavigate}\n                        onLogout={logout}\n                        persistentActions={\n                          shoppingEnabled ? (\n                            <PortalCartButton viewport=\"mobile\" />\n                          ) : undefined\n                        }\n                      />\n                    }\n                    sidebarHeader={\n                      sidebarHeader !== undefined ? (\n                        sidebarHeader\n                      ) : (\n                        <SdkCompanySwitcher />\n                      )\n                    }\n                    sidebarFooter={resolvedSidebarFooter}\n                    currentSlug={activeSlug}\n                    useBottomNav\n                    onRefresh={handleRefresh}\n                    afterContent={\n                      <SdkBottomNav\n                        navItems={filteredMobileNavItems}\n                        currentSlug={activeSlug}\n                        onNavigate={handleTabNavigate}\n                        appDefinitionId={appData?.definition_id ?? 0}\n                      />\n                    }\n                  >\n                    <ScreenAreaFullscreenProvider>\n                      <ScreenTransition\n                        transitionKey={activeSlug}\n                        direction={navDirectionRef.current}\n                      >\n                        {content}\n                      </ScreenTransition>\n                    </ScreenAreaFullscreenProvider>\n                  </AppShellLayout>\n                </ScreenHeaderProvider>\n                {/* Outside the layout on purpose: toasts are position fixed, and\n                    a transform anywhere above them would trap them. */}\n                <PortalToaster />\n              </BottomNavVisibilityProvider>\n            </WidgetInteractionProvider>\n          </AppNavigationProvider>\n          {shoppingEnabled ? <PortalCartRuntime /> : null}\n        </div>\n      </ThemeModeProvider>\n    </RepUserProvider>\n  );\n}\n","/**\n * Pure builder for a per-tenant Web App Manifest.\n *\n * The portal is a single static SPA served byte-identical to every company\n * subdomain, so the installable manifest cannot be baked at build time — it is\n * generated at runtime from the tenant's {@link https://developer.mozilla.org/docs/Web/Manifest Store}\n * branding and injected as a `data:` URL (see the sdk `PwaManifestInjector`).\n *\n * This function is intentionally pure and DOM-free so the branching logic\n * (icons, colors, short-name capping) can be unit-tested in isolation.\n */\n\n/** Recommended maximum length for a home-screen label before OSes truncate. */\nconst SHORT_NAME_MAX_LENGTH = 12;\n\nconst DEFAULT_COLOR = \"#ffffff\";\n\nexport type WebAppManifestDisplay =\n  | \"standalone\"\n  | \"browser\"\n  | \"minimal-ui\"\n  | \"fullscreen\";\n\nexport interface TenantManifestInput {\n  /** Company display name (from `Store.name`). */\n  readonly name: string;\n  /** Absolute https URL to the company icon (from `Store.icon_url`), or null. */\n  readonly iconUrl: string | null;\n  /** Theme color for the OS chrome; defaults to white. */\n  readonly themeColor?: string;\n  /** Splash/background color; defaults to white. */\n  readonly backgroundColor?: string;\n  /** How the installed app launches; defaults to `standalone`. */\n  readonly display?: WebAppManifestDisplay;\n}\n\nexport interface WebAppManifestIcon {\n  readonly src: string;\n  readonly sizes: string;\n  readonly type?: string;\n  readonly purpose?: string;\n}\n\nexport interface WebAppManifest {\n  readonly name: string;\n  readonly short_name: string;\n  readonly start_url: string;\n  readonly scope: string;\n  readonly display: WebAppManifestDisplay;\n  readonly theme_color: string;\n  readonly background_color: string;\n  readonly icons: readonly WebAppManifestIcon[];\n}\n\nexport function buildTenantWebManifest(\n  input: TenantManifestInput,\n): WebAppManifest {\n  return {\n    name: input.name,\n    short_name: capShortName(input.name),\n    start_url: \"/\",\n    scope: \"/\",\n    display: input.display ?? \"standalone\",\n    theme_color: input.themeColor ?? DEFAULT_COLOR,\n    background_color: input.backgroundColor ?? DEFAULT_COLOR,\n    icons: buildIcons(input.iconUrl, input.name),\n  };\n}\n\nfunction capShortName(name: string): string {\n  if (name.length <= SHORT_NAME_MAX_LENGTH) {\n    return name;\n  }\n  return name.slice(0, SHORT_NAME_MAX_LENGTH).trimEnd();\n}\n\nfunction buildIcons(\n  iconUrl: string | null,\n  name: string,\n): WebAppManifestIcon[] {\n  if (!hasUploadedIcon(iconUrl)) {\n    // A company without an uploaded icon must still be installable — Chrome\n    // requires an icon or it refuses to install. Synthesize a letter-avatar\n    // from the company initial so every tenant gets a distinct, installable\n    // home-screen icon with no uploaded asset.\n    const fallback = buildFallbackIconDataUri(name);\n    return [\n      { src: fallback, sizes: \"any\", type: SVG_MIME, purpose: \"any\" },\n      { src: fallback, sizes: \"any\", type: SVG_MIME, purpose: \"maskable\" },\n    ];\n  }\n\n  const type = inferImageMimeType(iconUrl);\n  // Omit `type` entirely when unknown — `exactOptionalPropertyTypes` forbids an\n  // explicit `undefined` on the optional property.\n  const typeProp = type ? { type } : {};\n\n  // Declare both installable sizes (Chrome requires a >=192 icon) plus a\n  // maskable variant so Android crops it into the adaptive-icon shape.\n  return [\n    { src: iconUrl, sizes: \"192x192\", purpose: \"any\", ...typeProp },\n    { src: iconUrl, sizes: \"512x512\", purpose: \"any\", ...typeProp },\n    { src: iconUrl, sizes: \"512x512\", purpose: \"maskable\", ...typeProp },\n  ];\n}\n\nconst SVG_MIME = \"image/svg+xml\";\n\n/**\n * Resolve the icon href to use for a tenant: the uploaded `icon_url` when it is\n * an absolute http(s) URL, otherwise the generated letter-avatar fallback.\n * Shared by the manifest builder and the `<head>` injector so the manifest,\n * favicon, and apple-touch-icon all agree on the same image for a given tenant.\n */\nexport function resolveTenantIconHref(\n  iconUrl: string | null,\n  name: string,\n): string {\n  return hasUploadedIcon(iconUrl) ? iconUrl : buildFallbackIconDataUri(name);\n}\n\n/**\n * Whether the tenant has a usable uploaded icon — an absolute http(s) URL.\n * Anything else (null, relative, data URI) means we synthesize a fallback.\n */\nexport function hasUploadedIcon(value: string | null): value is string {\n  if (value === null) {\n    return false;\n  }\n  try {\n    const url = new URL(value);\n    return url.protocol === \"http:\" || url.protocol === \"https:\";\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Build a deterministic letter-avatar icon (as an SVG `data:` URL) for a tenant\n * with no uploaded `icon_url`. The background hue is derived from the name so\n * each company gets a stable, distinct icon; the glyph is the first letter.\n *\n * Used for the manifest icons and favicon (which accept SVG). iOS's\n * `apple-touch-icon` rejects SVG, so the sdk injector rasterizes the same\n * initial + hue to a PNG for that surface.\n */\nexport function buildFallbackIconDataUri(name: string): string {\n  const initial = tenantIconInitial(name);\n  const hue = tenantIconHue(name);\n  // 20% inner margin keeps the glyph inside Android's maskable safe zone.\n  const svg =\n    `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"512\" height=\"512\" viewBox=\"0 0 512 512\">` +\n    `<rect width=\"512\" height=\"512\" fill=\"hsl(${hue} 65% 45%)\"/>` +\n    `<text x=\"50%\" y=\"50%\" dy=\".35em\" text-anchor=\"middle\" ` +\n    `font-family=\"system-ui, -apple-system, Segoe UI, Roboto, sans-serif\" ` +\n    `font-size=\"256\" font-weight=\"600\" fill=\"#ffffff\">${initial}</text>` +\n    `</svg>`;\n  return `data:${SVG_MIME},${encodeURIComponent(svg)}`;\n}\n\n/** Raster MIME types iOS reliably renders as an `apple-touch-icon`. */\nconst IOS_TOUCH_ICON_TYPES: ReadonlySet<string> = new Set([\n  \"image/png\",\n  \"image/jpeg\",\n]);\n\n/**\n * Whether an uploaded icon URL is a raster format iOS accepts for\n * `apple-touch-icon`. iOS ignores SVG (and unreliably supports webp), so an\n * uploaded SVG/webp — or an extension-less URL we can't classify — must be\n * rasterized to PNG instead of used directly.\n */\nexport function isIosTouchIconCompatible(iconUrl: string): boolean {\n  const type = inferImageMimeType(iconUrl);\n  return type !== undefined && IOS_TOUCH_ICON_TYPES.has(type);\n}\n\n/** Uppercased first character of the name, or `#` when there is none. */\nexport function tenantIconInitial(name: string): string {\n  for (const char of name.trim()) {\n    return char.toUpperCase();\n  }\n  return \"#\";\n}\n\n/** Deterministic hue in `[0, 360)` derived from the name. */\nexport function tenantIconHue(value: string): number {\n  let hash = 0;\n  for (let i = 0; i < value.length; i++) {\n    hash = (hash * 31 + value.charCodeAt(i)) % 360;\n  }\n  return hash;\n}\n\nfunction inferImageMimeType(url: string): string | undefined {\n  const withoutQuery = url.split(/[?#]/)[0] ?? \"\";\n  const extension = withoutQuery\n    .slice(withoutQuery.lastIndexOf(\".\") + 1)\n    .toLowerCase();\n\n  switch (extension) {\n    case \"png\":\n      return \"image/png\";\n    case \"jpg\":\n    case \"jpeg\":\n      return \"image/jpeg\";\n    case \"webp\":\n      return \"image/webp\";\n    case \"svg\":\n      return \"image/svg+xml\";\n    default:\n      return undefined;\n  }\n}\n","import {\n  tenantIconHue,\n  tenantIconInitial,\n} from \"@fluid-app/portal-core/pwa/build-tenant-web-manifest\";\n\n/** Apple's recommended apple-touch-icon edge length, in CSS px. */\nconst APPLE_TOUCH_ICON_SIZE = 180;\n\n/**\n * Rasterize the tenant letter-avatar to a **PNG** `data:` URL via `<canvas>`.\n *\n * iOS Safari's `apple-touch-icon` rejects SVG, so the SVG fallback used for the\n * manifest/favicon can't serve iOS. This draws the same initial + hue to a\n * canvas and exports PNG, which iOS accepts. Returns `null` when canvas is\n * unavailable (SSR / jsdom / blocked), so callers degrade gracefully rather\n * than setting an unusable icon.\n */\nexport function rasterizeLetterAvatarPng(\n  name: string,\n  size: number = APPLE_TOUCH_ICON_SIZE,\n): string | null {\n  if (typeof document === \"undefined\") {\n    return null;\n  }\n\n  const canvas = document.createElement(\"canvas\");\n  canvas.width = size;\n  canvas.height = size;\n\n  const ctx = canvas.getContext(\"2d\");\n  if (!ctx) {\n    return null;\n  }\n\n  ctx.fillStyle = `hsl(${tenantIconHue(name)} 65% 45%)`;\n  ctx.fillRect(0, 0, size, size);\n\n  ctx.fillStyle = \"#ffffff\";\n  ctx.textAlign = \"center\";\n  ctx.textBaseline = \"middle\";\n  ctx.font = `600 ${Math.round(\n    size * 0.5,\n  )}px system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif`;\n  ctx.fillText(tenantIconInitial(name), size / 2, size / 2);\n\n  try {\n    return canvas.toDataURL(\"image/png\");\n  } catch {\n    return null;\n  }\n}\n","import {\n  buildTenantWebManifest,\n  hasUploadedIcon,\n  isIosTouchIconCompatible,\n  resolveTenantIconHref,\n} from \"@fluid-app/portal-core/pwa/build-tenant-web-manifest\";\nimport { rasterizeLetterAvatarPng } from \"./rasterize-letter-avatar\";\n\n/**\n * Per-tenant branding needed to make the portal installable as that company's\n * own PWA. Sourced from the tenant `Store` (`name`, `icon_url`, theme).\n */\nexport interface TenantManifestBranding {\n  readonly name: string;\n  readonly iconUrl: string | null;\n  readonly themeColor?: string;\n  readonly backgroundColor?: string;\n}\n\nexport interface InjectTenantManifestOptions {\n  /**\n   * Produces a PNG `data:` URL avatar for the iOS `apple-touch-icon` when the\n   * tenant has no uploaded icon. Injectable for testing; defaults to the\n   * canvas-based rasterizer. Returns `null` when rasterization isn't possible.\n   */\n  readonly rasterizeAppleIcon?: (name: string) => string | null;\n}\n\nconst MANIFEST_MIME = \"application/manifest+json\";\n\n/**\n * Inject (or update) the `<head>` tags that make the portal installable as the\n * current company's PWA. Idempotent: safe to call on every `Store` change.\n *\n * - Android/Chrome read the Web App Manifest — injected as a `data:` URL so a\n *   single static SPA can be branded per subdomain with no server round trip.\n * - iOS Safari ignores the manifest for \"Add to Home Screen\" and instead reads\n *   `apple-touch-icon` + `apple-mobile-web-app-*` tags from the live DOM, so we\n *   inject those too.\n */\nexport function injectTenantManifest(\n  doc: Document,\n  branding: TenantManifestBranding,\n  options: InjectTenantManifestOptions = {},\n): void {\n  const manifest = buildTenantWebManifest({\n    name: branding.name,\n    iconUrl: branding.iconUrl,\n    themeColor: branding.themeColor,\n    backgroundColor: branding.backgroundColor,\n  });\n\n  const manifestHref = `data:${MANIFEST_MIME};charset=utf-8,${encodeURIComponent(\n    JSON.stringify(manifest),\n  )}`;\n  upsertLink(doc, 'link[rel=\"manifest\"]', { rel: \"manifest\" }, manifestHref);\n\n  // Favicon accepts SVG, so use the real icon or the SVG letter-avatar.\n  const faviconHref = resolveTenantIconHref(branding.iconUrl, branding.name);\n  upsertLink(doc, 'link[rel=\"icon\"]', { rel: \"icon\" }, faviconHref);\n\n  // iOS reads apple-touch-icon (not the manifest) and only renders raster\n  // formats. Use the uploaded icon only when it's an iOS-compatible raster;\n  // otherwise (no icon, or an SVG/webp upload) rasterize the avatar to PNG.\n  // Omit it entirely when rasterization isn't possible.\n  const rasterize = options.rasterizeAppleIcon ?? rasterizeLetterAvatarPng;\n  const appleTouchHref =\n    hasUploadedIcon(branding.iconUrl) &&\n    isIosTouchIconCompatible(branding.iconUrl)\n      ? branding.iconUrl\n      : rasterize(branding.name);\n  if (appleTouchHref) {\n    upsertLink(\n      doc,\n      'link[rel=\"apple-touch-icon\"]',\n      { rel: \"apple-touch-icon\" },\n      appleTouchHref,\n    );\n  } else {\n    doc.querySelector('link[rel=\"apple-touch-icon\"]')?.remove();\n  }\n\n  upsertMeta(doc, \"apple-mobile-web-app-title\", branding.name);\n  upsertMeta(doc, \"apple-mobile-web-app-capable\", \"yes\");\n  upsertMeta(doc, \"mobile-web-app-capable\", \"yes\");\n}\n\nfunction upsertLink(\n  doc: Document,\n  selector: string,\n  attributes: Record<string, string>,\n  href: string,\n): void {\n  let link = doc.querySelector<HTMLLinkElement>(selector);\n  if (!link) {\n    link = doc.createElement(\"link\");\n    for (const [name, value] of Object.entries(attributes)) {\n      link.setAttribute(name, value);\n    }\n    doc.head.appendChild(link);\n  }\n  link.setAttribute(\"href\", href);\n}\n\nfunction upsertMeta(doc: Document, name: string, content: string): void {\n  let meta = doc.querySelector<HTMLMetaElement>(`meta[name=\"${name}\"]`);\n  if (!meta) {\n    meta = doc.createElement(\"meta\");\n    meta.setAttribute(\"name\", name);\n    doc.head.appendChild(meta);\n  }\n  meta.setAttribute(\"content\", content);\n}\n","import type { TenantManifestBranding } from \"./inject-tenant-manifest\";\n\n/**\n * Last-known tenant branding, cached per origin so a returning user's installed\n * icon/name can be injected synchronously on load — before the authenticated\n * `GET /api/store` fetch resolves. Purely a progressive-enhancement cache; the\n * live `Store` always wins once it arrives.\n */\nexport const PWA_BRANDING_CACHE_KEY = \"fluid.portal.pwa.branding\";\n\nexport function readCachedBranding(\n  storage: Storage | undefined = safeLocalStorage(),\n): TenantManifestBranding | null {\n  if (!storage) {\n    return null;\n  }\n\n  let raw: string | null;\n  try {\n    raw = storage.getItem(PWA_BRANDING_CACHE_KEY);\n  } catch {\n    return null;\n  }\n  if (!raw) {\n    return null;\n  }\n\n  try {\n    const parsed = JSON.parse(raw) as Partial<TenantManifestBranding>;\n    if (typeof parsed.name !== \"string\") {\n      return null;\n    }\n    return {\n      name: parsed.name,\n      iconUrl: typeof parsed.iconUrl === \"string\" ? parsed.iconUrl : null,\n      ...(typeof parsed.themeColor === \"string\"\n        ? { themeColor: parsed.themeColor }\n        : {}),\n      ...(typeof parsed.backgroundColor === \"string\"\n        ? { backgroundColor: parsed.backgroundColor }\n        : {}),\n    };\n  } catch {\n    return null;\n  }\n}\n\nexport function writeCachedBranding(\n  branding: TenantManifestBranding,\n  storage: Storage | undefined = safeLocalStorage(),\n): void {\n  if (!storage) {\n    return;\n  }\n  try {\n    storage.setItem(PWA_BRANDING_CACHE_KEY, JSON.stringify(branding));\n  } catch {\n    // Private mode / quota — caching is best-effort, never fatal.\n  }\n}\n\nfunction safeLocalStorage(): Storage | undefined {\n  try {\n    return typeof window !== \"undefined\" ? window.localStorage : undefined;\n  } catch {\n    return undefined;\n  }\n}\n","import { useEffect } from \"react\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\nimport {\n  injectTenantManifest,\n  type TenantManifestBranding,\n} from \"./inject-tenant-manifest\";\nimport { readCachedBranding, writeCachedBranding } from \"./pwa-icon-cache\";\n\n/**\n * Makes the portal installable as the **current company's** PWA.\n *\n * The portal is one static SPA served identically to every company subdomain,\n * so the installable manifest + icons cannot be baked at build time — they are\n * derived at runtime from the tenant `Store` and injected into `<head>`\n * (see {@link injectTenantManifest}). A returning user's last-known branding is\n * injected synchronously on mount so the install affordance is correct before\n * the authenticated `GET /api/store` resolves; the live store then wins.\n *\n * Renders nothing. Mount once inside the authenticated shell.\n */\nexport function PwaManifestInjector(): null {\n  const store = useOptionalStore();\n\n  // Paint the last-known branding immediately, ahead of the store fetch.\n  useEffect(() => {\n    const cached = readCachedBranding();\n    if (cached) {\n      injectTenantManifest(document, cached);\n    }\n  }, []);\n\n  const name = store.data?.name;\n  const iconUrl = store.data?.icon_url ?? null;\n\n  useEffect(() => {\n    if (name === undefined) {\n      return;\n    }\n    const branding: TenantManifestBranding = { name, iconUrl };\n    injectTenantManifest(document, branding);\n    writeCachedBranding(branding);\n  }, [name, iconUrl]);\n\n  return null;\n}\n","import { getFluidNativeBridge } from \"../adapters/native-capabilities-api-adapter\";\n\n/**\n * URL of the portal service worker. Served same-origin from the Vite `public/`\n * dir (`apps/portal/public/sw.js`) so it controls the whole origin scope.\n */\nconst SERVICE_WORKER_URL = \"/sw.js\";\n\nexport interface ServiceWorkerRegistrationContext {\n  readonly supportsServiceWorker: boolean;\n  /** True when running inside the portal-mobile native WebView shell. */\n  readonly isNativeShell: boolean;\n}\n\n/**\n * Whether to register the portal service worker. Pure so the policy is\n * unit-tested independently of the browser APIs it gates.\n *\n * Skipped inside the native shell: the WebView manages its own caching and a\n * page-level SW would only add a redundant layer there.\n */\nexport function shouldRegisterServiceWorker(\n  ctx: ServiceWorkerRegistrationContext,\n): boolean {\n  return ctx.supportsServiceWorker && !ctx.isNativeShell;\n}\n\n/**\n * Register the portal service worker if the environment warrants it. Safe to\n * call unconditionally on the rep-facing portal; a no-op everywhere else.\n * Failures are swallowed — a missing SW degrades gracefully to a non-offline,\n * still-installable (on iOS) web app.\n */\nexport function registerPortalServiceWorker(): void {\n  if (typeof window === \"undefined\" || typeof navigator === \"undefined\") {\n    return;\n  }\n\n  const ctx: ServiceWorkerRegistrationContext = {\n    supportsServiceWorker: \"serviceWorker\" in navigator,\n    isNativeShell: getFluidNativeBridge() !== null,\n  };\n\n  if (!shouldRegisterServiceWorker(ctx)) {\n    return;\n  }\n\n  // Register after load so the SW install never competes with first paint.\n  window.addEventListener(\"load\", () => {\n    void navigator.serviceWorker.register(SERVICE_WORKER_URL).catch(() => {\n      // Best-effort: installability/offline is an enhancement, not required.\n    });\n  });\n}\n","/**\n * Whether the portal is running as an installed PWA (`standalone`) or in a\n * normal browser tab (`browser`).\n *\n * This is the PWA analogue of the native shell's `isNativeApp`: it lets the app\n * render app-like UI (native-feel sheets, hidden browser-only affordances) once\n * a company's PWA is added to the home screen. Kept separate from the\n * `native-capabilities` port, which models the native WebView bridge — a\n * different concern. Compose them at the point of use:\n * `isNativeApp || displayMode === \"standalone\"`.\n */\nexport type PwaDisplayMode = \"standalone\" | \"browser\";\n\nconst STANDALONE_MEDIA_QUERY = \"(display-mode: standalone)\";\n\nexport function detectPwaDisplayMode(): PwaDisplayMode {\n  if (typeof window === \"undefined\") {\n    return \"browser\";\n  }\n\n  // iOS Safari does not report `display-mode: standalone`; it exposes a\n  // non-standard `navigator.standalone` instead.\n  const iosStandalone = (navigator as { standalone?: boolean }).standalone;\n  if (iosStandalone === true) {\n    return \"standalone\";\n  }\n\n  if (typeof window.matchMedia !== \"function\") {\n    return \"browser\";\n  }\n\n  return window.matchMedia(STANDALONE_MEDIA_QUERY).matches\n    ? \"standalone\"\n    : \"browser\";\n}\n\nexport { STANDALONE_MEDIA_QUERY };\n","import { detectPwaDisplayMode } from \"./detect-pwa-display-mode\";\n\n/**\n * Enable `viewport-fit=cover` on the viewport meta **only when running as an\n * installed standalone PWA**.\n *\n * The portal already pads its fixed header/bottom-nav with\n * `env(safe-area-inset-*)`, but those insets resolve to `0` unless the viewport\n * opts into `viewport-fit=cover`. In a browser tab the browser chrome handles\n * the safe area, and the native WebView shell insets itself via React Native's\n * safe-area provider — so adding cover there would double-inset. Gating on\n * standalone confines the change to the installed PWA, where there is no chrome\n * and the home-indicator area would otherwise swallow the bottom nav.\n *\n * Idempotent and safe to call on mount.\n */\nexport function ensureStandaloneViewportFit(doc: Document = document): void {\n  if (detectPwaDisplayMode() !== \"standalone\") {\n    return;\n  }\n\n  const meta = doc.querySelector<HTMLMetaElement>('meta[name=\"viewport\"]');\n  if (!meta) {\n    return;\n  }\n\n  const content = meta.getAttribute(\"content\") ?? \"\";\n  if (/viewport-fit\\s*=/.test(content)) {\n    return;\n  }\n\n  meta.setAttribute(\n    \"content\",\n    content ? `${content}, viewport-fit=cover` : \"viewport-fit=cover\",\n  );\n}\n","import { useEffect, type ReactElement } from \"react\";\nimport { PwaManifestInjector } from \"./PwaManifestInjector\";\nimport { registerPortalServiceWorker } from \"./register-portal-service-worker\";\nimport { ensureStandaloneViewportFit } from \"./ensure-standalone-viewport-fit\";\n\n/**\n * PWA surface for the rep-facing portal. Mounted once inside `FluidProvider`\n * (so it can read the tenant `Store`) by `createPortal`.\n *\n * - {@link PwaManifestInjector} makes the portal installable as the company's\n *   own branded PWA (per-subdomain manifest + icons, no rebuild per company).\n * - Registers the service worker required for installability.\n *\n * Install discovery is left to the browser's own affordance (Chrome's install\n * button / iOS Share → Add to Home Screen); we intentionally do not render an\n * in-app install prompt.\n *\n * Deliberately not mounted in `FluidProvider` itself, which also wraps the\n * screen-builder preview — those surfaces are not tenant portals and must not\n * hijack the page's manifest/icon.\n */\nexport function PortalPwa(): ReactElement {\n  useEffect(() => {\n    registerPortalServiceWorker();\n    // Opt the installed PWA into the device safe area so the fixed bottom nav\n    // and header clear the iOS home indicator / status bar.\n    ensureStandaloneViewportFit();\n  }, []);\n\n  return <PwaManifestInjector />;\n}\n","/**\n * Read Vite environment variables at runtime.\n *\n * Isolated into its own module so that Jest tests can mock it\n * (import.meta is a syntax-level construct that CJS/Jest cannot parse).\n */\nexport function getViteEnv(key: string): string | undefined {\n  const env = import.meta.env as unknown as Record<string, string> | undefined;\n  return env?.[key];\n}\n","import type { FluidSDKConfig } from \"../types/config\";\nimport { getViteEnv } from \"./env\";\n\n/**\n * Creates a FluidSDKConfig with sensible defaults.\n *\n * Default behavior:\n * - baseUrl: reads from `VITE_API_URL` env var, falls back to `\"\"` (same-origin relative)\n * - Auth: relies on session cookies sent via `credentials: 'include'`\n *\n * Pass overrides to customize any field:\n * ```ts\n * const config = createDefaultFluidConfig({ baseUrl: \"https://my-api.example.com\" });\n * ```\n */\nexport function createDefaultFluidConfig(\n  overrides?: Partial<FluidSDKConfig>,\n): FluidSDKConfig {\n  return {\n    baseUrl: getViteEnv(\"VITE_API_URL\") ?? \"\",\n    smartyEmbeddedKey: getViteEnv(\"NEXT_PUBLIC_SMARTY_EMBEDDED_KEY\"),\n    googleMapsApiKey: getViteEnv(\"NEXT_PUBLIC_GOOGLE_MAPS_API_KEY\"),\n    ...overrides,\n  };\n}\n","import {\n  Component,\n  StrictMode,\n  type ComponentType,\n  type ErrorInfo,\n  type ReactNode,\n} from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport type { RemoteDomWidgetPackageDescriptor } from \"@fluid-app/portal-core/remote-dom-widget-package\";\nimport { FluidProvider } from \"../providers/FluidProvider\";\nimport { AppShell, type AppShellProps } from \"../shell/AppShell\";\nimport { PortalPwa } from \"../pwa/PortalPwa\";\nimport type { PortalErrorReporter } from \"../errors/portal-error-reporter\";\nimport { createDefaultFluidConfig } from \"../config/defaults\";\nimport type { FluidSDKConfig } from \"../types/config\";\nimport type { MemberTypeCustomPages } from \"@fluid-app/portal-core/member-type-content\";\nimport type { RemoteWidgetOptions } from \"../types/remote-widgets\";\n\n/**\n * Last-resort error boundary for crashes above the AppShell (provider\n * setup, theme/auth bootstrap). Renders above FluidThemeProvider, so the\n * theme CSS custom properties (`--color-foreground`, `--color-muted`, etc.)\n * are not yet applied — using inline styles + literal colors avoids\n * referencing theme tokens that would resolve to nothing.\n */\nclass RootBoundary extends Component<\n  { children: ReactNode; errorReporter?: PortalErrorReporter },\n  { error: Error | null }\n> {\n  override state = { error: null as Error | null };\n\n  static getDerivedStateFromError(error: Error): { error: Error } {\n    return { error };\n  }\n\n  override componentDidCatch(error: Error, info: ErrorInfo): void {\n    if (this.props.errorReporter) {\n      console.warn(\"[portal] Root crashed; reporting error:\", error, info);\n      try {\n        this.props.errorReporter(error, {\n          boundary: \"root\",\n          componentStack: info.componentStack,\n          pathname:\n            typeof window === \"undefined\"\n              ? undefined\n              : window.location.pathname,\n        });\n      } catch (callbackError) {\n        // A throwing reporter must not mask the original crash.\n        console.error(\"[portal] root error reporter threw:\", callbackError);\n        console.error(\"[portal] Root crashed:\", error, info);\n      }\n      return;\n    }\n\n    console.error(\"[portal] Root crashed:\", error, info);\n  }\n\n  override render(): ReactNode {\n    if (!this.state.error) return this.props.children;\n    return (\n      <div\n        style={{\n          minHeight: \"100vh\",\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          padding: \"1rem\",\n          fontFamily: \"system-ui, sans-serif\",\n        }}\n      >\n        <div style={{ maxWidth: \"32rem\", textAlign: \"center\" }}>\n          <h1 style={{ fontSize: \"1.25rem\", fontWeight: 600 }}>\n            The app failed to load\n          </h1>\n          <p style={{ marginTop: \"0.5rem\", color: \"#666\" }}>\n            Something went wrong while starting the portal. Please reload the\n            page; if the problem persists, contact support.\n          </p>\n          <button\n            type=\"button\"\n            onClick={() => {\n              window.location.reload();\n            }}\n            style={{\n              marginTop: \"1.5rem\",\n              padding: \"0.5rem 1rem\",\n              borderRadius: \"0.375rem\",\n              border: \"1px solid #ccc\",\n              background: \"#fff\",\n              cursor: \"pointer\",\n            }}\n          >\n            Reload page\n          </button>\n        </div>\n      </div>\n    );\n  }\n}\n\n/** Route values supplied to a custom portal page component. */\nexport interface PortalCustomPageProps {\n  /** Matched portal route slug. */\n  readonly slug?: string;\n  /** Remaining route path after the matched slug. */\n  readonly params?: string;\n}\n\n/** Children supplied to a portal-wide provider component. */\nexport interface PortalProviderProps {\n  /** Complete portal tree wrapped by the provider. */\n  readonly children: ReactNode;\n}\n\n/** Configuration accepted by {@link createPortal}. */\nexport interface PortalConfig {\n  /** Custom React pages keyed by their portal slug. */\n  readonly customPages?: Record<string, ComponentType<PortalCustomPageProps>>;\n  /**\n   * Per-member-type page overrides: memberTypeSlug -> (pageSlug -> component).\n   * Serves different screens to different member types (e.g. an `affiliate`\n   * dashboard) at the same slug. Wins over `customPages` for that member type.\n   */\n  readonly memberTypeCustomPages?: MemberTypeCustomPages;\n  /** Remote DOM packages, host functions, and package-loading options. */\n  readonly remoteWidgets?: RemoteWidgetOptions;\n  /** Partial SDK configuration merged with the SDK defaults. */\n  readonly fluid?: Partial<FluidSDKConfig>;\n  /** DOM element id where the portal mounts. @defaultValue `\"root\"` */\n  readonly rootId?: string;\n  /** App shell options; page and error hooks come from the top-level config. */\n  readonly shell?: Omit<\n    AppShellProps,\n    \"customPages\" | \"memberTypeCustomPages\" | \"errorReporter\"\n  >;\n  /** Optional component that wraps the complete portal tree with app providers. */\n  readonly providers?: ComponentType<PortalProviderProps>;\n  /** Receives uncaught root and shell errors with portal context. */\n  readonly errorReporter?: PortalErrorReporter;\n  /** Disables React Strict Mode when an integration cannot tolerate development double invocation. */\n  readonly disableStrictMode?: boolean;\n}\n\nexport type { RemoteDomWidgetPackageDescriptor, RemoteWidgetOptions };\n\n/**\n * Mounts a portal with the shared SDK provider and canonical widget catalog.\n *\n * @param config - Portal pages, SDK settings, Remote DOM packages, and host integration hooks.\n * @throws If the configured root element does not exist.\n */\nexport function createPortal(config: PortalConfig = {}): void {\n  const rootId = config.rootId ?? \"root\";\n  const rootElement = document.getElementById(rootId);\n  if (!rootElement) {\n    throw new Error(`Portal root element \"#${rootId}\" not found`);\n  }\n\n  let app: ReactNode = (\n    <>\n      <AppShell\n        customPages={config.customPages}\n        memberTypeCustomPages={config.memberTypeCustomPages}\n        errorReporter={config.errorReporter}\n        {...config.shell}\n      />\n      {/* Makes the portal installable as this company's branded PWA. Inside\n          FluidProvider (for the tenant Store) but scoped to the real portal —\n          not the builder preview, which also uses FluidProvider directly. */}\n      <PortalPwa />\n    </>\n  );\n  if (config.providers) {\n    const Providers = config.providers;\n    app = <Providers>{app}</Providers>;\n  }\n\n  const tree = (\n    <RootBoundary errorReporter={config.errorReporter}>\n      <FluidProvider\n        config={createDefaultFluidConfig(config.fluid)}\n        {...(config.remoteWidgets === undefined\n          ? {}\n          : { remoteWidgets: config.remoteWidgets })}\n      >\n        {app}\n      </FluidProvider>\n    </RootBoundary>\n  );\n\n  createRoot(rootElement).render(\n    config.disableStrictMode ? tree : <StrictMode>{tree}</StrictMode>,\n  );\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport { transformManifestToRepAppData } from \"../transforms\";\nimport type { RawManifestResponse } from \"../transforms\";\nimport type { Profile } from \"../types/profile\";\nimport { APP_DATA_QUERY_KEY, fetchRawManifest } from \"./use-fluid-app\";\n\n/**\n * Base query key for profile data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n *\n * @deprecated Use {@link APP_DATA_QUERY_KEY} with `useFluidApp` instead.\n */\nexport const PROFILE_QUERY_KEY = [\"fluid\", \"profile\"] as const;\n\n/**\n * Hook to fetch the portal profile (themes, navigation, screens).\n *\n * Internally fetches from the fluidos API (same data source as\n * {@link useFluidApp}) and selects the `profile` slice, so no\n * legacy `/api/rep_app/manifest` call is made.\n *\n * @deprecated Use `useFluidApp()` instead — it returns the full\n * `RepAppData` including `profile`, `screens`, and more.\n *\n * @example\n * ```tsx\n * function Navigation() {\n *   const { data: profile, isLoading } = useFluidProfile();\n *\n *   if (isLoading) return <Spinner />;\n *\n *   return (\n *     <nav>\n *       {profile?.navigation.navigation_items.map(item => (\n *         <NavItem key={item.id} item={item} />\n *       ))}\n *     </nav>\n *   );\n * }\n * ```\n */\nexport function useFluidProfile(): UseQueryResult<Profile> {\n  const appDefinitionApi = useAppDefinitionApi();\n  const { scopeKey } = useCompanyScopedQueryKey();\n\n  return useQuery<\n    RawManifestResponse,\n    Error,\n    Profile,\n    readonly (string | number)[]\n  >({\n    queryKey: scopeKey(APP_DATA_QUERY_KEY),\n    queryFn: () => fetchRawManifest(appDefinitionApi),\n    select: (raw) => {\n      const appData = transformManifestToRepAppData(raw);\n      return appData.profile;\n    },\n  });\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport type { AppDefinitionResponse } from \"@fluid-app/portal-core/app-definition-types\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\n\n/**\n * Base query key for the app definition endpoint.\n * The runtime key includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const APP_DEFINITION_QUERY_KEY = [\"fluid\", \"app-definition\"] as const;\n\n/**\n * Hook to fetch the active app manifest from the portal-tenant BFF.\n *\n * Returns the manifest metadata (id, name, version)\n * sourced from `GET /api/app/manifest` via the {@link AppDefinitionApi} port.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n *   const { data } = useAppDefinition();\n *   const definitionId = data?.definition.id ?? 0;\n * }\n * ```\n */\nexport function useAppDefinition(options?: {\n  enabled?: boolean;\n}): UseQueryResult<AppDefinitionResponse> {\n  const api = useAppDefinitionApi();\n  const { scopeKey } = useCompanyScopedQueryKey();\n\n  return useQuery({\n    queryKey: scopeKey(APP_DEFINITION_QUERY_KEY),\n    queryFn: () => api.fetchDefinition(),\n    ...(options?.enabled !== undefined && { enabled: options.enabled }),\n  });\n}\n","import { useThemeContext } from \"../providers/FluidThemeProvider\";\nimport type { ThemeDefinition } from \"../types/theme\";\n\n/**\n * Result of useFluidTheme hook\n */\nexport interface UseFluidThemeResult {\n  /** Currently active theme */\n  currentTheme: ThemeDefinition | null;\n  /** Switch to a different theme */\n  setTheme: (theme: ThemeDefinition) => void;\n  /** Switch between light and dark mode */\n  setThemeMode: (mode: \"light\" | \"dark\") => void;\n  /** Current theme mode (convenience accessor) */\n  mode: \"light\" | \"dark\" | undefined;\n}\n\n/**\n * Hook to access and control theme settings\n *\n * @example\n * ```tsx\n * function ThemeSwitcher({ themes }: { themes: ThemeDefinition[] }) {\n *   const { currentTheme, setTheme, setThemeMode, mode } = useFluidTheme();\n *\n *   return (\n *     <div>\n *       <select\n *         value={currentTheme?.name}\n *         onChange={(e) => {\n *           const theme = themes.find(t => t.name === e.target.value);\n *           if (theme) setTheme(theme);\n *         }}\n *       >\n *         {themes.map(theme => (\n *           <option key={theme.name} value={theme.name}>\n *             {theme.name}\n *           </option>\n *         ))}\n *       </select>\n *\n *       <button onClick={() => setThemeMode(mode === \"dark\" ? \"light\" : \"dark\")}>\n *         Toggle {mode === \"dark\" ? \"Light\" : \"Dark\"} Mode\n *       </button>\n *     </div>\n *   );\n * }\n * ```\n */\nexport function useFluidTheme(): UseFluidThemeResult {\n  const { currentTheme, setTheme, setThemeMode, mode } = useThemeContext();\n\n  return {\n    currentTheme,\n    setTheme,\n    setThemeMode,\n    mode,\n  };\n}\n","import { useSyncExternalStore } from \"react\";\nimport {\n  detectPwaDisplayMode,\n  STANDALONE_MEDIA_QUERY,\n  type PwaDisplayMode,\n} from \"./detect-pwa-display-mode\";\n\n/**\n * Reactive `\"standalone\" | \"browser\"` for the current session. Updates if the\n * display mode changes mid-session (e.g. the user installs and relaunches).\n */\nexport function usePwaDisplayMode(): PwaDisplayMode {\n  return useSyncExternalStore(\n    subscribe,\n    detectPwaDisplayMode,\n    getServerSnapshot,\n  );\n}\n\nfunction subscribe(onChange: () => void): () => void {\n  if (\n    typeof window === \"undefined\" ||\n    typeof window.matchMedia !== \"function\"\n  ) {\n    return () => {};\n  }\n  const mql = window.matchMedia(STANDALONE_MEDIA_QUERY);\n  mql.addEventListener(\"change\", onChange);\n  return () => mql.removeEventListener(\"change\", onChange);\n}\n\nfunction getServerSnapshot(): PwaDisplayMode {\n  return \"browser\";\n}\n","import { useCallback } from \"react\";\nimport type { MemberPermissionKey } from \"@fluid-app/portal-core/account-types\";\nimport {\n  canAccessRepSurfaces,\n  hasMemberPermission,\n  memberTypeName,\n  memberTypeSlug,\n} from \"@fluid-app/portal-core/member-permissions\";\nimport { useAccount } from \"./use-account\";\n\nexport interface MemberTypeInfo {\n  /** Real per-company member-type slug (rep/customer/affiliate/...), or null while loading. */\n  slug: string | null;\n  /** Admin-facing display label (e.g. \"Affiliate\"), or null when unknown. */\n  name: string | null;\n  /** Whether the member may access rep-only surfaces (rep_eligible). */\n  canAccessRepSurfaces: boolean;\n  /** Predicate for any member-type permission key. */\n  can: (key: MemberPermissionKey) => boolean;\n  /** True until the account query resolves. */\n  isLoading: boolean;\n}\n\n/**\n * Resolve the current member's type identity and capabilities.\n *\n * The single hook UI should use to display the member type (name/slug) and\n * to gate behavior on permissions, instead of comparing the binary\n * `member_type` string. Backed by the same cached `useAccount()` query.\n */\nexport function useMemberType(): MemberTypeInfo {\n  const { data: account, isLoading } = useAccount();\n\n  // Stable reference so consumers can safely list `can` in dependency arrays.\n  const can = useCallback(\n    (key: MemberPermissionKey) => hasMemberPermission(account, key),\n    [account],\n  );\n\n  return {\n    slug: memberTypeSlug(account),\n    name: memberTypeName(account),\n    canAccessRepSurfaces: canAccessRepSurfaces(account),\n    can,\n    isLoading,\n  };\n}\n","import { useCallback, useRef } from \"react\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\nimport { useLegacyPortalTenantClient } from \"../providers/PortalTenantClientProvider\";\nimport { resetFairShareSdk } from \"../utils/reset-fairshare-sdk\";\n\nexport interface UseCompanySwitchOptions {\n  // Preserved for API compatibility; no longer used internally.\n}\n\n/**\n * Hook that handles company switching for the portal.\n *\n * Calls PUT /api/authentication/company/{id}/switch, clears the TanStack\n * Query cache and IndexedDB persisted cache, then reloads the page so all\n * queries re-fetch with the new company context.\n *\n * The server updates the session cookie automatically via the switch\n * endpoint response; no client-side token storage is needed.\n */\nexport function useCompanySwitch(_options?: UseCompanySwitchOptions): {\n  switchCompany: (companyId: number) => void;\n  isPending: boolean;\n  isError: boolean;\n  error: Error | null;\n} {\n  const client = useLegacyPortalTenantClient();\n  const queryClient = useQueryClient();\n  const switchingRef = useRef(false);\n\n  const { mutate, isPending, isError, error } = useMutation({\n    mutationFn: (companyId: number) =>\n      client.put(`/api/authentication/company/${companyId}/switch`),\n    onSuccess: async () => {\n      // Clear in-memory cache and IndexedDB to prevent stale data\n      // rehydration after reload.\n      queryClient.clear();\n      try {\n        await deleteDatabase(\"company-switch\");\n      } catch {\n        // Non-fatal: company-scoped query keys prevent cross-company reads\n        // even if the IDB delete fails.\n      }\n      // Reset the FairShare SDK's shopping identity so the new company's\n      // session doesn't inherit the previous membership's cart/customer\n      // (the SDK's cart/session cookies aren't company-scoped) — CURRENT-2180.\n      resetFairShareSdk();\n\n      // Session cookie is updated server-side by the switch endpoint.\n      // Reload to re-fetch all queries with the new company context.\n      window.location.reload();\n    },\n    onError: () => {\n      switchingRef.current = false;\n    },\n  });\n\n  const switchCompany = useCallback(\n    (companyId: number) => {\n      if (switchingRef.current) return;\n      switchingRef.current = true;\n      mutate(companyId);\n    },\n    [mutate],\n  );\n\n  return {\n    switchCompany: switchCompany,\n    isPending: isPending,\n    isError: isError,\n    error: error,\n  };\n}\n","import type { CalendarEvent } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number, hour: number, minute: number = 0): Date {\n  const d = new Date(now);\n  d.setDate(d.getDate() + days);\n  d.setHours(hour, minute, 0, 0);\n  return d;\n}\n\nexport const DEMO_CALENDAR_EVENTS: readonly CalendarEvent[] = [\n  {\n    id: 1,\n    title: \"Team Standup\",\n    description: { body: \"Daily sync with the sales team\" },\n    color: \"#4f46e5\",\n    start: daysFromNow(0, 9, 0).toISOString(),\n    end: daysFromNow(0, 9, 30).toISOString(),\n    active: true,\n    status: \"confirmed\",\n  },\n  {\n    id: 2,\n    title: \"Client Review - Acme Corp\",\n    description: { body: \"Quarterly business review with key accounts\" },\n    color: \"#059669\",\n    start: daysFromNow(2, 14, 0).toISOString(),\n    end: daysFromNow(2, 15, 0).toISOString(),\n    active: true,\n    status: \"confirmed\",\n    venue: \"Conference Room B\",\n  },\n  {\n    id: 3,\n    title: \"Product Training Webinar\",\n    description: { body: \"New product line training for the field\" },\n    color: \"#d97706\",\n    start: daysFromNow(4, 11, 0).toISOString(),\n    end: daysFromNow(4, 12, 30).toISOString(),\n    active: true,\n    status: \"confirmed\",\n    url: \"https://example.com/webinar\",\n  },\n  {\n    id: 4,\n    title: \"Regional Conference\",\n    description: { body: \"Annual West Coast regional conference\" },\n    color: \"#dc2626\",\n    start: daysFromNow(10, 8, 0).toISOString(),\n    end: daysFromNow(12, 17, 0).toISOString(),\n    active: true,\n    status: \"confirmed\",\n    venue: \"San Diego Convention Center\",\n    isAllDay: true,\n  },\n];\n","/**\n * Calendar events hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CalendarEvent, CalendarEventDescription } from \"./hook-types\";\nimport { DEMO_CALENDAR_EVENTS } from \"./demo-data/calendar-events\";\n\n// Re-export types so external consumers are unaffected\nexport type { CalendarEvent, CalendarEventDescription };\n\n/**\n * Result type for useCalendarEvents hook.\n * Uses QueryResult<CalendarEvent[]> with default Error type.\n */\nexport type UseCalendarEventsResult = QueryResult<CalendarEvent[]>;\n\n/**\n * Hook to fetch calendar events.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCalendarEvents(): UseCalendarEventsResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: [...DEMO_CALENDAR_EVENTS],\n    isLoading: false,\n    isError: false,\n  };\n}\n","import type { Todo } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n  const d = new Date(now);\n  d.setDate(d.getDate() + days);\n  return d.toISOString();\n}\n\nexport const DEMO_TODOS: readonly Todo[] = [\n  {\n    id: 1,\n    body: \"Follow up with Sarah about Q2 order\",\n    dueAt: daysFromNow(1),\n    completedAt: null,\n    createdAt: daysFromNow(-2),\n    contactName: \"Sarah Johnson\",\n  },\n  {\n    id: 2,\n    body: \"Send pricing proposal to Acme Corp\",\n    dueAt: daysFromNow(7),\n    completedAt: null,\n    createdAt: daysFromNow(-1),\n    contactName: \"Mike Chen\",\n  },\n  {\n    id: 3,\n    body: \"Schedule onboarding call with new team member\",\n    dueAt: daysFromNow(3),\n    completedAt: null,\n    createdAt: daysFromNow(0),\n    contactName: \"Emily Rodriguez\",\n  },\n  {\n    id: 4,\n    body: \"Review and approve Q1 expense report\",\n    dueAt: daysFromNow(-1),\n    completedAt: daysFromNow(-1),\n    createdAt: daysFromNow(-5),\n    contactName: null,\n  },\n  {\n    id: 5,\n    body: \"Prepare presentation for Friday team meeting\",\n    dueAt: daysFromNow(4),\n    completedAt: daysFromNow(0),\n    createdAt: daysFromNow(-3),\n    contactName: null,\n  },\n];\n","/**\n * Todos hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { Todo } from \"./hook-types\";\nimport { DEMO_TODOS } from \"./demo-data/todos\";\n\n// Re-export type so external consumers are unaffected\nexport type { Todo };\n\n/**\n * Result type for useTodos hook.\n * Uses QueryResult<Todo[]> with default Error type.\n */\nexport type UseTodosResult = QueryResult<Todo[]>;\n\n/**\n * Hook to fetch todo items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useTodos(): UseTodosResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: [...DEMO_TODOS],\n    isLoading: false,\n    isError: false,\n  };\n}\n","/**\n * Hook type utilities and type predicates.\n *\n * This module provides:\n * - Generic hook result types with default type parameters\n * - Type predicates for query state narrowing\n * - Reusable patterns for type-safe property access in hooks\n *\n * Following generics best practices:\n * - generics-default-type-parameters: Default E to Error for common case\n * - generics-type-predicates: Type predicates for result state narrowing\n * - generics-constrain-type-parameters: K extends keyof T for property access\n */\n\n// =============================================================================\n// Base Result Types with Default Type Parameters\n// =============================================================================\n\n/**\n * Base result type for query hooks with default error type.\n * Uses default type parameter for E (generics-default-type-parameters rule).\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n *\n * @example\n * // Error type defaults to Error\n * type UsersResult = QueryResult<User[]>;\n *\n * // Can override when needed\n * type CustomResult = QueryResult<User[], ApiError>;\n */\nexport interface QueryResult<T, E = Error> {\n  readonly data: T;\n  readonly isLoading: boolean;\n  readonly isError: boolean;\n  readonly error?: E | undefined;\n}\n\n/**\n * Result type for hooks that may not have data yet.\n * Extends QueryResult with nullable data.\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface QueryResultNullable<T, E = Error> {\n  readonly data: T | null | undefined;\n  readonly isLoading: boolean;\n  readonly isError: boolean;\n  readonly error?: E | undefined;\n}\n\n/**\n * Result type for list/collection hooks with aggregates.\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ListQueryResult<T, E = Error> extends QueryResult<T[], E> {\n  readonly totalCount: number;\n}\n\n/**\n * Result type for list hooks with value aggregation (e.g., deals with total value).\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ValueListQueryResult<T, E = Error> extends ListQueryResult<\n  T,\n  E\n> {\n  readonly totalValue: number;\n}\n\n// =============================================================================\n// Type Predicates for Query State Narrowing\n// =============================================================================\n\n/**\n * Type predicate to check if a query result has successfully loaded data.\n * Narrows the data type from T | null | undefined to T.\n *\n * @example\n * const result = useContact(id);\n * if (hasData(result)) {\n *   // TypeScript knows result.data is Contact, not Contact | null\n *   console.log(result.data.name);\n * }\n */\nexport function hasData<T, E = Error>(\n  result: QueryResultNullable<T, E>,\n): result is QueryResultNullable<T, E> & { readonly data: T } {\n  return result.data != null && !result.isLoading && !result.isError;\n}\n\n/**\n * Type predicate to check if a query result is in loading state.\n * Useful for conditional rendering.\n *\n * @example\n * if (isLoading(result)) {\n *   return <Spinner />;\n * }\n */\nexport function isLoading<T, E = Error>(\n  result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n  return result.isLoading;\n}\n\n/**\n * Type predicate to check if a query result has an error.\n * Narrows to include the error property.\n *\n * @example\n * if (isErrorResult(result)) {\n *   console.error(result.error); // error is E, not undefined\n * }\n */\nexport function isErrorResult<T, E = Error>(\n  result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): result is (QueryResult<T, E> | QueryResultNullable<T, E>) & {\n  readonly isError: true;\n  readonly error: E;\n} {\n  return result.isError && result.error !== undefined;\n}\n\n/**\n * Type predicate to check if a query result is in idle state (not loading, no error, has data).\n *\n * @example\n * if (isIdle(result)) {\n *   // Safe to access and render data\n * }\n */\nexport function isIdle<T, E = Error>(\n  result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n  return !result.isLoading && !result.isError;\n}\n\n// =============================================================================\n// Generic Property Selector Pattern\n// =============================================================================\n\n/**\n * Type-safe property selector for hook results.\n * Uses K extends keyof T constraint (generics-function-constraints rule).\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n *\n * @example\n * const users = [{ name: \"Alice\", age: 30 }];\n * const names = selectProperty(users, \"name\"); // string[]\n * const ages = selectProperty(users, \"age\");   // number[]\n * selectProperty(users, \"invalid\"); // Error: \"invalid\" not in \"name\" | \"age\"\n */\nexport function selectProperty<T, K extends keyof T>(\n  items: readonly T[],\n  key: K,\n): T[K][] {\n  return items.map((item) => item[key]);\n}\n\n/**\n * Type-safe property getter for a single item.\n * Returns undefined if item is null/undefined.\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n */\nexport function getProperty<T, K extends keyof T>(\n  item: T | null | undefined,\n  key: K,\n): T[K] | undefined {\n  return item?.[key];\n}\n\n// =============================================================================\n// Hook Factory Types\n// =============================================================================\n\n/**\n * Generic type for hooks that fetch a single resource by ID.\n * Useful for creating consistent API across different resource types.\n *\n * @typeParam T - The resource type\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseSingleResourceHook<T, E = Error> = (\n  id: string,\n) => QueryResultNullable<T, E>;\n\n/**\n * Generic type for hooks that fetch a list of resources with optional params.\n * Uses generics-default-type-parameters for the params type.\n *\n * @typeParam T - The item type\n * @typeParam P - The params type (defaults to empty object)\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseListResourceHook<\n  T,\n  P extends Record<string, unknown> = Record<string, never>,\n  E = Error,\n> = (params?: P) => ListQueryResult<T, E>;\n\n/**\n * Transforms a nullable result to a non-nullable one if data exists.\n * Useful when you've already checked hasData().\n */\nexport type WithData<R extends QueryResultNullable<unknown>> =\n  R extends QueryResultNullable<infer T, infer E>\n    ? QueryResultNullable<T, E> & { readonly data: T }\n    : never;\n\n// =============================================================================\n// Domain Types\n// Shared between hook files and demo-data files to avoid circular imports.\n// =============================================================================\n\n/**\n * Activity slug constants as a const object.\n * Derive the ActivitySlug type from this single source of truth.\n */\nexport const ACTIVITY_SLUGS = {\n  abandonedCart: \"abandoned_cart\",\n  announcements: \"announcements\",\n  cartItemsAdded: \"cart_items_added\",\n  commentReply: \"comment_reply\",\n  directMessage: \"direct_message\",\n  fantasyPoint: \"fantasy_point\",\n  newLead: \"new_lead\",\n  orderPlaced: \"order_placed\",\n  pageViews: \"page_views\",\n  pageViewsContact: \"page_views_contact\",\n  tasks: \"tasks\",\n  upcomingEvent: \"upcoming_event\",\n  video: \"video\",\n  videoComplete: \"video_complete\",\n  videoCompleteContact: \"video_complete_contact\",\n  videoContact: \"video_contact\",\n  messageReceived: \"message_received\",\n  messageSent: \"message_sent\",\n  newCartItemsAdded: \"new_cart_items_added\",\n  smartLinkClicked: \"smart_link_clicked\",\n  reviewLeft: \"review_left\",\n} as const;\n\n/** Activity slug union type derived from ACTIVITY_SLUGS constant. */\nexport type ActivitySlug = (typeof ACTIVITY_SLUGS)[keyof typeof ACTIVITY_SLUGS];\n\n/** Type predicate to check if a string is a valid ActivitySlug. */\nexport function isActivitySlug(value: string): value is ActivitySlug {\n  return Object.values(ACTIVITY_SLUGS).includes(value as ActivitySlug);\n}\n\n/** Transformed activity for display. */\nexport interface Activity {\n  readonly id: number;\n  readonly userName: string;\n  readonly avatarUrl: string | null;\n  readonly activityType: string;\n  readonly targetName: string;\n  readonly timestamp: string;\n  readonly slug: ActivitySlug;\n}\n\n/** Description/rich text metadata for a calendar event. */\nexport interface CalendarEventDescription {\n  readonly id?: number | null;\n  readonly name?: string | null;\n  readonly body?: string | null;\n  readonly record_type?: string | null;\n  readonly record_id?: number | null;\n  readonly created_at?: string | null;\n  readonly updated_at?: string | null;\n  readonly locale?: string | null;\n}\n\n/** Calendar event data from the API. */\nexport interface CalendarEvent {\n  readonly id: number;\n  readonly title: string;\n  readonly description?: CalendarEventDescription | null;\n  readonly color?: string | null;\n  readonly url?: string | null;\n  readonly start: string;\n  readonly end: string;\n  readonly active?: boolean | null;\n  readonly time_zone?: string | null;\n  readonly status?: string | null;\n  readonly image_url?: string | null;\n  readonly images?: readonly unknown[] | null;\n  readonly venue?: string | null;\n  readonly countries?: readonly string[] | null;\n  readonly hasTomorrow?: boolean | null;\n  readonly hasYesterday?: boolean | null;\n  readonly isAllDay?: boolean;\n}\n\n/** Catch up suggestion data from the API. */\nexport interface CatchUp {\n  readonly id: number;\n  readonly suggestion_title: string;\n}\n\n/** MySite data returned by the hook. */\nexport interface MySiteData {\n  readonly url: string | null;\n  readonly views: number;\n  readonly leads: number;\n  readonly userName: string;\n}\n\n/** Transformed todo for display. */\nexport interface Todo {\n  readonly id: number;\n  readonly body: string;\n  readonly dueAt: string | null;\n  readonly completedAt: string | null;\n  readonly createdAt: string;\n  readonly contactName: string | null;\n}\n","import type { Activity } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n  const d = new Date(now);\n  d.setHours(d.getHours() - hours);\n  return d.toISOString();\n}\nexport const DEMO_ACTIVITIES: readonly Activity[] = [\n  {\n    id: 1,\n    userName: \"Sarah Johnson\",\n    avatarUrl: null,\n    activityType: \"New Order\",\n    targetName: \"Wellness Starter Kit\",\n    timestamp: hoursAgo(1),\n    slug: \"order_placed\",\n  },\n  {\n    id: 2,\n    userName: \"Mike Chen\",\n    avatarUrl: null,\n    activityType: \"New Lead\",\n    targetName: \"Referral from LinkedIn campaign\",\n    timestamp: hoursAgo(3),\n    slug: \"new_lead\",\n  },\n  {\n    id: 3,\n    userName: \"Emily Rodriguez\",\n    avatarUrl: null,\n    activityType: \"Page View\",\n    targetName: \"Product Catalog\",\n    timestamp: hoursAgo(5),\n    slug: \"page_views\",\n  },\n  {\n    id: 4,\n    userName: \"David Park\",\n    avatarUrl: null,\n    activityType: \"Cart Items Added\",\n    targetName: \"Premium Bundle (3 items)\",\n    timestamp: hoursAgo(8),\n    slug: \"cart_items_added\",\n  },\n  {\n    id: 5,\n    userName: \"Lisa Thompson\",\n    avatarUrl: null,\n    activityType: \"Video Watched\",\n    targetName: \"Getting Started Tutorial\",\n    timestamp: hoursAgo(12),\n    slug: \"video_complete\",\n  },\n  {\n    id: 6,\n    userName: \"James Wilson\",\n    avatarUrl: null,\n    activityType: \"Message Received\",\n    targetName: \"Question about shipping\",\n    timestamp: hoursAgo(18),\n    slug: \"message_received\",\n  },\n  {\n    id: 7,\n    userName: \"Rachel Kim\",\n    avatarUrl: null,\n    activityType: \"Smart Link Clicked\",\n    targetName: \"Holiday Promo Link\",\n    timestamp: hoursAgo(24),\n    slug: \"smart_link_clicked\",\n  },\n  {\n    id: 8,\n    userName: \"Tom Martinez\",\n    avatarUrl: null,\n    activityType: \"Review Left\",\n    targetName: \"Essential Oil Set - 5 stars\",\n    timestamp: hoursAgo(36),\n    slug: \"review_left\",\n  },\n];\n","/**\n * Activities hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport {\n  ACTIVITY_SLUGS,\n  isActivitySlug,\n  type Activity,\n  type ActivitySlug,\n} from \"./hook-types\";\nimport { DEMO_ACTIVITIES } from \"./demo-data/activities\";\n\n// Re-export types and constants so external consumers are unaffected\nexport { ACTIVITY_SLUGS, isActivitySlug };\nexport type { Activity, ActivitySlug };\n\n/**\n * Result type for useActivities hook.\n * Uses QueryResult generic with the activities + optional windowed totalCount.\n */\nexport type UseActivitiesData = {\n  activities: Activity[];\n  totalCount?: number;\n};\nexport type UseActivitiesResult = QueryResult<UseActivitiesData>;\n\n/**\n * Hook to fetch recent activities. The optional `daysAgo` arg windows the\n * result (e.g. `useActivities({ daysAgo: 7 })`) and surfaces the windowed\n * total via `data.totalCount` — used by the Recent Activity widget chip.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useActivities(_args?: {\n  daysAgo?: number;\n}): UseActivitiesResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: {\n      activities: [...DEMO_ACTIVITIES],\n      totalCount: DEMO_ACTIVITIES.length,\n    },\n    isLoading: false,\n    isError: false,\n  };\n}\n","import type { CatchUp } from \"../hook-types\";\n\nexport const DEMO_CATCHUPS: readonly CatchUp[] = [\n  {\n    id: 1,\n    suggestion_title: \"Sarah Johnson hasn't ordered in 30 days\",\n  },\n  {\n    id: 2,\n    suggestion_title: \"Mike Chen's subscription is expiring soon\",\n  },\n  {\n    id: 3,\n    suggestion_title: \"Emily Rodriguez left a cart with 3 items\",\n  },\n];\n","/**\n * Catch ups hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CatchUp } from \"./hook-types\";\nimport { DEMO_CATCHUPS } from \"./demo-data/catchups\";\n\n// Re-export type so external consumers are unaffected\nexport type { CatchUp };\n\n/**\n * Result type for useCatchUps hook.\n * Uses QueryResult<CatchUp[]> with default Error type.\n */\nexport type UseCatchUpsResult = QueryResult<CatchUp[]>;\n\n/**\n * Hook to fetch catch up items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCatchUps(): UseCatchUpsResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: [...DEMO_CATCHUPS],\n    isLoading: false,\n    isError: false,\n  };\n}\n","import type { MySiteData } from \"../hook-types\";\n\nexport const DEMO_MYSITE: MySiteData = {\n  url: \"https://my-portal.example.com\",\n  views: 1243,\n  leads: 37,\n  userName: \"Demo User\",\n};\n","/**\n * MySite hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResultNullable } from \"./hook-types\";\nimport type { MySiteData } from \"./hook-types\";\nimport { DEMO_MYSITE } from \"./demo-data/mysite\";\n\n// Re-export type so external consumers are unaffected\nexport type { MySiteData };\n\n/**\n * Result type for useMySite hook.\n * Uses QueryResultNullable since MySite data may not be available.\n */\nexport type UseMySiteResult = QueryResultNullable<MySiteData>;\n\n/**\n * Hook to fetch MySite data.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useMySite(): UseMySiteResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: DEMO_MYSITE,\n    isLoading: false,\n    isError: false,\n  };\n}\n","import type { Conversation, Message } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n  const d = new Date(now);\n  d.setHours(d.getHours() - hours);\n  return d.toISOString();\n}\n\nfunction daysAgo(days: number): string {\n  const d = new Date(now);\n  d.setDate(d.getDate() - days);\n  return d.toISOString();\n}\n\nexport const DEMO_CONVERSATIONS: readonly Conversation[] = [\n  {\n    id: \"conv-1\",\n    title: \"Sarah Johnson\",\n    participants: [\n      { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n      {\n        id: \"user-2\",\n        name: \"Sarah Johnson\",\n        email: \"sarah.johnson@example.com\",\n        isOnline: true,\n      },\n    ],\n    lastMessage: {\n      id: \"msg-1-3\",\n      conversationId: \"conv-1\",\n      senderId: \"user-2\",\n      senderName: \"Sarah Johnson\",\n      type: \"text\",\n      content: \"Sounds great! I'll place the order by end of day.\",\n      timestamp: hoursAgo(1),\n      isRead: false,\n    },\n    unreadCount: 1,\n    status: \"active\",\n    createdAt: daysAgo(30),\n    updatedAt: hoursAgo(1),\n  },\n  {\n    id: \"conv-2\",\n    title: \"Mike Chen\",\n    participants: [\n      { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n      {\n        id: \"user-3\",\n        name: \"Mike Chen\",\n        email: \"mike.chen@acmecorp.com\",\n        isOnline: false,\n      },\n    ],\n    lastMessage: {\n      id: \"msg-2-2\",\n      conversationId: \"conv-2\",\n      senderId: \"user-1\",\n      senderName: \"You\",\n      type: \"text\",\n      content:\n        \"I've attached the updated pricing sheet. Let me know if you have any questions!\",\n      timestamp: hoursAgo(5),\n      isRead: true,\n    },\n    unreadCount: 0,\n    status: \"active\",\n    createdAt: daysAgo(14),\n    updatedAt: hoursAgo(5),\n  },\n  {\n    id: \"conv-3\",\n    title: \"Team Updates\",\n    participants: [\n      { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n      {\n        id: \"user-4\",\n        name: \"Emily Rodriguez\",\n        email: \"emily.r@healthfirst.io\",\n      },\n      { id: \"user-5\", name: \"David Park\", email: \"david.park@email.com\" },\n    ],\n    lastMessage: {\n      id: \"msg-3-4\",\n      conversationId: \"conv-3\",\n      senderId: \"user-4\",\n      senderName: \"Emily Rodriguez\",\n      type: \"text\",\n      content:\n        \"The new product samples arrived today. Will distribute to the team tomorrow.\",\n      timestamp: daysAgo(1),\n      isRead: true,\n    },\n    unreadCount: 0,\n    status: \"active\",\n    createdAt: daysAgo(60),\n    updatedAt: daysAgo(1),\n  },\n];\n\nexport const DEMO_MESSAGES: readonly Message[] = [\n  {\n    id: \"msg-1-1\",\n    conversationId: \"conv-1\",\n    senderId: \"user-1\",\n    senderName: \"You\",\n    type: \"text\",\n    content:\n      \"Hi Sarah! I wanted to follow up on the Wellness Starter Kit. We have a special promotion running this month.\",\n    timestamp: hoursAgo(3),\n    isRead: true,\n  },\n  {\n    id: \"msg-1-2\",\n    conversationId: \"conv-1\",\n    senderId: \"user-2\",\n    senderName: \"Sarah Johnson\",\n    type: \"text\",\n    content:\n      \"That's perfect timing! I was just thinking about reordering. What's the promo?\",\n    timestamp: hoursAgo(2),\n    isRead: true,\n  },\n  {\n    id: \"msg-1-3\",\n    conversationId: \"conv-1\",\n    senderId: \"user-2\",\n    senderName: \"Sarah Johnson\",\n    type: \"text\",\n    content: \"Sounds great! I'll place the order by end of day.\",\n    timestamp: hoursAgo(1),\n    isRead: false,\n  },\n];\n","/**\n * Conversations hooks - stub implementations for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Conversation, Message } from \"../types/screen-types\";\nimport type { QueryResult } from \"./hook-types\";\nimport { DEMO_CONVERSATIONS, DEMO_MESSAGES } from \"./demo-data/conversations\";\n\n// =============================================================================\n// useConversations Hook\n// =============================================================================\n\n/**\n * Result type for useConversations hook.\n * Uses QueryResult<Conversation[]> with default Error type.\n */\nexport type UseConversationsResult = QueryResult<Conversation[]>;\n\n/**\n * Hook to fetch all conversations.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @returns UseConversationsResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: conversations, isLoading, isError } = useConversations();\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return conversations.map(conv => <ConversationItem key={conv.id} {...conv} />);\n * ```\n */\nexport function useConversations(): UseConversationsResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: [...DEMO_CONVERSATIONS],\n    isLoading: false,\n    isError: false,\n  };\n}\n\n// =============================================================================\n// useConversationMessages Hook\n// =============================================================================\n\n/**\n * Result type for useConversationMessages hook.\n * Uses QueryResult<Message[]> with default Error type.\n */\nexport type UseConversationMessagesResult = QueryResult<Message[]>;\n\n/**\n * Hook to fetch messages for a specific conversation.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param conversationId - The ID of the conversation to fetch messages for\n * @returns UseConversationMessagesResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: messages, isLoading, isError } = useConversationMessages(conversationId);\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return messages.map(msg => <MessageBubble key={msg.id} {...msg} />);\n * ```\n */\nexport function useConversationMessages(\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  _conversationId: string,\n): UseConversationMessagesResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching using _conversationId\n  return {\n    data: [...DEMO_MESSAGES],\n    isLoading: false,\n    isError: false,\n  };\n}\n","/**\n * Screen Types - Type definitions for core feature screens\n *\n * All status and type unions are derived from constants for single source of truth.\n * Use the constants (e.g., CONVERSATION_STATUSES.active) for type-safe comparisons.\n */\n\n// =============================================================================\n// Messaging Types\n// =============================================================================\n\n/**\n * Conversation status constant - single source of truth.\n */\nexport const CONVERSATION_STATUSES = {\n  active: \"active\",\n  archived: \"archived\",\n  muted: \"muted\",\n} as const;\n\n/**\n * Union type derived from CONVERSATION_STATUSES constant.\n */\nexport type ConversationStatus =\n  (typeof CONVERSATION_STATUSES)[keyof typeof CONVERSATION_STATUSES];\n\n/**\n * Message type constant - single source of truth.\n */\nexport const MESSAGE_TYPES = {\n  text: \"text\",\n  image: \"image\",\n  file: \"file\",\n  system: \"system\",\n} as const;\n\n/**\n * Union type derived from MESSAGE_TYPES constant.\n */\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES];\n\nexport interface Participant {\n  readonly id: string;\n  readonly name: string;\n  readonly email: string;\n  readonly avatarUrl?: string;\n  readonly isOnline?: boolean;\n}\n\n/**\n * Message attachment type - extracted for reusability and clarity.\n */\nexport interface MessageAttachment {\n  readonly id: string;\n  readonly name: string;\n  readonly url: string;\n  readonly type: string;\n  readonly size?: number;\n}\n\nexport interface Message {\n  readonly id: string;\n  readonly conversationId: string;\n  readonly senderId: string;\n  readonly senderName: string;\n  readonly senderAvatarUrl?: string;\n  readonly type: MessageType;\n  readonly content: string;\n  readonly timestamp: string;\n  readonly isRead: boolean;\n  readonly attachments?: readonly MessageAttachment[];\n}\n\nexport interface Conversation {\n  readonly id: string;\n  readonly title: string;\n  readonly participants: readonly Participant[];\n  readonly lastMessage?: Message;\n  readonly unreadCount: number;\n  readonly status: ConversationStatus;\n  readonly createdAt: string;\n  readonly updatedAt: string;\n}\n\n// =============================================================================\n// Contacts Types\n// =============================================================================\n\n/**\n * Contact status constant - single source of truth.\n */\nexport const CONTACT_STATUSES = {\n  active: \"active\",\n  inactive: \"inactive\",\n  lead: \"lead\",\n  prospect: \"prospect\",\n} as const;\n\n/**\n * Union type derived from CONTACT_STATUSES constant.\n */\nexport type ContactStatus =\n  (typeof CONTACT_STATUSES)[keyof typeof CONTACT_STATUSES];\n\n/**\n * Contact type constant - single source of truth.\n */\nexport const CONTACT_TYPES = {\n  individual: \"individual\",\n  company: \"company\",\n} as const;\n\n/**\n * Union type derived from CONTACT_TYPES constant.\n */\nexport type ContactType = (typeof CONTACT_TYPES)[keyof typeof CONTACT_TYPES];\n\nexport interface ContactAddress {\n  readonly street?: string;\n  readonly city?: string;\n  readonly state?: string;\n  readonly postalCode?: string;\n  readonly country?: string;\n}\n\nexport interface Contact {\n  readonly id: string;\n  readonly firstName: string;\n  readonly lastName: string;\n  readonly email: string;\n  readonly phone?: string;\n  readonly company?: string;\n  readonly jobTitle?: string;\n  readonly avatarUrl?: string;\n  readonly status: ContactStatus;\n  readonly type: ContactType;\n  readonly address?: ContactAddress;\n  readonly tags?: readonly string[];\n  readonly notes?: string;\n  readonly createdAt: string;\n  readonly updatedAt: string;\n}\n","import type { Contact } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction daysAgo(days: number): string {\n  const d = new Date(now);\n  d.setDate(d.getDate() - days);\n  return d.toISOString();\n}\n\nexport const DEMO_CONTACTS: readonly Contact[] = [\n  {\n    id: \"contact-1\",\n    firstName: \"Sarah\",\n    lastName: \"Johnson\",\n    email: \"sarah.johnson@example.com\",\n    phone: \"+1 (555) 123-4567\",\n    company: \"Wellness Works Inc.\",\n    jobTitle: \"Purchasing Manager\",\n    status: \"active\",\n    type: \"individual\",\n    tags: [\"VIP\", \"Repeat Buyer\"],\n    createdAt: daysAgo(90),\n    updatedAt: daysAgo(2),\n  },\n  {\n    id: \"contact-2\",\n    firstName: \"Mike\",\n    lastName: \"Chen\",\n    email: \"mike.chen@acmecorp.com\",\n    phone: \"+1 (555) 234-5678\",\n    company: \"Acme Corp\",\n    jobTitle: \"Director of Operations\",\n    status: \"active\",\n    type: \"individual\",\n    tags: [\"Enterprise\"],\n    createdAt: daysAgo(60),\n    updatedAt: daysAgo(5),\n  },\n  {\n    id: \"contact-3\",\n    firstName: \"Emily\",\n    lastName: \"Rodriguez\",\n    email: \"emily.r@healthfirst.io\",\n    company: \"HealthFirst\",\n    status: \"lead\",\n    type: \"individual\",\n    notes: \"Interested in bulk pricing for team orders\",\n    createdAt: daysAgo(7),\n    updatedAt: daysAgo(1),\n  },\n  {\n    id: \"contact-4\",\n    firstName: \"David\",\n    lastName: \"Park\",\n    email: \"david.park@email.com\",\n    phone: \"+1 (555) 345-6789\",\n    status: \"prospect\",\n    type: \"individual\",\n    tags: [\"Referral\"],\n    createdAt: daysAgo(14),\n    updatedAt: daysAgo(10),\n  },\n  {\n    id: \"contact-5\",\n    firstName: \"Lisa\",\n    lastName: \"Thompson\",\n    email: \"lisa.t@globalfit.com\",\n    company: \"Global Fitness\",\n    jobTitle: \"CEO\",\n    status: \"active\",\n    type: \"individual\",\n    address: {\n      city: \"Los Angeles\",\n      state: \"CA\",\n      country: \"US\",\n    },\n    createdAt: daysAgo(120),\n    updatedAt: daysAgo(15),\n  },\n  {\n    id: \"contact-6\",\n    firstName: \"James\",\n    lastName: \"Wilson\",\n    email: \"jwilson@retired.net\",\n    status: \"inactive\",\n    type: \"individual\",\n    notes: \"Moved out of area, no longer purchasing\",\n    createdAt: daysAgo(200),\n    updatedAt: daysAgo(45),\n  },\n];\n\nexport const DEMO_CONTACT: Contact = DEMO_CONTACTS[0]!;\n","/**\n * Contacts hooks - stub implementation for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Contact, ContactStatus } from \"../types/screen-types\";\nimport { CONTACT_STATUSES } from \"../types/screen-types\";\nimport type { ListQueryResult, QueryResultNullable } from \"./hook-types\";\nimport { DEMO_CONTACTS, DEMO_CONTACT } from \"./demo-data/contacts\";\n\n/**\n * Type predicate to check if a status string is a valid ContactStatus.\n * Enables runtime validation with type narrowing.\n */\nexport function isContactStatus(value: string): value is ContactStatus {\n  return Object.values(CONTACT_STATUSES).includes(value as ContactStatus);\n}\n\n/**\n * Parameters for filtering and paginating contacts.\n * Uses readonly properties and proper ContactStatus type for status.\n */\nexport interface UseContactsParams {\n  /** Search query to filter contacts by name, email, or company */\n  readonly search?: string;\n  /** Filter contacts by status - uses ContactStatus union type for type safety */\n  readonly status?: ContactStatus;\n  /** Maximum number of contacts to return */\n  readonly limit?: number;\n}\n\n/**\n * Result type for the useContacts hook.\n * Uses ListQueryResult<Contact> with totalCount and default Error type.\n */\nexport type UseContactsResult = ListQueryResult<Contact>;\n\n/**\n * Result type for the useContact hook.\n * Uses QueryResultNullable since a specific contact may not exist.\n */\nexport type UseContactResult = QueryResultNullable<Contact>;\n\n/**\n * Hook to fetch a list of contacts with optional filtering and pagination.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param params - Optional parameters for filtering and pagination\n * @returns Object containing contacts data, loading state, error state, and total count\n *\n * @example\n * ```tsx\n * const { data: contacts, isLoading, totalCount } = useContacts({\n *   search: 'john',\n *   status: 'active',\n *   limit: 20\n * });\n * ```\n */\nexport function useContacts(\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  _params?: UseContactsParams,\n): UseContactsResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching\n  return {\n    data: [...DEMO_CONTACTS],\n    isLoading: false,\n    isError: false,\n    totalCount: DEMO_CONTACTS.length,\n  };\n}\n\n/**\n * Hook to fetch a single contact by ID.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param contactId - The unique identifier of the contact to fetch\n * @returns Object containing contact data, loading state, and error state\n *\n * @example\n * ```tsx\n * const { data: contact, isLoading, isError } = useContact('contact-123');\n * ```\n */\nexport function useContact(\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  _contactId: string,\n): UseContactResult {\n  // Demo data for first-run experience\n  // In production, replace with actual data fetching using _contactId\n  return {\n    data: DEMO_CONTACT,\n    isLoading: false,\n    isError: false,\n  };\n}\n","/**\n * Auth Types\n *\n * These types define the JWT payload structure and authentication\n * configuration options.\n */\n\n// ============================================================================\n// User Types - Derive from constant for single source of truth\n// ============================================================================\n\n/**\n * User type constant - single source of truth for user role values.\n * Use USER_TYPES.admin instead of \"admin\" for type-safe comparisons.\n */\nexport const USER_TYPES = {\n  admin: \"admin\",\n  rep: \"rep\",\n  root_admin: \"root_admin\",\n  customer: \"customer\",\n} as const;\n\n/**\n * Union type of all user types, derived from USER_TYPES constant.\n * @see deriving-typeof-for-object-keys pattern\n */\nexport type UserType = (typeof USER_TYPES)[keyof typeof USER_TYPES];\n\n/**\n * Runtime validation for user types.\n * @param value - The value to check\n * @returns true if value is a valid UserType\n */\nexport function isUserType(value: string): value is UserType {\n  return Object.values(USER_TYPES).includes(value as UserType);\n}\n\n/**\n * JWT payload structure from Fluid Commerce authentication.\n * Contains user identity and role information.\n */\nexport interface JWTPayload {\n  /** User ID */\n  id?: number | undefined;\n  /** User email address */\n  email?: string | undefined;\n  /** Full name of the user */\n  full_name?: string | undefined;\n  /** User role type */\n  user_type: UserType;\n  /** Original user type (for impersonation scenarios) */\n  og_user_type?: UserType | undefined;\n  /** Company ID the user belongs to */\n  company_id?: number | undefined;\n  /** Token expiration timestamp (Unix seconds) */\n  exp?: number | undefined;\n  /** Authentication type (e.g., \"standard\", \"impersonation\") */\n  auth_type?: string | undefined;\n}\n\n/**\n * Configuration options for FluidAuthProvider.\n * All options have sensible defaults.\n */\nexport interface FluidAuthConfig {\n  /**\n   * URL parameter name for the auth token.\n   * @default \"fluidUserToken\"\n   */\n  tokenKey?: string;\n\n  /**\n   * Cookie name for storing the auth token.\n   * @default \"auth_token\"\n   */\n  cookieKey?: string;\n\n  /**\n   * Cookie max age in seconds.\n   * @default 777600 (9 days)\n   */\n  cookieMaxAge?: number;\n\n  /**\n   * Grace period in milliseconds to account for clock skew\n   * when checking token expiration.\n   * @default 30000 (30 seconds)\n   */\n  gracePeriodMs?: number;\n\n  /**\n   * Callback invoked when authentication fails (no valid token).\n   * When omitted, the SDK redirects to `authUrl` with the current URL\n   * as a redirect parameter so users can log in and return.\n   */\n  onAuthFailure?: () => void;\n\n  /**\n   * Base URL for the authentication page.\n   * Used by the default auth failure redirect when `onAuthFailure` is not provided.\n   * Ignored when a custom `onAuthFailure` callback is set.\n   * @default \"https://auth.fluid.app\"\n   */\n  authUrl?: string;\n\n  /**\n   * Enable dev-mode auth bypass.\n   * When true AND running in Vite dev mode (import.meta.env.DEV),\n   * auth will use a synthetic mock user instead of requiring a real JWT.\n   * The mock user allows UI rendering but API calls will fail (token is null).\n   * @default false\n   */\n  devBypass?: boolean;\n\n  /**\n   * JWKS (JSON Web Key Set) URL for signature verification.\n   * When provided, JWT signatures will be verified against keys\n   * from this endpoint before accepting the token.\n   *\n   * This provides defense-in-depth client-side verification.\n   * Without this, tokens are only decoded (not verified) client-side,\n   * and real verification happens server-side on API calls.\n   *\n   * @example \"https://api.fluid.app/.well-known/jwks.json\"\n   */\n  jwksUrl?: string;\n}\n\n/**\n * Value provided by the FluidAuthContext.\n * All properties are readonly since context values should not be mutated by consumers.\n */\nexport interface FluidAuthContextValue {\n  /** Whether the user is authenticated with a valid token */\n  readonly isAuthenticated: boolean;\n  /** Whether authentication is still being initialized */\n  readonly isLoading: boolean;\n  /** Decoded JWT payload if authenticated, null otherwise */\n  readonly user: JWTPayload | null;\n  /** Raw JWT token string if authenticated, null otherwise */\n  readonly token: string | null;\n  /** Clear authentication state and stored tokens */\n  readonly clearAuth: () => void;\n  /** Authentication error if any occurred during initialization */\n  readonly error: Error | null;\n}\n\n/**\n * Result of token validation.\n * Uses a discriminated union for type-safe handling of valid/invalid states.\n */\nexport type TokenValidationResult =\n  | {\n      /** Token is valid */\n      isValid: true;\n      /** Decoded JWT payload */\n      payload: JWTPayload;\n      /** No error when valid */\n      error?: undefined;\n    }\n  | {\n      /** Token is invalid */\n      isValid: false;\n      /** Decoded JWT payload if parseable but expired */\n      payload?: JWTPayload;\n      /** Error message explaining why validation failed */\n      error: string;\n    };\n","import { z } from \"zod\";\nimport type { FetchClientInstance } from \"@fluid-app/api-client-core\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Company {\n  id: number;\n  name: string;\n  logo_url?: string | null;\n  icon_url?: string | null;\n}\n\nexport interface SwitchCompanyResponseCompany {\n  id: number;\n  name: string;\n  fluid_shop: string;\n  logo_url?: string | null;\n  jwt: string;\n}\n\nexport interface SwitchCompanyResponseMeta {\n  request_id: string;\n  timestamp: string;\n}\n\nexport interface SwitchCompanyResponse {\n  company: SwitchCompanyResponseCompany;\n  meta: SwitchCompanyResponseMeta;\n}\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nexport const companySchema: z.ZodType<Company> = z.object({\n  id: z.number(),\n  name: z.string(),\n  logo_url: z.string().optional().nullable(),\n  icon_url: z.string().nullable().optional(),\n});\n\nexport const switchCompanyResponseCompanySchema: z.ZodType<SwitchCompanyResponseCompany> =\n  z.object({\n    id: z.number().int().positive(),\n    name: z.string(),\n    fluid_shop: z.string(),\n    logo_url: z.string().url().nullable().optional(),\n    jwt: z.string(),\n  });\n\nexport const switchCompanyResponseMetaSchema: z.ZodType<SwitchCompanyResponseMeta> =\n  z.object({\n    request_id: z.string(),\n    timestamp: z.string(),\n  });\n\nexport const switchCompanyResponseSchema: z.ZodType<SwitchCompanyResponse> =\n  z.object({\n    company: switchCompanyResponseCompanySchema,\n    meta: switchCompanyResponseMetaSchema,\n  });\n\n// ============================================================================\n// API function\n// ============================================================================\n\nexport function switchCompany(\n  client: FetchClientInstance,\n  companyId: number,\n): Promise<SwitchCompanyResponse> {\n  return client\n    .put<unknown>(`/authentication/company/${companyId}/switch`)\n    .then((data) => switchCompanyResponseSchema.parse(data));\n}\n","/**\n * Core page template IDs\n */\nexport const CORE_PAGE_IDS = {\n  PROFILE: \"core-profile\",\n  MESSAGING: \"core-messaging\",\n  CONTACTS: \"core-contacts\",\n  ORDERS: \"core-orders\",\n  SUBSCRIPTIONS: \"core-subscriptions\",\n  CUSTOMERS: \"core-customers\",\n  MY_SITE: \"core-my-site\",\n  SHAREABLES: \"core-shareables\",\n  SHOP: \"core-shop\",\n  APP_DOWNLOAD: \"core-app-download\",\n  ACTIVITY: \"core-activity\",\n} as const;\n","// Screen Components\nexport { ProfileScreen, profileScreenPropertySchema } from \"./ProfileScreen\";\nexport {\n  MessagingScreen,\n  messagingScreenPropertySchema,\n} from \"./MessagingScreen\";\nexport { ContactsScreen, contactsScreenPropertySchema } from \"./ContactsScreen\";\nexport { OrdersScreen, ordersScreenPropertySchema } from \"./OrdersScreen\";\nexport {\n  SubscriptionsScreen,\n  subscriptionsScreenPropertySchema,\n} from \"./SubscriptionsScreen\";\nexport {\n  CustomersScreen,\n  customersScreenPropertySchema,\n} from \"./CustomersScreen\";\nexport { MySiteScreen, mySiteScreenPropertySchema } from \"./MySiteScreen\";\nexport {\n  ShareablesScreen,\n  shareablesScreenPropertySchema,\n} from \"./ShareablesScreen\";\nexport { ShopScreen, shopScreenPropertySchema } from \"./ShopScreen\";\nexport {\n  AppDownloadScreen,\n  appDownloadScreenPropertySchema,\n} from \"./AppDownloadScreen\";\nexport { ActivityScreen, activityScreenPropertySchema } from \"./ActivityScreen\";\n\n// Re-export all property schemas as a lazy-loadable collection\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\n\nexport const screenPropertySchemas: Record<\n  string,\n  () => Promise<WidgetPropertySchema>\n> = {\n  ProfileScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./ProfileScreen\").then((m) => m.profileScreenPropertySchema),\n  MessagingScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./MessagingScreen\").then((m) => m.messagingScreenPropertySchema),\n  ContactsScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./ContactsScreen\").then((m) => m.contactsScreenPropertySchema),\n  OrdersScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./OrdersScreen\").then((m) => m.ordersScreenPropertySchema),\n  SubscriptionsScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./SubscriptionsScreen\").then(\n      (m) => m.subscriptionsScreenPropertySchema,\n    ),\n  CustomersScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./CustomersScreen\").then((m) => m.customersScreenPropertySchema),\n  MySiteScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./MySiteScreen\").then((m) => m.mySiteScreenPropertySchema),\n  ShareablesScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./ShareablesScreen\").then((m) => m.shareablesScreenPropertySchema),\n  ShopScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./ShopScreen\").then((m) => m.shopScreenPropertySchema),\n  AppDownloadScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./AppDownloadScreen\").then(\n      (m) => m.appDownloadScreenPropertySchema,\n    ),\n  ActivityScreen: (): Promise<WidgetPropertySchema> =>\n    import(\"./ActivityScreen\").then((m) => m.activityScreenPropertySchema),\n};\n\n// Page Template Registration\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\nimport { CORE_PAGE_IDS } from \"./core-page-ids\";\n\nexport { CORE_PAGE_IDS } from \"./core-page-ids\";\n\n/**\n * Register core page templates.\n * These are automatically registered when the SDK is imported.\n */\nfunction registerCorePageTemplates(): void {\n  // Profile Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.PROFILE,\n    slug: \"profile\",\n    name: \"Profile\",\n    description: \"User profile management\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"profile\", \"account\", \"user\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"ProfileScreen\",\n        id: \"profile-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Messaging Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.MESSAGING,\n    slug: \"messaging\",\n    name: \"Messaging\",\n    description: \"Messaging interface provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.COMMUNICATION,\n    tags: [\"messaging\", \"chat\", \"conversations\", \"communication\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"MessagingScreen\",\n        id: \"messaging-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Contacts Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.CONTACTS,\n    slug: \"contacts\",\n    name: \"Contacts\",\n    description: \"Contact management provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"contacts\", \"people\", \"address-book\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"ContactsScreen\",\n        id: \"contacts-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Orders Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.ORDERS,\n    slug: \"orders\",\n    name: \"Orders\",\n    description: \"Order management provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"orders\", \"commerce\", \"sales\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"OrdersScreen\",\n        id: \"orders-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Subscriptions Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.SUBSCRIPTIONS,\n    slug: \"subscriptions\",\n    name: \"Subscriptions\",\n    description: \"Subscription management provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"subscriptions\", \"recurring\", \"commerce\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"SubscriptionsScreen\",\n        id: \"subscriptions-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Customers Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.CUSTOMERS,\n    slug: \"customers\",\n    name: \"Customers\",\n    description: \"Customer management provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"customers\", \"people\", \"commerce\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"CustomersScreen\",\n        id: \"customers-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Shop Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.SHOP,\n    slug: \"shop\",\n    name: \"Shop\",\n    description: \"Product shop with catalog browsing and product details\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"shop\", \"store\", \"products\", \"commerce\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"ShopScreen\",\n        id: \"shop-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // MySite Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.MY_SITE,\n    slug: \"my-site\",\n    name: \"MySite\",\n    description: \"Personal site management provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"my-site\", \"website\", \"portal\", \"personal\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"MySiteScreen\",\n        id: \"my-site-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // App Download Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.APP_DOWNLOAD,\n    slug: \"app-download\",\n    name: \"App Download\",\n    description: \"Mobile app download page with store links and QR code\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"app-download\", \"mobile\", \"qr-code\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"AppDownloadScreen\",\n        id: \"app-download-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Shareables Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.SHAREABLES,\n    slug: \"share\",\n    name: \"Shareables\",\n    description:\n      \"Marketing assets and shareable content provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"shareables\", \"marketing\", \"assets\", \"media\", \"products\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"ShareablesScreen\",\n        id: \"shareables-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n\n  // Activity Screen\n  PageTemplateRegistry.register({\n    id: CORE_PAGE_IDS.ACTIVITY,\n    slug: \"activity\",\n    name: \"Activity\",\n    description: \"Paginated activity feed provided by Fluid Commerce\",\n    category: PAGE_CATEGORIES.CORE,\n    tags: [\"activity\", \"feed\", \"notifications\"],\n    version: \"1.0.0\",\n    isCore: true,\n    component_tree: [\n      {\n        type: \"ActivityScreen\",\n        id: \"activity-screen-root\",\n        props: {},\n      },\n    ],\n    defaultProps: {},\n  });\n}\n\n// Auto-register core templates on module load\nregisterCorePageTemplates();\n","import { useState, useMemo } from \"react\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n  Button,\n} from \"@fluid-app/ui-primitives\";\nimport { LayoutGrid } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { getSystemNavigationBySection } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport {\n  translateNavLabel,\n  translateSectionLabel,\n} from \"@fluid-app/portal-core/navigation/translate-nav-label\";\nimport { filterRepOnlySections } from \"../navigation/filter-nav-items\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { deniesRepSurfaces } from \"@fluid-app/portal-core/member-permissions\";\n\nexport interface QuickLinksDropdownProps {\n  onNavigate: (slug: string) => void;\n}\n\nexport function QuickLinksDropdown({\n  onNavigate,\n}: QuickLinksDropdownProps): React.JSX.Element {\n  const [open, setOpen] = useState(false);\n  const shellApi = useShellTranslation();\n  const { t } = shellApi;\n\n  const { data: account } = useAccount();\n  const canRep = !deniesRepSurfaces(account);\n\n  const sections = useMemo(() => {\n    const all = getSystemNavigationBySection();\n    return canRep ? all : filterRepOnlySections(all);\n  }, [canRep]);\n\n  return (\n    <Popover open={open} onOpenChange={setOpen}>\n      <PopoverTrigger asChild>\n        <Button\n          variant=\"ghost\"\n          size=\"sm\"\n          className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shrink-0\"\n          aria-label={t(\"nav_quick_links\")}\n        >\n          <LayoutGrid className=\"size-4\" />\n        </Button>\n      </PopoverTrigger>\n      <PopoverContent\n        align=\"end\"\n        className=\"w-175 max-w-[90vw] overflow-hidden rounded-lg p-0 shadow-lg\"\n      >\n        <div className=\"flex flex-col\">\n          {/* Header */}\n          <div className=\"bg-background flex items-center gap-2 border-b p-4\">\n            <LayoutGrid className=\"text-muted-foreground size-5\" />\n            <h3 className=\"text-foreground text-sm font-semibold\">\n              {t(\"nav_shortcuts\")}\n            </h3>\n          </div>\n\n          {/* Sections */}\n          <div className=\"bg-muted space-y-6 p-6\">\n            {Object.entries(sections).map(([sectionName, items]) => (\n              <div key={sectionName} className=\"space-y-3\">\n                <h3 className=\"text-foreground text-sm font-semibold\">\n                  {translateSectionLabel(shellApi, sectionName)}\n                </h3>\n                <div className=\"grid grid-cols-4 gap-2\">\n                  {items.map((item) => (\n                    <Button\n                      key={item.slug}\n                      variant=\"ghost\"\n                      className=\"text-sidebar-foreground hover:bg-sidebar-primary hover:text-sidebar-primary-foreground h-auto justify-start gap-2 rounded-lg px-3 py-2 text-sm\"\n                      onClick={() => {\n                        if (item.slug) onNavigate(item.slug);\n                        setOpen(false);\n                      }}\n                    >\n                      {item.icon && (\n                        <RepIcon name={item.icon} className=\"size-4 shrink-0\" />\n                      )}\n                      <span className=\"truncate\">\n                        {translateNavLabel(shellApi, item.slug, item.label)}\n                      </span>\n                    </Button>\n                  ))}\n                </div>\n              </div>\n            ))}\n          </div>\n        </div>\n      </PopoverContent>\n    </Popover>\n  );\n}\n","/**\n * Scaffold Manifest\n *\n * Tracks which files belong to the portal scaffold and their category.\n * Used by `fluid doctor` to detect drift between a scaffolded portal\n * and the canonical templates shipped with the SDK.\n *\n * Categories:\n * - \"entry\"          — App bootstrap files (main.tsx, index.css)\n * - \"config\"         — Developer-owned config (portal.config.ts, navigation.config.ts)\n * - \"infrastructure\" — Build/tooling config (vite, tsconfig, index.html, linting)\n */\n\nexport type FileCategory = \"entry\" | \"config\" | \"infrastructure\";\n\nexport interface ManifestEntry {\n  readonly category: FileCategory;\n}\n\n/**\n * Canonical scaffold file manifest.\n *\n * Files marked as \"entry\" or \"infrastructure\" are checked by `fluid doctor`.\n * Files marked as \"config\" are developer-owned and intentionally excluded from drift checks.\n */\nexport const SCAFFOLD_MANIFEST = {\n  version: 2,\n  files: {\n    \"src/main.tsx\": { category: \"entry\" },\n    \"src/index.css\": { category: \"entry\" },\n    \"index.html\": { category: \"infrastructure\" },\n    \"tsconfig.json\": { category: \"infrastructure\" },\n    \"vite.config.ts\": { category: \"infrastructure\" },\n    \".oxlintrc.json\": { category: \"infrastructure\" },\n  },\n  /** Developer-owned files — never checked for drift */\n  developerOwned: [\n    \"src/portal.config.ts\",\n    \"src/navigation.config.ts\",\n    \"src/screens/*\",\n  ],\n} as const;\n\nexport type ScaffoldFile = keyof typeof SCAFFOLD_MANIFEST.files;\n"],"mappings":"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"}