@eric-emg/symphiq-components 1.2.246 → 1.2.248

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.
@@ -13667,39 +13667,39 @@ class RelatedRecommendationChipsComponent {
13667
13667
  standalone: true,
13668
13668
  imports: [CommonModule, SymphiqIconComponent],
13669
13669
  changeDetection: ChangeDetectionStrategy.OnPush,
13670
- template: `
13671
- @if (displayedRecommendations().length > 0) {
13672
- <div class="space-y-3">
13673
- <div class="flex flex-wrap gap-2">
13674
- @for (rec of displayedRecommendations(); track rec.id) {
13675
- <button
13676
- type="button"
13677
- [ngClass]="getChipClasses(rec)"
13678
- (click)="openRecommendationModal(rec.id!, $event)"
13679
- class="transition-all duration-200 cursor-pointer"
13680
- >
13681
- <symphiq-icon [icon]="getPriorityIcon(rec)" size="w-3.5 h-3.5" class="flex-shrink-0"></symphiq-icon>
13682
- <span class="font-medium">{{ rec.title }}</span>
13683
- <symphiq-icon [icon]="{ name: 'chevron-right', source: IconSourceEnum.HEROICONS }" size="w-3.5 h-3.5" class="flex-shrink-0 opacity-60"></symphiq-icon>
13684
- </button>
13685
- }
13686
- </div>
13687
-
13688
- @if (hasMoreRecommendations()) {
13689
- <button
13690
- type="button"
13691
- (click)="toggleShowAll($event)"
13692
- [ngClass]="getViewMoreButtonClasses()"
13693
- class="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer"
13694
- >
13695
- <span>{{ showAll() ? 'Show Less' : 'View More' }}</span>
13696
- <svg class="w-4 h-4 transition-transform duration-200" [class.rotate-180]="showAll()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
13697
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
13698
- </svg>
13699
- </button>
13700
- }
13701
- </div>
13702
- }
13670
+ template: `
13671
+ @if (displayedRecommendations().length > 0) {
13672
+ <div class="space-y-3">
13673
+ <div class="flex flex-wrap gap-2">
13674
+ @for (rec of displayedRecommendations(); track rec.id) {
13675
+ <button
13676
+ type="button"
13677
+ [ngClass]="getChipClasses(rec)"
13678
+ (click)="openRecommendationModal(rec.id!, $event)"
13679
+ class="transition-all duration-200 cursor-pointer"
13680
+ >
13681
+ <symphiq-icon [icon]="getPriorityIcon(rec)" size="w-3.5 h-3.5" class="flex-shrink-0"></symphiq-icon>
13682
+ <span class="font-medium">{{ rec.title }}</span>
13683
+ <symphiq-icon [icon]="{ name: 'chevron-right', source: IconSourceEnum.HEROICONS }" size="w-3.5 h-3.5" class="flex-shrink-0 opacity-60"></symphiq-icon>
13684
+ </button>
13685
+ }
13686
+ </div>
13687
+
13688
+ @if (hasMoreRecommendations()) {
13689
+ <button
13690
+ type="button"
13691
+ (click)="toggleShowAll($event)"
13692
+ [ngClass]="getViewMoreButtonClasses()"
13693
+ class="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer"
13694
+ >
13695
+ <span>{{ showAll() ? 'Show Less' : 'View More' }}</span>
13696
+ <svg class="w-4 h-4 transition-transform duration-200" [class.rotate-180]="showAll()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
13697
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
13698
+ </svg>
13699
+ </button>
13700
+ }
13701
+ </div>
13702
+ }
13703
13703
  `
13704
13704
  }]
13705
13705
  }], null, { recommendations: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendations", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], maxInitialDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxInitialDisplay", required: false }] }], inModalContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "inModalContext", required: false }] }] }); })();
@@ -47936,1001 +47936,1001 @@ class SymphiqFunnelAnalysisDashboardComponent {
47936
47936
  ViewModeSwitcherModalComponent,
47937
47937
  ProfileAnalysisModalComponent,
47938
47938
  BusinessAnalysisModalComponent,
47939
- ], template: `
47940
- <div
47941
- class="bg-transparent"
47942
- [class.min-h-screen]="!embedded()"
47943
- [class.relative]="!embedded()"
47944
- [style.display]="embedded() ? 'block' : null"
47945
- [style.min-height]="embedded() ? 'auto' : null"
47946
- #dashboardContainer>
47947
- <!-- Animated Background Bubbles -->
47948
- <div class="animated-bubbles" [class.light-mode]="isLightMode()" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100vw; height: 100vh; z-index: 1; pointer-events: none;"></div>
47949
-
47950
- <!-- Scroll Progress Bar -->
47951
- <div [class]="embedded() ? 'sticky top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30' : 'fixed top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30'">
47952
- <div
47953
- [style.width.%]="scrollProgress()"
47954
- [ngClass]="isLightMode() ? 'bg-gradient-to-r from-blue-500 to-purple-500' : 'bg-gradient-to-r from-blue-400 to-purple-400'"
47955
- class="h-full transition-all duration-200 ease-out">
47956
- </div>
47957
- </div>
47958
-
47959
- <header [class]="headerClass()" class="sticky top-0 z-50 animate-fade-in" style="animation-delay: 0s;">
47960
- <!-- Expanded Header (default state) -->
47961
- <div
47962
- class="transition-all duration-300 ease-in-out overflow-hidden"
47963
- [class.max-h-0]="isScrolled()"
47964
- [class.opacity-0]="isScrolled()"
47965
- [class.max-h-96]="!isScrolled()"
47966
- [class.opacity-100]="!isScrolled()">
47967
- <div
47968
- class="max-w-7xl mx-auto px-6 sm:px-8 py-6 sm:py-8"
47969
- [class.pointer-events-none]="isScrolled()"
47970
- [class.pointer-events-auto]="!isScrolled()">
47971
- <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-0">
47972
- <div class="flex-1">
47973
- <div class="flex items-center gap-3">
47974
- <h1 class="text-2xl sm:text-3xl font-bold mb-2 bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
47975
- @if (isLoading() && !isShowingLoader()) {
47976
- <!-- Subtle refresh indicator -->
47977
- <div class="animate-spin w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full" title="Refreshing data..."></div>
47978
- }
47979
- </div>
47980
- <div class="flex flex-wrap items-center justify-between gap-3 sm:gap-4">
47981
- <p [class]="headerSubtitleClass()" class="text-sm sm:text-base">Revenue Orchestration & Funnel Analysis</p>
47982
- <div class="flex items-center gap-4">
47983
- @if (!isSimplifiedView()) {
47984
- <!-- Search Button -->
47985
- <button
47986
- type="button"
47987
- (click)="searchService.openSearch(); $event.preventDefault()"
47988
- [class]="buttonClass()"
47989
- class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105"
47990
- title="Search (/ or Cmd+K)">
47991
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
47992
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
47993
- </svg>
47994
- <span>Search</span>
47995
- </button>
47996
- }
47997
- <!-- View Mode Switcher Button -->
47998
- <button
47999
- type="button"
48000
- (click)="openViewModeSwitcher(); $event.preventDefault()"
48001
- [class]="buttonClass()"
48002
- class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105">
48003
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48004
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
48005
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
48006
- </svg>
48007
- <span>{{ displayModeLabel() }}</span>
48008
- </button>
48009
- @if (!isSimplifiedView()) {
48010
- <div class="flex items-center gap-2 sm:gap-3 whitespace-nowrap">
48011
- <label [class]="metaLabelClass()" class="text-xs sm:text-sm font-medium">View:</label>
48012
- <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
48013
- <select
48014
- [ngModel]="selectedSectionFilter()"
48015
- (ngModelChange)="changeSectionFilter($event)"
48016
- [class]="selectClass()"
48017
- class="px-3 sm:px-4 py-1.5 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
48018
- @for (section of sectionFilters; track section.value) {
48019
- <option [value]="section.value">{{ section.label }}</option>
48020
- }
48021
- </select>
48022
- </div>
48023
- </div>
48024
- }
48025
- </div>
48026
- </div>
48027
- </div>
48028
- <div class="flex flex-col gap-4 min-w-[180px]">
48029
- @if (formattedGeneratedDate()) {
48030
- <div class="text-left sm:text-right">
48031
- <div [class]="metaLabelClass()" class="text-xs sm:text-sm">Generated At</div>
48032
- <div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ formattedGeneratedDate() }}</div>
48033
- </div>
48034
- }
48035
- <div class="text-left sm:text-right">
48036
- <div [class]="metaLabelClass()" class="text-xs sm:text-sm">Requested by</div>
48037
- <div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ requestedByUser()?.firstName }} {{ requestedByUser()?.lastName }}</div>
48038
- </div>
48039
- </div>
48040
- </div>
48041
- </div>
48042
- </div>
48043
-
48044
- <!-- Condensed Header (scrolled state) -->
48045
- <div
48046
- class="transition-all duration-300 ease-in-out overflow-hidden"
48047
- [class.max-h-0]="!isScrolled()"
48048
- [class.opacity-0]="!isScrolled()"
48049
- [class.max-h-20]="isScrolled()"
48050
- [class.opacity-100]="isScrolled()">
48051
- <div
48052
- class="max-w-7xl mx-auto px-6 sm:px-8 py-3"
48053
- [class.pointer-events-none]="!isScrolled()"
48054
- [class.pointer-events-auto]="isScrolled()">
48055
- <div class="flex items-center justify-between gap-4">
48056
- <div class="flex items-center gap-4 flex-1 min-w-0">
48057
- <h1 class="text-lg font-bold truncate bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
48058
- @if (revenueMetric()) {
48059
- <div class="hidden lg:flex items-center gap-3 px-4 py-1.5 rounded-lg" [ngClass]="isLightMode() ? 'bg-emerald-50 border border-emerald-200' : 'bg-emerald-500/10 border border-emerald-500/20'">
48060
- <span [class]="metaLabelClass()" class="text-xs font-medium">Revenue:</span>
48061
- <span [class]="headerTitleClass()" class="text-sm font-bold">{{ formatValue(revenueValue()) }}</span>
48062
- <span class="text-xs font-semibold" [ngClass]="revenueTrend() >= 0 ? 'text-emerald-600' : 'text-red-600'">
48063
- {{ revenueTrend() >= 0 ? '+' : '' }}{{ revenueTrend().toFixed(1) }}%
48064
- </span>
48065
- </div>
48066
- }
48067
- </div>
48068
- <div class="flex items-center gap-3">
48069
- @if (!isSimplifiedView()) {
48070
- <!-- Search Button (Icon Only in Sticky Header) -->
48071
- <button
48072
- type="button"
48073
- (click)="searchService.openSearch(); $event.preventDefault()"
48074
- [class]="buttonClass()"
48075
- title="Search (/ or Cmd+K)"
48076
- class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
48077
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48078
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
48079
- </svg>
48080
- </button>
48081
- }
48082
- <!-- View Mode Switcher (Icon Only in Sticky Header) -->
48083
- <button
48084
- type="button"
48085
- (click)="openViewModeSwitcher(); $event.preventDefault()"
48086
- [class]="buttonClass()"
48087
- [title]="'Change View Mode: ' + displayModeLabel()"
48088
- class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
48089
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48090
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
48091
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
48092
- </svg>
48093
- </button>
48094
- @if (!isSimplifiedView()) {
48095
- <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
48096
- <select
48097
- [ngModel]="selectedSectionFilter()"
48098
- (ngModelChange)="changeSectionFilter($event)"
48099
- [class]="selectClass()"
48100
- class="px-3 py-1.5 rounded-lg text-xs font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
48101
- @for (section of sectionFilters; track section.value) {
48102
- <option [value]="section.value">{{ section.label }}</option>
48103
- }
48104
- </select>
48105
- </div>
48106
- }
48107
- </div>
48108
- </div>
48109
- </div>
48110
- </div>
48111
- </header>
48112
-
48113
- <!-- Search Breadcrumb -->
48114
- @if (searchService.activeSearchResult()) {
48115
- <div [ngClass]="isLightMode() ? 'bg-blue-50/95 border-blue-200' : 'bg-blue-900/20 border-blue-800/30'" class="sticky top-[var(--header-height)] z-40 border-b backdrop-blur-md animate-slide-up-fade">
48116
- <div class="max-w-7xl mx-auto px-6 sm:px-8 py-3">
48117
- <div class="flex items-center justify-between gap-4">
48118
- <div class="flex items-center gap-3 flex-1 min-w-0">
48119
- <svg [ngClass]="isLightMode() ? 'text-blue-600' : 'text-blue-400'" class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48120
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
48121
- </svg>
48122
- <div class="flex items-center gap-2 flex-1 min-w-0">
48123
- <span [ngClass]="isLightMode() ? 'text-blue-900' : 'text-blue-100'" class="text-sm font-medium">Showing:</span>
48124
- <span [ngClass]="isLightMode() ? 'text-blue-700' : 'text-blue-300'" class="text-sm font-semibold truncate">
48125
- {{ searchService.activeSearchResult()!.title }}
48126
- </span>
48127
- <span [ngClass]="isLightMode() ? 'bg-blue-100 text-blue-700 border-blue-200' : 'bg-blue-800/50 text-blue-300 border-blue-700/50'" class="px-2 py-0.5 rounded text-xs font-medium uppercase border flex-shrink-0">
48128
- {{ searchService.activeSearchResult()!.type }}
48129
- </span>
48130
- </div>
48131
- </div>
48132
- <button
48133
- (click)="clearSearchResult(); $event.stopPropagation()"
48134
- [ngClass]="isLightMode() ? 'text-blue-600 hover:text-blue-800 hover:bg-blue-100' : 'text-blue-400 hover:text-blue-200 hover:bg-blue-800/50'"
48135
- class="p-2 rounded-lg transition-colors flex-shrink-0"
48136
- title="Clear search">
48137
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48138
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
48139
- </svg>
48140
- </button>
48141
- </div>
48142
- </div>
48143
- </div>
48144
- }
48145
-
48146
- <!-- Floating Table of Contents -->
48147
- @if (!isSimplifiedView()) {
48148
- <symphiq-floating-toc
48149
- [sections]="tocSections()"
48150
- [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48151
- [embedded]="embedded()"
48152
- [scrollElement]="scrollElement() ?? undefined"
48153
- />
48154
- }
48155
-
48156
- <!-- Quick Navigation Dots -->
48157
- @if (!isSimplifiedView()) {
48158
- <div class="fixed right-6 top-1/2 -translate-y-1/2 z-40 hidden xl:flex flex-col gap-4">
48159
- @if (showOverallPerformance()) {
48160
- <button
48161
- (click)="scrollToTop()"
48162
- [libSymphiqTooltip]="'Scroll to Top'"
48163
- [tooltipPosition]="'left'"
48164
- [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48165
- class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48166
- </button>
48167
- }
48168
- @if (showKeyInsights()) {
48169
- <button
48170
- (click)="scrollToSection('section-insights')"
48171
- [libSymphiqTooltip]="'Key Insights'"
48172
- [tooltipPosition]="'left'"
48173
- [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48174
- class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48175
- </button>
48176
- }
48177
- @if (showPerformanceMetrics()) {
48178
- <button
48179
- (click)="scrollToSection('section-metrics')"
48180
- [libSymphiqTooltip]="'Performance Metrics'"
48181
- [tooltipPosition]="'left'"
48182
- [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48183
- class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48184
- </button>
48185
- }
48186
- @if (showPerformanceBreakdowns()) {
48187
- <button
48188
- (click)="scrollToSection('section-breakdowns')"
48189
- [libSymphiqTooltip]="'Performance Breakdowns'"
48190
- [tooltipPosition]="'left'"
48191
- [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48192
- class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48193
- </button>
48194
- }
48195
- @if (showCompetitiveIntelligence()) {
48196
- <button
48197
- (click)="scrollToSection('section-competitive')"
48198
- [libSymphiqTooltip]="'Competitive Intelligence'"
48199
- [tooltipPosition]="'left'"
48200
- [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-indigo-500' : 'bg-slate-600 hover:bg-indigo-400'"
48201
- class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48202
- </button>
48203
- }
48204
- </div>
48205
- }
48206
-
48207
- @if (isSimplifiedView()) {
48208
- <!-- Journey Progress Banner -->
48209
- @if (!isOnboarded()) {
48210
- <symphiq-journey-progress-indicator
48211
- [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48212
- [currentStepId]="JourneyStepIdEnum.FUNNEL_ANALYSIS"
48213
- [showNextStepAction]="true"
48214
- [forDemo]="forDemo()"
48215
- [maxAccessibleStepId]="maxAccessibleStepId()"
48216
- (stepClick)="stepClick.emit($event)"
48217
- (nextStepClick)="nextStepClick.emit()"
48218
- />
48219
- }
48220
-
48221
- <main class="max-w-7xl mx-auto px-6 sm:px-8">
48222
- <div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
48223
- <!-- Welcome Banner -->
48224
- <div class="mb-8">
48225
- <symphiq-funnel-welcome-banner
48226
- [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48227
- [isOnboarded]="isOnboarded()"
48228
- />
48229
- </div>
48230
-
48231
- <!-- Key Insights Section -->
48232
- @if (showKeyInsights()) {
48233
- <section id="section-insights" class="mb-8">
48234
- <div class="flex items-center justify-between mb-6">
48235
- <div class="flex items-center gap-3">
48236
- <div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
48237
- <div class="flex items-center gap-3">
48238
- <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48239
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
48240
- </svg>
48241
- <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
48242
- </div>
48243
- </div>
48244
- </div>
48245
- <span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
48246
- </div>
48247
-
48248
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
48249
- @for (insight of insights(); track $index) {
48250
- <symphiq-funnel-analysis-insight-card
48251
- [insight]="insight"
48252
- [allMetrics]="allMetrics()"
48253
- [charts]="chartsForInsight(insight)"
48254
- [allCharts]="allCharts()"
48255
- [allBusinessInsights]="allBusinessInsights()"
48256
- [isLightMode]="isLightMode()"
48257
- [viewMode]="viewMode()"
48258
- [isCompactMode]="true"
48259
- [isLoading]="isDataLoading()" />
48260
- }
48261
- </div>
48262
- </section>
48263
- }
48264
-
48265
- <!-- Supporting Data Section -->
48266
- <symphiq-collapsible-funnel-section-group
48267
- [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK">
48268
- <!-- Overall Performance Slot -->
48269
- <div slot="overall-performance">
48270
- @if (showOverallPerformance()) {
48271
- <div class="p-6">
48272
- @if (isDataLoading()) {
48273
- <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48274
- } @else {
48275
- <symphiq-funnel-analysis-overall-assessment
48276
- [assessment]="performanceOverview().overallAssessment || {}"
48277
- [revenueMetric]="revenueMetric()"
48278
- [charts]="chartsForItem('OVERALL_ASSESSMENT')"
48279
- [metrics]="allMetrics()"
48280
- [isLightMode]="isLightMode()"
48281
- [isLoading]="isOverallAssessmentLoading()"
48282
- [isCompactMode]="true"
48283
- [isChartsLoading]="areChartsLoading()"
48284
- [strengths]="strengths()"
48285
- [weaknesses]="weaknesses()"
48286
- [currencySymbol]="currencySymbol()"
48287
- (scrollToSection)="scrollToSection($event)" />
48288
- }
48289
- </div>
48290
- }
48291
- </div>
48292
-
48293
- <!-- Performance Metrics Slot -->
48294
- <div slot="performance-metrics">
48295
- @if (showPerformanceMetrics()) {
48296
- <div class="p-6 space-y-8">
48297
- @for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
48298
- <!-- Funnel Stage Metric (Full Width) -->
48299
- <div class="w-full">
48300
- <symphiq-funnel-analysis-metric-card
48301
- [metric]="funnelGroup.funnelMetric"
48302
- [insights]="insights()"
48303
- [charts]="chartsForMetric(funnelGroup.funnelMetric)"
48304
- [allCharts]="allCharts()"
48305
- [analysis]="analysisData()"
48306
- [isLightMode]="isLightMode()"
48307
- [viewMode]="viewMode()"
48308
- [isCompactMode]="true"
48309
- [currencySymbol]="currencySymbol()" />
48310
- </div>
48311
- <!-- Related Metrics (Grid Layout) -->
48312
- @if (funnelGroup.relatedMetrics.length > 0) {
48313
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-4">
48314
- @for (metric of funnelGroup.relatedMetrics; track $index) {
48315
- <symphiq-funnel-analysis-metric-card
48316
- [metric]="metric"
48317
- [insights]="insights()"
48318
- [charts]="chartsForMetric(metric)"
48319
- [allCharts]="allCharts()"
48320
- [analysis]="analysisData()"
48321
- [isLightMode]="isLightMode()"
48322
- [viewMode]="viewMode()"
48323
- [isCompactMode]="true"
48324
- [currencySymbol]="currencySymbol()" />
48325
- }
48326
- </div>
48327
- }
48328
- }
48329
- </div>
48330
- }
48331
- </div>
48332
-
48333
- <!-- Performance Breakdowns Slot -->
48334
- <div slot="performance-breakdowns">
48335
- @if (showPerformanceBreakdowns()) {
48336
- <div class="p-6 space-y-8">
48337
- @for (breakdown of breakdowns(); track $index) {
48338
- <symphiq-funnel-analysis-breakdown-section
48339
- [breakdown]="breakdown"
48340
- [charts]="chartsForBreakdown(breakdown)"
48341
- [isLightMode]="isLightMode()"
48342
- [isLoading]="isDataLoading()"
48343
- [isCompactMode]="true"
48344
- [currencySymbol]="currencySymbol()" />
48345
- }
48346
- </div>
48347
- }
48348
- </div>
48349
-
48350
- <!-- Competitive Intelligence Slot -->
48351
- <div slot="competitive-intelligence">
48352
- @if (showCompetitiveIntelligence()) {
48353
- <div class="p-6">
48354
- <symphiq-competitive-intelligence-view
48355
- [metrics]="competitiveMetrics()"
48356
- [allCharts]="allCharts()"
48357
- [isLightMode]="isLightMode()"
48358
- [isCompactMode]="true"
48359
- [competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
48360
- [currencySymbol]="currencySymbol()" />
48361
- </div>
48362
- }
48363
- </div>
48364
- </symphiq-collapsible-funnel-section-group>
48365
- </div>
48366
- </main>
48367
- } @else {
48368
- <main class="max-w-7xl mx-auto px-6 sm:px-8">
48369
- <div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
48370
- @if (showOverallPerformance()) {
48371
- <div id="section-overall" class="animate-fade-in-up mb-20 sm:mb-28" style="animation-delay: 0.1s;">
48372
- @if (isDataLoading()) {
48373
- <!-- Overall Assessment Skeleton -->
48374
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 sm:p-8 animate-pulse">
48375
- <div class="space-y-6">
48376
- <!-- Header -->
48377
- <div class="flex items-center gap-3">
48378
- <symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48379
- <div class="flex-1 space-y-2">
48380
- <symphiq-skeleton-loader [width]="'40%'" [height]="'32px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48381
- <symphiq-skeleton-loader [width]="'60%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48382
- </div>
48383
- </div>
48384
- <!-- Summary text -->
48385
- <div class="space-y-2">
48386
- <symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48387
- <symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48388
- <symphiq-skeleton-loader [width]="'90%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48389
- </div>
48390
- <!-- Chart placeholder -->
48391
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
48392
- <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48393
- <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48394
- </div>
48395
- </div>
48396
- </div>
48397
- } @else {
48398
- <symphiq-funnel-analysis-overall-assessment
48399
- [assessment]="performanceOverview().overallAssessment || {}"
48400
- [revenueMetric]="revenueMetric()"
48401
- [charts]="chartsForItem('OVERALL_ASSESSMENT')"
48402
- [metrics]="allMetrics()"
48403
- [isLightMode]="isLightMode()"
48404
- [isLoading]="isOverallAssessmentLoading()"
48405
- [isCompactMode]="viewModeService.isCompact()"
48406
- [isChartsLoading]="areChartsLoading()"
48407
- [strengths]="strengths()"
48408
- [weaknesses]="weaknesses()"
48409
- [currencySymbol]="currencySymbol()"
48410
- (scrollToSection)="scrollToSection($event)" />
48411
- }
48412
- </div>
48413
- }
48414
-
48415
- @if (showKeyInsights()) {
48416
- @if (selectedSectionFilter() === 'ALL') {
48417
- <!-- Section Divider -->
48418
- <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.15s"></symphiq-section-divider>
48419
- }
48420
-
48421
- <section id="section-insights" class="relative">
48422
- <!-- Background Pattern -->
48423
- <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-blue-50/50 to-transparent' : 'bg-gradient-to-br from-blue-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
48424
- <div class="relative">
48425
- <div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.2s;">
48426
- <div class="flex items-center gap-3">
48427
- <div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
48428
- <div class="flex items-center gap-3">
48429
- <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48430
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
48431
- </svg>
48432
- <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
48433
- </div>
48434
- </div>
48435
- </div>
48436
- <span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
48437
- </div>
48438
- <!-- Masonry Layout for Insights -->
48439
- @if (isDataLoading() || (viewModeService.isExpanded() && viewModeService.getIsTransitioning())) {
48440
- <!-- Skeleton loaders during data loading or transition to expanded view -->
48441
- <div class="masonry-grid">
48442
- @for (i of [1,2,3,4,5,6]; track i) {
48443
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[280px]">
48444
- <div class="space-y-4">
48445
- <div class="flex items-center gap-3 mb-4">
48446
- <symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48447
- <symphiq-skeleton-loader [width]="'60%'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48448
- </div>
48449
- <symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48450
- <symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48451
- <symphiq-skeleton-loader [width]="'85%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48452
- <div class="mt-6 space-y-2">
48453
- <symphiq-skeleton-loader [width]="'40%'" [height]="'14px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48454
- <symphiq-skeleton-loader [width]="'50%'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48455
- </div>
48456
- <div class="flex gap-2 mt-4">
48457
- <symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48458
- <symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48459
- </div>
48460
- </div>
48461
- </div>
48462
- }
48463
- </div>
48464
- } @else if (viewModeService.isExpanded()) {
48465
- <div class="masonry-grid">
48466
- @for (insight of insights(); track $index) {
48467
- <div
48468
- [class]="getInsightCardClass(insight)"
48469
- class="animate-fade-in-up"
48470
- [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
48471
- [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48472
- [highlightId]="'insight-' + $index">
48473
- <symphiq-funnel-analysis-insight-card
48474
- [insight]="insight"
48475
- [allMetrics]="allMetrics()"
48476
- [charts]="chartsForInsight(insight)"
48477
- [allCharts]="allCharts()"
48478
- [allBusinessInsights]="allBusinessInsights()"
48479
- [isLightMode]="isLightMode()"
48480
- [viewMode]="viewMode()"
48481
- [isCompactMode]="false" />
48482
- </div>
48483
- }
48484
- </div>
48485
- } @else {
48486
- <!-- Compact Grid for Insights -->
48487
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
48488
- @for (insight of insights(); track $index) {
48489
- <div class="animate-fade-in-up" [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
48490
- [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48491
- [highlightId]="'insight-' + $index">
48492
- <symphiq-funnel-analysis-insight-card
48493
- [insight]="insight"
48494
- [allMetrics]="allMetrics()"
48495
- [charts]="chartsForInsight(insight)"
48496
- [allCharts]="allCharts()"
48497
- [allBusinessInsights]="allBusinessInsights()"
48498
- [isLightMode]="isLightMode()"
48499
- [viewMode]="viewMode()"
48500
- [isCompactMode]="true" />
48501
- </div>
48502
- }
48503
- </div>
48504
- }
48505
- </div>
48506
- </section>
48507
- }
48508
-
48509
- @if (showPerformanceMetrics()) {
48510
- @if (selectedSectionFilter() === 'ALL') {
48511
- <!-- Section Divider -->
48512
- <div class="relative mb-14 sm:mb-24 mt-24 sm:mt-32 animate-fade-in" style="animation-delay: 0.35s;">
48513
- <div class="absolute inset-0 flex items-center" aria-hidden="true">
48514
- <div class="w-full h-px bg-gradient-to-r" [ngClass]="isLightMode() ? 'from-transparent via-emerald-500/30 to-transparent' : 'from-transparent via-emerald-400/20 to-transparent'"></div>
48515
- </div>
48516
- <div class="relative flex justify-center">
48517
- <div class="px-4 py-2 rounded-full" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-emerald-50 to-teal-50 border border-emerald-200/50 shadow-lg shadow-emerald-500/10' : 'bg-gradient-to-br from-slate-900 to-slate-800 border border-emerald-500/20 shadow-lg shadow-emerald-500/5'">
48518
- <svg class="w-5 h-5" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48519
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
48520
- </svg>
48521
- </div>
48522
- </div>
48523
- </div>
48524
- }
48525
-
48526
- <section id="section-metrics" class="relative">
48527
- <!-- Background Pattern -->
48528
- <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tl from-emerald-50/50 to-transparent' : 'bg-gradient-to-tl from-emerald-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at top right, black 0%, transparent 70%);"></div>
48529
- <div class="relative">
48530
- <div class="flex flex-col gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.4s;">
48531
- <div class="flex items-center justify-between">
48532
- <div class="flex items-center gap-3">
48533
- <div [ngClass]="isLightMode() ? 'border-l-4 border-emerald-500' : 'border-l-4 border-emerald-400'" class="pl-4">
48534
- <div class="flex items-center gap-3">
48535
- <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48536
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
48537
- </svg>
48538
- <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Metrics</h2>
48539
- </div>
48540
- </div>
48541
- </div>
48542
- <!-- Desktop controls -->
48543
- <div class="hidden sm:flex gap-2 sm:gap-3 items-center relative">
48544
- @if (isCategoryTransitioning()) {
48545
- <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48546
- <div class="w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full animate-spin"></div>
48547
- </div>
48548
- }
48549
- <select
48550
- [ngModel]="selectedCategory()"
48551
- (ngModelChange)="changeCategoryFilter($event)"
48552
- [class]="selectClass()"
48553
- [class.opacity-70]="isCategoryTransitioning()"
48554
- class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
48555
- @for (cat of categories; track cat.value) {
48556
- @if (cat.divider) {
48557
- <option [value]="cat.value" disabled class="font-semibold">{{ cat.label }}</option>
48558
- } @else {
48559
- <option [value]="cat.value">{{ cat.label }}</option>
48560
- }
48561
- }
48562
- </select>
48563
- <button
48564
- (click)="toggleSortOrder()"
48565
- [class]="sortButtonClass()"
48566
- class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all flex items-center gap-2 cursor-pointer hover:scale-105 active:scale-95"
48567
- [title]="reverseSortOrder() ? 'Sort: Revenue to Views' : 'Sort: Views to Revenue'">
48568
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48569
- @if (!reverseSortOrder()) {
48570
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"></path>
48571
- }
48572
- @if (reverseSortOrder()) {
48573
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"></path>
48574
- }
48575
- </svg>
48576
- <span>Sort</span>
48577
- </button>
48578
- </div>
48579
- </div>
48580
-
48581
- <!-- Mobile horizontal scrolling category pills -->
48582
- <div class="sm:hidden -mx-6 px-6">
48583
- <div class="flex gap-2 overflow-x-auto pb-2 snap-x snap-mandatory scrollbar-hide">
48584
- @for (cat of categories; track cat.value) {
48585
- @if (!cat.divider) {
48586
- <button
48587
- (click)="changeCategoryFilter(cat.value)"
48588
- [ngClass]="getCategoryPillClass(cat.value)"
48589
- [class.opacity-70]="isCategoryTransitioning()"
48590
- class="px-4 py-2 rounded-full text-xs font-medium whitespace-nowrap transition-all duration-200 flex-shrink-0 snap-start active:scale-95">
48591
- {{ cat.label }}
48592
- </button>
48593
- }
48594
- }
48595
- </div>
48596
- </div>
48597
- </div>
48598
- @if (isDataLoading()) {
48599
- <!-- Metrics Skeleton -->
48600
- <div class="space-y-8 sm:space-y-10">
48601
- @for (i of [1,2,3]; track i) {
48602
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48603
- <div class="flex items-center justify-between mb-4">
48604
- <div class="flex items-center gap-3">
48605
- <symphiq-skeleton-loader [width]="'40px'" [height]="'40px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48606
- <div class="space-y-2">
48607
- <symphiq-skeleton-loader [width]="'150px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48608
- <symphiq-skeleton-loader [width]="'100px'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48609
- </div>
48610
- </div>
48611
- <symphiq-skeleton-loader [width]="'80px'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48612
- </div>
48613
- <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
48614
- @for (j of [1,2,3,4]; track j) {
48615
- <symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48616
- }
48617
- </div>
48618
- </div>
48619
- }
48620
- </div>
48621
- } @else {
48622
- <div class="space-y-8 sm:space-y-10" [class.animate-content-change]="isCategoryTransitioning()" [class.transition-opacity-slow]="isCategoryTransitioning()">
48623
- @for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
48624
- <div class="w-full animate-fade-in-up" [style.animation-delay]="(0.5 + groupIdx * 0.15) + 's'"
48625
- [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48626
- [highlightId]="'metric-' + groupIdx">
48627
- <symphiq-funnel-analysis-metric-card
48628
- [metric]="funnelGroup.funnelMetric"
48629
- [insights]="insights()"
48630
- [charts]="chartsForMetric(funnelGroup.funnelMetric)"
48631
- [allCharts]="allCharts()"
48632
- [analysis]="analysisData()"
48633
- [isLightMode]="isLightMode()"
48634
- [viewMode]="viewMode()"
48635
- [isCompactMode]="viewModeService.isCompact()"
48636
- [currencySymbol]="currencySymbol()" />
48637
- </div>
48638
- @if (funnelGroup.relatedMetrics.length > 0) {
48639
- <!-- Bento Box Grid Layout -->
48640
- @if (viewModeService.isExpanded()) {
48641
- <div class="bento-grid mt-4">
48642
- @for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
48643
- <div
48644
- [class]="getBentoCardClass(metric, metricIdx)"
48645
- class="animate-fade-in-up"
48646
- [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
48647
- <symphiq-funnel-analysis-metric-card
48648
- class="h-full"
48649
- [metric]="metric"
48650
- [insights]="insights()"
48651
- [charts]="chartsForMetric(metric)"
48652
- [allCharts]="allCharts()"
48653
- [analysis]="analysisData()"
48654
- [isLightMode]="isLightMode()"
48655
- [viewMode]="viewMode()"
48656
- [isCompactMode]="false"
48657
- [currencySymbol]="currencySymbol()" />
48658
- </div>
48659
- }
48660
- </div>
48661
- } @else if (!viewModeService.isExpanded()) {
48662
- <!-- Compact Grid Layout -->
48663
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mt-4">
48664
- @for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
48665
- <div class="animate-fade-in-up" [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
48666
- <symphiq-funnel-analysis-metric-card
48667
- [metric]="metric"
48668
- [insights]="insights()"
48669
- [charts]="chartsForMetric(metric)"
48670
- [allCharts]="allCharts()"
48671
- [analysis]="analysisData()"
48672
- [isLightMode]="isLightMode()"
48673
- [viewMode]="viewMode()"
48674
- [isCompactMode]="true"
48675
- [currencySymbol]="currencySymbol()" />
48676
- </div>
48677
- }
48678
- </div>
48679
- } @else {
48680
- <!-- Skeleton loaders during transition to expanded view -->
48681
- <div class="bento-grid mt-4">
48682
- @for (i of [1,2,3,4]; track i) {
48683
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[240px]">
48684
- <div class="space-y-4">
48685
- <div class="flex items-center justify-between">
48686
- <symphiq-skeleton-loader [width]="'60%'" [height]="'22px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48687
- <symphiq-skeleton-loader [width]="'60px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48688
- </div>
48689
- <symphiq-skeleton-loader [width]="'45%'" [height]="'42px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48690
- <div class="flex items-center gap-3 mt-4">
48691
- <symphiq-skeleton-loader [width]="'24px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48692
- <symphiq-skeleton-loader [width]="'30%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48693
- </div>
48694
- <symphiq-skeleton-loader [width]="'100%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48695
- <symphiq-skeleton-loader [width]="'85%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48696
- <div class="mt-4">
48697
- <symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48698
- </div>
48699
- </div>
48700
- </div>
48701
- }
48702
- </div>
48703
- }
48704
- }
48705
- } @empty {
48706
- <div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
48707
- <svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48708
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
48709
- </svg>
48710
- <h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Metrics Found</h3>
48711
- <p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance metrics match your current filter selection. Try adjusting your filters to see more results.</p>
48712
- </div>
48713
- }
48714
- </div>
48715
- }
48716
- </div>
48717
- </section>
48718
- }
48719
-
48720
- @if (showPerformanceBreakdowns()) {
48721
- @if (selectedSectionFilter() === 'ALL') {
48722
- <!-- Section Divider -->
48723
- <div class="mt-28 sm:mt-36">
48724
- <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.65s"></symphiq-section-divider>
48725
- </div>
48726
- }
48727
-
48728
- <section id="section-breakdowns" class="relative">
48729
- <!-- Background Pattern -->
48730
- <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tr from-purple-50/50 to-transparent' : 'bg-gradient-to-tr from-purple-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at bottom left, black 0%, transparent 70%);"></div>
48731
- <div class="relative">
48732
- <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.7s;">
48733
- <div [ngClass]="isLightMode() ? 'border-l-4 border-purple-500' : 'border-l-4 border-purple-400'" class="pl-4">
48734
- <div class="flex items-center gap-3">
48735
- <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-purple-500' : 'text-purple-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48736
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
48737
- </svg>
48738
- <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Breakdowns</h2>
48739
- </div>
48740
- </div>
48741
- <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()" class="relative inline-block">
48742
- @if (isBreakdownTransitioning()) {
48743
- <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48744
- <div class="w-4 h-4 border-2 border-purple-500/30 border-t-purple-500 rounded-full animate-spin"></div>
48745
- </div>
48746
- }
48747
- <select
48748
- [ngModel]="selectedBreakdownFilter()"
48749
- (ngModelChange)="changeBreakdownFilter($event)"
48750
- [ngClass]="isLightMode()
48751
- ? 'bg-white border-slate-300 text-slate-900 hover:border-blue-400 focus:border-blue-500'
48752
- : 'bg-slate-700 border-slate-600 text-white hover:border-slate-500 focus:border-blue-500'"
48753
- [class.opacity-70]="isBreakdownTransitioning()"
48754
- class="px-3 py-2 text-sm rounded-lg border transition-all duration-200 cursor-pointer focus:ring-2 focus:ring-blue-500 focus:outline-none">
48755
- @for (filter of breakdownFilters; track filter.value) {
48756
- @if (filter.divider) {
48757
- <option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
48758
- } @else {
48759
- <option [value]="filter.value">{{ filter.label }}</option>
48760
- }
48761
- }
48762
- </select>
48763
- </div>
48764
- </div>
48765
- @if (isDataLoading()) {
48766
- <!-- Breakdowns Skeleton -->
48767
- <div class="space-y-6">
48768
- @for (i of [1,2]; track i) {
48769
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48770
- <div class="flex items-center justify-between mb-4">
48771
- <symphiq-skeleton-loader [width]="'200px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48772
- <symphiq-skeleton-loader [width]="'100px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48773
- </div>
48774
- <div class="space-y-3">
48775
- @for (j of [1,2,3,4]; track j) {
48776
- <div class="flex items-center justify-between p-3 rounded-lg" [ngClass]="isLightMode() ? 'bg-slate-50' : 'bg-slate-700/50'">
48777
- <symphiq-skeleton-loader [width]="'150px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48778
- <symphiq-skeleton-loader [width]="'80px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48779
- </div>
48780
- }
48781
- </div>
48782
- </div>
48783
- }
48784
- </div>
48785
- } @else {
48786
- <div class="space-y-6" [class.animate-content-change]="isBreakdownTransitioning()" [class.transition-opacity-slow]="isBreakdownTransitioning()">
48787
- @for (breakdown of breakdowns(); track $index) {
48788
- <div class="animate-fade-in-up" [style.animation-delay]="(0.8 + $index * 0.1) + 's'"
48789
- [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48790
- [highlightId]="'breakdown-' + $index">
48791
- <symphiq-funnel-analysis-breakdown-section
48792
- [breakdown]="breakdown"
48793
- [charts]="chartsForBreakdown(breakdown)"
48794
- [isLightMode]="isLightMode()"
48795
- [isCompactMode]="viewModeService.isCompact()"
48796
- [currencySymbol]="currencySymbol()" />
48797
- </div>
48798
- } @empty {
48799
- <div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
48800
- <svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48801
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
48802
- </svg>
48803
- <h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Breakdowns Found</h3>
48804
- <p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance breakdowns match your current filter selection. Try adjusting your filters to see more results.</p>
48805
- </div>
48806
- }
48807
- </div>
48808
- }
48809
- </div>
48810
- </section>
48811
- }
48812
-
48813
- @if (showCompetitiveIntelligence()) {
48814
- @if (selectedSectionFilter() === 'ALL') {
48815
- <!-- Section Divider -->
48816
- <div class="mt-28 sm:mt-36">
48817
- <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.85s"></symphiq-section-divider>
48818
- </div>
48819
- }
48820
-
48821
- <!-- Competitive Intelligence Section -->
48822
- <section id="section-competitive" class="relative">
48823
- <!-- Background Pattern -->
48824
- <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-indigo-50/50 to-transparent' : 'bg-gradient-to-br from-indigo-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
48825
- <div class="relative">
48826
- <div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.9s;">
48827
- <div class="flex items-center gap-3">
48828
- <div [ngClass]="isLightMode() ? 'border-l-4 border-indigo-500' : 'border-l-4 border-indigo-400'" class="pl-4">
48829
- <div class="flex items-center gap-3">
48830
- <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-indigo-500' : 'text-indigo-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48831
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
48832
- </svg>
48833
- <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Competitive Intelligence</h2>
48834
- </div>
48835
- </div>
48836
- </div>
48837
- <!-- Filter Dropdown -->
48838
- <div class="hidden sm:block relative">
48839
- @if (isCompetitiveTransitioning()) {
48840
- <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48841
- <div class="w-4 h-4 border-2 border-indigo-500/30 border-t-indigo-500 rounded-full animate-spin"></div>
48842
- </div>
48843
- }
48844
- <select
48845
- [ngModel]="selectedCompetitiveFilter()"
48846
- (ngModelChange)="changeCompetitiveFilter($event)"
48847
- [class]="selectClass()"
48848
- [class.opacity-70]="isCompetitiveTransitioning()"
48849
- class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
48850
- @for (filter of competitiveFilters; track filter.value) {
48851
- @if (filter.divider) {
48852
- <option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
48853
- } @else {
48854
- <option [value]="filter.value">{{ filter.label }}</option>
48855
- }
48856
- }
48857
- </select>
48858
- </div>
48859
- </div>
48860
-
48861
- @if (isDataLoading()) {
48862
- <!-- Competitive Intelligence Skeleton -->
48863
- <div class="space-y-6">
48864
- <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48865
- <symphiq-skeleton-loader [width]="'60%'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48866
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
48867
- @for (i of [1,2,3]; track i) {
48868
- <symphiq-skeleton-loader [width]="'100%'" [height]="'140px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48869
- }
48870
- </div>
48871
- </div>
48872
- </div>
48873
- } @else {
48874
- <symphiq-competitive-intelligence-view
48875
- [metrics]="competitiveMetrics()"
48876
- [allCharts]="allCharts()"
48877
- [isLightMode]="isLightMode()"
48878
- [isCompactMode]="viewModeService.isCompact()"
48879
- [competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
48880
- [currencySymbol]="currencySymbol()" />
48881
- }
48882
- </div>
48883
- </section>
48884
- }
48885
- </div>
48886
- </main>
48887
- }
48888
-
48889
- <symphiq-funnel-analysis-modal
48890
- [isLightMode]="isLightMode()"
48891
- [viewMode]="viewMode()"
48892
- [allMetrics]="allMetrics()"
48893
- [allInsights]="insights()"
48894
- [allCharts]="allCharts()"
48895
- [currencySymbol]="currencySymbol()"
48896
- [businessProfile]="businessProfile()"></symphiq-funnel-analysis-modal>
48897
- <symphiq-profile-analysis-modal
48898
- [isLightMode]="isLightMode()"
48899
- [allMetrics]="allMetrics()"
48900
- ></symphiq-profile-analysis-modal>
48901
- <symphiq-business-analysis-modal [isLightMode]="isLightMode()" />
48902
- <symphiq-tooltip-container></symphiq-tooltip-container>
48903
- <symphiq-search-bar
48904
- [isLightMode]="isLightMode()"
48905
- (resultSelected)="handleSearchResult($event)" />
48906
-
48907
- <!-- View Mode Switcher Modal -->
48908
- <symphiq-view-mode-switcher-modal
48909
- [isOpen]="isViewModeSwitcherOpen()"
48910
- [currentMode]="displayMode()"
48911
- [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48912
- [isLoading]="isViewModeSwitching()"
48913
- (close)="closeViewModeSwitcher()"
48914
- (modeSelected)="handleDisplayModeChange($event)"
48915
- />
48916
-
48917
- <!-- Mobile FAB -->
48918
- <symphiq-mobile-fab
48919
- [isLightMode]="isLightMode()"
48920
- [isCompactMode]="viewModeService.isCompact()"
48921
- [isExpanded]="fabExpanded()"
48922
- (expandedChange)="fabExpanded.set($event)"
48923
- (scrollToTop)="scrollToTop()"
48924
- (toggleView)="viewModeService.toggleViewMode()" />
48925
-
48926
- <!-- Mobile Bottom Navigation -->
48927
- <symphiq-mobile-bottom-nav
48928
- [isLightMode]="isLightMode()"
48929
- [sections]="navSections"
48930
- [activeSection]="activeNavSection()"
48931
- (navigate)="handleMobileNavigation($event)" />
48932
-
48933
- </div>
47939
+ ], template: `
47940
+ <div
47941
+ class="bg-transparent"
47942
+ [class.min-h-screen]="!embedded()"
47943
+ [class.relative]="!embedded()"
47944
+ [style.display]="embedded() ? 'block' : null"
47945
+ [style.min-height]="embedded() ? 'auto' : null"
47946
+ #dashboardContainer>
47947
+ <!-- Animated Background Bubbles -->
47948
+ <div class="animated-bubbles" [class.light-mode]="isLightMode()" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100vw; height: 100vh; z-index: 1; pointer-events: none;"></div>
47949
+
47950
+ <!-- Scroll Progress Bar -->
47951
+ <div [class]="embedded() ? 'sticky top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30' : 'fixed top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30'">
47952
+ <div
47953
+ [style.width.%]="scrollProgress()"
47954
+ [ngClass]="isLightMode() ? 'bg-gradient-to-r from-blue-500 to-purple-500' : 'bg-gradient-to-r from-blue-400 to-purple-400'"
47955
+ class="h-full transition-all duration-200 ease-out">
47956
+ </div>
47957
+ </div>
47958
+
47959
+ <header [class]="headerClass()" class="sticky top-0 z-50 animate-fade-in" style="animation-delay: 0s;">
47960
+ <!-- Expanded Header (default state) -->
47961
+ <div
47962
+ class="transition-all duration-300 ease-in-out overflow-hidden"
47963
+ [class.max-h-0]="isScrolled()"
47964
+ [class.opacity-0]="isScrolled()"
47965
+ [class.max-h-96]="!isScrolled()"
47966
+ [class.opacity-100]="!isScrolled()">
47967
+ <div
47968
+ class="max-w-7xl mx-auto px-6 sm:px-8 py-6 sm:py-8"
47969
+ [class.pointer-events-none]="isScrolled()"
47970
+ [class.pointer-events-auto]="!isScrolled()">
47971
+ <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-0">
47972
+ <div class="flex-1">
47973
+ <div class="flex items-center gap-3">
47974
+ <h1 class="text-2xl sm:text-3xl font-bold mb-2 bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
47975
+ @if (isLoading() && !isShowingLoader()) {
47976
+ <!-- Subtle refresh indicator -->
47977
+ <div class="animate-spin w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full" title="Refreshing data..."></div>
47978
+ }
47979
+ </div>
47980
+ <div class="flex flex-wrap items-center justify-between gap-3 sm:gap-4">
47981
+ <p [class]="headerSubtitleClass()" class="text-sm sm:text-base">Revenue Orchestration & Funnel Analysis</p>
47982
+ <div class="flex items-center gap-4">
47983
+ @if (!isSimplifiedView()) {
47984
+ <!-- Search Button -->
47985
+ <button
47986
+ type="button"
47987
+ (click)="searchService.openSearch(); $event.preventDefault()"
47988
+ [class]="buttonClass()"
47989
+ class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105"
47990
+ title="Search (/ or Cmd+K)">
47991
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
47992
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
47993
+ </svg>
47994
+ <span>Search</span>
47995
+ </button>
47996
+ }
47997
+ <!-- View Mode Switcher Button -->
47998
+ <button
47999
+ type="button"
48000
+ (click)="openViewModeSwitcher(); $event.preventDefault()"
48001
+ [class]="buttonClass()"
48002
+ class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105">
48003
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48004
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
48005
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
48006
+ </svg>
48007
+ <span>{{ displayModeLabel() }}</span>
48008
+ </button>
48009
+ @if (!isSimplifiedView()) {
48010
+ <div class="flex items-center gap-2 sm:gap-3 whitespace-nowrap">
48011
+ <label [class]="metaLabelClass()" class="text-xs sm:text-sm font-medium">View:</label>
48012
+ <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
48013
+ <select
48014
+ [ngModel]="selectedSectionFilter()"
48015
+ (ngModelChange)="changeSectionFilter($event)"
48016
+ [class]="selectClass()"
48017
+ class="px-3 sm:px-4 py-1.5 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
48018
+ @for (section of sectionFilters; track section.value) {
48019
+ <option [value]="section.value">{{ section.label }}</option>
48020
+ }
48021
+ </select>
48022
+ </div>
48023
+ </div>
48024
+ }
48025
+ </div>
48026
+ </div>
48027
+ </div>
48028
+ <div class="flex flex-col gap-4 min-w-[180px]">
48029
+ @if (formattedGeneratedDate()) {
48030
+ <div class="text-left sm:text-right">
48031
+ <div [class]="metaLabelClass()" class="text-xs sm:text-sm">Generated At</div>
48032
+ <div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ formattedGeneratedDate() }}</div>
48033
+ </div>
48034
+ }
48035
+ <div class="text-left sm:text-right">
48036
+ <div [class]="metaLabelClass()" class="text-xs sm:text-sm">Requested by</div>
48037
+ <div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ requestedByUser()?.firstName }} {{ requestedByUser()?.lastName }}</div>
48038
+ </div>
48039
+ </div>
48040
+ </div>
48041
+ </div>
48042
+ </div>
48043
+
48044
+ <!-- Condensed Header (scrolled state) -->
48045
+ <div
48046
+ class="transition-all duration-300 ease-in-out overflow-hidden"
48047
+ [class.max-h-0]="!isScrolled()"
48048
+ [class.opacity-0]="!isScrolled()"
48049
+ [class.max-h-20]="isScrolled()"
48050
+ [class.opacity-100]="isScrolled()">
48051
+ <div
48052
+ class="max-w-7xl mx-auto px-6 sm:px-8 py-3"
48053
+ [class.pointer-events-none]="!isScrolled()"
48054
+ [class.pointer-events-auto]="isScrolled()">
48055
+ <div class="flex items-center justify-between gap-4">
48056
+ <div class="flex items-center gap-4 flex-1 min-w-0">
48057
+ <h1 class="text-lg font-bold truncate bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
48058
+ @if (revenueMetric()) {
48059
+ <div class="hidden lg:flex items-center gap-3 px-4 py-1.5 rounded-lg" [ngClass]="isLightMode() ? 'bg-emerald-50 border border-emerald-200' : 'bg-emerald-500/10 border border-emerald-500/20'">
48060
+ <span [class]="metaLabelClass()" class="text-xs font-medium">Revenue:</span>
48061
+ <span [class]="headerTitleClass()" class="text-sm font-bold">{{ formatValue(revenueValue()) }}</span>
48062
+ <span class="text-xs font-semibold" [ngClass]="revenueTrend() >= 0 ? 'text-emerald-600' : 'text-red-600'">
48063
+ {{ revenueTrend() >= 0 ? '+' : '' }}{{ revenueTrend().toFixed(1) }}%
48064
+ </span>
48065
+ </div>
48066
+ }
48067
+ </div>
48068
+ <div class="flex items-center gap-3">
48069
+ @if (!isSimplifiedView()) {
48070
+ <!-- Search Button (Icon Only in Sticky Header) -->
48071
+ <button
48072
+ type="button"
48073
+ (click)="searchService.openSearch(); $event.preventDefault()"
48074
+ [class]="buttonClass()"
48075
+ title="Search (/ or Cmd+K)"
48076
+ class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
48077
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48078
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
48079
+ </svg>
48080
+ </button>
48081
+ }
48082
+ <!-- View Mode Switcher (Icon Only in Sticky Header) -->
48083
+ <button
48084
+ type="button"
48085
+ (click)="openViewModeSwitcher(); $event.preventDefault()"
48086
+ [class]="buttonClass()"
48087
+ [title]="'Change View Mode: ' + displayModeLabel()"
48088
+ class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
48089
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48090
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
48091
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
48092
+ </svg>
48093
+ </button>
48094
+ @if (!isSimplifiedView()) {
48095
+ <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
48096
+ <select
48097
+ [ngModel]="selectedSectionFilter()"
48098
+ (ngModelChange)="changeSectionFilter($event)"
48099
+ [class]="selectClass()"
48100
+ class="px-3 py-1.5 rounded-lg text-xs font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
48101
+ @for (section of sectionFilters; track section.value) {
48102
+ <option [value]="section.value">{{ section.label }}</option>
48103
+ }
48104
+ </select>
48105
+ </div>
48106
+ }
48107
+ </div>
48108
+ </div>
48109
+ </div>
48110
+ </div>
48111
+ </header>
48112
+
48113
+ <!-- Search Breadcrumb -->
48114
+ @if (searchService.activeSearchResult()) {
48115
+ <div [ngClass]="isLightMode() ? 'bg-blue-50/95 border-blue-200' : 'bg-blue-900/20 border-blue-800/30'" class="sticky top-[var(--header-height)] z-40 border-b backdrop-blur-md animate-slide-up-fade">
48116
+ <div class="max-w-7xl mx-auto px-6 sm:px-8 py-3">
48117
+ <div class="flex items-center justify-between gap-4">
48118
+ <div class="flex items-center gap-3 flex-1 min-w-0">
48119
+ <svg [ngClass]="isLightMode() ? 'text-blue-600' : 'text-blue-400'" class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48120
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
48121
+ </svg>
48122
+ <div class="flex items-center gap-2 flex-1 min-w-0">
48123
+ <span [ngClass]="isLightMode() ? 'text-blue-900' : 'text-blue-100'" class="text-sm font-medium">Showing:</span>
48124
+ <span [ngClass]="isLightMode() ? 'text-blue-700' : 'text-blue-300'" class="text-sm font-semibold truncate">
48125
+ {{ searchService.activeSearchResult()!.title }}
48126
+ </span>
48127
+ <span [ngClass]="isLightMode() ? 'bg-blue-100 text-blue-700 border-blue-200' : 'bg-blue-800/50 text-blue-300 border-blue-700/50'" class="px-2 py-0.5 rounded text-xs font-medium uppercase border flex-shrink-0">
48128
+ {{ searchService.activeSearchResult()!.type }}
48129
+ </span>
48130
+ </div>
48131
+ </div>
48132
+ <button
48133
+ (click)="clearSearchResult(); $event.stopPropagation()"
48134
+ [ngClass]="isLightMode() ? 'text-blue-600 hover:text-blue-800 hover:bg-blue-100' : 'text-blue-400 hover:text-blue-200 hover:bg-blue-800/50'"
48135
+ class="p-2 rounded-lg transition-colors flex-shrink-0"
48136
+ title="Clear search">
48137
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48138
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
48139
+ </svg>
48140
+ </button>
48141
+ </div>
48142
+ </div>
48143
+ </div>
48144
+ }
48145
+
48146
+ <!-- Floating Table of Contents -->
48147
+ @if (!isSimplifiedView()) {
48148
+ <symphiq-floating-toc
48149
+ [sections]="tocSections()"
48150
+ [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48151
+ [embedded]="embedded()"
48152
+ [scrollElement]="scrollElement() ?? undefined"
48153
+ />
48154
+ }
48155
+
48156
+ <!-- Quick Navigation Dots -->
48157
+ @if (!isSimplifiedView()) {
48158
+ <div class="fixed right-6 top-1/2 -translate-y-1/2 z-40 hidden xl:flex flex-col gap-4">
48159
+ @if (showOverallPerformance()) {
48160
+ <button
48161
+ (click)="scrollToTop()"
48162
+ [libSymphiqTooltip]="'Scroll to Top'"
48163
+ [tooltipPosition]="'left'"
48164
+ [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48165
+ class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48166
+ </button>
48167
+ }
48168
+ @if (showKeyInsights()) {
48169
+ <button
48170
+ (click)="scrollToSection('section-insights')"
48171
+ [libSymphiqTooltip]="'Key Insights'"
48172
+ [tooltipPosition]="'left'"
48173
+ [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48174
+ class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48175
+ </button>
48176
+ }
48177
+ @if (showPerformanceMetrics()) {
48178
+ <button
48179
+ (click)="scrollToSection('section-metrics')"
48180
+ [libSymphiqTooltip]="'Performance Metrics'"
48181
+ [tooltipPosition]="'left'"
48182
+ [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48183
+ class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48184
+ </button>
48185
+ }
48186
+ @if (showPerformanceBreakdowns()) {
48187
+ <button
48188
+ (click)="scrollToSection('section-breakdowns')"
48189
+ [libSymphiqTooltip]="'Performance Breakdowns'"
48190
+ [tooltipPosition]="'left'"
48191
+ [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
48192
+ class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48193
+ </button>
48194
+ }
48195
+ @if (showCompetitiveIntelligence()) {
48196
+ <button
48197
+ (click)="scrollToSection('section-competitive')"
48198
+ [libSymphiqTooltip]="'Competitive Intelligence'"
48199
+ [tooltipPosition]="'left'"
48200
+ [ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-indigo-500' : 'bg-slate-600 hover:bg-indigo-400'"
48201
+ class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
48202
+ </button>
48203
+ }
48204
+ </div>
48205
+ }
48206
+
48207
+ @if (isSimplifiedView()) {
48208
+ <!-- Journey Progress Banner -->
48209
+ @if (!isOnboarded()) {
48210
+ <symphiq-journey-progress-indicator
48211
+ [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48212
+ [currentStepId]="JourneyStepIdEnum.FUNNEL_ANALYSIS"
48213
+ [showNextStepAction]="true"
48214
+ [forDemo]="forDemo()"
48215
+ [maxAccessibleStepId]="maxAccessibleStepId()"
48216
+ (stepClick)="stepClick.emit($event)"
48217
+ (nextStepClick)="nextStepClick.emit()"
48218
+ />
48219
+ }
48220
+
48221
+ <main class="max-w-7xl mx-auto px-6 sm:px-8">
48222
+ <div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
48223
+ <!-- Welcome Banner -->
48224
+ <div class="mb-8">
48225
+ <symphiq-funnel-welcome-banner
48226
+ [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48227
+ [isOnboarded]="isOnboarded()"
48228
+ />
48229
+ </div>
48230
+
48231
+ <!-- Key Insights Section -->
48232
+ @if (showKeyInsights()) {
48233
+ <section id="section-insights" class="mb-8">
48234
+ <div class="flex items-center justify-between mb-6">
48235
+ <div class="flex items-center gap-3">
48236
+ <div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
48237
+ <div class="flex items-center gap-3">
48238
+ <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48239
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
48240
+ </svg>
48241
+ <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
48242
+ </div>
48243
+ </div>
48244
+ </div>
48245
+ <span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
48246
+ </div>
48247
+
48248
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
48249
+ @for (insight of insights(); track $index) {
48250
+ <symphiq-funnel-analysis-insight-card
48251
+ [insight]="insight"
48252
+ [allMetrics]="allMetrics()"
48253
+ [charts]="chartsForInsight(insight)"
48254
+ [allCharts]="allCharts()"
48255
+ [allBusinessInsights]="allBusinessInsights()"
48256
+ [isLightMode]="isLightMode()"
48257
+ [viewMode]="viewMode()"
48258
+ [isCompactMode]="true"
48259
+ [isLoading]="isDataLoading()" />
48260
+ }
48261
+ </div>
48262
+ </section>
48263
+ }
48264
+
48265
+ <!-- Supporting Data Section -->
48266
+ <symphiq-collapsible-funnel-section-group
48267
+ [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK">
48268
+ <!-- Overall Performance Slot -->
48269
+ <div slot="overall-performance">
48270
+ @if (showOverallPerformance()) {
48271
+ <div class="p-6">
48272
+ @if (isDataLoading()) {
48273
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48274
+ } @else {
48275
+ <symphiq-funnel-analysis-overall-assessment
48276
+ [assessment]="performanceOverview().overallAssessment || {}"
48277
+ [revenueMetric]="revenueMetric()"
48278
+ [charts]="chartsForItem('OVERALL_ASSESSMENT')"
48279
+ [metrics]="allMetrics()"
48280
+ [isLightMode]="isLightMode()"
48281
+ [isLoading]="isOverallAssessmentLoading()"
48282
+ [isCompactMode]="true"
48283
+ [isChartsLoading]="areChartsLoading()"
48284
+ [strengths]="strengths()"
48285
+ [weaknesses]="weaknesses()"
48286
+ [currencySymbol]="currencySymbol()"
48287
+ (scrollToSection)="scrollToSection($event)" />
48288
+ }
48289
+ </div>
48290
+ }
48291
+ </div>
48292
+
48293
+ <!-- Performance Metrics Slot -->
48294
+ <div slot="performance-metrics">
48295
+ @if (showPerformanceMetrics()) {
48296
+ <div class="p-6 space-y-8">
48297
+ @for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
48298
+ <!-- Funnel Stage Metric (Full Width) -->
48299
+ <div class="w-full">
48300
+ <symphiq-funnel-analysis-metric-card
48301
+ [metric]="funnelGroup.funnelMetric"
48302
+ [insights]="insights()"
48303
+ [charts]="chartsForMetric(funnelGroup.funnelMetric)"
48304
+ [allCharts]="allCharts()"
48305
+ [analysis]="analysisData()"
48306
+ [isLightMode]="isLightMode()"
48307
+ [viewMode]="viewMode()"
48308
+ [isCompactMode]="true"
48309
+ [currencySymbol]="currencySymbol()" />
48310
+ </div>
48311
+ <!-- Related Metrics (Grid Layout) -->
48312
+ @if (funnelGroup.relatedMetrics.length > 0) {
48313
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-4">
48314
+ @for (metric of funnelGroup.relatedMetrics; track $index) {
48315
+ <symphiq-funnel-analysis-metric-card
48316
+ [metric]="metric"
48317
+ [insights]="insights()"
48318
+ [charts]="chartsForMetric(metric)"
48319
+ [allCharts]="allCharts()"
48320
+ [analysis]="analysisData()"
48321
+ [isLightMode]="isLightMode()"
48322
+ [viewMode]="viewMode()"
48323
+ [isCompactMode]="true"
48324
+ [currencySymbol]="currencySymbol()" />
48325
+ }
48326
+ </div>
48327
+ }
48328
+ }
48329
+ </div>
48330
+ }
48331
+ </div>
48332
+
48333
+ <!-- Performance Breakdowns Slot -->
48334
+ <div slot="performance-breakdowns">
48335
+ @if (showPerformanceBreakdowns()) {
48336
+ <div class="p-6 space-y-8">
48337
+ @for (breakdown of breakdowns(); track $index) {
48338
+ <symphiq-funnel-analysis-breakdown-section
48339
+ [breakdown]="breakdown"
48340
+ [charts]="chartsForBreakdown(breakdown)"
48341
+ [isLightMode]="isLightMode()"
48342
+ [isLoading]="isDataLoading()"
48343
+ [isCompactMode]="true"
48344
+ [currencySymbol]="currencySymbol()" />
48345
+ }
48346
+ </div>
48347
+ }
48348
+ </div>
48349
+
48350
+ <!-- Competitive Intelligence Slot -->
48351
+ <div slot="competitive-intelligence">
48352
+ @if (showCompetitiveIntelligence()) {
48353
+ <div class="p-6">
48354
+ <symphiq-competitive-intelligence-view
48355
+ [metrics]="competitiveMetrics()"
48356
+ [allCharts]="allCharts()"
48357
+ [isLightMode]="isLightMode()"
48358
+ [isCompactMode]="true"
48359
+ [competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
48360
+ [currencySymbol]="currencySymbol()" />
48361
+ </div>
48362
+ }
48363
+ </div>
48364
+ </symphiq-collapsible-funnel-section-group>
48365
+ </div>
48366
+ </main>
48367
+ } @else {
48368
+ <main class="max-w-7xl mx-auto px-6 sm:px-8">
48369
+ <div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
48370
+ @if (showOverallPerformance()) {
48371
+ <div id="section-overall" class="animate-fade-in-up mb-20 sm:mb-28" style="animation-delay: 0.1s;">
48372
+ @if (isDataLoading()) {
48373
+ <!-- Overall Assessment Skeleton -->
48374
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 sm:p-8 animate-pulse">
48375
+ <div class="space-y-6">
48376
+ <!-- Header -->
48377
+ <div class="flex items-center gap-3">
48378
+ <symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48379
+ <div class="flex-1 space-y-2">
48380
+ <symphiq-skeleton-loader [width]="'40%'" [height]="'32px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48381
+ <symphiq-skeleton-loader [width]="'60%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48382
+ </div>
48383
+ </div>
48384
+ <!-- Summary text -->
48385
+ <div class="space-y-2">
48386
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48387
+ <symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48388
+ <symphiq-skeleton-loader [width]="'90%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48389
+ </div>
48390
+ <!-- Chart placeholder -->
48391
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
48392
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48393
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48394
+ </div>
48395
+ </div>
48396
+ </div>
48397
+ } @else {
48398
+ <symphiq-funnel-analysis-overall-assessment
48399
+ [assessment]="performanceOverview().overallAssessment || {}"
48400
+ [revenueMetric]="revenueMetric()"
48401
+ [charts]="chartsForItem('OVERALL_ASSESSMENT')"
48402
+ [metrics]="allMetrics()"
48403
+ [isLightMode]="isLightMode()"
48404
+ [isLoading]="isOverallAssessmentLoading()"
48405
+ [isCompactMode]="viewModeService.isCompact()"
48406
+ [isChartsLoading]="areChartsLoading()"
48407
+ [strengths]="strengths()"
48408
+ [weaknesses]="weaknesses()"
48409
+ [currencySymbol]="currencySymbol()"
48410
+ (scrollToSection)="scrollToSection($event)" />
48411
+ }
48412
+ </div>
48413
+ }
48414
+
48415
+ @if (showKeyInsights()) {
48416
+ @if (selectedSectionFilter() === 'ALL') {
48417
+ <!-- Section Divider -->
48418
+ <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.15s"></symphiq-section-divider>
48419
+ }
48420
+
48421
+ <section id="section-insights" class="relative">
48422
+ <!-- Background Pattern -->
48423
+ <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-blue-50/50 to-transparent' : 'bg-gradient-to-br from-blue-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
48424
+ <div class="relative">
48425
+ <div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.2s;">
48426
+ <div class="flex items-center gap-3">
48427
+ <div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
48428
+ <div class="flex items-center gap-3">
48429
+ <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48430
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
48431
+ </svg>
48432
+ <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
48433
+ </div>
48434
+ </div>
48435
+ </div>
48436
+ <span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
48437
+ </div>
48438
+ <!-- Masonry Layout for Insights -->
48439
+ @if (isDataLoading() || (viewModeService.isExpanded() && viewModeService.getIsTransitioning())) {
48440
+ <!-- Skeleton loaders during data loading or transition to expanded view -->
48441
+ <div class="masonry-grid">
48442
+ @for (i of [1,2,3,4,5,6]; track i) {
48443
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[280px]">
48444
+ <div class="space-y-4">
48445
+ <div class="flex items-center gap-3 mb-4">
48446
+ <symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48447
+ <symphiq-skeleton-loader [width]="'60%'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48448
+ </div>
48449
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48450
+ <symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48451
+ <symphiq-skeleton-loader [width]="'85%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48452
+ <div class="mt-6 space-y-2">
48453
+ <symphiq-skeleton-loader [width]="'40%'" [height]="'14px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48454
+ <symphiq-skeleton-loader [width]="'50%'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48455
+ </div>
48456
+ <div class="flex gap-2 mt-4">
48457
+ <symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48458
+ <symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48459
+ </div>
48460
+ </div>
48461
+ </div>
48462
+ }
48463
+ </div>
48464
+ } @else if (viewModeService.isExpanded()) {
48465
+ <div class="masonry-grid">
48466
+ @for (insight of insights(); track $index) {
48467
+ <div
48468
+ [class]="getInsightCardClass(insight)"
48469
+ class="animate-fade-in-up"
48470
+ [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
48471
+ [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48472
+ [highlightId]="'insight-' + $index">
48473
+ <symphiq-funnel-analysis-insight-card
48474
+ [insight]="insight"
48475
+ [allMetrics]="allMetrics()"
48476
+ [charts]="chartsForInsight(insight)"
48477
+ [allCharts]="allCharts()"
48478
+ [allBusinessInsights]="allBusinessInsights()"
48479
+ [isLightMode]="isLightMode()"
48480
+ [viewMode]="viewMode()"
48481
+ [isCompactMode]="false" />
48482
+ </div>
48483
+ }
48484
+ </div>
48485
+ } @else {
48486
+ <!-- Compact Grid for Insights -->
48487
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
48488
+ @for (insight of insights(); track $index) {
48489
+ <div class="animate-fade-in-up" [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
48490
+ [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48491
+ [highlightId]="'insight-' + $index">
48492
+ <symphiq-funnel-analysis-insight-card
48493
+ [insight]="insight"
48494
+ [allMetrics]="allMetrics()"
48495
+ [charts]="chartsForInsight(insight)"
48496
+ [allCharts]="allCharts()"
48497
+ [allBusinessInsights]="allBusinessInsights()"
48498
+ [isLightMode]="isLightMode()"
48499
+ [viewMode]="viewMode()"
48500
+ [isCompactMode]="true" />
48501
+ </div>
48502
+ }
48503
+ </div>
48504
+ }
48505
+ </div>
48506
+ </section>
48507
+ }
48508
+
48509
+ @if (showPerformanceMetrics()) {
48510
+ @if (selectedSectionFilter() === 'ALL') {
48511
+ <!-- Section Divider -->
48512
+ <div class="relative mb-14 sm:mb-24 mt-24 sm:mt-32 animate-fade-in" style="animation-delay: 0.35s;">
48513
+ <div class="absolute inset-0 flex items-center" aria-hidden="true">
48514
+ <div class="w-full h-px bg-gradient-to-r" [ngClass]="isLightMode() ? 'from-transparent via-emerald-500/30 to-transparent' : 'from-transparent via-emerald-400/20 to-transparent'"></div>
48515
+ </div>
48516
+ <div class="relative flex justify-center">
48517
+ <div class="px-4 py-2 rounded-full" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-emerald-50 to-teal-50 border border-emerald-200/50 shadow-lg shadow-emerald-500/10' : 'bg-gradient-to-br from-slate-900 to-slate-800 border border-emerald-500/20 shadow-lg shadow-emerald-500/5'">
48518
+ <svg class="w-5 h-5" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48519
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
48520
+ </svg>
48521
+ </div>
48522
+ </div>
48523
+ </div>
48524
+ }
48525
+
48526
+ <section id="section-metrics" class="relative">
48527
+ <!-- Background Pattern -->
48528
+ <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tl from-emerald-50/50 to-transparent' : 'bg-gradient-to-tl from-emerald-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at top right, black 0%, transparent 70%);"></div>
48529
+ <div class="relative">
48530
+ <div class="flex flex-col gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.4s;">
48531
+ <div class="flex items-center justify-between">
48532
+ <div class="flex items-center gap-3">
48533
+ <div [ngClass]="isLightMode() ? 'border-l-4 border-emerald-500' : 'border-l-4 border-emerald-400'" class="pl-4">
48534
+ <div class="flex items-center gap-3">
48535
+ <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48536
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
48537
+ </svg>
48538
+ <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Metrics</h2>
48539
+ </div>
48540
+ </div>
48541
+ </div>
48542
+ <!-- Desktop controls -->
48543
+ <div class="hidden sm:flex gap-2 sm:gap-3 items-center relative">
48544
+ @if (isCategoryTransitioning()) {
48545
+ <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48546
+ <div class="w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full animate-spin"></div>
48547
+ </div>
48548
+ }
48549
+ <select
48550
+ [ngModel]="selectedCategory()"
48551
+ (ngModelChange)="changeCategoryFilter($event)"
48552
+ [class]="selectClass()"
48553
+ [class.opacity-70]="isCategoryTransitioning()"
48554
+ class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
48555
+ @for (cat of categories; track cat.value) {
48556
+ @if (cat.divider) {
48557
+ <option [value]="cat.value" disabled class="font-semibold">{{ cat.label }}</option>
48558
+ } @else {
48559
+ <option [value]="cat.value">{{ cat.label }}</option>
48560
+ }
48561
+ }
48562
+ </select>
48563
+ <button
48564
+ (click)="toggleSortOrder()"
48565
+ [class]="sortButtonClass()"
48566
+ class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all flex items-center gap-2 cursor-pointer hover:scale-105 active:scale-95"
48567
+ [title]="reverseSortOrder() ? 'Sort: Revenue to Views' : 'Sort: Views to Revenue'">
48568
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48569
+ @if (!reverseSortOrder()) {
48570
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"></path>
48571
+ }
48572
+ @if (reverseSortOrder()) {
48573
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"></path>
48574
+ }
48575
+ </svg>
48576
+ <span>Sort</span>
48577
+ </button>
48578
+ </div>
48579
+ </div>
48580
+
48581
+ <!-- Mobile horizontal scrolling category pills -->
48582
+ <div class="sm:hidden -mx-6 px-6">
48583
+ <div class="flex gap-2 overflow-x-auto pb-2 snap-x snap-mandatory scrollbar-hide">
48584
+ @for (cat of categories; track cat.value) {
48585
+ @if (!cat.divider) {
48586
+ <button
48587
+ (click)="changeCategoryFilter(cat.value)"
48588
+ [ngClass]="getCategoryPillClass(cat.value)"
48589
+ [class.opacity-70]="isCategoryTransitioning()"
48590
+ class="px-4 py-2 rounded-full text-xs font-medium whitespace-nowrap transition-all duration-200 flex-shrink-0 snap-start active:scale-95">
48591
+ {{ cat.label }}
48592
+ </button>
48593
+ }
48594
+ }
48595
+ </div>
48596
+ </div>
48597
+ </div>
48598
+ @if (isDataLoading()) {
48599
+ <!-- Metrics Skeleton -->
48600
+ <div class="space-y-8 sm:space-y-10">
48601
+ @for (i of [1,2,3]; track i) {
48602
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48603
+ <div class="flex items-center justify-between mb-4">
48604
+ <div class="flex items-center gap-3">
48605
+ <symphiq-skeleton-loader [width]="'40px'" [height]="'40px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48606
+ <div class="space-y-2">
48607
+ <symphiq-skeleton-loader [width]="'150px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48608
+ <symphiq-skeleton-loader [width]="'100px'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48609
+ </div>
48610
+ </div>
48611
+ <symphiq-skeleton-loader [width]="'80px'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48612
+ </div>
48613
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
48614
+ @for (j of [1,2,3,4]; track j) {
48615
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48616
+ }
48617
+ </div>
48618
+ </div>
48619
+ }
48620
+ </div>
48621
+ } @else {
48622
+ <div class="space-y-8 sm:space-y-10" [class.animate-content-change]="isCategoryTransitioning()" [class.transition-opacity-slow]="isCategoryTransitioning()">
48623
+ @for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
48624
+ <div class="w-full animate-fade-in-up" [style.animation-delay]="(0.5 + groupIdx * 0.15) + 's'"
48625
+ [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48626
+ [highlightId]="'metric-' + groupIdx">
48627
+ <symphiq-funnel-analysis-metric-card
48628
+ [metric]="funnelGroup.funnelMetric"
48629
+ [insights]="insights()"
48630
+ [charts]="chartsForMetric(funnelGroup.funnelMetric)"
48631
+ [allCharts]="allCharts()"
48632
+ [analysis]="analysisData()"
48633
+ [isLightMode]="isLightMode()"
48634
+ [viewMode]="viewMode()"
48635
+ [isCompactMode]="viewModeService.isCompact()"
48636
+ [currencySymbol]="currencySymbol()" />
48637
+ </div>
48638
+ @if (funnelGroup.relatedMetrics.length > 0) {
48639
+ <!-- Bento Box Grid Layout -->
48640
+ @if (viewModeService.isExpanded()) {
48641
+ <div class="bento-grid mt-4">
48642
+ @for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
48643
+ <div
48644
+ [class]="getBentoCardClass(metric, metricIdx)"
48645
+ class="animate-fade-in-up"
48646
+ [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
48647
+ <symphiq-funnel-analysis-metric-card
48648
+ class="h-full"
48649
+ [metric]="metric"
48650
+ [insights]="insights()"
48651
+ [charts]="chartsForMetric(metric)"
48652
+ [allCharts]="allCharts()"
48653
+ [analysis]="analysisData()"
48654
+ [isLightMode]="isLightMode()"
48655
+ [viewMode]="viewMode()"
48656
+ [isCompactMode]="false"
48657
+ [currencySymbol]="currencySymbol()" />
48658
+ </div>
48659
+ }
48660
+ </div>
48661
+ } @else if (!viewModeService.isExpanded()) {
48662
+ <!-- Compact Grid Layout -->
48663
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mt-4">
48664
+ @for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
48665
+ <div class="animate-fade-in-up" [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
48666
+ <symphiq-funnel-analysis-metric-card
48667
+ [metric]="metric"
48668
+ [insights]="insights()"
48669
+ [charts]="chartsForMetric(metric)"
48670
+ [allCharts]="allCharts()"
48671
+ [analysis]="analysisData()"
48672
+ [isLightMode]="isLightMode()"
48673
+ [viewMode]="viewMode()"
48674
+ [isCompactMode]="true"
48675
+ [currencySymbol]="currencySymbol()" />
48676
+ </div>
48677
+ }
48678
+ </div>
48679
+ } @else {
48680
+ <!-- Skeleton loaders during transition to expanded view -->
48681
+ <div class="bento-grid mt-4">
48682
+ @for (i of [1,2,3,4]; track i) {
48683
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[240px]">
48684
+ <div class="space-y-4">
48685
+ <div class="flex items-center justify-between">
48686
+ <symphiq-skeleton-loader [width]="'60%'" [height]="'22px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48687
+ <symphiq-skeleton-loader [width]="'60px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48688
+ </div>
48689
+ <symphiq-skeleton-loader [width]="'45%'" [height]="'42px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48690
+ <div class="flex items-center gap-3 mt-4">
48691
+ <symphiq-skeleton-loader [width]="'24px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48692
+ <symphiq-skeleton-loader [width]="'30%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48693
+ </div>
48694
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48695
+ <symphiq-skeleton-loader [width]="'85%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48696
+ <div class="mt-4">
48697
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48698
+ </div>
48699
+ </div>
48700
+ </div>
48701
+ }
48702
+ </div>
48703
+ }
48704
+ }
48705
+ } @empty {
48706
+ <div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
48707
+ <svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48708
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
48709
+ </svg>
48710
+ <h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Metrics Found</h3>
48711
+ <p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance metrics match your current filter selection. Try adjusting your filters to see more results.</p>
48712
+ </div>
48713
+ }
48714
+ </div>
48715
+ }
48716
+ </div>
48717
+ </section>
48718
+ }
48719
+
48720
+ @if (showPerformanceBreakdowns()) {
48721
+ @if (selectedSectionFilter() === 'ALL') {
48722
+ <!-- Section Divider -->
48723
+ <div class="mt-28 sm:mt-36">
48724
+ <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.65s"></symphiq-section-divider>
48725
+ </div>
48726
+ }
48727
+
48728
+ <section id="section-breakdowns" class="relative">
48729
+ <!-- Background Pattern -->
48730
+ <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tr from-purple-50/50 to-transparent' : 'bg-gradient-to-tr from-purple-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at bottom left, black 0%, transparent 70%);"></div>
48731
+ <div class="relative">
48732
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.7s;">
48733
+ <div [ngClass]="isLightMode() ? 'border-l-4 border-purple-500' : 'border-l-4 border-purple-400'" class="pl-4">
48734
+ <div class="flex items-center gap-3">
48735
+ <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-purple-500' : 'text-purple-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48736
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
48737
+ </svg>
48738
+ <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Breakdowns</h2>
48739
+ </div>
48740
+ </div>
48741
+ <div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()" class="relative inline-block">
48742
+ @if (isBreakdownTransitioning()) {
48743
+ <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48744
+ <div class="w-4 h-4 border-2 border-purple-500/30 border-t-purple-500 rounded-full animate-spin"></div>
48745
+ </div>
48746
+ }
48747
+ <select
48748
+ [ngModel]="selectedBreakdownFilter()"
48749
+ (ngModelChange)="changeBreakdownFilter($event)"
48750
+ [ngClass]="isLightMode()
48751
+ ? 'bg-white border-slate-300 text-slate-900 hover:border-blue-400 focus:border-blue-500'
48752
+ : 'bg-slate-700 border-slate-600 text-white hover:border-slate-500 focus:border-blue-500'"
48753
+ [class.opacity-70]="isBreakdownTransitioning()"
48754
+ class="px-3 py-2 text-sm rounded-lg border transition-all duration-200 cursor-pointer focus:ring-2 focus:ring-blue-500 focus:outline-none">
48755
+ @for (filter of breakdownFilters; track filter.value) {
48756
+ @if (filter.divider) {
48757
+ <option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
48758
+ } @else {
48759
+ <option [value]="filter.value">{{ filter.label }}</option>
48760
+ }
48761
+ }
48762
+ </select>
48763
+ </div>
48764
+ </div>
48765
+ @if (isDataLoading()) {
48766
+ <!-- Breakdowns Skeleton -->
48767
+ <div class="space-y-6">
48768
+ @for (i of [1,2]; track i) {
48769
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48770
+ <div class="flex items-center justify-between mb-4">
48771
+ <symphiq-skeleton-loader [width]="'200px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48772
+ <symphiq-skeleton-loader [width]="'100px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48773
+ </div>
48774
+ <div class="space-y-3">
48775
+ @for (j of [1,2,3,4]; track j) {
48776
+ <div class="flex items-center justify-between p-3 rounded-lg" [ngClass]="isLightMode() ? 'bg-slate-50' : 'bg-slate-700/50'">
48777
+ <symphiq-skeleton-loader [width]="'150px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48778
+ <symphiq-skeleton-loader [width]="'80px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48779
+ </div>
48780
+ }
48781
+ </div>
48782
+ </div>
48783
+ }
48784
+ </div>
48785
+ } @else {
48786
+ <div class="space-y-6" [class.animate-content-change]="isBreakdownTransitioning()" [class.transition-opacity-slow]="isBreakdownTransitioning()">
48787
+ @for (breakdown of breakdowns(); track $index) {
48788
+ <div class="animate-fade-in-up" [style.animation-delay]="(0.8 + $index * 0.1) + 's'"
48789
+ [libSymphiqSearchHighlight]="searchService.highlightedResultId()"
48790
+ [highlightId]="'breakdown-' + $index">
48791
+ <symphiq-funnel-analysis-breakdown-section
48792
+ [breakdown]="breakdown"
48793
+ [charts]="chartsForBreakdown(breakdown)"
48794
+ [isLightMode]="isLightMode()"
48795
+ [isCompactMode]="viewModeService.isCompact()"
48796
+ [currencySymbol]="currencySymbol()" />
48797
+ </div>
48798
+ } @empty {
48799
+ <div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
48800
+ <svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48801
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
48802
+ </svg>
48803
+ <h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Breakdowns Found</h3>
48804
+ <p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance breakdowns match your current filter selection. Try adjusting your filters to see more results.</p>
48805
+ </div>
48806
+ }
48807
+ </div>
48808
+ }
48809
+ </div>
48810
+ </section>
48811
+ }
48812
+
48813
+ @if (showCompetitiveIntelligence()) {
48814
+ @if (selectedSectionFilter() === 'ALL') {
48815
+ <!-- Section Divider -->
48816
+ <div class="mt-28 sm:mt-36">
48817
+ <symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.85s"></symphiq-section-divider>
48818
+ </div>
48819
+ }
48820
+
48821
+ <!-- Competitive Intelligence Section -->
48822
+ <section id="section-competitive" class="relative">
48823
+ <!-- Background Pattern -->
48824
+ <div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-indigo-50/50 to-transparent' : 'bg-gradient-to-br from-indigo-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
48825
+ <div class="relative">
48826
+ <div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.9s;">
48827
+ <div class="flex items-center gap-3">
48828
+ <div [ngClass]="isLightMode() ? 'border-l-4 border-indigo-500' : 'border-l-4 border-indigo-400'" class="pl-4">
48829
+ <div class="flex items-center gap-3">
48830
+ <svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-indigo-500' : 'text-indigo-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48831
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
48832
+ </svg>
48833
+ <h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Competitive Intelligence</h2>
48834
+ </div>
48835
+ </div>
48836
+ </div>
48837
+ <!-- Filter Dropdown -->
48838
+ <div class="hidden sm:block relative">
48839
+ @if (isCompetitiveTransitioning()) {
48840
+ <div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
48841
+ <div class="w-4 h-4 border-2 border-indigo-500/30 border-t-indigo-500 rounded-full animate-spin"></div>
48842
+ </div>
48843
+ }
48844
+ <select
48845
+ [ngModel]="selectedCompetitiveFilter()"
48846
+ (ngModelChange)="changeCompetitiveFilter($event)"
48847
+ [class]="selectClass()"
48848
+ [class.opacity-70]="isCompetitiveTransitioning()"
48849
+ class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
48850
+ @for (filter of competitiveFilters; track filter.value) {
48851
+ @if (filter.divider) {
48852
+ <option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
48853
+ } @else {
48854
+ <option [value]="filter.value">{{ filter.label }}</option>
48855
+ }
48856
+ }
48857
+ </select>
48858
+ </div>
48859
+ </div>
48860
+
48861
+ @if (isDataLoading()) {
48862
+ <!-- Competitive Intelligence Skeleton -->
48863
+ <div class="space-y-6">
48864
+ <div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
48865
+ <symphiq-skeleton-loader [width]="'60%'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48866
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
48867
+ @for (i of [1,2,3]; track i) {
48868
+ <symphiq-skeleton-loader [width]="'100%'" [height]="'140px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
48869
+ }
48870
+ </div>
48871
+ </div>
48872
+ </div>
48873
+ } @else {
48874
+ <symphiq-competitive-intelligence-view
48875
+ [metrics]="competitiveMetrics()"
48876
+ [allCharts]="allCharts()"
48877
+ [isLightMode]="isLightMode()"
48878
+ [isCompactMode]="viewModeService.isCompact()"
48879
+ [competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
48880
+ [currencySymbol]="currencySymbol()" />
48881
+ }
48882
+ </div>
48883
+ </section>
48884
+ }
48885
+ </div>
48886
+ </main>
48887
+ }
48888
+
48889
+ <symphiq-funnel-analysis-modal
48890
+ [isLightMode]="isLightMode()"
48891
+ [viewMode]="viewMode()"
48892
+ [allMetrics]="allMetrics()"
48893
+ [allInsights]="insights()"
48894
+ [allCharts]="allCharts()"
48895
+ [currencySymbol]="currencySymbol()"
48896
+ [businessProfile]="businessProfile()"></symphiq-funnel-analysis-modal>
48897
+ <symphiq-profile-analysis-modal
48898
+ [isLightMode]="isLightMode()"
48899
+ [allMetrics]="allMetrics()"
48900
+ ></symphiq-profile-analysis-modal>
48901
+ <symphiq-business-analysis-modal [isLightMode]="isLightMode()" />
48902
+ <symphiq-tooltip-container></symphiq-tooltip-container>
48903
+ <symphiq-search-bar
48904
+ [isLightMode]="isLightMode()"
48905
+ (resultSelected)="handleSearchResult($event)" />
48906
+
48907
+ <!-- View Mode Switcher Modal -->
48908
+ <symphiq-view-mode-switcher-modal
48909
+ [isOpen]="isViewModeSwitcherOpen()"
48910
+ [currentMode]="displayMode()"
48911
+ [viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
48912
+ [isLoading]="isViewModeSwitching()"
48913
+ (close)="closeViewModeSwitcher()"
48914
+ (modeSelected)="handleDisplayModeChange($event)"
48915
+ />
48916
+
48917
+ <!-- Mobile FAB -->
48918
+ <symphiq-mobile-fab
48919
+ [isLightMode]="isLightMode()"
48920
+ [isCompactMode]="viewModeService.isCompact()"
48921
+ [isExpanded]="fabExpanded()"
48922
+ (expandedChange)="fabExpanded.set($event)"
48923
+ (scrollToTop)="scrollToTop()"
48924
+ (toggleView)="viewModeService.toggleViewMode()" />
48925
+
48926
+ <!-- Mobile Bottom Navigation -->
48927
+ <symphiq-mobile-bottom-nav
48928
+ [isLightMode]="isLightMode()"
48929
+ [sections]="navSections"
48930
+ [activeSection]="activeNavSection()"
48931
+ (navigate)="handleMobileNavigation($event)" />
48932
+
48933
+ </div>
48934
48934
  `, styles: [":host{display:block;min-height:100%}.bg-gradient-radial{background:radial-gradient(circle,var(--tw-gradient-stops))}.bento-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem;grid-auto-flow:dense}@media (min-width: 768px){.bento-grid{grid-template-columns:repeat(6,1fr)}}.bento-small{grid-column:span 2;grid-row:span 1}.bento-medium{grid-column:span 3;grid-row:span 1}.bento-large{grid-column:span 4;grid-row:span 1}.bento-featured{grid-column:span 6;grid-row:span 1}@media (max-width: 767px){.bento-small,.bento-medium,.bento-large,.bento-featured{grid-column:span 1}}.masonry-grid{column-count:1;column-gap:1.5rem}@media (min-width: 768px){.masonry-grid{column-count:2}}@media (min-width: 1280px){.masonry-grid{column-count:3}}.masonry-grid>div{break-inside:avoid;margin-bottom:1.5rem}.masonry-featured{column-span:all}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}@media (max-width: 640px){.animate-fade-in-up{animation-duration:.4s}}\n"] }]
48935
48935
  }], () => [{ type: FunnelOrderService }, { type: ViewModeService }, { type: SearchService }, { type: TooltipService }, { type: ProfileContextService }, { type: ProfileItemLookupService }], { modalComponent: [{
48936
48936
  type: ViewChild,
@@ -54699,12 +54699,12 @@ function getPacingColorDark(pacingPercentage) {
54699
54699
  }
54700
54700
  function getPacingBgClass(status, isDark) {
54701
54701
  if (status === 'ahead') {
54702
- return isDark ? 'bg-emerald-900/30' : 'bg-emerald-50';
54702
+ return isDark ? 'bg-emerald-500/25' : 'bg-emerald-50';
54703
54703
  }
54704
54704
  if (status === 'on-pace') {
54705
- return isDark ? 'bg-amber-900/30' : 'bg-amber-50';
54705
+ return isDark ? 'bg-amber-500/25' : 'bg-amber-50';
54706
54706
  }
54707
- return isDark ? 'bg-red-900/30' : 'bg-red-50';
54707
+ return isDark ? 'bg-red-500/25' : 'bg-red-50';
54708
54708
  }
54709
54709
  function getPacingTextClass(status, isDark) {
54710
54710
  if (status === 'ahead') {
@@ -54717,12 +54717,12 @@ function getPacingTextClass(status, isDark) {
54717
54717
  }
54718
54718
  function getPacingBorderClass(status, isDark) {
54719
54719
  if (status === 'ahead') {
54720
- return isDark ? 'border-emerald-500/30' : 'border-emerald-300';
54720
+ return isDark ? 'border-emerald-400/40' : 'border-emerald-200';
54721
54721
  }
54722
54722
  if (status === 'on-pace') {
54723
- return isDark ? 'border-amber-500/30' : 'border-amber-300';
54723
+ return isDark ? 'border-amber-400/40' : 'border-amber-200';
54724
54724
  }
54725
- return isDark ? 'border-red-500/30' : 'border-red-300';
54725
+ return isDark ? 'border-red-400/40' : 'border-red-200';
54726
54726
  }
54727
54727
  function formatPacingDisplay(pacingPercentage) {
54728
54728
  const sign = pacingPercentage >= 0 ? '+' : '';
@@ -54828,7 +54828,7 @@ function PacingStatusBadgeComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
54828
54828
  i0.ɵɵadvance();
54829
54829
  i0.ɵɵtextInterpolate1(" ", ctx_r0.iconSymbol(), " ");
54830
54830
  i0.ɵɵadvance();
54831
- i0.ɵɵtextInterpolate1(" ", ctx_r0.extractPercentage(), " ");
54831
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.animatedPercentage(), " ");
54832
54832
  i0.ɵɵadvance();
54833
54833
  i0.ɵɵclassMap(ctx_r0.sizeClasses());
54834
54834
  i0.ɵɵadvance(2);
@@ -54861,6 +54861,7 @@ class PacingStatusBadgeComponent {
54861
54861
  this.showAsFullText = input(false, ...(ngDevMode ? [{ debugName: "showAsFullText" }] : []));
54862
54862
  this.isCompact = input(false, ...(ngDevMode ? [{ debugName: "isCompact" }] : []));
54863
54863
  this.showEmphasizedPercentage = input(false, ...(ngDevMode ? [{ debugName: "showEmphasizedPercentage" }] : []));
54864
+ this.animatedValue = signal(0, ...(ngDevMode ? [{ debugName: "animatedValue" }] : []));
54864
54865
  this.displayInfo = computed(() => {
54865
54866
  const isDark = this.viewMode() === ViewModeEnum.DARK;
54866
54867
  return getPacingDisplayInfo(this.pacingPercentage(), this.status(), isDark);
@@ -54871,9 +54872,12 @@ class PacingStatusBadgeComponent {
54871
54872
  }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
54872
54873
  this.containerSizeClasses = computed(() => {
54873
54874
  const compact = this.isCompact();
54875
+ const status = this.status();
54876
+ const tiltClass = status === 'ahead' ? 'rotate-1' : status === 'behind' ? '-rotate-1' : '';
54877
+ const baseClasses = 'inline-flex flex-row items-center rounded-xl border-2 overflow-visible transition-transform hover:rotate-0';
54874
54878
  return compact
54875
- ? 'inline-flex flex-row items-center rounded-full pl-1.5 overflow-visible'
54876
- : 'inline-flex flex-row items-center rounded-full pl-2 overflow-visible';
54879
+ ? `${baseClasses} pl-1.5 ${tiltClass}`
54880
+ : `${baseClasses} pl-2 ${tiltClass}`;
54877
54881
  }, ...(ngDevMode ? [{ debugName: "containerSizeClasses" }] : []));
54878
54882
  this.badgeClasses = computed(() => {
54879
54883
  const info = this.displayInfo();
@@ -54889,7 +54893,9 @@ class PacingStatusBadgeComponent {
54889
54893
  }, ...(ngDevMode ? [{ debugName: "sizeClasses" }] : []));
54890
54894
  this.fullBadgeSizeClasses = computed(() => {
54891
54895
  const isCompact = this.isCompact();
54892
- const baseClasses = 'inline-flex items-center gap-1.5 rounded-lg border font-semibold transition-all';
54896
+ const status = this.status();
54897
+ const tiltClass = status === 'ahead' ? 'rotate-1' : status === 'behind' ? '-rotate-1' : '';
54898
+ const baseClasses = `inline-flex items-center gap-1.5 rounded-xl border-2 font-bold tracking-wide shadow-md transition-all hover:rotate-0 ${tiltClass}`;
54893
54899
  if (isCompact) {
54894
54900
  return `${baseClasses} px-2.5 py-1 text-xs`;
54895
54901
  }
@@ -54921,6 +54927,9 @@ class PacingStatusBadgeComponent {
54921
54927
  : this.displayInfo().displayText;
54922
54928
  return /\d+\.?\d*%/.test(fullText);
54923
54929
  }, ...(ngDevMode ? [{ debugName: "hasPercentage" }] : []));
54930
+ this.animatedPercentage = computed(() => {
54931
+ return `${this.animatedValue().toFixed(1)}%`;
54932
+ }, ...(ngDevMode ? [{ debugName: "animatedPercentage" }] : []));
54924
54933
  this.extractPercentage = computed(() => {
54925
54934
  const fullText = this.showAsFullText()
54926
54935
  ? formatPacingDisplayFullText(this.pacingPercentage(), this.status())
@@ -54940,24 +54949,44 @@ class PacingStatusBadgeComponent {
54940
54949
  const isDark = this.viewMode() === ViewModeEnum.DARK;
54941
54950
  if (status === 'ahead') {
54942
54951
  return isDark
54943
- ? 'bg-gradient-to-r from-emerald-700 to-emerald-600 text-emerald-100 border-emerald-500'
54944
- : 'bg-gradient-to-r from-emerald-600 to-emerald-500 text-white border-emerald-400';
54952
+ ? 'bg-emerald-600 text-emerald-50'
54953
+ : 'bg-emerald-500 text-white';
54945
54954
  }
54946
54955
  if (status === 'on-pace') {
54947
54956
  return isDark
54948
- ? 'bg-gradient-to-r from-amber-700 to-amber-600 text-amber-100 border-amber-500'
54949
- : 'bg-gradient-to-r from-amber-600 to-amber-500 text-white border-amber-400';
54957
+ ? 'bg-amber-600 text-amber-50'
54958
+ : 'bg-amber-500 text-white';
54950
54959
  }
54951
54960
  return isDark
54952
- ? 'bg-gradient-to-r from-red-700 to-red-600 text-red-100 border-red-500'
54953
- : 'bg-gradient-to-r from-red-600 to-red-500 text-white border-red-400';
54961
+ ? 'bg-red-600 text-red-50'
54962
+ : 'bg-red-500 text-white';
54954
54963
  }, ...(ngDevMode ? [{ debugName: "overlayBadgeClasses" }] : []));
54955
54964
  this.overlaySizeClasses = computed(() => {
54956
54965
  const compact = this.isCompact();
54957
54966
  return compact
54958
- ? 'px-2 py-1.5 rounded text-sm font-extrabold tracking-tight border shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
54959
- : 'px-2.5 py-2 rounded-md text-sm font-extrabold tracking-tight border-2 shadow-lg transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
54967
+ ? 'px-2 py-1.5 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
54968
+ : 'px-2.5 py-2 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
54960
54969
  }, ...(ngDevMode ? [{ debugName: "overlaySizeClasses" }] : []));
54970
+ effect(() => {
54971
+ const target = Math.abs(this.pacingPercentage());
54972
+ this.animateValue(target);
54973
+ });
54974
+ }
54975
+ animateValue(target) {
54976
+ const start = 0;
54977
+ const duration = 800;
54978
+ const startTime = performance.now();
54979
+ const animate = (currentTime) => {
54980
+ const elapsed = currentTime - startTime;
54981
+ const progress = Math.min(elapsed / duration, 1);
54982
+ const easeOutQuart = 1 - Math.pow(1 - progress, 4);
54983
+ const current = start + (target - start) * easeOutQuart;
54984
+ this.animatedValue.set(current);
54985
+ if (progress < 1) {
54986
+ requestAnimationFrame(animate);
54987
+ }
54988
+ };
54989
+ requestAnimationFrame(animate);
54961
54990
  }
54962
54991
  static { this.ɵfac = function PacingStatusBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PacingStatusBadgeComponent)(); }; }
54963
54992
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PacingStatusBadgeComponent, selectors: [["symphiq-pacing-status-badge"]], inputs: { viewMode: [1, "viewMode"], pacingPercentage: [1, "pacingPercentage"], status: [1, "status"], showAsFullText: [1, "showAsFullText"], isCompact: [1, "isCompact"], showEmphasizedPercentage: [1, "showEmphasizedPercentage"] }, decls: 2, vars: 1, consts: [[3, "ngClass", "class"], [3, "ngClass"]], template: function PacingStatusBadgeComponent_Template(rf, ctx) { if (rf & 1) {
@@ -54973,35 +55002,35 @@ class PacingStatusBadgeComponent {
54973
55002
  standalone: true,
54974
55003
  imports: [CommonModule],
54975
55004
  changeDetection: ChangeDetectionStrategy.OnPush,
54976
- template: `
54977
- @if (showEmphasizedPercentage() && hasPercentage()) {
54978
- <div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
54979
- <div [ngClass]="overlayBadgeClasses()" [class]="overlaySizeClasses()">
54980
- <span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
54981
- {{ iconSymbol() }}
54982
- </span>
54983
- {{ extractPercentage() }}
54984
- </div>
54985
- <div
54986
- [class]="sizeClasses()"
54987
- >
54988
- <span>{{ displayTextWithoutPercentage() }}</span>
54989
- </div>
54990
- </div>
54991
- } @else {
54992
- <div
54993
- [ngClass]="badgeClasses()"
54994
- [class]="fullBadgeSizeClasses()"
54995
- >
54996
- <span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
54997
- {{ iconSymbol() }}
54998
- </span>
54999
- <span>{{ displayText() }}</span>
55000
- </div>
55001
- }
55005
+ template: `
55006
+ @if (showEmphasizedPercentage() && hasPercentage()) {
55007
+ <div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
55008
+ <div [ngClass]="overlayBadgeClasses()" [class]="overlaySizeClasses()">
55009
+ <span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
55010
+ {{ iconSymbol() }}
55011
+ </span>
55012
+ {{ animatedPercentage() }}
55013
+ </div>
55014
+ <div
55015
+ [class]="sizeClasses()"
55016
+ >
55017
+ <span>{{ displayTextWithoutPercentage() }}</span>
55018
+ </div>
55019
+ </div>
55020
+ } @else {
55021
+ <div
55022
+ [ngClass]="badgeClasses()"
55023
+ [class]="fullBadgeSizeClasses()"
55024
+ >
55025
+ <span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
55026
+ {{ iconSymbol() }}
55027
+ </span>
55028
+ <span>{{ displayText() }}</span>
55029
+ </div>
55030
+ }
55002
55031
  `
55003
55032
  }]
55004
- }], null, { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], pacingPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "pacingPercentage", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showAsFullText: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAsFullText", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }], showEmphasizedPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmphasizedPercentage", required: false }] }] }); })();
55033
+ }], () => [], { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], pacingPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "pacingPercentage", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showAsFullText: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAsFullText", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }], showEmphasizedPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmphasizedPercentage", required: false }] }] }); })();
55005
55034
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PacingStatusBadgeComponent, { className: "PacingStatusBadgeComponent", filePath: "lib/components/revenue-calculator-dashboard/pacing-status-badge.component.ts", lineNumber: 39 }); })();
55006
55035
 
55007
55036
  class TargetChangeBadgeComponent {
@@ -55011,6 +55040,7 @@ class TargetChangeBadgeComponent {
55011
55040
  this.metric = input('', ...(ngDevMode ? [{ debugName: "metric" }] : []));
55012
55041
  this.priorYear = input(new Date().getFullYear() - 1, ...(ngDevMode ? [{ debugName: "priorYear" }] : []));
55013
55042
  this.isCompact = input(false, ...(ngDevMode ? [{ debugName: "isCompact" }] : []));
55043
+ this.animatedValue = signal(0, ...(ngDevMode ? [{ debugName: "animatedValue" }] : []));
55014
55044
  this.isDark = computed(() => this.viewMode() === ViewModeEnum.DARK, ...(ngDevMode ? [{ debugName: "isDark" }] : []));
55015
55045
  this.isIncreaseBad = computed(() => {
55016
55046
  const metricStr = this.metric();
@@ -55026,11 +55056,11 @@ class TargetChangeBadgeComponent {
55026
55056
  return '↘';
55027
55057
  return '→';
55028
55058
  }, ...(ngDevMode ? [{ debugName: "iconSymbol" }] : []));
55029
- this.percentageText = computed(() => {
55059
+ this.animatedPercentageText = computed(() => {
55030
55060
  const sign = this.isIncreaseBad() ? '' : '+';
55031
- const absValue = Math.abs(this.percentageChange());
55061
+ const absValue = Math.abs(this.animatedValue());
55032
55062
  return `${sign}${formatPercentage(absValue, 1)}`;
55033
- }, ...(ngDevMode ? [{ debugName: "percentageText" }] : []));
55063
+ }, ...(ngDevMode ? [{ debugName: "animatedPercentageText" }] : []));
55034
55064
  this.descriptionText = computed(() => {
55035
55065
  const action = this.isIncreaseBad() ? 'decrease from' : 'increase over';
55036
55066
  return `${action} ${this.priorYear()}`;
@@ -55038,26 +55068,30 @@ class TargetChangeBadgeComponent {
55038
55068
  this.containerClasses = computed(() => {
55039
55069
  const dark = this.isDark();
55040
55070
  return dark
55041
- ? 'bg-purple-500/30 border-purple-400/30'
55042
- : 'bg-purple-100 border-purple-300';
55071
+ ? 'bg-purple-500/25 border-purple-400/40'
55072
+ : 'bg-purple-50 border-purple-200';
55043
55073
  }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
55074
+ this.isIncrease = computed(() => this.percentageChange() > 0, ...(ngDevMode ? [{ debugName: "isIncrease" }] : []));
55044
55075
  this.containerSizeClasses = computed(() => {
55045
55076
  const compact = this.isCompact();
55077
+ const change = this.percentageChange();
55078
+ const tiltClass = change > 0 ? 'rotate-1' : change < 0 ? '-rotate-1' : '';
55079
+ const baseClasses = 'inline-flex flex-row items-center rounded-xl border-2 overflow-visible transition-transform hover:rotate-0';
55046
55080
  return compact
55047
- ? 'inline-flex flex-row items-center rounded-full border pl-1.5 overflow-visible'
55048
- : 'inline-flex flex-row items-center rounded-full border pl-2 overflow-visible';
55081
+ ? `${baseClasses} pl-1.5 ${tiltClass}`
55082
+ : `${baseClasses} pl-2 ${tiltClass}`;
55049
55083
  }, ...(ngDevMode ? [{ debugName: "containerSizeClasses" }] : []));
55050
55084
  this.overlayClasses = computed(() => {
55051
55085
  const dark = this.isDark();
55052
55086
  return dark
55053
- ? 'bg-gradient-to-r from-purple-700 to-purple-600 text-purple-100 border-purple-500'
55054
- : 'bg-gradient-to-r from-purple-600 to-purple-500 text-white border-purple-400';
55087
+ ? 'bg-purple-600 text-purple-50'
55088
+ : 'bg-purple-500 text-white';
55055
55089
  }, ...(ngDevMode ? [{ debugName: "overlayClasses" }] : []));
55056
55090
  this.overlaySizeClasses = computed(() => {
55057
55091
  const compact = this.isCompact();
55058
55092
  return compact
55059
- ? 'px-2 py-1.5 rounded text-sm font-extrabold tracking-tight border shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
55060
- : 'px-2.5 py-2 rounded-md font-extrabold text-base tracking-tight border-2 shadow-lg transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
55093
+ ? 'px-2 py-1.5 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
55094
+ : 'px-2.5 py-2 rounded-lg font-extrabold text-base tracking-wide shadow-md transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
55061
55095
  }, ...(ngDevMode ? [{ debugName: "overlaySizeClasses" }] : []));
55062
55096
  this.iconSizeClass = computed(() => {
55063
55097
  return this.isCompact() ? 'text-sm' : 'text-base';
@@ -55068,6 +55102,26 @@ class TargetChangeBadgeComponent {
55068
55102
  ? 'px-2.5 py-0.5 text-xs font-semibold inline-block'
55069
55103
  : 'px-3 py-0.5 font-semibold text-xs inline-block';
55070
55104
  }, ...(ngDevMode ? [{ debugName: "descriptionSizeClasses" }] : []));
55105
+ effect(() => {
55106
+ const target = this.percentageChange();
55107
+ this.animateValue(target);
55108
+ });
55109
+ }
55110
+ animateValue(target) {
55111
+ const start = 0;
55112
+ const duration = 800;
55113
+ const startTime = performance.now();
55114
+ const animate = (currentTime) => {
55115
+ const elapsed = currentTime - startTime;
55116
+ const progress = Math.min(elapsed / duration, 1);
55117
+ const easeOutQuart = 1 - Math.pow(1 - progress, 4);
55118
+ const current = start + (target - start) * easeOutQuart;
55119
+ this.animatedValue.set(current);
55120
+ if (progress < 1) {
55121
+ requestAnimationFrame(animate);
55122
+ }
55123
+ };
55124
+ requestAnimationFrame(animate);
55071
55125
  }
55072
55126
  static { this.ɵfac = function TargetChangeBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TargetChangeBadgeComponent)(); }; }
55073
55127
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TargetChangeBadgeComponent, selectors: [["symphiq-target-change-badge"]], inputs: { viewMode: [1, "viewMode"], percentageChange: [1, "percentageChange"], metric: [1, "metric"], priorYear: [1, "priorYear"], isCompact: [1, "isCompact"] }, decls: 7, vars: 13, consts: [[3, "ngClass"]], template: function TargetChangeBadgeComponent_Template(rf, ctx) { if (rf & 1) {
@@ -55090,7 +55144,7 @@ class TargetChangeBadgeComponent {
55090
55144
  i0.ɵɵadvance();
55091
55145
  i0.ɵɵtextInterpolate(ctx.iconSymbol());
55092
55146
  i0.ɵɵadvance();
55093
- i0.ɵɵtextInterpolate1(" ", ctx.percentageText(), " ");
55147
+ i0.ɵɵtextInterpolate1(" ", ctx.animatedPercentageText(), " ");
55094
55148
  i0.ɵɵadvance();
55095
55149
  i0.ɵɵclassMap(ctx.descriptionSizeClasses());
55096
55150
  i0.ɵɵadvance();
@@ -55104,19 +55158,19 @@ class TargetChangeBadgeComponent {
55104
55158
  standalone: true,
55105
55159
  imports: [CommonModule],
55106
55160
  changeDetection: ChangeDetectionStrategy.OnPush,
55107
- template: `
55108
- <div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
55109
- <div [ngClass]="overlayClasses()" [class]="overlaySizeClasses()">
55110
- <span [class]="iconSizeClass()">{{ iconSymbol() }}</span>
55111
- {{ percentageText() }}
55112
- </div>
55113
- <div [class]="descriptionSizeClasses()">
55114
- {{ descriptionText() }}
55115
- </div>
55116
- </div>
55161
+ template: `
55162
+ <div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
55163
+ <div [ngClass]="overlayClasses()" [class]="overlaySizeClasses()">
55164
+ <span [class]="iconSizeClass()">{{ iconSymbol() }}</span>
55165
+ {{ animatedPercentageText() }}
55166
+ </div>
55167
+ <div [class]="descriptionSizeClasses()">
55168
+ {{ descriptionText() }}
55169
+ </div>
55170
+ </div>
55117
55171
  `
55118
55172
  }]
55119
- }], null, { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], percentageChange: [{ type: i0.Input, args: [{ isSignal: true, alias: "percentageChange", required: false }] }], metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: false }] }], priorYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "priorYear", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }] }); })();
55173
+ }], () => [], { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], percentageChange: [{ type: i0.Input, args: [{ isSignal: true, alias: "percentageChange", required: false }] }], metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: false }] }], priorYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "priorYear", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }] }); })();
55120
55174
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TargetChangeBadgeComponent, { className: "TargetChangeBadgeComponent", filePath: "lib/components/revenue-calculator-dashboard/target-change-badge.component.ts", lineNumber: 23 }); })();
55121
55175
 
