@eric-emg/symphiq-components 1.2.247 → 1.2.249

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;
@@ -56705,8 +56759,7 @@ class LineChartComponent {
56705
56759
  // Check for explicit keywords
56706
56760
  if (name.includes('last year') ||
56707
56761
  name.includes('prior year') ||
56708
- name.includes('previous year') ||
56709
- name.includes('comparison')) {
56762
+ name.includes('previous year')) {
56710
56763
  return true;
56711
56764
  }
56712
56765
  // Check for year patterns - extract any 4-digit year and compare to current year
@@ -56717,13 +56770,6 @@ class LineChartComponent {
56717
56770
  }
56718
56771
  return false;
56719
56772
  }
56720
- isProjectionSeries(seriesData) {
56721
- if (!seriesData || !seriesData.name) {
56722
- return false;
56723
- }
56724
- const name = seriesData.name.toLowerCase();
56725
- return name.includes('projection') || name.includes('projected') || name.includes('target');
56726
- }
56727
56773
  extractMetricName(seriesName) {
56728
56774
  // Extract metric name from series name by removing year patterns
56729
56775
  // e.g., "Purchase Revenue (2025)" -> "Purchase Revenue"
@@ -56924,8 +56970,6 @@ class LineChartComponent {
56924
56970
  const seriesColor = color(seriesColorValue);
56925
56971
  // Check if this is a prior year series for YoY charts
56926
56972
  const isPriorYear = isYoYChart && this.isPriorYearSeries(seriesData);
56927
- const isProjection = this.isProjectionSeries(seriesData);
56928
- console.log('[LineChart] Series:', seriesData.name, { isPriorYear, isProjection, isYoYChart, dataPoints: parsedData.length });
56929
56973
  if (!this.chartElement || !this.root)
56930
56974
  return;
56931
56975
  const series = this.chartElement.series.push(LineSeries.new(this.root, {
@@ -56937,7 +56981,7 @@ class LineChartComponent {
56937
56981
  stroke: seriesColor
56938
56982
  }));
56939
56983
  // Store valueFormat and prior year flag in userData for tooltip formatting
56940
- series.set('userData', { valueFormat: seriesData.valueFormat, isPriorYear, isProjection });
56984
+ series.set('userData', { valueFormat: seriesData.valueFormat, isPriorYear });
56941
56985
  // Disable individual series tooltips - use floating tooltip instead
56942
56986
  series.set('tooltip', undefined);
56943
56987
  // Configure stroke styling based on series type
@@ -56955,16 +56999,6 @@ class LineChartComponent {
56955
56999
  stroke.set('strokeOpacity', 0.5);
56956
57000
  });
56957
57001
  }
56958
- else if (isProjection) {
56959
- // Apply dotted line for projection data
56960
- series.strokes.template.setAll({
56961
- strokeDasharray: [10, 5],
56962
- strokeWidth: 3
56963
- });
56964
- series.strokes.each((stroke) => {
56965
- stroke.set('strokeDasharray', [10, 5]);
56966
- });
56967
- }
56968
57002
  // Add bullets with larger hit area for better hover detection
56969
57003
  series.bullets.push(() => {
56970
57004
  const bulletConfig = {
@@ -57018,10 +57052,10 @@ class LineChartComponent {
57018
57052
  }
57019
57053
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LineChartComponent, [{
57020
57054
  type: Component,
57021
- args: [{ selector: 'symphiq-line-chart', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
57022
- <div class="chart-container" [class.mini-mode]="!showAxisLabels()">
57023
- <div #chartdiv class="chart" [style.height]="chartHeight()" style="width: 100%;"></div>
57024
- </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>
57025
57059
  `, styles: [".chart-container{width:100%;padding:1rem}.chart-container.mini-mode{padding:.25rem}\n"] }]
57026
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: [{
57027
57061
  type: ViewChild,
@@ -57110,6 +57144,10 @@ class ProgressToTargetChartComponent {
57110
57144
  return;
57111
57145
  this.chart.series.clear();
57112
57146
  this.xAxis.axisRanges.clear();
57147
+ if (this.legend) {
57148
+ this.legend.dispose();
57149
+ this.legend = undefined;
57150
+ }
57113
57151
  this.buildChart(chartData);
57114
57152
  }
57115
57153
  buildChart(chartData) {
@@ -57216,15 +57254,15 @@ class ProgressToTargetChartComponent {
57216
57254
  dy: -18,
57217
57255
  fill: this.labelColor()
57218
57256
  });
57219
- const legend = this.chart.children.push(Legend.new(this.root, {
57257
+ this.legend = this.chart.children.push(Legend.new(this.root, {
57220
57258
  centerX: p50,
57221
57259
  x: p50,
57222
57260
  marginTop: 8
57223
57261
  }));
57224
- legend.labels.template.setAll({
57262
+ this.legend.labels.template.setAll({
57225
57263
  fill: this.labelColor()
57226
57264
  });
57227
- legend.data.setAll(this.chart.series.values.slice().reverse());
57265
+ this.legend.data.setAll(this.chart.series.values.slice().reverse());
57228
57266
  this.chart.appear(1000, 100);
57229
57267
  paceSeries.appear();
57230
57268
  currentSeries.appear();
@@ -57289,20 +57327,20 @@ class ProgressToTargetChartComponent {
57289
57327
  i0.ɵɵdomElementStart(0, "div", 1);
57290
57328
  i0.ɵɵdomElement(1, "div", 2, 0);
57291
57329
  i0.ɵɵdomElementEnd();
57292
- } }, 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:50px;overflow:visible}.chart[_ngcontent-%COMP%]{overflow:visible}"], changeDetection: 0 }); }
57293
57331
  }
57294
57332
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ProgressToTargetChartComponent, [{
57295
57333
  type: Component,
57296
- args: [{ selector: 'symphiq-progress-to-target-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
57297
- <div class="progress-chart-container">
57298
- <div #chartdiv class="chart" style="width: 100%; height: 160px;"></div>
57299
- </div>
57300
- `, 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:50px;overflow:visible}.chart{overflow:visible}\n"] }]
57301
57339
  }], () => [], { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], chartDiv: [{
57302
57340
  type: ViewChild,
57303
57341
  args: ['chartdiv', { static: true }]
57304
57342
  }] }); })();
57305
- (() => { (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: 66 }); })();
57306
57344
 
