@memberjunction/ng-explorer-core 5.27.1 → 5.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/generated/lazy-feature-config.d.ts +1 -1
  2. package/dist/generated/lazy-feature-config.d.ts.map +1 -1
  3. package/dist/generated/lazy-feature-config.js +6 -1
  4. package/dist/generated/lazy-feature-config.js.map +1 -1
  5. package/dist/lib/generic/resource-container-component.d.ts +4 -0
  6. package/dist/lib/generic/resource-container-component.d.ts.map +1 -1
  7. package/dist/lib/generic/resource-container-component.js +9 -2
  8. package/dist/lib/generic/resource-container-component.js.map +1 -1
  9. package/dist/lib/resource-wrappers/artifact-resource.component.d.ts +12 -1
  10. package/dist/lib/resource-wrappers/artifact-resource.component.d.ts.map +1 -1
  11. package/dist/lib/resource-wrappers/artifact-resource.component.js +45 -9
  12. package/dist/lib/resource-wrappers/artifact-resource.component.js.map +1 -1
  13. package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts +12 -1
  14. package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts.map +1 -1
  15. package/dist/lib/resource-wrappers/chat-collections-resource.component.js +32 -4
  16. package/dist/lib/resource-wrappers/chat-collections-resource.component.js.map +1 -1
  17. package/dist/lib/shell/shell.component.d.ts +13 -1
  18. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  19. package/dist/lib/shell/shell.component.js +76 -16
  20. package/dist/lib/shell/shell.component.js.map +1 -1
  21. package/dist/lib/user-menu/base-user-menu.d.ts +2 -0
  22. package/dist/lib/user-menu/base-user-menu.d.ts.map +1 -1
  23. package/dist/lib/user-menu/base-user-menu.js +19 -0
  24. package/dist/lib/user-menu/base-user-menu.js.map +1 -1
  25. package/dist/lib/user-menu/user-menu.types.d.ts +2 -0
  26. package/dist/lib/user-menu/user-menu.types.d.ts.map +1 -1
  27. package/dist/lib/user-menu/user-menu.types.js.map +1 -1
  28. package/package.json +41 -40
@@ -19,15 +19,16 @@ import * as i5 from "@memberjunction/ng-user-avatar";
19
19
  import * as i6 from "./services/settings-dialog.service";
20
20
  import * as i7 from "../command-palette/command-palette.service";
21
21
  import * as i8 from "@memberjunction/ng-file-storage";
22
- import * as i9 from "@angular/forms";
23
- import * as i10 from "@memberjunction/ng-ui-components";
24
- import * as i11 from "@memberjunction/ng-shared-generic";
25
- import * as i12 from "@memberjunction/ng-search";
26
- import * as i13 from "./components/header/app-switcher.component";
27
- import * as i14 from "./components/header/app-nav.component";
28
- import * as i15 from "./components/tabs/tab-container.component";
29
- import * as i16 from "./components/dialogs/app-access-dialog.component";
30
- import * as i17 from "../command-palette/command-palette.component";
22
+ import * as i9 from "@memberjunction/ng-feedback";
23
+ import * as i10 from "@angular/forms";
24
+ import * as i11 from "@memberjunction/ng-ui-components";
25
+ import * as i12 from "@memberjunction/ng-shared-generic";
26
+ import * as i13 from "@memberjunction/ng-search";
27
+ import * as i14 from "./components/header/app-switcher.component";
28
+ import * as i15 from "./components/header/app-nav.component";
29
+ import * as i16 from "./components/tabs/tab-container.component";
30
+ import * as i17 from "./components/dialogs/app-access-dialog.component";
31
+ import * as i18 from "../command-palette/command-palette.component";
31
32
  const _c0 = ["searchInput"];
32
33
  const _c1 = ["shellSearchComposite"];
33
34
  const _c2 = ["appAccessDialog"];