55122
55176
  const _forTrack0$j = ($index, $item) => $item.stageMetric.metric;
@@ -56930,20 +56984,19 @@ class LineChartComponent {
56930
56984
  series.set('userData', { valueFormat: seriesData.valueFormat, isPriorYear });
56931
56985
  // Disable individual series tooltips - use floating tooltip instead
56932
56986
  series.set('tooltip', undefined);
56933
- // Configure stroke styling based on whether it's a prior year series
56987
+ // Configure stroke styling based on series type
56934
56988
  series.strokes.template.setAll({
56935
- strokeWidth: 2
56989
+ strokeWidth: isPriorYear ? 2 : 3
56936
56990
  });
56937
56991
  if (isPriorYear) {
56938
56992
  // Apply dashed line and reduced opacity for prior year data
56939
56993
  series.strokes.template.setAll({
56940
56994
  strokeDasharray: [5, 5],
56941
- strokeOpacity: 0.4
56995
+ strokeOpacity: 0.5
56942
56996
  });
56943
- // Also set on each individual stroke
56944
56997
  series.strokes.each((stroke) => {
56945
56998
  stroke.set('strokeDasharray', [5, 5]);
56946
- stroke.set('strokeOpacity', 0.4);
56999
+ stroke.set('strokeOpacity', 0.5);
56947
57000
  });
56948
57001
  }
56949
57002
  // Add bullets with larger hit area for better hover detection
@@ -56953,7 +57006,7 @@ class LineChartComponent {
56953
57006
  fill: seriesColor
56954
57007
  };
56955
57008
  if (isPriorYear) {
56956
- bulletConfig['fillOpacity'] = 0.4;
57009
+ bulletConfig['fillOpacity'] = 0.5;
56957
57010
  }
56958
57011
  if (!this.root)
56959
57012
  return Bullet.new({}, { sprite: Circle.new({}, {}) });
@@ -56999,10 +57052,10 @@ class LineChartComponent {
56999
57052
  }
57000
57053
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LineChartComponent, [{
57001
57054
  type: Component,
57002
- args: [{ selector: 'symphiq-line-chart', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
57003
- <div class="chart-container" [class.mini-mode]="!showAxisLabels()">
57004
- <div #chartdiv class="chart" [style.height]="chartHeight()" style="width: 100%;"></div>
57005
- </div>
57055
+ args: [{ selector: 'symphiq-line-chart', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
57056
+ <div class="chart-container" [class.mini-mode]="!showAxisLabels()">
57057
+ <div #chartdiv class="chart" [style.height]="chartHeight()" style="width: 100%;"></div>
57058
+ </div>
57006
57059
  `, styles: [".chart-container{width:100%;padding:1rem}.chart-container.mini-mode{padding:.25rem}\n"] }]
57007
57060
  }], () => [], { chart: [{ type: i0.Input, args: [{ isSignal: true, alias: "chart", required: false }] }], showAxisLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAxisLabels", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], currencySymbol: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencySymbol", required: false }] }], chartDiv: [{
57008
57061
  type: ViewChild,
@@ -57064,6 +57117,7 @@ class ProgressToTargetChartComponent {
57064
57117
  paddingRight: 0
57065
57118
  }));
57066
57119
  this.chart.zoomOutButton.set('forceHidden', true);
57120
+ this.chart.plotContainer.set('maskContent', false);
57067
57121
  const xRenderer = AxisRendererX.new(this.root, {
57068
57122
  strokeOpacity: 0.1
57069
57123
  });
@@ -57090,6 +57144,10 @@ class ProgressToTargetChartComponent {
57090
57144
  return;
57091
57145
  this.chart.series.clear();
57092
57146
  this.xAxis.axisRanges.clear();
57147
+ if (this.legend) {
57148
+ this.legend.dispose();
57149
+ this.legend = undefined;
57150
+ }
57093
57151
  this.buildChart(chartData);
57094
57152
  }
57095
57153
  buildChart(chartData) {
@@ -57196,15 +57254,15 @@ class ProgressToTargetChartComponent {
57196
57254
  dy: -18,
57197
57255
  fill: this.labelColor()
57198
57256
  });
57199
- const legend = this.chart.children.push(Legend.new(this.root, {
57257
+ this.legend = this.chart.children.push(Legend.new(this.root, {
57200
57258
  centerX: p50,
57201
57259
  x: p50,
57202
57260
  marginTop: 8
57203
57261
  }));
57204
- legend.labels.template.setAll({
57262
+ this.legend.labels.template.setAll({
57205
57263
  fill: this.labelColor()
57206
57264
  });
57207
- legend.data.setAll(this.chart.series.values.slice().reverse());
57265
+ this.legend.data.setAll(this.chart.series.values.slice().reverse());
57208
57266
  this.chart.appear(1000, 100);
57209
57267
  paceSeries.appear();
57210
57268
  currentSeries.appear();
@@ -57269,20 +57327,20 @@ class ProgressToTargetChartComponent {
57269
57327
  i0.ɵɵdomElementStart(0, "div", 1);
57270
57328
  i0.ɵɵdomElement(1, "div", 2, 0);
57271
57329
  i0.ɵɵdomElementEnd();
57272
- } }, dependencies: [CommonModule], styles: [".progress-chart-container[_ngcontent-%COMP%]{width:100%}"], changeDetection: 0 }); }
57330
+ } }, dependencies: [CommonModule], styles: [".progress-chart-container[_ngcontent-%COMP%]{width:100%;margin-top:24px}"], changeDetection: 0 }); }
57273
57331
  }
57274
57332
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ProgressToTargetChartComponent, [{
57275
57333
  type: Component,
57276
- args: [{ selector: 'symphiq-progress-to-target-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
57277
- <div class="progress-chart-container">
57278
- <div #chartdiv class="chart" style="width: 100%; height: 160px;"></div>
57279
- </div>
57280
- `, styles: [".progress-chart-container{width:100%}\n"] }]
57334
+ args: [{ selector: 'symphiq-progress-to-target-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
57335
+ <div class="progress-chart-container">
57336
+ <div #chartdiv class="chart" style="width: 100%; height: 160px;"></div>
57337
+ </div>
57338
+ `, styles: [".progress-chart-container{width:100%;margin-top:24px}\n"] }]
57281
57339
  }], () => [], { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], chartDiv: [{
57282
57340
  type: ViewChild,
57283
57341
  args: ['chartdiv', { static: true }]
57284
57342
  }] }); })();
57285
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProgressToTargetChartComponent, { className: "ProgressToTargetChartComponent", filePath: "lib/components/revenue-calculator-dashboard/progress-to-target-chart.component.ts", lineNumber: 61 }); })();
57343
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProgressToTargetChartComponent, { className: "ProgressToTargetChartComponent", filePath: "lib/components/revenue-calculator-dashboard/progress-to-target-chart.component.ts", lineNumber: 62 }); })();
57286
57344
 
57287
57345
  const _forTrack0$i = ($index, $item) => $item.metric;
57288
57346
  function MetricReportModalComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
@@ -57390,7 +57448,7 @@ function MetricReportModalComponent_Conditional_0_Conditional_65_For_15_Template
57390
57448
  } }
57391
57449
  function MetricReportModalComponent_Conditional_0_Conditional_65_Template(rf, ctx) { if (rf & 1) {
57392
57450
  i0.ɵɵelementStart(0, "div", 16)(1, "h4", 17);
57393
- i0.ɵɵtext(2, " Contributing Metrics ");
57451
+ i0.ɵɵtext(2, " Contributing Metric Targets ");
57394
57452
  i0.ɵɵelementEnd();
57395
57453
  i0.ɵɵelementStart(3, "div", 36)(4, "table", 37)(5, "thead")(6, "tr", 38)(7, "th", 39);
57396
57454
  i0.ɵɵtext(8, "Metric");
@@ -57423,6 +57481,9 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
57423
57481
  i0.ɵɵelementEnd();
57424
57482
  i0.ɵɵelementStart(5, "p", 54);
57425
57483
  i0.ɵɵtext(6);
57484
+ i0.ɵɵelementEnd();
57485
+ i0.ɵɵelementStart(7, "p", 55);
57486
+ i0.ɵɵtext(8);
57426
57487
  i0.ɵɵelementEnd()();
57427
57488
  } if (rf & 2) {
57428
57489
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -57434,7 +57495,11 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
57434
57495
  i0.ɵɵadvance();
57435
57496
  i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
57436
57497
  i0.ɵɵadvance();
57437
- i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionText(), " ");
57498
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence1(), " ");
57499
+ i0.ɵɵadvance();
57500
+ i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
57501
+ i0.ɵɵadvance();
57502
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence2(), " ");
57438
57503
  } }
57439
57504
  function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
57440
57505
  const _r1 = i0.ɵɵgetCurrentView();
@@ -57518,7 +57583,7 @@ function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
57518
57583
  i0.ɵɵconditionalCreate(64, MetricReportModalComponent_Conditional_0_Conditional_64_Template, 6, 10);
57519
57584
  i0.ɵɵelementEnd();
57520
57585
  i0.ɵɵconditionalCreate(65, MetricReportModalComponent_Conditional_0_Conditional_65_Template, 16, 3, "div", 16);
57521
- i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template, 7, 8, "div", 29);
57586
+ i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template, 9, 10, "div", 29);
57522
57587
  i0.ɵɵelementEnd();
57523
57588
  i0.ɵɵelementStart(67, "div", 30)(68, "button", 31);
57524
57589
  i0.ɵɵlistener("click", function MetricReportModalComponent_Conditional_0_Template_button_click_68_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.close()); });
@@ -57681,6 +57746,18 @@ class MetricReportModalComponent {
57681
57746
  }
57682
57747
  return 0;
57683
57748
  }, ...(ngDevMode ? [{ debugName: "samePeriodLastYearValue" }] : []));
57749
+ this.fullYearLastYearValue = computed(() => {
57750
+ const pacingResponse = this.pacingMetrics();
57751
+ const metric = this.metricData();
57752
+ if (!pacingResponse || !metric)
57753
+ return 0;
57754
+ const monthlyData = pacingResponse.lastYearMetricValuesMonthly;
57755
+ if (!monthlyData)
57756
+ return 0;
57757
+ return monthlyData
57758
+ .filter(item => item.metric === metric.metric)
57759
+ .reduce((total, item) => total + (parseFloat(item.value || '0') || 0), 0);
57760
+ }, ...(ngDevMode ? [{ debugName: "fullYearLastYearValue" }] : []));
57684
57761
  this.ytdChangePercentage = computed(() => {
57685
57762
  const current = this.ytdValue();
57686
57763
  const lastYear = this.samePeriodLastYearValue();
@@ -57774,12 +57851,23 @@ class MetricReportModalComponent {
57774
57851
  status: pacing.status
57775
57852
  };
57776
57853
  }, ...(ngDevMode ? [{ debugName: "progressToTargetData" }] : []));
57777
- this.chartDescriptionText = computed(() => {
57778
- const metric = this.metricTitle();
57779
- const currentYear = this.currentYear();
57854
+ this.chartDescriptionSentence1 = computed(() => {
57855
+ const metricData = this.metricData();
57856
+ const metricName = this.metricTitle().toLowerCase();
57857
+ const startDate = this.ytdStartDate();
57858
+ const endDate = this.ytdEndDate();
57859
+ const ytdValue = this.formatMetricValue(this.ytdValue(), metricData?.metric || '');
57860
+ const samePeriodLastYear = this.formatMetricValue(this.samePeriodLastYearValue(), metricData?.metric || '');
57780
57861
  const priorYear = this.priorYear();
57781
- return `This chart shows the ${metric} performance trend for ${currentYear} (solid line), compared to ${priorYear} (dashed line), with the target projection (dotted line) for the remainder of the year.`;
57782
- }, ...(ngDevMode ? [{ debugName: "chartDescriptionText" }] : []));
57862
+ return `For the period (${startDate} - ${endDate}) you had ${ytdValue} ${metricName}, compared to ${samePeriodLastYear} for the same period in ${priorYear}.`;
57863
+ }, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence1" }] : []));
57864
+ this.chartDescriptionSentence2 = computed(() => {
57865
+ const metricData = this.metricData();
57866
+ const metricName = this.metricTitle().toLowerCase();
57867
+ const projectedValue = this.formatMetricValue(this.pacingInfo()?.projectedValue || 0, metricData?.metric || '');
57868
+ const fullYearLastYear = this.formatMetricValue(this.fullYearLastYearValue(), metricData?.metric || '');
57869
+ return `By maintaining this pace, your ${metricName} could increase to ${projectedValue} compared to ${fullYearLastYear} last year.`;
57870
+ }, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence2" }] : []));
57783
57871
  this.pacingChartData = computed(() => {
57784
57872
  const metric = this.metricData();
57785
57873
  const pacingResponse = this.pacingMetrics();
@@ -57792,7 +57880,6 @@ class MetricReportModalComponent {
57792
57880
  chartType: 'LINE',
57793
57881
  title: 'Pace',
57794
57882
  description: '',
57795
- lineChartUseCase: LineChartUseCaseEnum.THIS_YEAR_VS_LAST_YEAR,
57796
57883
  lineChartData: {
57797
57884
  series: [
57798
57885
  {
@@ -57812,94 +57899,61 @@ class MetricReportModalComponent {
57812
57899
  };
57813
57900
  }, ...(ngDevMode ? [{ debugName: "pacingChartData" }] : []));
57814
57901
  }
57815
- formatDateForChart(year, month, day) {
57816
- const m = String(month + 1).padStart(2, '0');
57817
- const d = String(day).padStart(2, '0');
57818
- return `${year}-${m}-${d}`;
57819
- }
57820
57902
  generateCurrentYearData(pacingResponse, metricEnum) {
57821
57903
  const data = [];
57822
57904
  const currentYear = this.currentYear();
57823
- if (pacingResponse?.soFarMetricValuesMonthly) {
57824
- const metricValues = pacingResponse.soFarMetricValuesMonthly.filter(m => m.metric === metricEnum);
57825
- metricValues.forEach(mv => {
57826
- if (mv.date && mv.value) {
57827
- const originalDate = new Date(mv.date);
57905
+ const monthlyData = pacingResponse?.soFarMetricValuesMonthly;
57906
+ if (monthlyData) {
57907
+ monthlyData
57908
+ .filter(item => item.metric === metricEnum)
57909
+ .forEach((item) => {
57910
+ if (item.value && item.date) {
57911
+ const month = new Date(item.date).getMonth();
57828
57912
  data.push({
57829
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57830
- value: parseFloat(mv.value)
57913
+ date: new Date(currentYear, month, 15).toISOString(),
57914
+ value: parseFloat(item.value) || 0
57831
57915
  });
57832
57916
  }
57833
57917
  });
57834
57918
  }
57835
- if (data.length === 0) {
57836
- const baseValue = this.metricData()?.currentValue || 1000;
57837
- const now = new Date();
57838
- const currentMonth = now.getMonth();
57839
- for (let i = 0; i <= currentMonth; i++) {
57840
- const value = baseValue * ((i + 1) / 12);
57841
- data.push({
57842
- date: this.formatDateForChart(currentYear, i, 15),
57843
- value: Math.round(value * 100) / 100
57844
- });
57845
- }
57846
- }
57847
57919
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57848
57920
  }
57849
57921
  generatePriorYearData(pacingResponse, metricEnum) {
57850
57922
  const data = [];
57851
57923
  const currentYear = this.currentYear();
57852
- if (pacingResponse?.lastYearMetricValuesMonthly) {
57853
- const metricValues = pacingResponse.lastYearMetricValuesMonthly.filter(m => m.metric === metricEnum);
57854
- metricValues.forEach(mv => {
57855
- if (mv.date && mv.value) {
57856
- const originalDate = new Date(mv.date);
57924
+ const monthlyData = pacingResponse?.lastYearMetricValuesMonthly;
57925
+ if (monthlyData) {
57926
+ monthlyData
57927
+ .filter(item => item.metric === metricEnum)
57928
+ .forEach((item) => {
57929
+ if (item.value && item.date) {
57930
+ const month = new Date(item.date).getMonth();
57857
57931
  data.push({
57858
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57859
- value: parseFloat(mv.value)
57932
+ date: new Date(currentYear, month, 15).toISOString(),
57933
+ value: parseFloat(item.value) || 0
57860
57934
  });
57861
57935
  }
57862
57936
  });
57863
57937
  }
57864
- if (data.length === 0) {
57865
- const baseValue = this.metricData()?.currentValue || 1000;
57866
- for (let i = 0; i < 12; i++) {
57867
- const value = baseValue * ((i + 1) / 12) * 0.9;
57868
- data.push({
57869
- date: this.formatDateForChart(currentYear, i, 15),
57870
- value: Math.round(value * 100) / 100
57871
- });
57872
- }
57873
- }
57874
57938
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57875
57939
  }
57876
57940
  generateProjectionData(pacingResponse, metricEnum) {
57877
57941
  const data = [];
57878
57942
  const currentYear = this.currentYear();
57879
- if (pacingResponse?.projectedMetricValuesMonthly) {
57880
- const metricValues = pacingResponse.projectedMetricValuesMonthly.filter(m => m.metric === metricEnum);
57881
- metricValues.forEach(mv => {
57882
- if (mv.date && mv.value) {
57883
- const originalDate = new Date(mv.date);
57943
+ const monthlyData = pacingResponse?.projectedMetricValuesMonthly;
57944
+ if (monthlyData) {
57945
+ monthlyData
57946
+ .filter(item => item.metric === metricEnum)
57947
+ .forEach((item) => {
57948
+ if (item.value && item.date) {
57949
+ const month = new Date(item.date).getMonth();
57884
57950
  data.push({
57885
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57886
- value: parseFloat(mv.value)
57951
+ date: new Date(currentYear, month, 15).toISOString(),
57952
+ value: parseFloat(item.value) || 0
57887
57953
  });
57888
57954
  }
57889
57955
  });
57890
57956
  }
57891
- if (data.length === 0) {
57892
- const targetValue = this.metricData()?.targetValue || 1200;
57893
- const now = new Date();
57894
- const currentMonth = now.getMonth();
57895
- for (let i = currentMonth; i < 12; i++) {
57896
- const value = targetValue * ((i + 1) / 12);
57897
- data.push({
57898
- date: this.formatDateForChart(currentYear, i, 15),
57899
- value: Math.round(value * 100) / 100
57900
- });
57901
- }
57902
- }
57903
57957
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57904
57958
  }
57905
57959
  formatMetricValue(value, metric, fromUiData = true) {
@@ -58046,7 +58100,7 @@ class MetricReportModalComponent {
58046
58100
  : 'bg-slate-700 hover:bg-slate-600 text-white';
58047
58101
  }
58048
58102
  static { this.ɵfac = function MetricReportModalComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MetricReportModalComponent)(); }; }
58049
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MetricReportModalComponent, selectors: [["symphiq-metric-report-modal"]], inputs: { viewMode: [1, "viewMode"], metricEnum: [1, "metricEnum"], metricData: [1, "metricData"], contributingMetrics: [1, "contributingMetrics"], pacingMetrics: [1, "pacingMetrics"], isOpen: [1, "isOpen"] }, outputs: { closed: "closed" }, decls: 1, vars: 1, consts: [[1, "fixed", "inset-0", "overflow-y-auto", "z-50"], [1, "fixed", "inset-0", "overflow-y-auto", "z-50", 3, "click"], [1, "flex", "items-center", "justify-center", "min-h-screen", "px-4", "pt-4", "pb-20", "text-center", "sm:block", "sm:p-0"], ["aria-hidden", "true", 1, "fixed", "inset-0", "backdrop-blur-md", 3, "ngClass"], ["aria-hidden", "true", 1, "hidden", "sm:inline-block", "sm:align-middle", "sm:h-screen"], [1, "relative", "inline-block", "align-bottom", "rounded-2xl", "text-left", "overflow-hidden", "shadow-xl", "sm:my-8", "sm:align-middle", "sm:w-full", "sm:max-w-4xl", "border", "backdrop-blur-xl", 3, "click", "ngClass"], [1, "px-6", "py-5", "border-b", "backdrop-blur-sm", "sticky", "top-0", "z-10", 3, "ngClass"], [1, "flex", "items-start", "justify-between"], [1, "flex-1"], [1, "flex", "items-center", "gap-3", "mb-2"], [1, "text-xl", "font-bold", 3, "ngClass"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-7", "h-7", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", "self-center", 3, "ngClass", "libSymphiqTooltip"], [1, "ml-4", "transition-all", "rounded-lg", "p-1", "hover:scale-110", "active:scale-90", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-6", "h-6"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M6 18L18 6M6 6l12 12"], [1, "px-6", "py-6", "max-h-[70vh]", "overflow-y-auto", "backdrop-blur-sm", 3, "ngClass"], [1, "rounded-xl", "p-6", "mb-6", 3, "ngClass"], [1, "text-sm", "font-semibold", "uppercase", "tracking-wider", "mb-4", 3, "ngClass"], [1, "grid", "grid-cols-1", "sm:grid-cols-2", "lg:grid-cols-3", "gap-6"], [1, "mb-1.5"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", 3, "ngClass"], [1, "text-xs", 3, "ngClass"], [1, "text-xl", "font-bold", "mb-2", 3, "ngClass"], [3, "viewMode", "percentageChange", "metric", "priorYear", "isCompact"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-1.5", 3, "ngClass"], [1, "mb-4"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-2", 3, "ngClass"], [1, "text-3xl", "font-extrabold", "mb-3", 3, "ngClass"], [1, "text-sm", "leading-relaxed", 3, "ngClass"], [1, "rounded-xl", "p-6", 3, "ngClass"], [1, "px-6", "py-4", "border-t", 3, "ngClass"], [1, "w-full", "px-4", "py-2", "rounded-lg", "transition-all", "font-medium", "hover:scale-[1.02]", "active:scale-[0.98]", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [3, "viewMode", "pacingPercentage", "status", "showAsFullText", "isCompact", "showEmphasizedPercentage"], [3, "data", "viewMode"], [1, "overflow-x-auto"], [1, "w-full"], [1, "border-b", 3, "ngClass"], [1, "text-left", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "text-right", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "border-b", "transition-colors", 3, "ngClass"], [1, "py-3", "px-4"], [1, "flex", "items-center", "gap-2"], [1, "text-sm", "font-medium"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-5", "h-5", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", 3, "ngClass", "libSymphiqTooltip"], [1, "py-3", "px-4", "text-right"], [1, "text-sm", "font-semibold", 3, "ngClass"], [1, "flex", "items-center", "justify-end", "gap-2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4", "text-emerald-500"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3"], [1, "min-h-[400px]"], [3, "chart", "showAxisLabels", "viewMode", "currencySymbol"], [1, "text-sm", "leading-relaxed", "mt-4", 3, "ngClass"]], template: function MetricReportModalComponent_Template(rf, ctx) { if (rf & 1) {
58103
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MetricReportModalComponent, selectors: [["symphiq-metric-report-modal"]], inputs: { viewMode: [1, "viewMode"], metricEnum: [1, "metricEnum"], metricData: [1, "metricData"], contributingMetrics: [1, "contributingMetrics"], pacingMetrics: [1, "pacingMetrics"], isOpen: [1, "isOpen"] }, outputs: { closed: "closed" }, decls: 1, vars: 1, consts: [[1, "fixed", "inset-0", "overflow-y-auto", "z-50"], [1, "fixed", "inset-0", "overflow-y-auto", "z-50", 3, "click"], [1, "flex", "items-center", "justify-center", "min-h-screen", "px-4", "pt-4", "pb-20", "text-center", "sm:block", "sm:p-0"], ["aria-hidden", "true", 1, "fixed", "inset-0", "backdrop-blur-md", 3, "ngClass"], ["aria-hidden", "true", 1, "hidden", "sm:inline-block", "sm:align-middle", "sm:h-screen"], [1, "relative", "inline-block", "align-bottom", "rounded-2xl", "text-left", "overflow-hidden", "shadow-xl", "sm:my-8", "sm:align-middle", "sm:w-full", "sm:max-w-4xl", "border", "backdrop-blur-xl", 3, "click", "ngClass"], [1, "px-6", "py-5", "border-b", "backdrop-blur-sm", "sticky", "top-0", "z-10", 3, "ngClass"], [1, "flex", "items-start", "justify-between"], [1, "flex-1"], [1, "flex", "items-center", "gap-3", "mb-2"], [1, "text-xl", "font-bold", 3, "ngClass"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-7", "h-7", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", "self-center", 3, "ngClass", "libSymphiqTooltip"], [1, "ml-4", "transition-all", "rounded-lg", "p-1", "hover:scale-110", "active:scale-90", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-6", "h-6"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M6 18L18 6M6 6l12 12"], [1, "px-6", "py-6", "max-h-[70vh]", "overflow-y-auto", "backdrop-blur-sm", 3, "ngClass"], [1, "rounded-xl", "p-6", "mb-6", 3, "ngClass"], [1, "text-sm", "font-semibold", "uppercase", "tracking-wider", "mb-4", 3, "ngClass"], [1, "grid", "grid-cols-1", "sm:grid-cols-2", "lg:grid-cols-3", "gap-6"], [1, "mb-1.5"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", 3, "ngClass"], [1, "text-xs", 3, "ngClass"], [1, "text-xl", "font-bold", "mb-2", 3, "ngClass"], [3, "viewMode", "percentageChange", "metric", "priorYear", "isCompact"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-1.5", 3, "ngClass"], [1, "mb-4"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-2", 3, "ngClass"], [1, "text-3xl", "font-extrabold", "mb-3", 3, "ngClass"], [1, "text-sm", "leading-relaxed", 3, "ngClass"], [1, "rounded-xl", "p-6", 3, "ngClass"], [1, "px-6", "py-4", "border-t", 3, "ngClass"], [1, "w-full", "px-4", "py-2", "rounded-lg", "transition-all", "font-medium", "hover:scale-[1.02]", "active:scale-[0.98]", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [3, "viewMode", "pacingPercentage", "status", "showAsFullText", "isCompact", "showEmphasizedPercentage"], [3, "data", "viewMode"], [1, "overflow-x-auto"], [1, "w-full"], [1, "border-b", 3, "ngClass"], [1, "text-left", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "text-right", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "border-b", "transition-colors", 3, "ngClass"], [1, "py-3", "px-4"], [1, "flex", "items-center", "gap-2"], [1, "text-sm", "font-medium"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-5", "h-5", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", 3, "ngClass", "libSymphiqTooltip"], [1, "py-3", "px-4", "text-right"], [1, "text-sm", "font-semibold", 3, "ngClass"], [1, "flex", "items-center", "justify-end", "gap-2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4", "text-emerald-500"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3"], [1, "min-h-[400px]"], [3, "chart", "showAxisLabels", "viewMode", "currencySymbol"], [1, "text-sm", "leading-relaxed", "mt-4", 3, "ngClass"], [1, "text-sm", "leading-relaxed", "mt-2", 3, "ngClass"]], template: function MetricReportModalComponent_Template(rf, ctx) { if (rf & 1) {
58050
58104
  i0.ɵɵconditionalCreate(0, MetricReportModalComponent_Conditional_0_Template, 70, 51, "div", 0);
58051
58105
  } if (rf & 2) {
58052
58106
  i0.ɵɵconditional(ctx.isOpen() ? 0 : -1);
@@ -58300,7 +58354,7 @@ class MetricReportModalComponent {
58300
58354
  @if (contributingMetrics().length > 0) {
58301
58355
  <div [ngClass]="sectionCardClasses()" class="rounded-xl p-6 mb-6">
58302
58356
  <h4 [ngClass]="sectionTitleClasses()" class="text-sm font-semibold uppercase tracking-wider mb-4">
58303
- Contributing Metrics
58357
+ Contributing Metric Targets
58304
58358
  </h4>
58305
58359
  <div class="overflow-x-auto">
58306
58360
  <table class="w-full">
@@ -58378,7 +58432,10 @@ class MetricReportModalComponent {
58378
58432
  />
58379
58433
  </div>
58380
58434
  <p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-4">
58381
- {{ chartDescriptionText() }}
58435
+ {{ chartDescriptionSentence1() }}
58436
+ </p>
58437
+ <p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-2">
58438
+ {{ chartDescriptionSentence2() }}
58382
58439
  </p>
58383
58440
  </div>
58384
58441
  }
@@ -58400,7 +58457,7 @@ class MetricReportModalComponent {
58400
58457
  `
58401
58458
  }]
58402
58459
  }], null, { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], metricEnum: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricEnum", required: false }] }], metricData: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricData", required: false }] }], contributingMetrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "contributingMetrics", required: false }] }], pacingMetrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "pacingMetrics", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] }); })();