57307
57345
  const _forTrack0$i = ($index, $item) => $item.metric;
57308
57346
  function MetricReportModalComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
@@ -57410,7 +57448,7 @@ function MetricReportModalComponent_Conditional_0_Conditional_65_For_15_Template
57410
57448
  } }
57411
57449
  function MetricReportModalComponent_Conditional_0_Conditional_65_Template(rf, ctx) { if (rf & 1) {
57412
57450
  i0.ɵɵelementStart(0, "div", 16)(1, "h4", 17);
57413
- i0.ɵɵtext(2, " Contributing Metrics ");
57451
+ i0.ɵɵtext(2, " Contributing Metric Targets ");
57414
57452
  i0.ɵɵelementEnd();
57415
57453
  i0.ɵɵelementStart(3, "div", 36)(4, "table", 37)(5, "thead")(6, "tr", 38)(7, "th", 39);
57416
57454
  i0.ɵɵtext(8, "Metric");
@@ -57443,6 +57481,12 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
57443
57481
  i0.ɵɵelementEnd();
57444
57482
  i0.ɵɵelementStart(5, "p", 54);
57445
57483
  i0.ɵɵtext(6);
57484
+ i0.ɵɵelementEnd();
57485
+ i0.ɵɵelementStart(7, "p", 55);
57486
+ i0.ɵɵtext(8);
57487
+ i0.ɵɵelementEnd();
57488
+ i0.ɵɵelementStart(9, "p", 55);
57489
+ i0.ɵɵtext(10);
57446
57490
  i0.ɵɵelementEnd()();
57447
57491
  } if (rf & 2) {
57448
57492
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -57454,7 +57498,15 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
57454
57498
  i0.ɵɵadvance();
57455
57499
  i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
57456
57500
  i0.ɵɵadvance();
57457
- i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionText(), " ");
57501
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.chartLegendDescription(), " ");
57502
+ i0.ɵɵadvance();
57503
+ i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
57504
+ i0.ɵɵadvance();
57505
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence1(), " ");
57506
+ i0.ɵɵadvance();
57507
+ i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
57508
+ i0.ɵɵadvance();
57509
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence2(), " ");
57458
57510
  } }
57459
57511
  function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
57460
57512
  const _r1 = i0.ɵɵgetCurrentView();
@@ -57538,7 +57590,7 @@ function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
57538
57590
  i0.ɵɵconditionalCreate(64, MetricReportModalComponent_Conditional_0_Conditional_64_Template, 6, 10);
57539
57591
  i0.ɵɵelementEnd();