@@ -362,6 +363,8 @@ export class ShellComponent {
362
363
  themeService;
363
364
  homePinService;
364
365
  fileOpenService;
366
+ feedbackDialogService;
367
+ feedbackService;
365
368
  subscriptions = [];
366
369
  urlBasedNavigation = false; // Track if we're loading from a URL
367
370
  initialNavigationComplete = false; // Track if initial navigation has completed
@@ -447,7 +450,7 @@ export class ShellComponent {
447
450
  return this.appManager.GetNavBarApps('Left of User Menu')
448
451
  .filter(app => !(app.HideNavBarIconWhenActive && UUIDsEqual(app.ID, this.activeApp?.ID)));
449
452
  }
450
- constructor(appManager, workspaceManager, layoutManager, tabService, navigationService, route, router, authBase, cdr, userAvatarService, settingsDialogService, viewContainerRef, titleService, developerModeService, commandPaletteService, themeService, homePinService, fileOpenService) {
453
+ constructor(appManager, workspaceManager, layoutManager, tabService, navigationService, route, router, authBase, cdr, userAvatarService, settingsDialogService, viewContainerRef, titleService, developerModeService, commandPaletteService, themeService, homePinService, fileOpenService, feedbackDialogService, feedbackService) {
451
454
  this.appManager = appManager;
452
455
  this.workspaceManager = workspaceManager;
453
456
  this.layoutManager = layoutManager;
@@ -466,6 +469,8 @@ export class ShellComponent {
466
469
  this.themeService = themeService;
467
470
  this.homePinService = homePinService;
468
471
  this.fileOpenService = fileOpenService;
472
+ this.feedbackDialogService = feedbackDialogService;
473
+ this.feedbackService = feedbackService;
469
474
  // Initialize theme immediately so loading UI shows correct colors from the start
470
475
  this.activeTheme = getActiveTheme();
471
476
  // Initialize animation based on theme configuration
@@ -1961,6 +1966,8 @@ export class ShellComponent {
1961
1966
  if (this.userEntity) {
1962
1967
  await this.developerModeService.Initialize(this.userEntity);
1963
1968
  }
1969
+ // Check org-level feedback kill switch (defaults to enabled on error)
1970
+ const feedbackEnabled = await this.feedbackService.IsEnabled();
1964
1971
  // Build context for the menu
1965
1972
  const context = {
1966
1973
  user: new Metadata().CurrentUser,
@@ -1976,7 +1983,8 @@ export class ShellComponent {
1976
1983
  openSettings: () => this.openSettingsDialog(),
1977
1984
  themePreference: this.themeService.Preference,
1978
1985
  availableThemes: this.themeService.AvailableThemes,
1979
- appliedTheme: this.themeService.AppliedTheme
1986
+ appliedTheme: this.themeService.AppliedTheme,
1987
+ feedbackEnabled
1980
1988
  };
1981
1989
  // Initialize menu
1982
1990
  await this.userMenu.Initialize(context);
@@ -2057,6 +2065,11 @@ export class ShellComponent {
2057
2065
  this.hidePinProgress();
2058
2066
  return;
2059
2067
  }
2068
+ if (result.message === 'submit-feedback') {
2069
+ this.userMenuVisible = false;
2070
+ this.ShowFeedbackDialog();
2071
+ return;
2072
+ }
2060
2073
  if (result.closeMenu) {
2061
2074
  this.userMenuVisible = false;
2062
2075
  }
@@ -2541,6 +2554,53 @@ export class ShellComponent {
2541
2554
  IsPinned: false
2542
2555
  });
2543
2556
  }
2557
+ /**
2558
+ * Open the feedback dialog with current workspace context.
2559
+ * Captures a screenshot in the background and attaches it once ready.
2560
+ */
2561
+ async ShowFeedbackDialog() {
2562
+ // Check if feedback is enabled for this org
2563
+ const enabled = await this.feedbackService.IsEnabled();
2564
+ if (!enabled) {
2565
+ return;
2566
+ }
2567
+ const config = this.workspaceManager.GetConfiguration();
2568
+ const currentPage = config?.tabs
2569
+ ?.map(t => t.title)
2570
+ .filter(Boolean)
2571
+ .join(' \u2192 ') || undefined;
2572
+ // Open dialog immediately — screenshot loads in background
2573
+ this.feedbackDialogService.OpenFeedbackDialog({ currentPage });
2574
+ // Capture screenshot in background and attach when ready
2575
+ this.captureAndAttachFeedbackScreenshot();
2576
+ }
2577
+ /**
2578
+ * Capture a screenshot in the background and attach it to the open feedback dialog.
2579
+ */
2580
+ async captureAndAttachFeedbackScreenshot() {
2581
+ try {
2582
+ let screenshot;
2583
+ if (this.tabContainerRef) {
2584
+ screenshot = await this.tabContainerRef.CaptureActiveThumbnail();
2585
+ }
2586
+ if (!screenshot) {
2587
+ const contentEl = document.querySelector('.shell-content')
2588
+ || document.querySelector('mj-tab-container');
2589
+ if (contentEl) {
2590
+ screenshot = await this.homePinService.CaptureThumbnail(contentEl);
2591
+ }
2592
+ }
2593
+ if (screenshot) {
2594
+ this.feedbackDialogService.AttachScreenshot(screenshot);
2595
+ }
2596
+ else {
2597
+ this.feedbackDialogService.StopScreenshotLoading();
2598
+ }
2599
+ }
2600
+ catch {
2601
+ this.feedbackDialogService.StopScreenshotLoading();
2602
+ }
2603
+ }
2544
2604
  // ========================================
2545
2605
  // APP ACCESS ERROR HANDLING
2546
2606
  // ========================================
@@ -2786,7 +2846,7 @@ export class ShellComponent {
2786
2846
  this.cdr.detectChanges();
2787
2847
  }
2788
2848
  }
2789
- static ɵfac = function ShellComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShellComponent)(i0.ɵɵdirectiveInject(i1.ApplicationManager), i0.ɵɵdirectiveInject(i1.WorkspaceStateManager), i0.ɵɵdirectiveInject(i1.GoldenLayoutManager), i0.ɵɵdirectiveInject(i1.TabService), i0.ɵɵdirectiveInject(i2.NavigationService), i0.ɵɵdirectiveInject(i3.ActivatedRoute), i0.ɵɵdirectiveInject(i3.Router), i0.ɵɵdirectiveInject(i4.MJAuthBase), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i5.UserAvatarService), i0.ɵɵdirectiveInject(i6.SettingsDialogService), i0.ɵɵdirectiveInject(i0.ViewContainerRef), i0.ɵɵdirectiveInject(i2.TitleService), i0.ɵɵdirectiveInject(i2.DeveloperModeService), i0.ɵɵdirectiveInject(i7.CommandPaletteService), i0.ɵɵdirectiveInject(i2.ThemeService), i0.ɵɵdirectiveInject(i2.HomeAppPinService), i0.ɵɵdirectiveInject(i8.FileOpenService)); };
2849
+ static ɵfac = function ShellComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShellComponent)(i0.ɵɵdirectiveInject(i1.ApplicationManager), i0.ɵɵdirectiveInject(i1.WorkspaceStateManager), i0.ɵɵdirectiveInject(i1.GoldenLayoutManager), i0.ɵɵdirectiveInject(i1.TabService), i0.ɵɵdirectiveInject(i2.NavigationService), i0.ɵɵdirectiveInject(i3.ActivatedRoute), i0.ɵɵdirectiveInject(i3.Router), i0.ɵɵdirectiveInject(i4.MJAuthBase), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i5.UserAvatarService), i0.ɵɵdirectiveInject(i6.SettingsDialogService), i0.ɵɵdirectiveInject(i0.ViewContainerRef), i0.ɵɵdirectiveInject(i2.TitleService), i0.ɵɵdirectiveInject(i2.DeveloperModeService), i0.ɵɵdirectiveInject(i7.CommandPaletteService), i0.ɵɵdirectiveInject(i2.ThemeService), i0.ɵɵdirectiveInject(i2.HomeAppPinService), i0.ɵɵdirectiveInject(i8.FileOpenService), i0.ɵɵdirectiveInject(i9.FeedbackDialogService), i0.ɵɵdirectiveInject(i9.FeedbackService)); };
2790
2850
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShellComponent, selectors: [["mj-shell"]], viewQuery: function ShellComponent_Query(rf, ctx) { if (rf & 1) {
2791
2851
  i0.ɵɵviewQuery(_c0, 5)(_c1, 5)(TabContainerComponent, 5)(_c2, 5);
2792
2852
  } if (rf & 2) {
@@ -2910,12 +2970,12 @@ export class ShellComponent {
2910
2970
  i0.ɵɵconditional(ctx.loading ? 47 : -1);
2911
2971
  i0.ɵɵadvance(4);
2912
2972
  i0.ɵɵconditional(ctx.PinProgressVisible ? 51 : -1);
2913
- } }, dependencies: [i9.NgControlStatus, i9.NgModel, i10.MJDropdownComponent, i11.LoadingComponent, i12.SearchCompositeComponent, i13.AppSwitcherComponent, i14.AppNavComponent, i15.TabContainerComponent, i16.AppAccessDialogComponent, i17.CommandPaletteComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: 32px;\n height: 18px;\n background-image: var(--mj-logo-mark);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n\n\n\n.shell-container.hidden[_ngcontent-%COMP%] {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n \n\n\n position: relative;\n z-index: 500;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.15s ease;\n margin-top: 2px; \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 16px;\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-email[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n transition: background 0.15s;\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n}\n\n\n\n.user-menu-item.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n\n\n.theme-toggle-item[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.theme-toggle-track[_ngcontent-%COMP%] {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: 11px;\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background 0.2s ease;\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s ease;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-thumb[_ngcontent-%COMP%] {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n\n\n.user-menu-item[_ngcontent-%COMP%] .menu-shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n\n\n.user-context-menu.menu-fade[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuSlideIn 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100vh;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n\n\n.loading-reset-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: _ngcontent-%COMP%_resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes _ngcontent-%COMP%_resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 16px;\n color: var(--mj-text-primary);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] {\n flex: 0 1 420px;\n min-width: 200px;\n max-width: 520px;\n margin: 0 12px;\n position: relative;\n z-index: 99999;\n}\n@media (max-width: 768px) {\n .shell-search-bar[_ngcontent-%COMP%] { display: none; }\n}\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: absolute;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}\n\n\n\n\n\n.pin-progress-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: _ngcontent-%COMP%_pinBackdropIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: 28px 40px;\n display: flex;\n align-items: center;\n gap: 16px;\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: _ngcontent-%COMP%_pinModalIn 0.25s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}"] });
2973
+ } }, dependencies: [i10.NgControlStatus, i10.NgModel, i11.MJDropdownComponent, i12.LoadingComponent, i13.SearchCompositeComponent, i14.AppSwitcherComponent, i15.AppNavComponent, i16.TabContainerComponent, i17.AppAccessDialogComponent, i18.CommandPaletteComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: 32px;\n height: 18px;\n background-image: var(--mj-logo-mark);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n\n\n\n.shell-container.hidden[_ngcontent-%COMP%] {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n \n\n\n position: relative;\n z-index: 500;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.15s ease;\n margin-top: 2px; \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 16px;\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-email[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n transition: background 0.15s;\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n}\n\n\n\n.user-menu-item.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n\n\n.theme-toggle-item[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.theme-toggle-track[_ngcontent-%COMP%] {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: 11px;\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background 0.2s ease;\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s ease;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-thumb[_ngcontent-%COMP%] {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n\n\n.user-menu-item[_ngcontent-%COMP%] .menu-shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n\n\n.user-context-menu.menu-fade[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuSlideIn 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100vh;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n\n\n.loading-reset-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: _ngcontent-%COMP%_resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes _ngcontent-%COMP%_resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 16px;\n color: var(--mj-text-primary);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] {\n flex: 0 1 420px;\n min-width: 200px;\n max-width: 520px;\n margin: 0 12px;\n position: relative;\n z-index: 99999;\n}\n@media (max-width: 768px) {\n .shell-search-bar[_ngcontent-%COMP%] { display: none; }\n}\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: absolute;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}\n\n\n\n\n\n.pin-progress-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: _ngcontent-%COMP%_pinBackdropIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: 28px 40px;\n display: flex;\n align-items: center;\n gap: 16px;\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: _ngcontent-%COMP%_pinModalIn 0.25s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}"] });
2914
2974
  }
2915
2975
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShellComponent, [{
2916
2976
  type: Component,
2917
- args: [{ standalone: false, selector: 'mj-shell', template: "<div class=\"shell-container\" [class.hidden]=\"loading\" [class.tabs-visible]=\"tabBarVisible\">\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n @if (leftOfSwitcherApps.length > 0) {\n <div class=\"nav-bar-apps left-of-switcher\">\n @for (app of leftOfSwitcherApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <!-- App Switcher -->\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n\n <!-- App Navigation (desktop only) -->\n @if (activeApp) {\n <mj-app-nav\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n }\n\n <!-- Universal Search Bar -->\n @if (ShowSearchBar) {\n <div class=\"shell-search-bar desktop-only\">\n <mj-search-composite\n #shellSearchComposite\n Placeholder=\"Search everything...\"\n [ShowShortcutHint]=\"true\"\n [EnablePreview]=\"ShowSearchPreview\"\n [EnableRecent]=\"true\"\n [MaxPreviewResults]=\"8\"\n (ResultSelected)=\"OnSearchResultSelected($event)\"\n (SearchSubmitted)=\"OnSearchSubmitted($event)\"\n (SeeAllRequested)=\"OnSeeAllSearch($event)\">\n </mj-search-composite>\n </div>\n }\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n <!-- Actions (notifications, user menu) -->\n <div class=\"header-actions\">\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n\n <!-- Nav Bar Apps: Left of User Menu -->\n @if (leftOfUserMenuApps.length > 0) {\n <div class=\"nav-bar-apps left-of-user-menu\">\n @for (app of leftOfUserMenuApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n @if (userImageURL) {\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n } @else {\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n }\n </button>\n <!-- User Context Menu (Dynamic) -->\n @if (userMenuVisible) {\n <div class=\"user-context-menu\"\n [class.menu-fade]=\"getUserMenuOptions()?.animationStyle === 'fade'\"\n [class.menu-slide]=\"getUserMenuOptions()?.animationStyle === 'slide'\">\n <!-- User Header -->\n @if (getUserMenuOptions()?.showUserName) {\n <div class=\"user-menu-header\">\n <div class=\"user-info\">\n <span class=\"user-name\">{{ getUserDisplayInfo()?.name || userName }}</span>\n @if (getUserMenuOptions()?.showUserEmail && getUserDisplayInfo()?.email) {\n <span class=\"user-email\">\n {{ getUserDisplayInfo()?.email }}\n </span>\n }\n @if (getUserDisplayInfo()?.subtitle) {\n <span class=\"user-subtitle\">{{ getUserDisplayInfo()?.subtitle }}</span>\n }\n </div>\n </div>\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Dynamic Menu Items -->\n @for (element of userMenuElements; track element) {\n <!-- Divider -->\n @if (isMenuDivider(element)) {\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Menu Item -->\n @if (!isMenuDivider(element)) {\n @if (asMenuItem(element); as item) {\n @if (item.id === 'toggle-theme') {\n <div class=\"user-menu-item theme-toggle-item\"\n [title]=\"item.tooltip || ''\"\n (click)=\"onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n <div class=\"theme-toggle-track\" [class.dark]=\"IsDarkMode\">\n <div class=\"theme-toggle-thumb\">\n <i [class]=\"IsDarkMode ? 'fa-solid fa-moon' : 'fa-solid fa-sun'\" class=\"theme-toggle-icon\"></i>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"user-menu-item\"\n [class.disabled]=\"!item.enabled\"\n [class.danger]=\"item.cssClass === 'danger'\"\n [style.color]=\"item.color || null\"\n [title]=\"item.tooltip || ''\"\n (click)=\"item.enabled && onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"menu-shortcut\">{{ item.shortcut }}</span>\n }\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n @if (isSearchOpen) {\n <div class=\"search-popup-overlay\" (click)=\"closeSearch()\"></div>\n }\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <mj-dropdown\n [Data]=\"searchableEntities\"\n TextField=\"Name\"\n ValueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </mj-dropdown>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n class=\"mj-input search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n @if (mobileNavOpen) {\n <div class=\"mobile-nav-overlay\" (click)=\"closeMobileNav()\"></div>\n }\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n @if (activeApp) {\n <div class=\"mobile-nav-content\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n </div>\n }\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge-mobile\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container\n [class.hide-tab-bar]=\"!tabBarVisible\"\n (firstResourceLoadComplete)=\"onFirstResourceLoadComplete()\"\n (layoutInitError)=\"handleLayoutError()\">\n </mj-tab-container>\n</div>\n\n<!-- Loading State -->\n@if (loading) {\n <div class=\"shell-loading\">\n <mj-loading\n [text]=\"currentLoadingText\"\n [textColor]=\"currentLoadingTextColor\"\n [logoColor]=\"currentLoadingColor\"\n [logoGradient]=\"currentLoadingGradient\"\n [animation]=\"currentLoadingAnimation\"\n size=\"large\">\n </mj-loading>\n @if (ShowResetOption) {\n <div class=\"loading-reset-panel\">\n <p class=\"loading-reset-message\">\n <i class=\"fa-regular fa-clock\"></i>\n Taking longer than expected\n </p>\n <p class=\"loading-reset-hint\">\n This can happen after updates or due to cached data issues.\n </p>\n <button class=\"loading-reset-btn\" (click)=\"ResetApplication()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n Reset\n </button>\n </div>\n }\n </div>\n}\n\n<!-- App Access Error Dialog -->\n<mj-app-access-dialog\n #appAccessDialog\n (result)=\"onAppAccessDialogResult($event)\">\n</mj-app-access-dialog>\n\n<!-- Command Palette -->\n<mj-command-palette (AppSelected)=\"onAppSwitch($event)\"></mj-command-palette>\n\n<!-- Pin Progress Overlay -->\n@if (PinProgressVisible) {\n <div class=\"pin-progress-backdrop\">\n <div class=\"pin-progress-modal\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span class=\"pin-progress-text\">{{ PinProgressText }}</span>\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - uses design token for theme switching & white-labeling */\n.mj-logo {\n width: 32px;\n height: 18px;\n background-image: var(--mj-logo-mark);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* Hide shell container while loading - allows tab container to render and load\n first resource in background while shell loading indicator is visible */\n.shell-container.hidden {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n /* Creates a stacking context so children (search bar z-index: 99999, dropdown)\n are contained within this level. Modal overlays (z-index: 1000+) sit above. */\n position: relative;\n z-index: 500;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn i {\n transition: transform 0.15s ease;\n margin-top: 2px; /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: var(--mj-text-muted);\n font-size: 16px;\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header .user-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.user-menu-header .user-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.user-menu-header .user-email {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.user-menu-header .user-subtitle {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n transition: background 0.15s;\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.user-menu-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger i {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n}\n\n/* Menu item disabled state */\n.user-menu-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled:hover {\n background: transparent;\n}\n\n/* Theme Toggle Switch */\n.theme-toggle-item {\n cursor: pointer;\n}\n\n.theme-toggle-track {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: 11px;\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background 0.2s ease;\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s ease;\n}\n\n.theme-toggle-track.dark .theme-toggle-thumb {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark .theme-toggle-icon {\n color: var(--mj-text-inverse);\n}\n\n/* Menu shortcut hint */\n.user-menu-item .menu-shortcut {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n/* Menu animations */\n.user-context-menu.menu-fade {\n animation: menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide {\n animation: menuSlideIn 0.2s ease-out;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100vh;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n/* Loading Recovery Reset Panel */\n.loading-reset-panel {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message i {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn i {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header span {\n font-weight: 600;\n font-size: 16px;\n color: var(--mj-text-primary);\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header .close-btn:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action i {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* ========================================\n UNIVERSAL SEARCH BAR\n ======================================== */\n.shell-search-bar {\n flex: 0 1 420px;\n min-width: 200px;\n max-width: 520px;\n margin: 0 12px;\n position: relative;\n z-index: 99999;\n}\n@media (max-width: 768px) {\n .shell-search-bar { display: none; }\n}\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: absolute;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn:active {\n background: var(--mj-brand-primary-hover);\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}\n\n/* ========================================\n PIN PROGRESS OVERLAY\n ======================================== */\n.pin-progress-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: pinBackdropIn 0.2s ease;\n}\n\n@keyframes pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: 28px 40px;\n display: flex;\n align-items: center;\n gap: 16px;\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: pinModalIn 0.25s ease;\n}\n\n@keyframes pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}"] }]
2918
- }], () => [{ type: i1.ApplicationManager }, { type: i1.WorkspaceStateManager }, { type: i1.GoldenLayoutManager }, { type: i1.TabService }, { type: i2.NavigationService }, { type: i3.ActivatedRoute }, { type: i3.Router }, { type: i4.MJAuthBase }, { type: i0.ChangeDetectorRef }, { type: i5.UserAvatarService }, { type: i6.SettingsDialogService }, { type: i0.ViewContainerRef }, { type: i2.TitleService }, { type: i2.DeveloperModeService }, { type: i7.CommandPaletteService }, { type: i2.ThemeService }, { type: i2.HomeAppPinService }, { type: i8.FileOpenService }], { searchInput: [{
2977
+ args: [{ standalone: false, selector: 'mj-shell', template: "<div class=\"shell-container\" [class.hidden]=\"loading\" [class.tabs-visible]=\"tabBarVisible\">\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n @if (leftOfSwitcherApps.length > 0) {\n <div class=\"nav-bar-apps left-of-switcher\">\n @for (app of leftOfSwitcherApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <!-- App Switcher -->\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n\n <!-- App Navigation (desktop only) -->\n @if (activeApp) {\n <mj-app-nav\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n }\n\n <!-- Universal Search Bar -->\n @if (ShowSearchBar) {\n <div class=\"shell-search-bar desktop-only\">\n <mj-search-composite\n #shellSearchComposite\n Placeholder=\"Search everything...\"\n [ShowShortcutHint]=\"true\"\n [EnablePreview]=\"ShowSearchPreview\"\n [EnableRecent]=\"true\"\n [MaxPreviewResults]=\"8\"\n (ResultSelected)=\"OnSearchResultSelected($event)\"\n (SearchSubmitted)=\"OnSearchSubmitted($event)\"\n (SeeAllRequested)=\"OnSeeAllSearch($event)\">\n </mj-search-composite>\n </div>\n }\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n <!-- Actions (notifications, user menu) -->\n <div class=\"header-actions\">\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n <!-- Nav Bar Apps: Left of User Menu -->\n @if (leftOfUserMenuApps.length > 0) {\n <div class=\"nav-bar-apps left-of-user-menu\">\n @for (app of leftOfUserMenuApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n @if (userImageURL) {\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n } @else {\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n }\n </button>\n <!-- User Context Menu (Dynamic) -->\n @if (userMenuVisible) {\n <div class=\"user-context-menu\"\n [class.menu-fade]=\"getUserMenuOptions()?.animationStyle === 'fade'\"\n [class.menu-slide]=\"getUserMenuOptions()?.animationStyle === 'slide'\">\n <!-- User Header -->\n @if (getUserMenuOptions()?.showUserName) {\n <div class=\"user-menu-header\">\n <div class=\"user-info\">\n <span class=\"user-name\">{{ getUserDisplayInfo()?.name || userName }}</span>\n @if (getUserMenuOptions()?.showUserEmail && getUserDisplayInfo()?.email) {\n <span class=\"user-email\">\n {{ getUserDisplayInfo()?.email }}\n </span>\n }\n @if (getUserDisplayInfo()?.subtitle) {\n <span class=\"user-subtitle\">{{ getUserDisplayInfo()?.subtitle }}</span>\n }\n </div>\n </div>\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Dynamic Menu Items -->\n @for (element of userMenuElements; track element) {\n <!-- Divider -->\n @if (isMenuDivider(element)) {\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Menu Item -->\n @if (!isMenuDivider(element)) {\n @if (asMenuItem(element); as item) {\n @if (item.id === 'toggle-theme') {\n <div class=\"user-menu-item theme-toggle-item\"\n [title]=\"item.tooltip || ''\"\n (click)=\"onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n <div class=\"theme-toggle-track\" [class.dark]=\"IsDarkMode\">\n <div class=\"theme-toggle-thumb\">\n <i [class]=\"IsDarkMode ? 'fa-solid fa-moon' : 'fa-solid fa-sun'\" class=\"theme-toggle-icon\"></i>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"user-menu-item\"\n [class.disabled]=\"!item.enabled\"\n [class.danger]=\"item.cssClass === 'danger'\"\n [style.color]=\"item.color || null\"\n [title]=\"item.tooltip || ''\"\n (click)=\"item.enabled && onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"menu-shortcut\">{{ item.shortcut }}</span>\n }\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n @if (isSearchOpen) {\n <div class=\"search-popup-overlay\" (click)=\"closeSearch()\"></div>\n }\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <mj-dropdown\n [Data]=\"searchableEntities\"\n TextField=\"Name\"\n ValueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </mj-dropdown>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n class=\"mj-input search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n @if (mobileNavOpen) {\n <div class=\"mobile-nav-overlay\" (click)=\"closeMobileNav()\"></div>\n }\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n @if (activeApp) {\n <div class=\"mobile-nav-content\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n </div>\n }\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge-mobile\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container\n [class.hide-tab-bar]=\"!tabBarVisible\"\n (firstResourceLoadComplete)=\"onFirstResourceLoadComplete()\"\n (layoutInitError)=\"handleLayoutError()\">\n </mj-tab-container>\n</div>\n\n<!-- Loading State -->\n@if (loading) {\n <div class=\"shell-loading\">\n <mj-loading\n [text]=\"currentLoadingText\"\n [textColor]=\"currentLoadingTextColor\"\n [logoColor]=\"currentLoadingColor\"\n [logoGradient]=\"currentLoadingGradient\"\n [animation]=\"currentLoadingAnimation\"\n size=\"large\">\n </mj-loading>\n @if (ShowResetOption) {\n <div class=\"loading-reset-panel\">\n <p class=\"loading-reset-message\">\n <i class=\"fa-regular fa-clock\"></i>\n Taking longer than expected\n </p>\n <p class=\"loading-reset-hint\">\n This can happen after updates or due to cached data issues.\n </p>\n <button class=\"loading-reset-btn\" (click)=\"ResetApplication()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n Reset\n </button>\n </div>\n }\n </div>\n}\n\n<!-- App Access Error Dialog -->\n<mj-app-access-dialog\n #appAccessDialog\n (result)=\"onAppAccessDialogResult($event)\">\n</mj-app-access-dialog>\n\n<!-- Command Palette -->\n<mj-command-palette (AppSelected)=\"onAppSwitch($event)\"></mj-command-palette>\n\n<!-- Pin Progress Overlay -->\n@if (PinProgressVisible) {\n <div class=\"pin-progress-backdrop\">\n <div class=\"pin-progress-modal\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span class=\"pin-progress-text\">{{ PinProgressText }}</span>\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - uses design token for theme switching & white-labeling */\n.mj-logo {\n width: 32px;\n height: 18px;\n background-image: var(--mj-logo-mark);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* Hide shell container while loading - allows tab container to render and load\n first resource in background while shell loading indicator is visible */\n.shell-container.hidden {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n /* Creates a stacking context so children (search bar z-index: 99999, dropdown)\n are contained within this level. Modal overlays (z-index: 1000+) sit above. */\n position: relative;\n z-index: 500;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn i {\n transition: transform 0.15s ease;\n margin-top: 2px; /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: var(--mj-text-muted);\n font-size: 16px;\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header .user-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.user-menu-header .user-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.user-menu-header .user-email {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.user-menu-header .user-subtitle {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n transition: background 0.15s;\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.user-menu-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger i {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n}\n\n/* Menu item disabled state */\n.user-menu-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled:hover {\n background: transparent;\n}\n\n/* Theme Toggle Switch */\n.theme-toggle-item {\n cursor: pointer;\n}\n\n.theme-toggle-track {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: 11px;\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background 0.2s ease;\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s ease;\n}\n\n.theme-toggle-track.dark .theme-toggle-thumb {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark .theme-toggle-icon {\n color: var(--mj-text-inverse);\n}\n\n/* Menu shortcut hint */\n.user-menu-item .menu-shortcut {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n/* Menu animations */\n.user-context-menu.menu-fade {\n animation: menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide {\n animation: menuSlideIn 0.2s ease-out;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100vh;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n/* Loading Recovery Reset Panel */\n.loading-reset-panel {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message i {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn i {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header span {\n font-weight: 600;\n font-size: 16px;\n color: var(--mj-text-primary);\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header .close-btn:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action i {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 12px 16px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* ========================================\n UNIVERSAL SEARCH BAR\n ======================================== */\n.shell-search-bar {\n flex: 0 1 420px;\n min-width: 200px;\n max-width: 520px;\n margin: 0 12px;\n position: relative;\n z-index: 99999;\n}\n@media (max-width: 768px) {\n .shell-search-bar { display: none; }\n}\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: absolute;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn:active {\n background: var(--mj-brand-primary-hover);\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}\n\n/* ========================================\n PIN PROGRESS OVERLAY\n ======================================== */\n.pin-progress-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: pinBackdropIn 0.2s ease;\n}\n\n@keyframes pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: 28px 40px;\n display: flex;\n align-items: center;\n gap: 16px;\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: pinModalIn 0.25s ease;\n}\n\n@keyframes pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}"] }]
2978
+ }], () => [{ type: i1.ApplicationManager }, { type: i1.WorkspaceStateManager }, { type: i1.GoldenLayoutManager }, { type: i1.TabService }, { type: i2.NavigationService }, { type: i3.ActivatedRoute }, { type: i3.Router }, { type: i4.MJAuthBase }, { type: i0.ChangeDetectorRef }, { type: i5.UserAvatarService }, { type: i6.SettingsDialogService }, { type: i0.ViewContainerRef }, { type: i2.TitleService }, { type: i2.DeveloperModeService }, { type: i7.CommandPaletteService }, { type: i2.ThemeService }, { type: i2.HomeAppPinService }, { type: i8.FileOpenService }, { type: i9.FeedbackDialogService }, { type: i9.FeedbackService }], { searchInput: [{
2919
2979
  type: ViewChild,
2920
2980
  args: ['searchInput']
2921
2981
  }], shellSearchComposite: [{
@@ -2934,5 +2994,5 @@ export class ShellComponent {
2934
2994
  type: HostListener,
2935
2995
  args: ['document:keydown', ['$event']]
2936
2996
  }] }); })();
2937
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber: 47 }); })();
2997
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber: 48 }); })();
2938
2998
  //# sourceMappingURL=shell.component.js.map