58403
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber: 343 }); })();
58460
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber: 346 }); })();
58404
58461
 
58405
58462
  const _c0$q = ["absoluteInputRef"];
58406
58463
  const _c1$b = ["percentageInputRef"];
@@ -63728,92 +63785,92 @@ class CollapsibleSectionGroupComponent {
63728
63785
  standalone: true,
63729
63786
  imports: [CommonModule, SymphiqIconComponent, ProfileSectionComponent],
63730
63787
  changeDetection: ChangeDetectionStrategy.OnPush,
63731
- template: `
63732
- <div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
63733
- <div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
63734
- <div class="flex items-center justify-between">
63735
- <div class="flex items-center gap-3">
63736
- <div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
63737
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63738
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
63739
- </svg>
63740
- </div>
63741
- <div>
63742
- <h2 [ngClass]="titleClasses()" class="text-xl font-bold">
63743
- Supporting Business Context
63744
- </h2>
63745
- <p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
63746
- Additional insights gathered from publicly available information
63747
- </p>
63748
- </div>
63749
- </div>
63750
- </div>
63751
- </div>
63752
-
63753
- <div [ngClass]="contentClasses()" class="p-6">
63754
- <div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
63755
- <svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63756
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
63757
- </svg>
63758
- <div class="flex-1">
63759
- <h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
63760
- Building Context for Better Recommendations
63761
- </h4>
63762
- <p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
63763
- The information below was gathered from your website and competitor research. While recommendations above are based on this initial analysis, connecting your GA4 data will provide quantitative insights that dramatically improve recommendation accuracy.
63764
- </p>
63765
- </div>
63766
- </div>
63767
-
63768
- <div class="space-y-3">
63769
- @for (section of sections(); track section.id; let idx = $index) {
63770
- <div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
63771
- <button
63772
- type="button"
63773
- (click)="toggleSection(idx)"
63774
- [ngClass]="sectionHeaderClasses(section, idx)"
63775
- class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
63776
- <div class="flex items-center gap-3 flex-1 min-w-0">
63777
- @if (section.icon) {
63778
- <div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
63779
- <symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
63780
- </div>
63781
- }
63782
- <div class="flex-1 min-w-0">
63783
- <h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
63784
- {{ section.title }}
63785
- </h3>
63786
- <p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
63787
- {{ getSectionItemCount(section) }} items
63788
- </p>
63789
- </div>
63790
- </div>
63791
- <svg
63792
- [ngClass]="chevronClasses(idx)"
63793
- [class.rotate-180]="expandedSections()[idx]"
63794
- class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
63795
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
63796
- </svg>
63797
- </button>
63798
-
63799
- <div
63800
- class="grid transition-[grid-template-rows] duration-300 ease-in-out"
63801
- [style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
63802
- <div class="overflow-hidden">
63803
- <div [ngClass]="sectionContentClasses()" class="border-t">
63804
- <symphiq-profile-section
63805
- [section]="section"
63806
- [viewMode]="viewMode()"
63807
- [forceExpanded]="false"
63808
- />
63809
- </div>
63810
- </div>
63811
- </div>
63812
- </div>
63813
- }
63814
- </div>
63815
- </div>
63816
- </div>
63788
+ template: `
63789
+ <div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
63790
+ <div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
63791
+ <div class="flex items-center justify-between">
63792
+ <div class="flex items-center gap-3">
63793
+ <div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
63794
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63795
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
63796
+ </svg>
63797
+ </div>
63798
+ <div>
63799
+ <h2 [ngClass]="titleClasses()" class="text-xl font-bold">
63800
+ Supporting Business Context
63801
+ </h2>
63802
+ <p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
63803
+ Additional insights gathered from publicly available information
63804
+ </p>
63805
+ </div>
63806
+ </div>
63807
+ </div>
63808
+ </div>
63809
+
63810
+ <div [ngClass]="contentClasses()" class="p-6">
63811
+ <div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
63812
+ <svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63813
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
63814
+ </svg>
63815
+ <div class="flex-1">
63816
+ <h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
63817
+ Building Context for Better Recommendations
63818
+ </h4>
63819
+ <p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
63820
+ The information below was gathered from your website and competitor research. While recommendations above are based on this initial analysis, connecting your GA4 data will provide quantitative insights that dramatically improve recommendation accuracy.
63821
+ </p>
63822
+ </div>
63823
+ </div>
63824
+
63825
+ <div class="space-y-3">
63826
+ @for (section of sections(); track section.id; let idx = $index) {
63827
+ <div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
63828
+ <button
63829
+ type="button"
63830
+ (click)="toggleSection(idx)"
63831
+ [ngClass]="sectionHeaderClasses(section, idx)"
63832
+ class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
63833
+ <div class="flex items-center gap-3 flex-1 min-w-0">
63834
+ @if (section.icon) {
63835
+ <div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
63836
+ <symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
63837
+ </div>
63838
+ }
63839
+ <div class="flex-1 min-w-0">
63840
+ <h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
63841
+ {{ section.title }}
63842
+ </h3>
63843
+ <p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
63844
+ {{ getSectionItemCount(section) }} items
63845
+ </p>
63846
+ </div>
63847
+ </div>
63848
+ <svg
63849
+ [ngClass]="chevronClasses(idx)"
63850
+ [class.rotate-180]="expandedSections()[idx]"
63851
+ class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
63852
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
63853
+ </svg>
63854
+ </button>
63855
+
63856
+ <div
63857
+ class="grid transition-[grid-template-rows] duration-300 ease-in-out"
63858
+ [style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
63859
+ <div class="overflow-hidden">
63860
+ <div [ngClass]="sectionContentClasses()" class="border-t">
63861
+ <symphiq-profile-section
63862
+ [section]="section"
63863
+ [viewMode]="viewMode()"
63864
+ [forceExpanded]="false"
63865
+ />
63866
+ </div>
63867
+ </div>
63868
+ </div>
63869
+ </div>
63870
+ }
63871
+ </div>
63872
+ </div>
63873
+ </div>
63817
63874
  `
63818
63875
  }]
63819
63876
  }], null, { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }] }); })();