57540
57592
  i0.ɵɵconditionalCreate(65, MetricReportModalComponent_Conditional_0_Conditional_65_Template, 16, 3, "div", 16);
57541
- i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template, 7, 8, "div", 29);
57593
+ i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template, 11, 12, "div", 29);
57542
57594
  i0.ɵɵelementEnd();
57543
57595
  i0.ɵɵelementStart(67, "div", 30)(68, "button", 31);
57544
57596
  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()); });
@@ -57701,6 +57753,18 @@ class MetricReportModalComponent {
57701
57753
  }
57702
57754
  return 0;
57703
57755
  }, ...(ngDevMode ? [{ debugName: "samePeriodLastYearValue" }] : []));
57756
+ this.fullYearLastYearValue = computed(() => {
57757
+ const pacingResponse = this.pacingMetrics();
57758
+ const metric = this.metricData();
57759
+ if (!pacingResponse || !metric)
57760
+ return 0;
57761
+ const monthlyData = pacingResponse.lastYearMetricValuesMonthly;
57762
+ if (!monthlyData)
57763
+ return 0;
57764
+ return monthlyData
57765
+ .filter(item => item.metric === metric.metric)
57766
+ .reduce((total, item) => total + (parseFloat(item.value || '0') || 0), 0);
57767
+ }, ...(ngDevMode ? [{ debugName: "fullYearLastYearValue" }] : []));
57704
57768
  this.ytdChangePercentage = computed(() => {
57705
57769
  const current = this.ytdValue();
57706
57770
  const lastYear = this.samePeriodLastYearValue();
@@ -57794,12 +57858,29 @@ class MetricReportModalComponent {
57794
57858
  status: pacing.status
57795
57859
  };
57796
57860
  }, ...(ngDevMode ? [{ debugName: "progressToTargetData" }] : []));
57797
- this.chartDescriptionText = computed(() => {
57861
+ this.chartLegendDescription = computed(() => {
57798
57862
  const metric = this.metricTitle();
57799
57863
  const currentYear = this.currentYear();
57800
57864
  const priorYear = this.priorYear();
57801
57865
  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.`;
57802
- }, ...(ngDevMode ? [{ debugName: "chartDescriptionText" }] : []));
57866
+ }, ...(ngDevMode ? [{ debugName: "chartLegendDescription" }] : []));
57867
+ this.chartDescriptionSentence1 = computed(() => {
57868
+ const metricData = this.metricData();
57869
+ const metricName = this.metricTitle().toLowerCase();
57870
+ const startDate = this.ytdStartDate();
57871
+ const endDate = this.ytdEndDate();
57872
+ const ytdValue = this.formatMetricValue(this.ytdValue(), metricData?.metric || '');
57873
+ const samePeriodLastYear = this.formatMetricValue(this.samePeriodLastYearValue(), metricData?.metric || '');
57874
+ const priorYear = this.priorYear();
57875
+ return `For the period (${startDate} - ${endDate}) you had ${ytdValue} ${metricName}, compared to ${samePeriodLastYear} for the same period in ${priorYear}.`;
57876
+ }, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence1" }] : []));
57877
+ this.chartDescriptionSentence2 = computed(() => {
57878
+ const metricData = this.metricData();
57879
+ const metricName = this.metricTitle().toLowerCase();
57880
+ const projectedValue = this.formatMetricValue(this.pacingInfo()?.projectedValue || 0, metricData?.metric || '');
57881
+ const fullYearLastYear = this.formatMetricValue(this.fullYearLastYearValue(), metricData?.metric || '');
57882
+ return `By maintaining this pace, your ${metricName} could increase to ${projectedValue} compared to ${fullYearLastYear} last year.`;
57883
+ }, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence2" }] : []));
57803
57884
  this.pacingChartData = computed(() => {
57804
57885
  const metric = this.metricData();
57805
57886
  const pacingResponse = this.pacingMetrics();
@@ -57808,16 +57889,10 @@ class MetricReportModalComponent {
57808
57889
  const currentYearData = this.generateCurrentYearData(pacingResponse, metric.metric);
57809
57890
  const priorYearData = this.generatePriorYearData(pacingResponse, metric.metric);
57810
57891
  const projectionData = this.generateProjectionData(pacingResponse, metric.metric);
57811
- console.log('[PaceChart] Metric:', metric.metric);
57812
- console.log('[PaceChart] Current Year Data:', currentYearData);
57813
- console.log('[PaceChart] Prior Year Data:', priorYearData);
57814
- console.log('[PaceChart] Projection Data:', projectionData);
57815
- console.log('[PaceChart] Pacing Response:', pacingResponse);
57816
57892
  return {
57817
57893
  chartType: 'LINE',
57818
57894
  title: 'Pace',
57819
57895
  description: '',
57820
- lineChartUseCase: LineChartUseCaseEnum.THIS_YEAR_VS_LAST_YEAR,
57821
57896
  lineChartData: {
57822
57897
  series: [
57823
57898
  {
@@ -57845,86 +57920,58 @@ class MetricReportModalComponent {
57845
57920
  generateCurrentYearData(pacingResponse, metricEnum) {
57846
57921
  const data = [];
57847
57922
  const currentYear = this.currentYear();
57848
- if (pacingResponse?.soFarMetricValuesMonthly) {
57849
- const metricValues = pacingResponse.soFarMetricValuesMonthly.filter(m => m.metric === metricEnum);
57850
- metricValues.forEach(mv => {
57851
- if (mv.date && mv.value) {
57852
- const originalDate = new Date(mv.date);
57923
+ const monthlyData = pacingResponse?.soFarMetricValuesMonthly;
57924
+ if (monthlyData) {
57925
+ monthlyData
57926
+ .filter(item => item.metric === metricEnum)
57927
+ .forEach((item) => {
57928
+ if (item.value && item.date) {
57929
+ const month = new Date(item.date).getMonth();
57853
57930
  data.push({
57854
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57855
- value: parseFloat(mv.value)
57931
+ date: this.formatDateForChart(currentYear, month, 15),
57932
+ value: parseFloat(item.value) || 0
57856
57933
  });
57857
57934
  }
57858
57935
  });
57859
57936
  }
57860
- if (data.length === 0) {
57861
- const baseValue = this.metricData()?.currentValue || 1000;
57862
- const now = new Date();
57863
- const currentMonth = now.getMonth();
57864
- for (let i = 0; i <= currentMonth; i++) {
57865
- const value = baseValue * ((i + 1) / 12);
57866
- data.push({
57867
- date: this.formatDateForChart(currentYear, i, 15),
57868
- value: Math.round(value * 100) / 100
57869
- });
57870
- }
57871
- }
57872
57937
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57873
57938
  }
57874
57939
  generatePriorYearData(pacingResponse, metricEnum) {
57875
57940
  const data = [];
57876
57941
  const currentYear = this.currentYear();
57877
- if (pacingResponse?.lastYearMetricValuesMonthly) {
57878
- const metricValues = pacingResponse.lastYearMetricValuesMonthly.filter(m => m.metric === metricEnum);
57879
- metricValues.forEach(mv => {
57880
- if (mv.date && mv.value) {
57881
- const originalDate = new Date(mv.date);
57942
+ const monthlyData = pacingResponse?.lastYearMetricValuesMonthly;
57943
+ if (monthlyData) {
57944
+ monthlyData
57945
+ .filter(item => item.metric === metricEnum)
57946
+ .forEach((item) => {
57947
+ if (item.value && item.date) {
57948
+ const month = new Date(item.date).getMonth();
57882
57949
  data.push({
57883
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57884
- value: parseFloat(mv.value)
57950
+ date: this.formatDateForChart(currentYear, month, 15),
57951
+ value: parseFloat(item.value) || 0
57885
57952
  });
57886
57953
  }
57887
57954
  });
57888
57955
  }
57889
- if (data.length === 0) {
57890
- const baseValue = this.metricData()?.currentValue || 1000;
57891
- for (let i = 0; i < 12; i++) {
57892
- const value = baseValue * ((i + 1) / 12) * 0.9;
57893
- data.push({
57894
- date: this.formatDateForChart(currentYear, i, 15),
57895
- value: Math.round(value * 100) / 100
57896
- });
57897
- }
57898
- }
57899
57956
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57900
57957
  }
57901
57958
  generateProjectionData(pacingResponse, metricEnum) {
57902
57959
  const data = [];
57903
57960
  const currentYear = this.currentYear();
57904
- if (pacingResponse?.projectedMetricValuesMonthly) {
57905
- const metricValues = pacingResponse.projectedMetricValuesMonthly.filter(m => m.metric === metricEnum);
57906
- metricValues.forEach(mv => {
57907
- if (mv.date && mv.value) {
57908
- const originalDate = new Date(mv.date);
57961
+ const monthlyData = pacingResponse?.projectedMetricValuesMonthly;
57962
+ if (monthlyData) {
57963
+ monthlyData
57964
+ .filter(item => item.metric === metricEnum)
57965
+ .forEach((item) => {
57966
+ if (item.value && item.date) {
57967
+ const month = new Date(item.date).getMonth();
57909
57968
  data.push({
57910
- date: this.formatDateForChart(currentYear, originalDate.getMonth(), 15),
57911
- value: parseFloat(mv.value)
57969
+ date: this.formatDateForChart(currentYear, month, 15),
57970
+ value: parseFloat(item.value) || 0
57912
57971
  });
57913
57972
  }
57914
57973
  });
57915
57974
  }
57916
- if (data.length === 0) {
57917
- const targetValue = this.metricData()?.targetValue || 1200;
57918
- const now = new Date();
57919
- const currentMonth = now.getMonth();
57920
- for (let i = currentMonth; i < 12; i++) {
57921
- const value = targetValue * ((i + 1) / 12);
57922
- data.push({
57923
- date: this.formatDateForChart(currentYear, i, 15),
57924
- value: Math.round(value * 100) / 100
57925
- });
57926
- }
57927
- }
57928
57975
  return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
57929
57976
  }
57930
57977
  formatMetricValue(value, metric, fromUiData = true) {
@@ -58071,7 +58118,7 @@ class MetricReportModalComponent {
58071
58118
  : 'bg-slate-700 hover:bg-slate-600 text-white';
58072
58119
  }
58073
58120
  static { this.ɵfac = function MetricReportModalComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MetricReportModalComponent)(); }; }
58074
- 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) {
58121
+ 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) {
58075
58122
  i0.ɵɵconditionalCreate(0, MetricReportModalComponent_Conditional_0_Template, 70, 51, "div", 0);
58076
58123
  } if (rf & 2) {
58077
58124
  i0.ɵɵconditional(ctx.isOpen() ? 0 : -1);
@@ -58325,7 +58372,7 @@ class MetricReportModalComponent {
58325
58372
  @if (contributingMetrics().length > 0) {
58326
58373
  <div [ngClass]="sectionCardClasses()" class="rounded-xl p-6 mb-6">
58327
58374
  <h4 [ngClass]="sectionTitleClasses()" class="text-sm font-semibold uppercase tracking-wider mb-4">
58328
- Contributing Metrics
58375
+ Contributing Metric Targets
58329
58376
  </h4>
58330
58377
  <div class="overflow-x-auto">
58331
58378
  <table class="w-full">
@@ -58403,7 +58450,13 @@ class MetricReportModalComponent {
58403
58450
  />
58404
58451
  </div>
58405
58452
  <p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-4">
58406
- {{ chartDescriptionText() }}
58453
+ {{ chartLegendDescription() }}
58454
+ </p>
58455
+ <p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-2">
58456
+ {{ chartDescriptionSentence1() }}
58457
+ </p>
58458
+ <p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-2">
58459
+ {{ chartDescriptionSentence2() }}
58407
58460
  </p>
58408
58461
  </div>
58409
58462
  }
@@ -58425,7 +58478,7 @@ class MetricReportModalComponent {
58425
58478
  `
58426
58479
  }]
58427
58480
  }], 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"] }] }); })();
58428
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber: 343 }); })();
58481
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber: 349 }); })();
58429
58482
 
58430
58483
  const _c0$q = ["absoluteInputRef"];
58431
58484
  const _c1$b = ["percentageInputRef"];
@@ -63753,92 +63806,92 @@ class CollapsibleSectionGroupComponent {
63753
63806
  standalone: true,
63754
63807
  imports: [CommonModule, SymphiqIconComponent, ProfileSectionComponent],
63755
63808
  changeDetection: ChangeDetectionStrategy.OnPush,
63756
- template: `
63757
- <div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
63758
- <div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
63759
- <div class="flex items-center justify-between">
63760
- <div class="flex items-center gap-3">
63761
- <div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
63762
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63763
- <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>
63764
- </svg>
63765
- </div>
63766
- <div>
63767
- <h2 [ngClass]="titleClasses()" class="text-xl font-bold">
63768
- Supporting Business Context
63769
- </h2>
63770
- <p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
63771
- Additional insights gathered from publicly available information
63772
- </p>
63773
- </div>
63774
- </div>
63775
- </div>
63776
- </div>
63777
-
63778
- <div [ngClass]="contentClasses()" class="p-6">
63779
- <div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
63780
- <svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63781
- <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>
63782
- </svg>
63783
- <div class="flex-1">
63784
- <h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
63785
- Building Context for Better Recommendations
63786
- </h4>
63787
- <p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
63788
- 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.
63789
- </p>
63790
- </div>
63791
- </div>
63792
-
63793
- <div class="space-y-3">
63794
- @for (section of sections(); track section.id; let idx = $index) {
63795
- <div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
63796
- <button
63797
- type="button"
63798
- (click)="toggleSection(idx)"
63799
- [ngClass]="sectionHeaderClasses(section, idx)"
63800
- class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
63801
- <div class="flex items-center gap-3 flex-1 min-w-0">
63802
- @if (section.icon) {
63803
- <div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
63804
- <symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
63805
- </div>
63806
- }
63807
- <div class="flex-1 min-w-0">
63808
- <h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
63809
- {{ section.title }}
63810
- </h3>
63811
- <p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
63812
- {{ getSectionItemCount(section) }} items
63813
- </p>
63814
- </div>
63815
- </div>
63816
- <svg
63817
- [ngClass]="chevronClasses(idx)"
63818
- [class.rotate-180]="expandedSections()[idx]"
63819
- class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
63820
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
63821
- </svg>
63822
- </button>
63823
-
63824
- <div
63825
- class="grid transition-[grid-template-rows] duration-300 ease-in-out"
63826
- [style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
63827
- <div class="overflow-hidden">
63828
- <div [ngClass]="sectionContentClasses()" class="border-t">
63829
- <symphiq-profile-section
63830
- [section]="section"
63831
- [viewMode]="viewMode()"
63832
- [forceExpanded]="false"
63833
- />
63834
- </div>
63835
- </div>
63836
- </div>
63837
- </div>
63838
- }
63839
- </div>
63840
- </div>
63841
- </div>
63809
+ template: `
63810
+ <div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
63811
+ <div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
63812
+ <div class="flex items-center justify-between">
63813
+ <div class="flex items-center gap-3">
63814
+ <div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
63815
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63816
+ <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>
63817
+ </svg>
63818
+ </div>
63819
+ <div>
63820
+ <h2 [ngClass]="titleClasses()" class="text-xl font-bold">
63821
+ Supporting Business Context
63822
+ </h2>
63823
+ <p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
63824
+ Additional insights gathered from publicly available information
63825
+ </p>
63826
+ </div>
63827
+ </div>
63828
+ </div>
63829
+ </div>
63830
+
63831
+ <div [ngClass]="contentClasses()" class="p-6">
63832
+ <div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
63833
+ <svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63834
+ <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>
63835
+ </svg>
63836
+ <div class="flex-1">
63837
+ <h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
63838
+ Building Context for Better Recommendations
63839
+ </h4>
63840
+ <p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
63841
+ 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.
63842
+ </p>
63843
+ </div>
63844
+ </div>
63845
+
63846
+ <div class="space-y-3">
63847
+ @for (section of sections(); track section.id; let idx = $index) {
63848
+ <div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
63849
+ <button
63850
+ type="button"
63851
+ (click)="toggleSection(idx)"
63852
+ [ngClass]="sectionHeaderClasses(section, idx)"
63853
+ class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
63854
+ <div class="flex items-center gap-3 flex-1 min-w-0">
63855
+ @if (section.icon) {
63856
+ <div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
63857
+ <symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
63858
+ </div>
63859
+ }
63860
+ <div class="flex-1 min-w-0">
63861
+ <h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
63862
+ {{ section.title }}
63863
+ </h3>
63864
+ <p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
63865
+ {{ getSectionItemCount(section) }} items
63866
+ </p>
63867
+ </div>
63868
+ </div>
63869
+ <svg
63870
+ [ngClass]="chevronClasses(idx)"
63871
+ [class.rotate-180]="expandedSections()[idx]"
63872
+ class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
63873
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
63874
+ </svg>
63875
+ </button>
63876
+
63877
+ <div
63878
+ class="grid transition-[grid-template-rows] duration-300 ease-in-out"
63879
+ [style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
63880
+ <div class="overflow-hidden">
63881
+ <div [ngClass]="sectionContentClasses()" class="border-t">
63882
+ <symphiq-profile-section
63883
+ [section]="section"
63884
+ [viewMode]="viewMode()"
63885
+ [forceExpanded]="false"
63886
+ />
63887
+ </div>
63888
+ </div>
63889
+ </div>
63890
+ </div>
63891
+ }
63892
+ </div>
63893
+ </div>
63894
+ </div>
63842
63895
  `
63843
63896
  }]
63844
63897
  }], null, { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }] }); })();