@memberjunction/ng-dashboards 6.2.0-edge.5 → 6.2.0-edge.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +28 -0
  2. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
  3. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  4. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +15 -7
  5. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  6. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
  7. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  8. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +209 -57
  9. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  10. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
  11. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
  12. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
  13. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
  14. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  15. package/dist/AI/components/execution-monitoring.component.js +28 -16
  16. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  17. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
  18. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
  19. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +30 -6
  20. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
  21. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
  22. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  23. package/dist/AI/components/tags/tags-resource.component.js +15 -7
  24. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  25. package/dist/AI/components/vectors/sensitive-fields.d.ts +9 -4
  26. package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -1
  27. package/dist/AI/components/vectors/sensitive-fields.js +39 -14
  28. package/dist/AI/components/vectors/sensitive-fields.js.map +1 -1
  29. package/dist/AI/components/vectors/vector-document-rules.d.ts +13 -0
  30. package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -1
  31. package/dist/AI/components/vectors/vector-document-rules.js +14 -0
  32. package/dist/AI/components/vectors/vector-document-rules.js.map +1 -1
  33. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +34 -14
  34. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  35. package/dist/AI/components/vectors/vector-management-resource.component.js +127 -50
  36. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  37. package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
  38. package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
  39. package/dist/AI/components/vectors/vector-store-selection.js +57 -0
  40. package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
  41. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +236 -0
  42. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
  43. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +374 -0
  44. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
  45. package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts +195 -0
  46. package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts.map +1 -0
  47. package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js +2910 -0
  48. package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js.map +1 -0
  49. package/dist/ChiefOfStaff/index.d.ts +3 -0
  50. package/dist/ChiefOfStaff/index.d.ts.map +1 -0
  51. package/dist/ChiefOfStaff/index.js +3 -0
  52. package/dist/ChiefOfStaff/index.js.map +1 -0
  53. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  54. package/dist/Communication/communication-logs-resource.component.js +2 -1
  55. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  56. package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
  57. package/dist/Communication/communication-monitor-resource.component.js +23 -18
  58. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  59. package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
  60. package/dist/Communication/communication-runs-resource.component.js +11 -10
  61. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  62. package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
  63. package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
  64. package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
  65. package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
  66. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +24 -0
  67. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  68. package/dist/DataExplorer/data-explorer-dashboard.component.js +146 -50
  69. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  70. package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
  71. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  72. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  73. package/dist/LoginStudio/login-studio-resource.component.d.ts +10 -2
  74. package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -1
  75. package/dist/LoginStudio/login-studio-resource.component.js +110 -77
  76. package/dist/LoginStudio/login-studio-resource.component.js.map +1 -1
  77. package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
  78. package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
  79. package/dist/MCP/mcp-dashboard.component.js +118 -65
  80. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  81. package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
  82. package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
  83. package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
  84. package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
  85. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
  86. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
  87. package/dist/PredictiveStudio/components/ps-experiments.component.js +256 -521
  88. package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
  89. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
  90. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
  91. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +122 -249
  92. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
  93. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
  94. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  95. package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
  96. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  97. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
  98. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
  99. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +335 -326
  100. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
  101. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
  102. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
  103. package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
  104. package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
  105. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
  106. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
  107. package/dist/PredictiveStudio/engine/predictive-studio.engine.js +51 -2
  108. package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
  109. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
  110. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
  111. package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
  112. package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
  113. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
  114. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
  115. package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
  116. package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
  117. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
  118. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
  119. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +185 -103
  120. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
  121. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
  122. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
  123. package/dist/ai-dashboards.module.d.ts +22 -21
  124. package/dist/ai-dashboards.module.d.ts.map +1 -1
  125. package/dist/ai-dashboards.module.js +8 -2
  126. package/dist/ai-dashboards.module.js.map +1 -1
  127. package/dist/public-api.d.ts +2 -0
  128. package/dist/public-api.d.ts.map +1 -1
  129. package/dist/public-api.js +3 -0
  130. package/dist/public-api.js.map +1 -1
  131. package/package.json +71 -71
  132. package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
  133. package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
  134. package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
  135. package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
  136. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
  137. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
  138. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
  139. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
  140. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
  141. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
  142. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
  143. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, inject, } from '@angular/core';
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject, } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormsModule } from '@angular/forms';
4
4
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
@@ -6,14 +6,14 @@ import { NavigationService } from '@memberjunction/ng-shared';
6
6
  import { MJButtonDirective, MJViewToggleComponent, MjSlidePanelComponent, } from '@memberjunction/ng-ui-components';
7
7
  import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
8
8
  import { CompositeKey, LogError, RunView } from '@memberjunction/core';
9
- import { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
9
+ import { EscapeSQLString, NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
10
10
  import { UserInfoEngine } from '@memberjunction/core-entities';
11
11
  import { AgGridModule } from 'ag-grid-angular';
12
12
  import { AllCommunityModule, ModuleRegistry, themeAlpine, } from 'ag-grid-community';
13
- import { ParseAtRiskRows, ResolveRenewalPolarity, } from '../at-risk.view-models';
14
- import { resolveOutcomeConfig, resolveScoreBand, resolveOutcomeStyle, formatPredictionScore, } from '@memberjunction/predictive-studio-core';
13
+ import { AtRiskRules, ProblemTypes, resolveOutcomeConfig, ResolveScoreBand, resolveOutcomeStyle, formatPredictionScore, } from '@memberjunction/predictive-studio-core';
15
14
  import { PredictiveStudioScoreHistoryService, } from '../predictive-studio-score-history.service';
16
15
  import { PredictiveStudioEngine } from '../engine/predictive-studio.engine';
16
+ import { PSRowDriversComponent } from './ps-row-drivers.component';
17
17
  import * as i0 from "@angular/core";
18
18
  import * as i1 from "@memberjunction/ng-shared-generic";
19
19
  import * as i2 from "ag-grid-angular";
@@ -104,7 +104,16 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_7_T
104
104
  } if (rf & 2) {
105
105
  const ctx_r1 = i0.ɵɵnextContext(3);
106
106
  i0.ɵɵadvance();
107
- i0.ɵɵtextInterpolate2("Filtered by ", ctx_r1.selectedTier !== "all" ? ctx_r1.selectedTier + " risk" : "", "", ctx_r1.searchText ? " query \"" + ctx_r1.searchText + "\"" : "");
107
+ i0.ɵɵtextInterpolate2("Filtered by ", ctx_r1.SelectedTierLabel, "", ctx_r1.searchText ? " query \"" + ctx_r1.searchText + "\"" : "");
108
+ } }
109
+ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
110
+ i0.ɵɵelementStart(0, "span", 36);
111
+ i0.ɵɵtext(1);
112
+ i0.ɵɵelementEnd();
113
+ } if (rf & 2) {
114
+ const ctx_r1 = i0.ɵɵnextContext(3);
115
+ i0.ɵɵadvance();
116
+ i0.ɵɵtextInterpolate1("Showing the first ", ctx_r1.MaxRunDetailRowsLabel, " predictions");
108
117
  } }
109
118
  function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ctx) { if (rf & 1) {
110
119
  const _r7 = i0.ɵɵgetCurrentView();
@@ -119,8 +128,9 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ct
119
128
  i0.ɵɵtext(6);
120
129
  i0.ɵɵelementEnd();
121
130
  i0.ɵɵconditionalCreate(7, PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_7_Template, 2, 2, "span", 35);
122
- i0.ɵɵelementStart(8, "span", 35);
123
- i0.ɵɵtext(9, "Click any row to inspect details & score history");
131
+ i0.ɵɵconditionalCreate(8, PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_8_Template, 2, 1, "span", 36);
132
+ i0.ɵɵelementStart(9, "span", 35);
133
+ i0.ɵɵtext(10, "Click any row to inspect details & score history");
124
134
  i0.ɵɵelementEnd()();
125
135
  } if (rf & 2) {
126
136
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -131,6 +141,8 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ct
131
141
  i0.ɵɵtextInterpolate1(" of ", ctx_r1.allRows.length, " predictions");
132
142
  i0.ɵɵadvance();
133
143
  i0.ɵɵconditional(ctx_r1.selectedTier !== "all" || ctx_r1.searchText ? 7 : -1);
144
+ i0.ɵɵadvance();
145
+ i0.ɵɵconditional(ctx_r1.DetailRowsCapped ? 8 : -1);
134
146
  } }
135
147
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
136
148
  i0.ɵɵelement(0, "i");
@@ -142,17 +154,17 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditio
142
154
  } }
143
155
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template(rf, ctx) { if (rf & 1) {
144
156
  const _r8 = i0.ɵɵgetCurrentView();
145
- i0.ɵɵelementStart(0, "div", 54);
157
+ i0.ɵɵelementStart(0, "div", 55);
146
158
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template_div_click_0_listener() { const b_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setTierAndGrid(b_r9.key)); });
147
- i0.ɵɵelementStart(1, "span", 38);
148
- i0.ɵɵconditionalCreate(2, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template, 1, 5, "i", 55);
159
+ i0.ɵɵelementStart(1, "span", 39);
160
+ i0.ɵɵconditionalCreate(2, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template, 1, 5, "i", 56);
149
161
  i0.ɵɵtext(3);
150
162
  i0.ɵɵelementEnd();
151
- i0.ɵɵelementStart(4, "span", 40);
163
+ i0.ɵɵelementStart(4, "span", 41);
152
164
  i0.ɵɵtext(5);
153
165
  i0.ɵɵpipe(6, "number");
154
166
  i0.ɵɵelementEnd();
155
- i0.ɵɵelementStart(7, "span", 41);
167
+ i0.ɵɵelementStart(7, "span", 42);
156
168
  i0.ɵɵtext(8);
157
169
  i0.ɵɵelementEnd()();
158
170
  } if (rf & 2) {
@@ -172,7 +184,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template
172
184
  } }
173
185
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template(rf, ctx) { if (rf & 1) {
174
186
  const _r10 = i0.ɵɵgetCurrentView();
175
- i0.ɵɵelementStart(0, "button", 56);
187
+ i0.ɵɵelementStart(0, "button", 57);
176
188
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearDecileFilter()); });
177
189
  i0.ɵɵelement(1, "i", 22);
178
190
  i0.ɵɵtext(2, " Clear Decile Filter ");
@@ -180,35 +192,35 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_
180
192
  } }
181
193
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template(rf, ctx) { if (rf & 1) {
182
194
  const _r11 = i0.ɵɵgetCurrentView();
183
- i0.ɵɵelementStart(0, "div", 57);
195
+ i0.ɵɵelementStart(0, "div", 58);
184
196
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template_div_click_0_listener() { const b_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectDecile(b_r12.idx)); });
185
- i0.ɵɵelementStart(1, "span", 58);
197
+ i0.ɵɵelementStart(1, "span", 59);
186
198
  i0.ɵɵtext(2);
187
199
  i0.ɵɵpipe(3, "number");
188
200
  i0.ɵɵelementEnd();
189
- i0.ɵɵelementStart(4, "div", 59);
190
- i0.ɵɵelement(5, "div", 60);
201
+ i0.ɵɵelementStart(4, "div", 60);
202
+ i0.ɵɵelement(5, "div", 61);
191
203
  i0.ɵɵelementEnd();
192
- i0.ɵɵelementStart(6, "div", 61)(7, "span", 62);
204
+ i0.ɵɵelementStart(6, "div", 62)(7, "span", 63);
193
205
  i0.ɵɵtext(8);
194
206
  i0.ɵɵelementEnd();
195
- i0.ɵɵelementStart(9, "span", 63);
207
+ i0.ɵɵelementStart(9, "span", 64);
196
208
  i0.ɵɵtext(10);
197
209
  i0.ɵɵelementEnd()();
198
- i0.ɵɵelementStart(11, "div", 64)(12, "div", 65);
210
+ i0.ɵɵelementStart(11, "div", 65)(12, "div", 66);
199
211
  i0.ɵɵtext(13);
200
212
  i0.ɵɵelementEnd();
201
- i0.ɵɵelementStart(14, "div", 66)(15, "span", 67);
213
+ i0.ɵɵelementStart(14, "div", 67)(15, "span", 68);
202
214
  i0.ɵɵtext(16);
203
215
  i0.ɵɵpipe(17, "number");
204
216
  i0.ɵɵelementEnd();
205
- i0.ɵɵelementStart(18, "span", 68);
217
+ i0.ɵɵelementStart(18, "span", 69);
206
218
  i0.ɵɵtext(19);
207
219
  i0.ɵɵelementEnd()();
208
- i0.ɵɵelementStart(20, "div", 69);
220
+ i0.ɵɵelementStart(20, "div", 70);
209
221
  i0.ɵɵtext(21);
210
222
  i0.ɵɵelementEnd();
211
- i0.ɵɵelementStart(22, "div", 70);
223
+ i0.ɵɵelementStart(22, "div", 71);
212
224
  i0.ɵɵtext(23);
213
225
  i0.ɵɵelementEnd()()();
214
226
  } if (rf & 2) {
@@ -239,15 +251,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template
239
251
  i0.ɵɵtextInterpolate(ctx_r1.selectedDecileIndex === b_r12.idx ? "Click to clear filter" : "Click to filter grid");
240
252
  } }
241
253
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template(rf, ctx) { if (rf & 1) {
242
- i0.ɵɵelement(0, "div", 76);
254
+ i0.ɵɵelement(0, "div", 77);
243
255
  } if (rf & 2) {
244
256
  const c_r13 = ctx.$implicit;
245
257
  i0.ɵɵstyleProp("width", c_r13.pct, "%")("background", c_r13.color);
246
258
  i0.ɵɵproperty("title", c_r13.name + ": " + c_r13.count + " (" + c_r13.pct + "%)");
247
259
  } }
248
260
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template(rf, ctx) { if (rf & 1) {
249
- i0.ɵɵelementStart(0, "div", 75);
250
- i0.ɵɵelement(1, "span", 77);
261
+ i0.ɵɵelementStart(0, "div", 76);
262
+ i0.ɵɵelement(1, "span", 78);
251
263
  i0.ɵɵelementStart(2, "strong");
252
264
  i0.ɵɵtext(3);
253
265
  i0.ɵɵelementEnd();
@@ -264,15 +276,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_
264
276
  i0.ɵɵtextInterpolate2("", c_r14.count, " (", c_r14.pct, "%)");
265
277
  } }
266
278
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template(rf, ctx) { if (rf & 1) {
267
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 44)(2, "span");
268
- i0.ɵɵelement(3, "i", 71);
279
+ i0.ɵɵelementStart(0, "div", 44)(1, "div", 45)(2, "span");
280
+ i0.ɵɵelement(3, "i", 72);
269
281
  i0.ɵɵtext(4, " Predicted Outcome Classes");
270
282
  i0.ɵɵelementEnd()();
271
- i0.ɵɵelementStart(5, "div", 72);
272
- i0.ɵɵrepeaterCreate(6, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template, 1, 5, "div", 73, _forTrack2);
283
+ i0.ɵɵelementStart(5, "div", 73);
284
+ i0.ɵɵrepeaterCreate(6, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template, 1, 5, "div", 74, _forTrack2);
273
285
  i0.ɵɵelementEnd();
274
- i0.ɵɵelementStart(8, "div", 74);
275
- i0.ɵɵrepeaterCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template, 6, 5, "div", 75, _forTrack2);
286
+ i0.ɵɵelementStart(8, "div", 75);
287
+ i0.ɵɵrepeaterCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template, 6, 5, "div", 76, _forTrack2);
276
288
  i0.ɵɵelementEnd()();
277
289
  } if (rf & 2) {
278
290
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -282,7 +294,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_
282
294
  i0.ɵɵrepeater(ctx_r1.classBreakdown);
283
295
  } }
284
296
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template(rf, ctx) { if (rf & 1) {
285
- i0.ɵɵelementStart(0, "span", 84);
297
+ i0.ɵɵelementStart(0, "span", 85);
286
298
  i0.ɵɵtext(1);
287
299
  i0.ɵɵelementEnd();
288
300
  } if (rf & 2) {
@@ -293,17 +305,17 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
293
305
  } }
294
306
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template(rf, ctx) { if (rf & 1) {
295
307
  const _r15 = i0.ɵɵgetCurrentView();
296
- i0.ɵɵelementStart(0, "div", 53)(1, "div", 44)(2, "div", 45);
297
- i0.ɵɵelement(3, "i", 78);
308
+ i0.ɵɵelementStart(0, "div", 54)(1, "div", 45)(2, "div", 46);
309
+ i0.ɵɵelement(3, "i", 79);
298
310
  i0.ɵɵelementStart(4, "span");
299
311
  i0.ɵɵtext(5, " Decile Drill-Down: ");
300
- i0.ɵɵelementStart(6, "strong", 79);
312
+ i0.ɵɵelementStart(6, "strong", 80);
301
313
  i0.ɵɵtext(7);
302
314
  i0.ɵɵelementEnd();
303
315
  i0.ɵɵtext(8);
304
- i0.ɵɵconditionalCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template, 2, 3, "span", 80);
316
+ i0.ɵɵconditionalCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template, 2, 3, "span", 81);
305
317
  i0.ɵɵelementEnd()();
306
- i0.ɵɵelementStart(10, "div", 47)(11, "span", 48);
318
+ i0.ɵɵelementStart(10, "div", 48)(11, "span", 49);
307
319
  i0.ɵɵtext(12, " Showing ");
308
320
  i0.ɵɵelementStart(13, "strong");
309
321
  i0.ɵɵtext(14);
@@ -312,15 +324,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
312
324
  i0.ɵɵtext(16);
313
325
  i0.ɵɵpipe(17, "number");
314
326
  i0.ɵɵelementEnd();
315
- i0.ɵɵelementStart(18, "button", 56);
327
+ i0.ɵɵelementStart(18, "button", 57);
316
328
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearDecileFilter()); });
317
329
  i0.ɵɵelement(19, "i", 22);
318
330
  i0.ɵɵtext(20, " Show All Deciles ");
319
331
  i0.ɵɵelementEnd()()();
320
- i0.ɵɵelementStart(21, "div", 81)(22, "ag-grid-angular", 82);
332
+ i0.ɵɵelementStart(21, "div", 82)(22, "ag-grid-angular", 83);
321
333
  i0.ɵɵlistener("gridReady", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_gridReady_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onChartGridReady($event)); })("rowClicked", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_rowClicked_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRowClicked($event)); })("cellClicked", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_cellClicked_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onCellClicked($event)); });
322
334
  i0.ɵɵelementEnd()();
323
- i0.ɵɵelementStart(23, "div", 83)(24, "span", 35);
335
+ i0.ɵɵelementStart(23, "div", 84)(24, "span", 35);
324
336
  i0.ɵɵtext(25, "Click any row to inspect explainability drivers and score history in the slide-in drawer");
325
337
  i0.ɵɵelementEnd()()();
326
338
  } if (rf & 2) {
@@ -339,36 +351,36 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
339
351
  i0.ɵɵproperty("theme", ctx_r1.Theme)("columnDefs", ctx_r1.columnDefs)("defaultColDef", ctx_r1.defaultColDef)("gridOptions", ctx_r1.chartGridOptions)("rowData", ctx_r1.filteredRows);
340
352
  } }
341
353
  function PSPredictionsGridComponent_Conditional_25_Conditional_1_Template(rf, ctx) { if (rf & 1) {
342
- i0.ɵɵelementStart(0, "div", 32)(1, "div", 36)(2, "div", 37)(3, "span", 38);
343
- i0.ɵɵelement(4, "i", 39);
354
+ i0.ɵɵelementStart(0, "div", 32)(1, "div", 37)(2, "div", 38)(3, "span", 39);
355
+ i0.ɵɵelement(4, "i", 40);
344
356
  i0.ɵɵtext(5, " Scored Cohort");
345
357
  i0.ɵɵelementEnd();
346
- i0.ɵɵelementStart(6, "span", 40);
358
+ i0.ɵɵelementStart(6, "span", 41);
347
359
  i0.ɵɵtext(7);
348
360
  i0.ɵɵpipe(8, "number");
349
361
  i0.ɵɵelementEnd();
350
- i0.ɵɵelementStart(9, "span", 41);
362
+ i0.ɵɵelementStart(9, "span", 42);
351
363
  i0.ɵɵtext(10, "Total records");
352
364
  i0.ɵɵelementEnd()();
353
- i0.ɵɵrepeaterCreate(11, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template, 9, 12, "div", 42, _forTrack0);
365
+ i0.ɵɵrepeaterCreate(11, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template, 9, 12, "div", 43, _forTrack0);
354
366
  i0.ɵɵelementEnd();
355
- i0.ɵɵelementStart(13, "div", 43)(14, "div", 44)(15, "div", 45);
356
- i0.ɵɵelement(16, "i", 46);
367
+ i0.ɵɵelementStart(13, "div", 44)(14, "div", 45)(15, "div", 46);
368
+ i0.ɵɵelement(16, "i", 47);
357
369
  i0.ɵɵelementStart(17, "span");
358
370
  i0.ɵɵtext(18);
359
371
  i0.ɵɵelementEnd()();
360
- i0.ɵɵelementStart(19, "div", 47)(20, "span", 48);
372
+ i0.ɵɵelementStart(19, "div", 48)(20, "span", 49);
361
373
  i0.ɵɵtext(21, "Cohort Mean: ");
362
374
  i0.ɵɵelementStart(22, "strong");
363
375
  i0.ɵɵtext(23);
364
376
  i0.ɵɵelementEnd()();
365
- i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template, 3, 0, "button", 49);
377
+ i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template, 3, 0, "button", 50);
366
378
  i0.ɵɵelementEnd()();
367
- i0.ɵɵelementStart(25, "div", 50)(26, "div", 51);
368
- i0.ɵɵrepeaterCreate(27, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template, 24, 24, "div", 52, _forTrack1);
379
+ i0.ɵɵelementStart(25, "div", 51)(26, "div", 52);
380
+ i0.ɵɵrepeaterCreate(27, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template, 24, 24, "div", 53, _forTrack1);
369
381
  i0.ɵɵelementEnd()()();
370
- i0.ɵɵconditionalCreate(29, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template, 11, 0, "div", 43);
371
- i0.ɵɵconditionalCreate(30, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template, 26, 14, "div", 53);
382
+ i0.ɵɵconditionalCreate(29, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template, 11, 0, "div", 44);
383
+ i0.ɵɵconditionalCreate(30, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template, 26, 14, "div", 54);
372
384
  i0.ɵɵelementEnd();
373
385
  } if (rf & 2) {
374
386
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -390,7 +402,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Template(rf, ct
390
402
  i0.ɵɵconditional(ctx_r1.selectedDecileIndex !== null ? 30 : -1);
391
403
  } }
392
404
  function PSPredictionsGridComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
393
- i0.ɵɵconditionalCreate(0, PSPredictionsGridComponent_Conditional_25_Conditional_0_Template, 10, 8);
405
+ i0.ɵɵconditionalCreate(0, PSPredictionsGridComponent_Conditional_25_Conditional_0_Template, 11, 9);
394
406
  i0.ɵɵconditionalCreate(1, PSPredictionsGridComponent_Conditional_25_Conditional_1_Template, 31, 8, "div", 32);
395
407
  } if (rf & 2) {
396
408
  const ctx_r1 = i0.ɵɵnextContext();
@@ -400,9 +412,9 @@ function PSPredictionsGridComponent_Conditional_25_Template(rf, ctx) { if (rf &
400
412
  } }
401
413
  function PSPredictionsGridComponent_Conditional_26_Conditional_15_Template(rf, ctx) { if (rf & 1) {
402
414
  const _r17 = i0.ɵɵgetCurrentView();
403
- i0.ɵɵelementStart(0, "button", 110);
415
+ i0.ɵɵelementStart(0, "button", 111);
404
416
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_26_Conditional_15_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.openSubjectRecord()); });
405
- i0.ɵɵelement(1, "i", 111);
417
+ i0.ɵɵelement(1, "i", 112);
406
418
  i0.ɵɵtext(2);
407
419
  i0.ɵɵelementEnd();
408
420
  } if (rf & 2) {
@@ -417,10 +429,10 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_24_Template(rf, c
417
429
  i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", ctx_r1.selectedRow.icon));
418
430
  } }
419
431
  function PSPredictionsGridComponent_Conditional_26_Conditional_26_Template(rf, ctx) { if (rf & 1) {
420
- i0.ɵɵelementStart(0, "div", 98)(1, "strong");
432
+ i0.ɵɵelementStart(0, "div", 99)(1, "strong");
421
433
  i0.ɵɵtext(2, "Predicted Outcome:");
422
434
  i0.ɵɵelementEnd();
423
- i0.ɵɵelementStart(3, "span", 112);
435
+ i0.ɵɵelementStart(3, "span", 113);
424
436
  i0.ɵɵtext(4);
425
437
  i0.ɵɵelementEnd()();
426
438
  } if (rf & 2) {
@@ -430,141 +442,107 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_26_Template(rf, c
430
442
  i0.ɵɵadvance();
431
443
  i0.ɵɵtextInterpolate1(" ", ctx_r1.selectedRow.class, " ");
432
444
  } }
433
- function PSPredictionsGridComponent_Conditional_26_Conditional_39_Template(rf, ctx) { if (rf & 1) {
434
- i0.ɵɵelementStart(0, "div", 48);
435
- i0.ɵɵtext(1, "No individual driver breakdown was recorded for this row.");
436
- i0.ɵɵelementEnd();
437
- } }
438
- function PSPredictionsGridComponent_Conditional_26_Conditional_40_For_2_Template(rf, ctx) { if (rf & 1) {
439
- i0.ɵɵelementStart(0, "div", 113)(1, "div", 114);
440
- i0.ɵɵelement(2, "i", 115);
441
- i0.ɵɵtext(3);
442
- i0.ɵɵelementEnd();
443
- i0.ɵɵelementStart(4, "span", 112);
444
- i0.ɵɵtext(5);
445
- i0.ɵɵelementEnd()();
446
- } if (rf & 2) {
447
- const d_r18 = ctx.$implicit;
448
- i0.ɵɵadvance(2);
449
- i0.ɵɵstyleProp("color", d_r18.up ? "var(--mj-status-error)" : "var(--mj-status-success)");
450
- i0.ɵɵclassProp("fa-arrow-up", d_r18.up)("fa-arrow-down", !d_r18.up);
451
- i0.ɵɵadvance();
452
- i0.ɵɵtextInterpolate1(" ", d_r18.label, " ");
453
- i0.ɵɵadvance();
454
- i0.ɵɵclassMap(d_r18.up ? "red" : "green");
455
- i0.ɵɵadvance();
456
- i0.ɵɵtextInterpolate1(" ", d_r18.up ? "Increases Risk" : "Lowers Risk", " ");
445
+ function PSPredictionsGridComponent_Conditional_26_Conditional_47_Template(rf, ctx) { if (rf & 1) {
446
+ i0.ɵɵelement(0, "mj-loading", 110);
457
447
  } }
458
- function PSPredictionsGridComponent_Conditional_26_Conditional_40_Template(rf, ctx) { if (rf & 1) {
459
- i0.ɵɵelementStart(0, "div", 105);
460
- i0.ɵɵrepeaterCreate(1, PSPredictionsGridComponent_Conditional_26_Conditional_40_For_2_Template, 6, 10, "div", 113, _forTrack1);
461
- i0.ɵɵelementEnd();
462
- } if (rf & 2) {
463
- const ctx_r1 = i0.ɵɵnextContext(2);
464
- i0.ɵɵadvance();
465
- i0.ɵɵrepeater(ctx_r1.selectedRow.drivers);
466
- } }
467
- function PSPredictionsGridComponent_Conditional_26_Conditional_48_Template(rf, ctx) { if (rf & 1) {
468
- i0.ɵɵelement(0, "mj-loading", 109);
469
- } }
470
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_13_Template(rf, ctx) { if (rf & 1) {
448
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_13_Template(rf, ctx) { if (rf & 1) {
471
449
  i0.ɵɵnamespaceSVG();
472
- i0.ɵɵelementStart(0, "circle", 126)(1, "title");
450
+ i0.ɵɵelementStart(0, "circle", 124)(1, "title");
473
451
  i0.ɵɵtext(2);
474
452
  i0.ɵɵelementEnd()();
475
- i0.ɵɵelementStart(3, "text", 127);
453
+ i0.ɵɵelementStart(3, "text", 125);
476
454
  i0.ɵɵtext(4);
477
455
  i0.ɵɵelementEnd();
478
456
  } if (rf & 2) {
479
- const p_r19 = ctx.$implicit;
480
- i0.ɵɵattribute("cx", p_r19.x)("cy", p_r19.y)("fill", p_r19.color);
457
+ const p_r18 = ctx.$implicit;
458
+ i0.ɵɵattribute("cx", p_r18.x)("cy", p_r18.y)("fill", p_r18.color);
481
459
  i0.ɵɵadvance(2);
482
- i0.ɵɵtextInterpolate3("", p_r19.dateStr, ": ", p_r19.scoreFormatted, " (", p_r19.class || "No class", ")");
460
+ i0.ɵɵtextInterpolate3("", p_r18.dateStr, ": ", p_r18.scoreFormatted, " (", p_r18.class || "No class", ")");
483
461
  i0.ɵɵadvance();
484
- i0.ɵɵattribute("cx", p_r19.x)("cy", p_r19.y - 9);
462
+ i0.ɵɵattribute("cx", p_r18.x)("cy", p_r18.y - 9);
485
463
  i0.ɵɵadvance();
486
- i0.ɵɵtextInterpolate1(" ", p_r19.scoreFormatted, " ");
464
+ i0.ɵɵtextInterpolate1(" ", p_r18.scoreFormatted, " ");
487
465
  } }
488
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_11_Template(rf, ctx) { if (rf & 1) {
489
- i0.ɵɵelementStart(0, "span", 129);
466
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_11_Template(rf, ctx) { if (rf & 1) {
467
+ i0.ɵɵelementStart(0, "span", 127);
490
468
  i0.ɵɵtext(1, "Baseline");
491
469
  i0.ɵɵelementEnd();
492
470
  } }
493
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_12_Template(rf, ctx) { if (rf & 1) {
494
- i0.ɵɵelementStart(0, "span", 130);
495
- i0.ɵɵelement(1, "i", 132);
471
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_12_Template(rf, ctx) { if (rf & 1) {
472
+ i0.ɵɵelementStart(0, "span", 128);
473
+ i0.ɵɵelement(1, "i", 130);
496
474
  i0.ɵɵtext(2);
497
475
  i0.ɵɵelementEnd();
498
476
  } if (rf & 2) {
499
- const pt_r20 = i0.ɵɵnextContext().$implicit;
477
+ const pt_r19 = i0.ɵɵnextContext().$implicit;
500
478
  i0.ɵɵadvance(2);
501
- i0.ɵɵtextInterpolate1(" +", (pt_r20.Delta * 100).toFixed(1), "%");
479
+ i0.ɵɵtextInterpolate1(" +", (pt_r19.Delta * 100).toFixed(1), "%");
502
480
  } }
503
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_13_Template(rf, ctx) { if (rf & 1) {
504
- i0.ɵɵelementStart(0, "span", 131);
505
- i0.ɵɵelement(1, "i", 133);
481
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_13_Template(rf, ctx) { if (rf & 1) {
482
+ i0.ɵɵelementStart(0, "span", 129);
483
+ i0.ɵɵelement(1, "i", 131);
506
484
  i0.ɵɵtext(2);
507
485
  i0.ɵɵelementEnd();
508
486
  } if (rf & 2) {
509
- const pt_r20 = i0.ɵɵnextContext().$implicit;
487
+ const pt_r19 = i0.ɵɵnextContext().$implicit;
510
488
  i0.ɵɵadvance(2);
511
- i0.ɵɵtextInterpolate1(" ", (pt_r20.Delta * 100).toFixed(1), "%");
489
+ i0.ɵɵtextInterpolate1(" ", (pt_r19.Delta * 100).toFixed(1), "%");
512
490
  } }
513
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_14_Template(rf, ctx) { if (rf & 1) {
514
- i0.ɵɵelementStart(0, "span", 129);
491
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_14_Template(rf, ctx) { if (rf & 1) {
492
+ i0.ɵɵelementStart(0, "span", 127);
515
493
  i0.ɵɵtext(1, "0%");
516
494
  i0.ɵɵelementEnd();
517
495
  } }
518
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Template(rf, ctx) { if (rf & 1) {
496
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Template(rf, ctx) { if (rf & 1) {
519
497
  i0.ɵɵelementStart(0, "tr")(1, "td");
520
498
  i0.ɵɵtext(2);
521
499
  i0.ɵɵpipe(3, "date");
522
500
  i0.ɵɵelementEnd();
523
- i0.ɵɵelementStart(4, "td")(5, "span", 112);
501
+ i0.ɵɵelementStart(4, "td")(5, "span", 113);
524
502
  i0.ɵɵtext(6);
525
503
  i0.ɵɵelementEnd()();
526
- i0.ɵɵelementStart(7, "td")(8, "strong", 128);
504
+ i0.ɵɵelementStart(7, "td")(8, "strong", 126);
527
505
  i0.ɵɵtext(9);
528
506
  i0.ɵɵelementEnd()();
529
507
  i0.ɵɵelementStart(10, "td");
530
- i0.ɵɵconditionalCreate(11, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_11_Template, 2, 0, "span", 129)(12, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_12_Template, 3, 1, "span", 130)(13, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_13_Template, 3, 1, "span", 131)(14, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Conditional_14_Template, 2, 0, "span", 129);
508
+ i0.ɵɵconditionalCreate(11, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_11_Template, 2, 0, "span", 127)(12, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_12_Template, 3, 1, "span", 128)(13, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_13_Template, 3, 1, "span", 129)(14, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_14_Template, 2, 0, "span", 127);
531
509
  i0.ɵɵelementEnd();
532
510
  i0.ɵɵelementStart(15, "td");
533
511
  i0.ɵɵtext(16);
534
512
  i0.ɵɵelementEnd()();
535
513
  } if (rf & 2) {
536
- const pt_r20 = ctx.$implicit;
514
+ const pt_r19 = ctx.$implicit;
537
515
  i0.ɵɵadvance(2);
538
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 7, pt_r20.RunDate, "short"));
516
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 7, pt_r19.RunDate, "short"));
539
517
  i0.ɵɵadvance(3);
540
- i0.ɵɵclassMap(pt_r20.status === "Succeeded" ? "green" : "gray");
518
+ i0.ɵɵclassMap(pt_r19.status === "Succeeded" ? "green" : "gray");
541
519
  i0.ɵɵadvance();
542
- i0.ɵɵtextInterpolate(pt_r20.status);
520
+ i0.ɵɵtextInterpolate(pt_r19.status);
543
521
  i0.ɵɵadvance(3);
544
- i0.ɵɵtextInterpolate(pt_r20.ScoreFormatted);
522
+ i0.ɵɵtextInterpolate(pt_r19.ScoreFormatted);
545
523
  i0.ɵɵadvance(2);
546
- i0.ɵɵconditional(pt_r20.Delta == null ? 11 : pt_r20.Delta > 0.005 ? 12 : pt_r20.Delta < -0.005 ? 13 : 14);
524
+ i0.ɵɵconditional(pt_r19.Delta == null ? 11 : pt_r19.Delta > 0.005 ? 12 : pt_r19.Delta < -0.005 ? 13 : 14);
547
525
  i0.ɵɵadvance(5);
548
- i0.ɵɵtextInterpolate(pt_r20.class || "\u2014");
526
+ i0.ɵɵtextInterpolate(pt_r19.class || "\u2014");
549
527
  } }
550
- function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, ctx) { if (rf & 1) {
528
+ function PSPredictionsGridComponent_Conditional_26_Conditional_48_Template(rf, ctx) { if (rf & 1) {
551
529
  i0.ɵɵnamespaceSVG();
552
- i0.ɵɵelementStart(0, "svg", 116);
553
- i0.ɵɵelement(1, "line", 117)(2, "line", 118)(3, "line", 119);
554
- i0.ɵɵelementStart(4, "text", 120);
530
+ i0.ɵɵelementStart(0, "svg", 114);
531
+ i0.ɵɵelement(1, "line", 115)(2, "line", 116)(3, "line", 117);
532
+ i0.ɵɵelementStart(4, "text", 118);
555
533
  i0.ɵɵtext(5, "100%");
556
534
  i0.ɵɵelementEnd();
557
- i0.ɵɵelementStart(6, "text", 121);
535
+ i0.ɵɵelementStart(6, "text", 119);
558
536
  i0.ɵɵtext(7, "50%");
559
537
  i0.ɵɵelementEnd();
560
- i0.ɵɵelementStart(8, "text", 122);
538
+ i0.ɵɵelementStart(8, "text", 120);
561
539
  i0.ɵɵtext(9, "0%");
562
540
  i0.ɵɵelementEnd();
563
- i0.ɵɵelement(10, "polygon", 123)(11, "polyline", 124);
564
- i0.ɵɵrepeaterCreate(12, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_13_Template, 5, 9, null, null, _forTrack3);
541
+ i0.ɵɵelement(10, "polygon", 121)(11, "polyline", 122);
542
+ i0.ɵɵrepeaterCreate(12, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_13_Template, 5, 9, null, null, _forTrack3);
565
543
  i0.ɵɵelementEnd();
566
544
  i0.ɵɵnamespaceHTML();
567
- i0.ɵɵelementStart(14, "table", 125)(15, "thead")(16, "tr")(17, "th");
545
+ i0.ɵɵelementStart(14, "table", 123)(15, "thead")(16, "tr")(17, "th");
568
546
  i0.ɵɵtext(18, "When");
569
547
  i0.ɵɵelementEnd();
570
548
  i0.ɵɵelementStart(19, "th");
@@ -580,7 +558,7 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, c
580
558
  i0.ɵɵtext(26, "Class");
581
559
  i0.ɵɵelementEnd()()();
582
560
  i0.ɵɵelementStart(27, "tbody");
583
- i0.ɵɵrepeaterCreate(28, PSPredictionsGridComponent_Conditional_26_Conditional_49_For_29_Template, 17, 10, "tr", null, _forTrack3);
561
+ i0.ɵɵrepeaterCreate(28, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Template, 17, 10, "tr", null, _forTrack3);
584
562
  i0.ɵɵelementEnd()();
585
563
  } if (rf & 2) {
586
564
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -593,8 +571,8 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, c
593
571
  i0.ɵɵadvance(16);
594
572
  i0.ɵɵrepeater(ctx_r1.historyPoints);
595
573
  } }
596
- function PSPredictionsGridComponent_Conditional_26_Conditional_50_Template(rf, ctx) { if (rf & 1) {
597
- i0.ɵɵelementStart(0, "div", 48);
574
+ function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, ctx) { if (rf & 1) {
575
+ i0.ɵɵelementStart(0, "div", 49);
598
576
  i0.ɵɵtext(1);
599
577
  i0.ɵɵpipe(2, "date");
600
578
  i0.ɵɵelementEnd();
@@ -603,66 +581,66 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_50_Template(rf, c
603
581
  i0.ɵɵadvance();
604
582
  i0.ɵɵtextInterpolate1(" This record has been scored once so far (", i0.ɵɵpipeBind2(2, 1, ctx_r1.historyPoints[0].RunDate, "medium"), "). As more runs occur over time, the score trendline will track changes here. ");
605
583
  } }
606
- function PSPredictionsGridComponent_Conditional_26_Conditional_51_Template(rf, ctx) { if (rf & 1) {
607
- i0.ɵɵelementStart(0, "div", 48);
584
+ function PSPredictionsGridComponent_Conditional_26_Conditional_50_Template(rf, ctx) { if (rf & 1) {
585
+ i0.ɵɵelementStart(0, "div", 49);
608
586
  i0.ɵɵtext(1, "No historical runs found for this record.");
609
587
  i0.ɵɵelementEnd();
610
588
  } }
611
589
  function PSPredictionsGridComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) {
612
590
  const _r16 = i0.ɵɵgetCurrentView();
613
- i0.ɵɵelementStart(0, "mj-slide-panel", 85);
591
+ i0.ɵɵelementStart(0, "mj-slide-panel", 86);
614
592
  i0.ɵɵlistener("WidthChanged", function PSPredictionsGridComponent_Conditional_26_Template_mj_slide_panel_WidthChanged_0_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDrawerWidthChanged($event)); })("Closed", function PSPredictionsGridComponent_Conditional_26_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeDetail()); });
615
- i0.ɵɵelementStart(1, "div", 86)(2, "div", 87)(3, "div", 88)(4, "h3");
593
+ i0.ɵɵelementStart(1, "div", 87)(2, "div", 88)(3, "div", 89)(4, "h3");
616
594
  i0.ɵɵtext(5);
617
595
  i0.ɵɵelementEnd();
618
- i0.ɵɵelementStart(6, "div", 45)(7, "span", 89);
596
+ i0.ɵɵelementStart(6, "div", 46)(7, "span", 90);
619
597
  i0.ɵɵtext(8);
620
598
  i0.ɵɵelementEnd();
621
- i0.ɵɵelementStart(9, "span", 90);
599
+ i0.ɵɵelementStart(9, "span", 91);
622
600
  i0.ɵɵtext(10);
623
601
  i0.ɵɵelementEnd()()();
624
- i0.ɵɵelementStart(11, "div", 91)(12, "button", 92);
602
+ i0.ɵɵelementStart(11, "div", 92)(12, "button", 93);
625
603
  i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_26_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.drillThrough(ctx_r1.selectedRow)); });
626
- i0.ɵɵelement(13, "i", 93);
604
+ i0.ɵɵelement(13, "i", 94);
627
605
  i0.ɵɵtext(14);
628
606
  i0.ɵɵelementEnd();
629
- i0.ɵɵconditionalCreate(15, PSPredictionsGridComponent_Conditional_26_Conditional_15_Template, 3, 2, "button", 94);
607
+ i0.ɵɵconditionalCreate(15, PSPredictionsGridComponent_Conditional_26_Conditional_15_Template, 3, 2, "button", 95);
630
608
  i0.ɵɵelementEnd()();
631
- i0.ɵɵelementStart(16, "div", 95)(17, "div", 96);
609
+ i0.ɵɵelementStart(16, "div", 96)(17, "div", 97);
632
610
  i0.ɵɵtext(18);
633
611
  i0.ɵɵelementEnd();
634
- i0.ɵɵelementStart(19, "div", 97)(20, "div", 98)(21, "strong");
612
+ i0.ɵɵelementStart(19, "div", 98)(20, "div", 99)(21, "strong");
635
613
  i0.ɵɵtext(22);
636
614
  i0.ɵɵelementEnd();
637
- i0.ɵɵelementStart(23, "span", 84);
638
- i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_26_Conditional_24_Template, 1, 3, "i", 99);
615
+ i0.ɵɵelementStart(23, "span", 85);
616
+ i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_26_Conditional_24_Template, 1, 3, "i", 100);
639
617
  i0.ɵɵtext(25);
640
618
  i0.ɵɵelementEnd()();
641
- i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Conditional_26_Template, 5, 3, "div", 98);
642
- i0.ɵɵelementStart(27, "div", 98)(28, "strong");
619
+ i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Conditional_26_Template, 5, 3, "div", 99);
620
+ i0.ɵɵelementStart(27, "div", 99)(28, "strong");
643
621
  i0.ɵɵtext(29);
644
622
  i0.ɵɵelementEnd();
645
- i0.ɵɵelementStart(30, "span", 100);
623
+ i0.ɵɵelementStart(30, "span", 101);
646
624
  i0.ɵɵtext(31);
647
625
  i0.ɵɵelementEnd()();
648
- i0.ɵɵelementStart(32, "div", 101);
626
+ i0.ɵɵelementStart(32, "div", 102);
649
627
  i0.ɵɵtext(33);
650
628
  i0.ɵɵpipe(34, "date");
651
629
  i0.ɵɵelementEnd()()();
652
- i0.ɵɵelementStart(35, "div", 102)(36, "div", 103);
653
- i0.ɵɵelement(37, "i", 104);
654
- i0.ɵɵtext(38, " Key Decision Drivers (Explainability) ");
630
+ i0.ɵɵelementStart(35, "div", 103)(36, "div", 104);
631
+ i0.ɵɵelement(37, "i", 105);
632
+ i0.ɵɵtext(38, " Factors behind this score (associations, not causes) ");
655
633
  i0.ɵɵelementEnd();
656
- i0.ɵɵconditionalCreate(39, PSPredictionsGridComponent_Conditional_26_Conditional_39_Template, 2, 0, "div", 48)(40, PSPredictionsGridComponent_Conditional_26_Conditional_40_Template, 3, 0, "div", 105);
634
+ i0.ɵɵelement(39, "ps-row-drivers", 106);
657
635
  i0.ɵɵelementEnd();
658
- i0.ɵɵelementStart(41, "div", 106)(42, "div", 107)(43, "span");
659
- i0.ɵɵelement(44, "i", 108);
660
- i0.ɵɵtext(45, " Historical Score Trendline");
636
+ i0.ɵɵelementStart(40, "div", 107)(41, "div", 108)(42, "span");
637
+ i0.ɵɵelement(43, "i", 109);
638
+ i0.ɵɵtext(44, " Historical Score Trendline");
661
639
  i0.ɵɵelementEnd();
662
- i0.ɵɵelementStart(46, "span", 48);
663
- i0.ɵɵtext(47);
640
+ i0.ɵɵelementStart(45, "span", 49);
641
+ i0.ɵɵtext(46);
664
642
  i0.ɵɵelementEnd()();
665
- i0.ɵɵconditionalCreate(48, PSPredictionsGridComponent_Conditional_26_Conditional_48_Template, 1, 0, "mj-loading", 109)(49, PSPredictionsGridComponent_Conditional_26_Conditional_49_Template, 30, 2)(50, PSPredictionsGridComponent_Conditional_26_Conditional_50_Template, 3, 4, "div", 48)(51, PSPredictionsGridComponent_Conditional_26_Conditional_51_Template, 2, 0, "div", 48);
643
+ i0.ɵɵconditionalCreate(47, PSPredictionsGridComponent_Conditional_26_Conditional_47_Template, 1, 0, "mj-loading", 110)(48, PSPredictionsGridComponent_Conditional_26_Conditional_48_Template, 30, 2)(49, PSPredictionsGridComponent_Conditional_26_Conditional_49_Template, 3, 4, "div", 49)(50, PSPredictionsGridComponent_Conditional_26_Conditional_50_Template, 2, 0, "div", 49);
666
644
  i0.ɵɵelementEnd()()();
667
645
  } if (rf & 2) {
668
646
  const ctx_r1 = i0.ɵɵnextContext();
@@ -698,11 +676,11 @@ function PSPredictionsGridComponent_Conditional_26_Template(rf, ctx) { if (rf &
698
676
  i0.ɵɵadvance(2);
699
677
  i0.ɵɵtextInterpolate1(" Scored: ", ctx_r1.selectedRow.scoredAtDate ? i0.ɵɵpipeBind2(34, 23, ctx_r1.selectedRow.scoredAtDate, "medium") : "\u2014", " ");
700
678
  i0.ɵɵadvance(6);
701
- i0.ɵɵconditional(!ctx_r1.selectedRow.drivers || ctx_r1.selectedRow.drivers.length === 0 ? 39 : 40);
702
- i0.ɵɵadvance(8);
679
+ i0.ɵɵproperty("Drivers", ctx_r1.selectedRow.drivers);
680
+ i0.ɵɵadvance(7);
703
681
  i0.ɵɵtextInterpolate2("", ctx_r1.historyPoints.length, " run", ctx_r1.historyPoints.length === 1 ? "" : "s", " recorded");
704
682
  i0.ɵɵadvance();
705
- i0.ɵɵconditional(ctx_r1.historyLoading ? 48 : ctx_r1.historyPoints.length > 1 ? 49 : ctx_r1.historyPoints.length === 1 ? 50 : 51);
683
+ i0.ɵɵconditional(ctx_r1.historyLoading ? 47 : ctx_r1.historyPoints.length > 1 ? 48 : ctx_r1.historyPoints.length === 1 ? 49 : 50);
706
684
  } }
707
685
  ModuleRegistry.registerModules([AllCommunityModule]);
708
686
  /**
@@ -750,12 +728,25 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
750
728
  get readOnly() {
751
729
  return this.ReadOnly;
752
730
  }
731
+ /**
732
+ * Emitted after the grid parses a run, with the run's at-risk rows. A host that needs the rows (counts, export, a list)
733
+ * takes them from here rather than reading the run a second time. Also emitted, empty, when the model has no run.
734
+ */
735
+ RowsLoaded = new EventEmitter();
736
+ /** Emitted with the error message when the run's predictions fail to load. */
737
+ RowsLoadFailed = new EventEmitter();
753
738
  cdr = inject(ChangeDetectorRef);
754
739
  navigationService = inject(NavigationService);
755
740
  scoreHistoryService = inject(PredictiveStudioScoreHistoryService);
756
741
  Math = Math;
742
+ /** The run-detail cap, formatted for the footer notice. */
743
+ MaxRunDetailRowsLabel = PredictiveStudioEngine.MaxRunDetailRowsLabel;
744
+ /** The tier of a regression row whose value falls in none of the outcome bands. */
745
+ static unbandedTier = { Key: 'unbanded', Label: 'No band', BadgeColor: 'gray' };
757
746
  isLoading = false;
758
747
  loadError = null;
748
+ /** True when the run has more predictions than {@link PredictiveStudioEngine.MaxRunDetailRows}; only the first are shown. */
749
+ DetailRowsCapped = false;
759
750
  AllRows = [];
760
751
  /** @deprecated Use {@link AllRows}. */
761
752
  get allRows() {
@@ -994,6 +985,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
994
985
  set defaultColDef(value) {
995
986
  this.DefaultColDef = value;
996
987
  }
988
+ /** True when the model's score is the probability of the good outcome, so risk is `1 - score` (e.g. a renewal model). */
997
989
  IsRenewalModel = false;
998
990
  /** @deprecated Use {@link IsRenewalModel}. */
999
991
  get isRenewalModel() {
@@ -1012,10 +1004,12 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1012
1004
  set selectedDecileIndex(value) {
1013
1005
  this.SelectedDecileIndex = value;
1014
1006
  }
1007
+ /**
1008
+ * True for a regression model. Risk bands are classification rules, so a regression model's tiers, row band, status and
1009
+ * badge come from its outcome bands on the raw value, and the risk column is hidden.
1010
+ */
1015
1011
  get IsRegression() {
1016
- return ((this.ProblemType ?? '').toLowerCase() === 'regression' ||
1017
- this.OutcomeConfig?.Format === 'currency' ||
1018
- this.OutcomeConfig?.Format === 'number');
1012
+ return ProblemTypes.IsRegression(this.ProblemType);
1019
1013
  }
1020
1014
  /** @deprecated Use {@link IsRegression}. */
1021
1015
  get isRegression() {
@@ -1087,22 +1081,30 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1087
1081
  },
1088
1082
  },
1089
1083
  {
1090
- field: 'riskPct',
1084
+ field: 'status',
1091
1085
  headerName: statusLabel,
1092
1086
  width: 155,
1087
+ // The tier order: by risk for classification (the tiers are risk bands), by value for regression.
1088
+ comparator: (_a, _b, nodeA, nodeB) => this.IsRegression
1089
+ ? (nodeA.data?.score ?? 0) - (nodeB.data?.score ?? 0)
1090
+ : (nodeA.data?.riskPct ?? 0) - (nodeB.data?.riskPct ?? 0),
1093
1091
  cellRenderer: (params) => {
1094
1092
  if (!params.data)
1095
1093
  return '';
1096
1094
  const badgeColor = params.data.badgeColor || 'gray';
1097
1095
  const icon = params.data.icon ? `<i class="fa-solid ${this.escapeHtml(params.data.icon)}"></i> ` : '';
1098
1096
  const label = this.escapeHtml(params.data.status || params.data.band);
1099
- if (this.IsRegression) {
1100
- return `<span class="ps-badge ${badgeColor}" title="${scoreLabel}: ${this.escapeHtml(params.data.scoreFormatted)}">${icon}${label}</span>`;
1101
- }
1102
- const pct = Math.round(params.data.score * 100);
1103
- return `<span class="ps-badge ${badgeColor}" title="${pct}% ${scoreLabel}">${icon}${label} (${pct}%)</span>`;
1097
+ return `<span class="ps-badge ${badgeColor}" title="${this.escapeHtml(scoreLabel)}: ${this.escapeHtml(params.data.scoreFormatted)}">${icon}${label}</span>`;
1104
1098
  },
1105
1099
  },
1100
+ {
1101
+ field: 'riskPct',
1102
+ headerName: 'Risk',
1103
+ width: 95,
1104
+ // Risk is a classification measure (1 - score for a good-outcome model); a regression value has none.
1105
+ hide: this.IsRegression,
1106
+ cellRenderer: (params) => params.data ? `<span class="ps-mono" data-testid="ps-risk-cell">${params.data.riskPct}%</span>` : '',
1107
+ },
1106
1108
  {
1107
1109
  field: 'class',
1108
1110
  headerName: 'Predicted Outcome',
@@ -1128,11 +1130,13 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1128
1130
  return '<span class="ps-muted">—</span>';
1129
1131
  }
1130
1132
  const chips = params.data.drivers.slice(0, 2).map((d) => {
1131
- const cls = d.up ? 'up' : 'down';
1132
- const icon = d.up ? 'fa-arrow-up' : 'fa-arrow-down';
1133
- const label = this.escapeHtml(d.label);
1134
- return `<span class="ps-why-chip ${cls}" title="${label}"><i class="fa-solid ${icon}"></i> ${label}</span>`;
1135
- }).join('');
1133
+ const cls = d.Up ? 'up' : 'down';
1134
+ const icon = d.Up ? 'fa-arrow-up' : 'fa-arrow-down';
1135
+ const label = this.escapeHtml(d.Label);
1136
+ // The arrow is the direction of RISK, not of the score column, so the tooltip says so.
1137
+ const title = `${label}: ${d.Up ? 'raises' : 'lowers'} risk`;
1138
+ return `<span class="ps-why-chip ${cls}" title="${title}"><i class="fa-solid ${icon}"></i> ${label}</span>`;
1139
+ }).join(' ');
1136
1140
  return `<div class="pg-drivers-cell">${chips}</div>`;
1137
1141
  },
1138
1142
  },
@@ -1206,125 +1210,122 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1206
1210
  return this.Reload();
1207
1211
  }
1208
1212
  async loadPredictions() {
1213
+ this.resetRunState();
1209
1214
  if (!this.modelId && !this.RunId) {
1210
- this.AllRows = [];
1211
1215
  this.applyFilter();
1212
1216
  return;
1213
1217
  }
1214
1218
  this.isLoading = true;
1215
- this.loadError = null;
1216
1219
  this.cdr.markForCheck();
1217
1220
  try {
1218
1221
  const provider = this.ProviderToUse;
1219
1222
  const user = provider.CurrentUser ?? undefined;
1220
- // 1. Resolve effective run ID and model entity
1221
- let effectiveRunId = this.RunId;
1222
- let model = null;
1223
- if (this.modelId) {
1224
- const modelsRes = await RunView.FromMetadataProvider(provider).RunView({
1225
- EntityName: 'MJ: ML Models',
1226
- ExtraFilter: `ID = '${this.modelId.replace(/'/g, "''")}'`,
1227
- MaxRows: 1,
1228
- ResultType: 'entity_object',
1229
- }, user);
1230
- model = modelsRes.Success && modelsRes.Results ? modelsRes.Results[0] : null;
1231
- }
1232
- if (!effectiveRunId && this.modelId) {
1233
- // Query latest process run for this model using engine
1234
- try {
1235
- const engine = PredictiveStudioEngine.Instance;
1236
- const runs = await engine.LoadRecentRunsForModel(this.modelId, provider, user, { maxRows: 1 });
1237
- if (runs && runs.length > 0) {
1238
- effectiveRunId = runs[0].ID;
1239
- }
1240
- }
1241
- catch {
1242
- // Fallback if engine is not yet primed
1243
- }
1244
- }
1223
+ const model = await this.loadModel();
1224
+ const effectiveRunId = this.RunId ?? (await this.resolveLatestRunId());
1245
1225
  if (!effectiveRunId) {
1246
- this.AllRows = [];
1247
1226
  this.applyFilter();
1248
- this.isLoading = false;
1249
- this.cdr.markForCheck();
1227
+ this.RowsLoaded.emit({ Rows: [], Capped: false });
1250
1228
  return;
1251
1229
  }
1252
- // 2. Resolve target entity
1253
1230
  await this.resolveTargetEntity(model);
1254
- // 3. Load full process run details (removing 50/200 cap)
1255
- const detailsRes = await RunView.FromMetadataProvider(provider).RunView({
1256
- EntityName: 'MJ: Process Run Details',
1257
- ExtraFilter: `ProcessRunID = '${effectiveRunId.replace(/'/g, "''")}'`,
1258
- OrderBy: '__mj_CreatedAt ASC',
1259
- MaxRows: 10000,
1260
- ResultType: 'entity_object',
1261
- }, user);
1262
- if (!detailsRes.Success || !detailsRes.Results) {
1263
- this.AllRows = [];
1264
- this.applyFilter();
1265
- this.isLoading = false;
1266
- this.cdr.markForCheck();
1267
- return;
1268
- }
1269
- // 4. Resolve OutcomeConfig and determine polarity
1270
- if (model?.ProblemType) {
1271
- this.ProblemType = model.ProblemType.toLowerCase();
1272
- }
1273
- this.OutcomeConfig = resolveOutcomeConfig(model ?? undefined);
1274
- this.IsRenewalModel = this.OutcomeConfig.Polarity === 'positive' && !this.IsRegression;
1275
- this.SetupColumnDefs();
1276
- const polarity = ResolveRenewalPolarity(detailsRes.Results.map((d) => d.ResultPayload), model?.TargetVariable);
1277
- // When the model outputs P(Renewed) (scoreIsLapseRisk = false), adverse risk is inverted (1 - score).
1278
- // When the model outputs P(Lapse) (scoreIsLapseRisk = true), adverse risk is ALREADY score (invertedRisk = false).
1279
- const shouldInvertRisk = polarity.IsRenewalModel ? !polarity.ScoreIsLapseRisk : false;
1280
- const parsedAtRisk = ParseAtRiskRows(detailsRes.Results.map((d) => ({ recordId: d.RecordID, ResultPayload: d.ResultPayload })), { InvertedRisk: shouldInvertRisk, OutcomeConfig: this.OutcomeConfig });
1281
- // Map details into indexed lookup for scoredAt timestamp
1231
+ // The run's process run details by keyset paging, read-only and only the columns the grid uses; throws on failure.
1232
+ const read = await PredictiveStudioEngine.Instance.LoadRunDetails(effectiveRunId, provider, user);
1233
+ this.applyModelOptions(model);
1234
+ const parsedAtRisk = AtRiskRules.ParseAtRiskRows(read.Rows.map((d) => ({ RecordID: d.RecordID, ResultPayload: d.ResultPayload })), { InvertedRisk: this.IsRenewalModel });
1282
1235
  const detailByRecord = new Map();
1283
- for (const d of detailsRes.Results) {
1236
+ for (const d of read.Rows) {
1284
1237
  detailByRecord.set(NormalizeUUID(d.RecordID), d);
1285
1238
  }
1286
- this.AllRows = parsedAtRisk.map((r) => {
1287
- const detail = detailByRecord.get(NormalizeUUID(r.recordId));
1288
- const dt = detail?.CompletedAt ?? detail?.__mj_CreatedAt ?? null;
1289
- // For renewal models, the primary displayed score is Renewal Probability (0–1).
1290
- // If the raw score was lapse risk, renewal probability is 1 - r.score.
1291
- // Otherwise, raw score is already renewal probability.
1292
- const displayScore = polarity.IsRenewalModel
1293
- ? (polarity.ScoreIsLapseRisk ? Math.max(0, Math.min(1, 1 - r.score)) : r.score)
1294
- : r.score;
1295
- const resolved = this.OutcomeConfig
1296
- ? resolveScoreBand(displayScore, this.OutcomeConfig)
1297
- : null;
1298
- const formatted = formatPredictionScore(displayScore, this.OutcomeConfig, this.ProblemType);
1299
- return {
1300
- recordId: r.recordId,
1301
- recordName: r.label ?? r.recordId,
1302
- score: displayScore,
1303
- scoreFormatted: formatted,
1304
- riskPct: r.riskPct,
1305
- band: resolved?.Key ?? r.band,
1306
- badgeColor: resolved?.BadgeColor ?? r.badgeColor,
1307
- icon: resolved?.Icon ?? r.icon,
1308
- class: r.class,
1309
- drivers: r.drivers ?? [],
1310
- status: resolved?.Label ?? r.status ?? detail?.Status ?? 'Succeeded',
1311
- scoredAtDate: dt instanceof Date ? dt : dt ? new Date(dt) : null,
1312
- };
1313
- });
1239
+ this.AllRows = parsedAtRisk.map((r) => this.toGridRow(r, detailByRecord.get(NormalizeUUID(r.RecordID))));
1240
+ this.DetailRowsCapped = read.Capped;
1314
1241
  this.computeVisibleBands();
1315
1242
  this.applyFilter();
1316
- // 5. Schedule lazy lookup of record names for visible rows
1243
+ this.RowsLoaded.emit({ Rows: parsedAtRisk, Capped: read.Capped });
1244
+ // Lazy lookup of record names for visible rows
1317
1245
  this.ScheduleVisibleRowsLookup(0);
1318
1246
  }
1319
1247
  catch (err) {
1320
1248
  this.loadError = err instanceof Error ? err.message : String(err);
1321
1249
  LogError(`PSPredictionsGridComponent.loadPredictions: ${this.loadError}`);
1250
+ this.RowsLoadFailed.emit(this.loadError);
1322
1251
  }
1323
1252
  finally {
1324
1253
  this.isLoading = false;
1325
1254
  this.cdr.markForCheck();
1326
1255
  }
1327
1256
  }
1257
+ /** Clears everything derived from the previous run, so a model or run switch never shows the old run's rows or notices. */
1258
+ resetRunState() {
1259
+ this.AllRows = [];
1260
+ this.FilteredRows = [];
1261
+ this.VisibleBands = [];
1262
+ this.DetailRowsCapped = false;
1263
+ this.loadError = null;
1264
+ this.SelectedTier = 'all';
1265
+ this.SelectedDecileIndex = null;
1266
+ }
1267
+ /** The grid's model, or null when no model id is bound. */
1268
+ async loadModel() {
1269
+ if (!this.modelId)
1270
+ return null;
1271
+ const provider = this.ProviderToUse;
1272
+ const modelsRes = await RunView.FromMetadataProvider(provider).RunView({
1273
+ EntityName: 'MJ: ML Models',
1274
+ ExtraFilter: `ID = '${EscapeSQLString(this.modelId)}'`,
1275
+ MaxRows: 1,
1276
+ ResultType: 'entity_object',
1277
+ }, provider.CurrentUser ?? undefined);
1278
+ return modelsRes.Success && modelsRes.Results ? modelsRes.Results[0] ?? null : null;
1279
+ }
1280
+ /** The model's latest run when no run id is bound, or null when it has none. */
1281
+ async resolveLatestRunId() {
1282
+ if (!this.modelId)
1283
+ return null;
1284
+ const provider = this.ProviderToUse;
1285
+ const runs = await PredictiveStudioEngine.Instance.LoadRecentRunsForModel(this.modelId, provider, provider.CurrentUser ?? undefined, { maxRows: 1 });
1286
+ return runs[0]?.ID ?? null;
1287
+ }
1288
+ /** The model's problem type, outcome config and polarity: one rule (`BuildAtRiskOptions`), shared with the resource and the gate probe. */
1289
+ applyModelOptions(model) {
1290
+ if (model?.ProblemType) {
1291
+ this.ProblemType = model.ProblemType.toLowerCase();
1292
+ }
1293
+ const atRiskOptions = AtRiskRules.BuildAtRiskOptions(model ?? undefined);
1294
+ this.OutcomeConfig = atRiskOptions.OutcomeConfig;
1295
+ // A positive-polarity score is P(good outcome): risk is 1 - score, while the displayed score stays the model's own.
1296
+ this.IsRenewalModel = atRiskOptions.InvertedRisk === true;
1297
+ this.SetupColumnDefs();
1298
+ }
1299
+ /** One displayed row: the model's own score, its risk, and its tier (risk band, or outcome band for regression). */
1300
+ toGridRow(r, detail) {
1301
+ const dt = detail?.CompletedAt ?? detail?.__mj_CreatedAt ?? null;
1302
+ const tier = this.tierFor(r);
1303
+ return {
1304
+ recordId: r.RecordID,
1305
+ recordName: r.Label || r.RecordID,
1306
+ score: r.Score,
1307
+ scoreFormatted: formatPredictionScore(r.Score, this.OutcomeConfig, this.ProblemType),
1308
+ riskPct: r.RiskPct,
1309
+ band: tier.Key,
1310
+ badgeColor: tier.BadgeColor,
1311
+ icon: tier.Icon,
1312
+ class: r.Class,
1313
+ drivers: r.Drivers || [],
1314
+ status: tier.Label,
1315
+ scoredAtDate: dt instanceof Date ? dt : dt ? new Date(dt) : null,
1316
+ };
1317
+ }
1318
+ /**
1319
+ * A row's tier. Classification: the risk band Core put on the row, so "High" is the riskiest records whatever the
1320
+ * polarity. Regression: the outcome band of the raw value (risk bands do not apply to a value such as an LTV).
1321
+ */
1322
+ tierFor(r) {
1323
+ if (!this.IsRegression) {
1324
+ return { Key: r.Band, Label: r.Status, BadgeColor: r.BadgeColor, Icon: r.Icon };
1325
+ }
1326
+ const band = ResolveScoreBand(r.Score, this.OutcomeConfig);
1327
+ return band ? { Key: band.Key, Label: band.Label, BadgeColor: band.BadgeColor, Icon: band.Icon } : PSPredictionsGridComponent.unbandedTier;
1328
+ }
1328
1329
  async resolveTargetEntity(model) {
1329
1330
  const provider = this.ProviderToUse;
1330
1331
  if (this.entityName) {
@@ -1338,7 +1339,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1338
1339
  if (model?.PipelineID) {
1339
1340
  const pRes = await RunView.FromMetadataProvider(provider).RunView({
1340
1341
  EntityName: 'MJ: ML Training Pipelines',
1341
- ExtraFilter: `ID = '${model.PipelineID.replace(/'/g, "''")}'`,
1342
+ ExtraFilter: `ID = '${EscapeSQLString(model.PipelineID)}'`,
1342
1343
  MaxRows: 1,
1343
1344
  ResultType: 'simple',
1344
1345
  Fields: ['TargetEntityID'],
@@ -1595,47 +1596,42 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1595
1596
  getBadgeColorVar(color) {
1596
1597
  return this.GetBadgeColorVar(color);
1597
1598
  }
1599
+ /**
1600
+ * The tier chips and KPI cards, each with its tier's average model score. Classification: one per risk band (the
1601
+ * at-risk list's tiers). Regression: one per configured outcome band, plus any tier a row landed in outside them.
1602
+ */
1598
1603
  computeVisibleBands() {
1599
- const total = this.AllRows.length;
1600
- const bands = this.OutcomeConfig.Bands ?? [];
1601
- this.VisibleBands = bands.map((b) => {
1602
- const matching = this.AllRows.filter((r) => r.band === b.Key);
1603
- const count = matching.length;
1604
- const pct = total > 0 ? Math.round((count / total) * 100) : 0;
1605
- const rawAvg = count > 0 ? matching.reduce((sum, r) => sum + r.score, 0) / count : 0;
1606
- const avgScore = Math.round(rawAvg * 100);
1607
- const avgScoreFormatted = formatPredictionScore(rawAvg, this.OutcomeConfig, this.ProblemType);
1608
- return {
1609
- key: b.Key,
1610
- label: b.Label,
1611
- count,
1612
- pct,
1613
- avgScore,
1614
- avgScoreFormatted,
1615
- badgeColor: b.BadgeColor,
1616
- icon: b.Icon,
1617
- description: b.Description,
1618
- };
1619
- });
1620
- const knownKeys = new Set(bands.map((b) => b.Key));
1621
- const extraKeys = new Set(this.AllRows.map((r) => r.band).filter((k) => !knownKeys.has(k)));
1622
- for (const k of extraKeys) {
1623
- const matching = this.AllRows.filter((r) => r.band === k);
1624
- const count = matching.length;
1625
- const pct = total > 0 ? Math.round((count / total) * 100) : 0;
1626
- const rawAvg = count > 0 ? matching.reduce((sum, r) => sum + r.score, 0) / count : 0;
1627
- const avgScore = Math.round(rawAvg * 100);
1628
- const avgScoreFormatted = formatPredictionScore(rawAvg, this.OutcomeConfig, this.ProblemType);
1629
- this.VisibleBands.push({
1630
- key: k,
1631
- label: k.charAt(0).toUpperCase() + k.slice(1),
1632
- count,
1633
- pct,
1634
- avgScore,
1635
- avgScoreFormatted,
1636
- badgeColor: 'gray',
1637
- });
1604
+ const tiers = this.IsRegression ? this.regressionTiers() : AtRiskRules.RiskBands.map((b) => ({ Key: b.Key, Label: b.Label, BadgeColor: b.BadgeColor, Icon: b.Icon }));
1605
+ this.VisibleBands = tiers.map((t) => this.summarizeTier(t));
1606
+ }
1607
+ /** The configured outcome bands, then each other tier the rows carry (e.g. values outside every band), in row order. */
1608
+ regressionTiers() {
1609
+ const tiers = (this.OutcomeConfig.Bands ?? []).map((b) => ({ Key: b.Key, Label: b.Label, BadgeColor: b.BadgeColor, Icon: b.Icon }));
1610
+ const known = new Set(tiers.map((t) => t.Key));
1611
+ for (const r of this.AllRows) {
1612
+ if (!known.has(r.band)) {
1613
+ known.add(r.band);
1614
+ tiers.push({ Key: r.band, Label: r.status, BadgeColor: r.badgeColor || 'gray', Icon: r.icon });
1615
+ }
1638
1616
  }
1617
+ return tiers;
1618
+ }
1619
+ /** A tier's chip / KPI card: its row count, share and average model score. */
1620
+ summarizeTier(t) {
1621
+ const total = this.AllRows.length;
1622
+ const matching = this.AllRows.filter((r) => r.band === t.Key);
1623
+ const count = matching.length;
1624
+ const rawAvg = count > 0 ? matching.reduce((sum, r) => sum + r.score, 0) / count : 0;
1625
+ return {
1626
+ key: t.Key,
1627
+ label: t.Label,
1628
+ count,
1629
+ pct: total > 0 ? Math.round((count / total) * 100) : 0,
1630
+ avgScore: Math.round(rawAvg * 100),
1631
+ avgScoreFormatted: formatPredictionScore(rawAvg, this.OutcomeConfig, this.ProblemType),
1632
+ badgeColor: t.BadgeColor,
1633
+ icon: t.Icon,
1634
+ };
1639
1635
  }
1640
1636
  OnViewToggle(key) {
1641
1637
  this.ActiveView = key === 'chart' ? 'chart' : 'grid';
@@ -1682,6 +1678,12 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1682
1678
  clearDecileFilter() {
1683
1679
  return this.ClearDecileFilter();
1684
1680
  }
1681
+ /** The selected tier's label for the footer ("High risk", or an outcome band's label), empty when all tiers show. */
1682
+ get SelectedTierLabel() {
1683
+ if (this.SelectedTier === 'all')
1684
+ return '';
1685
+ return this.VisibleBands.find((b) => b.key === this.SelectedTier)?.label ?? this.SelectedTier;
1686
+ }
1685
1687
  get SelectedDecileLabel() {
1686
1688
  if (this.SelectedDecileIndex === null)
1687
1689
  return '';
@@ -1706,7 +1708,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1706
1708
  rows = rows.filter((r) => r.recordName.toLowerCase().includes(q) ||
1707
1709
  r.recordId.toLowerCase().includes(q) ||
1708
1710
  (r.class && r.class.toLowerCase().includes(q)) ||
1709
- r.drivers.some((d) => d.label.toLowerCase().includes(q)));
1711
+ r.drivers.some((d) => d.Label.toLowerCase().includes(q)));
1710
1712
  }
1711
1713
  this.FilteredRows = rows;
1712
1714
  this.cdr.markForCheck();
@@ -1823,7 +1825,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1823
1825
  return;
1824
1826
  const recRes = await RunView.FromMetadataProvider(provider).RunView({
1825
1827
  EntityName: entity.Name,
1826
- ExtraFilter: `${entity.FirstPrimaryKey.Name} = '${recordId.replace(/'/g, "''")}'`, // first-pk-ok: Single-key entity lookup by recordId
1828
+ ExtraFilter: `${entity.FirstPrimaryKey.Name} = '${EscapeSQLString(recordId)}'`, // first-pk-ok: Single-key entity lookup by recordId
1827
1829
  MaxRows: 1,
1828
1830
  ResultType: 'simple',
1829
1831
  Fields: [matchedField],
@@ -1864,6 +1866,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
1864
1866
  modelId: this.modelId,
1865
1867
  OutcomeConfig: this.OutcomeConfig,
1866
1868
  ProblemType: this.ProblemType,
1869
+ InvertedRisk: this.IsRenewalModel,
1867
1870
  });
1868
1871
  }
1869
1872
  finally {
@@ -2019,7 +2022,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2019
2022
  // Power scale height so smaller decile bins (e.g. 2, 21, 35) are visible alongside 5,390
2020
2023
  const height = count === 0 ? 0 : Math.round(14 + Math.pow(count / maxCount, 0.45) * 116);
2021
2024
  const centerScore = (binMin + binMax) / 2;
2022
- const band = resolveScoreBand(centerScore, this.OutcomeConfig);
2025
+ const band = ResolveScoreBand(centerScore, this.OutcomeConfig);
2023
2026
  const color = band ? this.GetBadgeColorVar(band.BadgeColor) : 'var(--mj-brand-primary)';
2024
2027
  let label;
2025
2028
  let shortLabel;
@@ -2113,7 +2116,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2113
2116
  ? Math.max(0, Math.min(1, (pt.score - minScore) / range))
2114
2117
  : Math.max(0, Math.min(1, pt.score));
2115
2118
  const y = Math.round(yBottom - clampedScore * ySpan);
2116
- const band = resolveScoreBand(pt.score, this.OutcomeConfig);
2119
+ const band = ResolveScoreBand(pt.score, this.OutcomeConfig);
2117
2120
  const color = band ? this.GetBadgeColorVar(band.BadgeColor) : 'var(--mj-brand-primary)';
2118
2121
  return {
2119
2122
  runId: pt.runId,
@@ -2155,10 +2158,11 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2155
2158
  return;
2156
2159
  const scoreHeader = this.OutcomeConfig.ScoreLabel || 'Prediction Score';
2157
2160
  const statusHeader = this.OutcomeConfig.StatusLabel || 'Risk Level';
2158
- const headers = ['Record ID', 'Record Name', scoreHeader, statusHeader, 'Predicted Class', 'Top Drivers', 'Scored At'];
2159
- const lines = [headers.join(',')];
2161
+ const headers = ['Record ID', 'Record Name', scoreHeader, statusHeader, 'Predicted Class', 'Top Drivers (+ raises risk, − lowers risk)', 'Scored At'];
2162
+ // Quoted: the drivers header carries a comma.
2163
+ const lines = [headers.map((h) => `"${h.replace(/"/g, '""')}"`).join(',')];
2160
2164
  for (const r of this.FilteredRows) {
2161
- const driversStr = r.drivers.map((d) => `${d.up ? '+' : '-'}${d.label}`).join('; ');
2165
+ const driversStr = r.drivers.map((d) => `${d.Up ? '+' : '−'}${d.Label}`).join('; ');
2162
2166
  const statusStr = `${r.status || r.band} (${r.scoreFormatted})`;
2163
2167
  const rowData = [
2164
2168
  `"${r.recordId.replace(/"/g, '""')}"`,
@@ -2192,7 +2196,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2192
2196
  .replace(/'/g, '&#039;');
2193
2197
  }
2194
2198
  static ɵfac = /*@__PURE__*/ (() => { let ɵPSPredictionsGridComponent_BaseFactory; return function PSPredictionsGridComponent_Factory(__ngFactoryType__) { return (ɵPSPredictionsGridComponent_BaseFactory || (ɵPSPredictionsGridComponent_BaseFactory = i0.ɵɵgetInheritedFactory(PSPredictionsGridComponent)))(__ngFactoryType__ || PSPredictionsGridComponent); }; })();
2195
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSPredictionsGridComponent, selectors: [["ps-predictions-grid"]], inputs: { modelId: "modelId", RunId: "RunId", runId: "runId", entityName: "entityName", ProblemType: "ProblemType", problemType: "problemType", title: "title", height: "height", ReadOnly: "ReadOnly", readOnly: "readOnly" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 27, vars: 15, consts: [[1, "ps-pred-grid-host"], [1, "pg-toolbar"], [1, "pg-toolbar-left"], [1, "pg-search-box"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Filter records, outcome, factors...", 1, "pg-search-input", 3, "input", "value"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear"], [1, "pg-tier-filters"], ["type", "button", 1, "pg-tier-btn", 3, "click"], [1, "pg-count-pill"], ["type", "button", 1, "pg-tier-btn", 3, "active"], [1, "pg-decile-pill"], [1, "pg-toolbar-right"], [3, "KeyChange", "Options", "ActiveKey"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-file-export"], [1, "pg-view-container"], ["text", "Loading predictions...", "size", "medium"], ["role", "alert", 1, "ps-load-error"], [1, "ps-empty", 2, "padding", "32px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "Resizable", "WidthPx"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-filter"], ["type", "button", "title", "Clear decile filter", 3, "click"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "ps-load-error-text"], [1, "ps-load-error-detail"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "ps-empty-ico"], [1, "fa-solid", "fa-chart-line"], [1, "pg-chart-container"], [1, "pg-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-footer"], [1, "ps-muted"], [1, "pg-chart-cards"], [1, "pg-chart-card", "total"], [1, "pg-chart-card-lbl"], [1, "fa-solid", "fa-users", "ps-muted"], [1, "pg-chart-card-val"], [1, "pg-chart-card-sub"], [1, "pg-chart-card", 3, "class"], [1, "pg-chart-section"], [1, "pg-chart-section-title"], [2, "display", "flex", "align-items", "center", "gap", "8px"], [1, "fa-solid", "fa-chart-simple", "ps-muted"], [1, "pg-chart-meta"], [1, "ps-small", "ps-muted"], ["type", "button", 1, "pg-clear-decile-btn"], [1, "pg-histogram"], [1, "pg-h-columns"], [1, "pg-h-col", 3, "active", "empty"], ["id", "pg-drilldown-anchor", 1, "pg-chart-section", "pg-chart-drilldown-section"], [1, "pg-chart-card", 3, "click"], [3, "class", "color"], ["type", "button", 1, "pg-clear-decile-btn", 3, "click"], [1, "pg-h-col", 3, "click"], [1, "pg-h-count", 3, "title"], [1, "pg-h-bar-track"], [1, "pg-h-bar"], [1, "pg-h-footer"], [1, "pg-h-range"], [1, "pg-h-pct"], [1, "pg-h-tooltip"], [1, "pg-h-tt-head"], [1, "pg-h-tt-row"], [1, "pg-h-tt-val"], [1, "pg-h-tt-pct"], [1, "pg-h-tt-badge"], [1, "pg-h-tt-hint"], [1, "fa-solid", "fa-layer-group", "ps-muted"], [2, "display", "flex", "height", "24px", "border-radius", "var(--mj-radius-full)", "overflow", "hidden", "background", "var(--mj-bg-surface-sunken)", "margin-bottom", "8px"], [3, "width", "background", "title"], [2, "display", "flex", "gap", "16px", "flex-wrap", "wrap"], [2, "display", "flex", "align-items", "center", "gap", "6px", "font-size", "var(--mj-text-xs)"], [3, "title"], [2, "width", "10px", "height", "10px", "border-radius", "2px", "display", "inline-block"], [1, "fa-solid", "fa-table-list", "ps-muted"], [2, "color", "var(--mj-brand-primary)"], [1, "ps-badge", 2, "margin-left", "6px", 3, "color"], [1, "pg-chart-grid-host"], [1, "pg-grid", "pg-chart-ag-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-drilldown-footer"], [1, "ps-badge", 2, "margin-left", "6px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "WidthChanged", "Closed", "Resizable", "WidthPx"], [1, "pg-detail-body"], [1, "pg-detail-record-head"], [1, "pg-detail-record-info"], [1, "ps-badge", "blue"], [1, "ps-mono", "ps-small", "ps-muted"], [1, "pg-detail-record-actions", 2, "display", "flex", "gap", "8px", "align-items", "center", "flex-wrap", "wrap"], ["mjButton", "", "variant", "primary", "size", "sm", "title", "Open record in Explorer", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer"], [1, "pg-detail-pred-card"], [1, "pg-detail-score-circle"], [1, "pg-detail-meta"], [1, "pg-detail-meta-line"], [3, "class"], [2, "font-weight", "700", "color", "var(--mj-text-primary)"], [1, "pg-detail-meta-sub"], [1, "pg-detail-drivers-wrap"], [1, "ps-section-title"], [1, "fa-solid", "fa-lightbulb", 2, "color", "var(--mj-status-warning)"], [1, "pg-detail-drivers-list"], [1, "pg-trendline-wrap"], [1, "ps-section-title", 2, "display", "flex", "align-items", "center", "justify-content", "space-between"], [1, "fa-solid", "fa-clock-rotate-left", "ps-muted"], ["text", "Loading score history...", "size", "small"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer", 3, "click"], [1, "fa-solid", "fa-user"], [1, "ps-badge"], [1, "pg-detail-driver-item"], [1, "pg-detail-driver-label"], [1, "fa-solid"], ["viewBox", "0 0 540 160", "preserveAspectRatio", "none", 1, "pg-trendline-svg"], ["x1", "40", "y1", "20", "x2", "520", "y2", "20", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "75", "x2", "520", "y2", "75", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "130", "x2", "520", "y2", "130", "stroke", "var(--mj-border-default)"], ["x", "32", "y", "24", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "79", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "134", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["fill", "color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)"], ["fill", "none", "stroke", "var(--mj-brand-primary)", "stroke-width", "2.5"], [1, "pg-history-table"], ["r", "5", "stroke", "var(--mj-bg-surface)", "stroke-width", "2"], ["font-size", "10", "font-weight", "700", "text-anchor", "middle", "fill", "var(--mj-text-primary)"], [1, "ps-mono"], [1, "pg-delta-pill", "neutral"], [1, "pg-delta-pill", "up"], [1, "pg-delta-pill", "down"], [1, "fa-solid", "fa-arrow-up"], [1, "fa-solid", "fa-arrow-down"]], template: function PSPredictionsGridComponent_Template(rf, ctx) { if (rf & 1) {
2199
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSPredictionsGridComponent, selectors: [["ps-predictions-grid"]], inputs: { modelId: "modelId", RunId: "RunId", runId: "runId", entityName: "entityName", ProblemType: "ProblemType", problemType: "problemType", title: "title", height: "height", ReadOnly: "ReadOnly", readOnly: "readOnly" }, outputs: { RowsLoaded: "RowsLoaded", RowsLoadFailed: "RowsLoadFailed" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 27, vars: 15, consts: [[1, "ps-pred-grid-host"], [1, "pg-toolbar"], [1, "pg-toolbar-left"], [1, "pg-search-box"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Filter records, outcome, factors...", 1, "pg-search-input", 3, "input", "value"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear"], [1, "pg-tier-filters"], ["type", "button", 1, "pg-tier-btn", 3, "click"], [1, "pg-count-pill"], ["type", "button", 1, "pg-tier-btn", 3, "active"], [1, "pg-decile-pill"], [1, "pg-toolbar-right"], [3, "KeyChange", "Options", "ActiveKey"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-file-export"], [1, "pg-view-container"], ["text", "Loading predictions...", "size", "medium"], ["role", "alert", 1, "ps-load-error"], [1, "ps-empty", 2, "padding", "32px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "Resizable", "WidthPx"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-filter"], ["type", "button", "title", "Clear decile filter", 3, "click"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "ps-load-error-text"], [1, "ps-load-error-detail"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "ps-empty-ico"], [1, "fa-solid", "fa-chart-line"], [1, "pg-chart-container"], [1, "pg-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-footer"], [1, "ps-muted"], ["data-testid", "ps-predictions-capped", 1, "ps-muted"], [1, "pg-chart-cards"], [1, "pg-chart-card", "total"], [1, "pg-chart-card-lbl"], [1, "fa-solid", "fa-users", "ps-muted"], [1, "pg-chart-card-val"], [1, "pg-chart-card-sub"], [1, "pg-chart-card", 3, "class"], [1, "pg-chart-section"], [1, "pg-chart-section-title"], [2, "display", "flex", "align-items", "center", "gap", "8px"], [1, "fa-solid", "fa-chart-simple", "ps-muted"], [1, "pg-chart-meta"], [1, "ps-small", "ps-muted"], ["type", "button", 1, "pg-clear-decile-btn"], [1, "pg-histogram"], [1, "pg-h-columns"], [1, "pg-h-col", 3, "active", "empty"], ["id", "pg-drilldown-anchor", 1, "pg-chart-section", "pg-chart-drilldown-section"], [1, "pg-chart-card", 3, "click"], [3, "class", "color"], ["type", "button", 1, "pg-clear-decile-btn", 3, "click"], [1, "pg-h-col", 3, "click"], [1, "pg-h-count", 3, "title"], [1, "pg-h-bar-track"], [1, "pg-h-bar"], [1, "pg-h-footer"], [1, "pg-h-range"], [1, "pg-h-pct"], [1, "pg-h-tooltip"], [1, "pg-h-tt-head"], [1, "pg-h-tt-row"], [1, "pg-h-tt-val"], [1, "pg-h-tt-pct"], [1, "pg-h-tt-badge"], [1, "pg-h-tt-hint"], [1, "fa-solid", "fa-layer-group", "ps-muted"], [2, "display", "flex", "height", "24px", "border-radius", "var(--mj-radius-full)", "overflow", "hidden", "background", "var(--mj-bg-surface-sunken)", "margin-bottom", "8px"], [3, "width", "background", "title"], [2, "display", "flex", "gap", "16px", "flex-wrap", "wrap"], [2, "display", "flex", "align-items", "center", "gap", "6px", "font-size", "var(--mj-text-xs)"], [3, "title"], [2, "width", "10px", "height", "10px", "border-radius", "2px", "display", "inline-block"], [1, "fa-solid", "fa-table-list", "ps-muted"], [2, "color", "var(--mj-brand-primary)"], [1, "ps-badge", 2, "margin-left", "6px", 3, "color"], [1, "pg-chart-grid-host"], [1, "pg-grid", "pg-chart-ag-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-drilldown-footer"], [1, "ps-badge", 2, "margin-left", "6px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "WidthChanged", "Closed", "Resizable", "WidthPx"], [1, "pg-detail-body"], [1, "pg-detail-record-head"], [1, "pg-detail-record-info"], [1, "ps-badge", "blue"], [1, "ps-mono", "ps-small", "ps-muted"], [1, "pg-detail-record-actions", 2, "display", "flex", "gap", "8px", "align-items", "center", "flex-wrap", "wrap"], ["mjButton", "", "variant", "primary", "size", "sm", "title", "Open record in Explorer", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer"], [1, "pg-detail-pred-card"], [1, "pg-detail-score-circle"], [1, "pg-detail-meta"], [1, "pg-detail-meta-line"], [3, "class"], [2, "font-weight", "700", "color", "var(--mj-text-primary)"], [1, "pg-detail-meta-sub"], [1, "pg-detail-drivers-wrap"], [1, "ps-section-title"], [1, "fa-solid", "fa-lightbulb", 2, "color", "var(--mj-status-warning)"], [3, "Drivers"], [1, "pg-trendline-wrap"], [1, "ps-section-title", 2, "display", "flex", "align-items", "center", "justify-content", "space-between"], [1, "fa-solid", "fa-clock-rotate-left", "ps-muted"], ["text", "Loading score history...", "size", "small"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer", 3, "click"], [1, "fa-solid", "fa-user"], [1, "ps-badge"], ["viewBox", "0 0 540 160", "preserveAspectRatio", "none", 1, "pg-trendline-svg"], ["x1", "40", "y1", "20", "x2", "520", "y2", "20", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "75", "x2", "520", "y2", "75", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "130", "x2", "520", "y2", "130", "stroke", "var(--mj-border-default)"], ["x", "32", "y", "24", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "79", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "134", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["fill", "color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)"], ["fill", "none", "stroke", "var(--mj-brand-primary)", "stroke-width", "2.5"], [1, "pg-history-table"], ["r", "5", "stroke", "var(--mj-bg-surface)", "stroke-width", "2"], ["font-size", "10", "font-weight", "700", "text-anchor", "middle", "fill", "var(--mj-text-primary)"], [1, "ps-mono"], [1, "pg-delta-pill", "neutral"], [1, "pg-delta-pill", "up"], [1, "pg-delta-pill", "down"], [1, "fa-solid", "fa-arrow-up"], [1, "fa-solid", "fa-arrow-down"]], template: function PSPredictionsGridComponent_Template(rf, ctx) { if (rf & 1) {
2196
2200
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3);
2197
2201
  i0.ɵɵelement(4, "i", 4);
2198
2202
  i0.ɵɵelementStart(5, "input", 5);
@@ -2221,7 +2225,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2221
2225
  i0.ɵɵelementStart(21, "div", 16);
2222
2226
  i0.ɵɵconditionalCreate(22, PSPredictionsGridComponent_Conditional_22_Template, 1, 0, "mj-loading", 17)(23, PSPredictionsGridComponent_Conditional_23_Template, 10, 1, "div", 18)(24, PSPredictionsGridComponent_Conditional_24_Template, 7, 0, "div", 19)(25, PSPredictionsGridComponent_Conditional_25_Template, 2, 2);
2223
2227
  i0.ɵɵelementEnd();
2224
- i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Template, 52, 26, "mj-slide-panel", 20);
2228
+ i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Template, 51, 26, "mj-slide-panel", 20);
2225
2229
  i0.ɵɵelementEnd();
2226
2230
  } if (rf & 2) {
2227
2231
  i0.ɵɵstyleProp("height", ctx.height);
@@ -2250,7 +2254,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2250
2254
  SharedGenericModule, i1.LoadingComponent, MJButtonDirective,
2251
2255
  MJViewToggleComponent,
2252
2256
  MjSlidePanelComponent,
2253
- AgGridModule, i2.AgGridAngular, i3.DecimalPipe, i3.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n.ps-panel[_ngcontent-%COMP%] {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n \n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n.ps-row[_ngcontent-%COMP%] { display: flex; gap: 16px; }\n.ps-col[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap[_ngcontent-%COMP%] { flex-wrap: wrap; }\n.ps-spacer[_ngcontent-%COMP%] { flex: 1; }\n.ps-muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-small[_ngcontent-%COMP%] { font-size: 12.5px; }\n.ps-mono[_ngcontent-%COMP%] { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title[_ngcontent-%COMP%] {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n\n.ps-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body[_ngcontent-%COMP%] { padding: 16px; }\n\n\n.ps-kpi[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi[_ngcontent-%COMP%] .val[_ngcontent-%COMP%] { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n\n.ps-badge[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n\n.ps-lvl[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-lvl-Strong[_ngcontent-%COMP%] { background: var(--mj-status-info); }\n.ps-lvl-Viable[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-lvl-Weak[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.ps-tag[_ngcontent-%COMP%] {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted[_ngcontent-%COMP%] { opacity: .6; }\n.ps-divider[_ngcontent-%COMP%] { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n\n.ps-table[_ngcontent-%COMP%] { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover td[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); }\n.ps-table[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n\n.ps-bar[_ngcontent-%COMP%] { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-bar.run[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n\n.ps-fbar[_ngcontent-%COMP%] { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar[_ngcontent-%COMP%] + .ps-fbar[_ngcontent-%COMP%] { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-fbar[_ngcontent-%COMP%] .name[_ngcontent-%COMP%] { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar[_ngcontent-%COMP%] > .ps-mono[_ngcontent-%COMP%] { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n\n.ps-gauge[_ngcontent-%COMP%] {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge[_ngcontent-%COMP%]::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge[_ngcontent-%COMP%] .g-val[_ngcontent-%COMP%] { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n\n.ps-callout[_ngcontent-%COMP%] { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 16px; margin-top: 1px; }\n\n\n.ps-stepper[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done[_ngcontent-%COMP%] { color: var(--mj-status-success-text); }\n.ps-step.done[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.ps-step.curr[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step[_ngcontent-%COMP%] .ln[_ngcontent-%COMP%] { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n\n.ps-flow[_ngcontent-%COMP%] {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node[_ngcontent-%COMP%] {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] .ps-tag[_ngcontent-%COMP%] { margin-left: auto; }\n.ps-node[_ngcontent-%COMP%] .nb[_ngcontent-%COMP%] { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] .k[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-node.src[_ngcontent-%COMP%] { border-left-color: var(--ps-node-source); }\n.ps-node.src[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-node.feat[_ngcontent-%COMP%] { border-left-color: var(--ps-node-feature); }\n.ps-node.feat[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-node.emb[_ngcontent-%COMP%] { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-node.target[_ngcontent-%COMP%] { border-left-color: var(--ps-node-target); }\n.ps-node.target[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-node.algo[_ngcontent-%COMP%] { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n.ps-node.output[_ngcontent-%COMP%] { border-left-color: var(--mj-status-success); }\n.ps-node.output[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-node.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node[_ngcontent-%COMP%] .port[_ngcontent-%COMP%] {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node[_ngcontent-%COMP%] .port.in[_ngcontent-%COMP%] { left: -6px; }\n.ps-node[_ngcontent-%COMP%] .port.out[_ngcontent-%COMP%] { right: -6px; }\nsvg.ps-edges[_ngcontent-%COMP%] { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges[_ngcontent-%COMP%] path[_ngcontent-%COMP%] { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n\n.ps-pchip[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-pchip.f[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-pchip.e[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-pchip.t[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-pchip.a[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n\n\n.ps-seg[_ngcontent-%COMP%] { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:last-child { border-right: none; }\n.ps-seg[_ngcontent-%COMP%] button.on[_ngcontent-%COMP%] { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n\n.ps-field[_ngcontent-%COMP%] { margin-bottom: 14px; }\n.ps-field[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input[_ngcontent-%COMP%] {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input[_ngcontent-%COMP%]:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n\n.ps-loading[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n\n.ps-empty[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty[_ngcontent-%COMP%] .ps-empty-ico[_ngcontent-%COMP%] {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n\n.ps-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal[_ngcontent-%COMP%] {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body[_ngcontent-%COMP%] { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body[_ngcontent-%COMP%] .ps-field[_ngcontent-%COMP%] { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot[_ngcontent-%COMP%] .ps-spacer[_ngcontent-%COMP%] { flex: 1; }", "\n\n\n\n\n.ps-pred-grid-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n\n.pg-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%] {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n\n.pg-view-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid[_ngcontent-%COMP%] {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n\n.pg-record-cell[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-name[_ngcontent-%COMP%] {\n text-decoration: underline;\n}\n\n.pg-record-open-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-open-icon[_ngcontent-%COMP%] {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high[_ngcontent-%COMP%], \n.pg-score-fill.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium[_ngcontent-%COMP%], \n.pg-score-fill.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low[_ngcontent-%COMP%], \n.pg-score-fill.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-score-val[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high[_ngcontent-%COMP%], \n.pg-score-val.badge-red[_ngcontent-%COMP%] { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium[_ngcontent-%COMP%], \n.pg-score-val.badge-amber[_ngcontent-%COMP%] { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low[_ngcontent-%COMP%], \n.pg-score-val.badge-green[_ngcontent-%COMP%] { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.pg-drivers-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n\n.pg-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n\n.pg-chart-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n\n.pg-histogram[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-bar[_ngcontent-%COMP%] {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active[_ngcontent-%COMP%] .pg-h-bar[_ngcontent-%COMP%] {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n.pg-h-tooltip[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-tooltip[_ngcontent-%COMP%] {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n\n.pg-detail-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-detail-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.pg-detail-drivers-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.pg-detail-driver-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-sm);\n}\n\n.pg-detail-driver-label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n\n.pg-trendline-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n.pg-delta-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.pg-chart-drilldown-section[_ngcontent-%COMP%] {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host[_ngcontent-%COMP%] {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}"], changeDetection: 0 });
2257
+ AgGridModule, i2.AgGridAngular, PSRowDriversComponent, i3.DecimalPipe, i3.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n.ps-panel[_ngcontent-%COMP%] {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n \n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n.ps-row[_ngcontent-%COMP%] { display: flex; gap: 16px; }\n.ps-col[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap[_ngcontent-%COMP%] { flex-wrap: wrap; }\n.ps-spacer[_ngcontent-%COMP%] { flex: 1; }\n.ps-muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-small[_ngcontent-%COMP%] { font-size: 12.5px; }\n.ps-mono[_ngcontent-%COMP%] { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title[_ngcontent-%COMP%] {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n\n.ps-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body[_ngcontent-%COMP%] { padding: 16px; }\n\n\n.ps-kpi[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi[_ngcontent-%COMP%] .val[_ngcontent-%COMP%] { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n\n.ps-badge[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n\n.ps-lvl[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-lvl-Strong[_ngcontent-%COMP%] { background: var(--mj-status-info); }\n.ps-lvl-Viable[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-lvl-Weak[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.ps-tag[_ngcontent-%COMP%] {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted[_ngcontent-%COMP%] { opacity: .6; }\n.ps-divider[_ngcontent-%COMP%] { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n\n.ps-table[_ngcontent-%COMP%] { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover td[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); }\n.ps-table[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n\n.ps-bar[_ngcontent-%COMP%] { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-bar.run[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n\n.ps-fbar[_ngcontent-%COMP%] { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar[_ngcontent-%COMP%] + .ps-fbar[_ngcontent-%COMP%] { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-fbar[_ngcontent-%COMP%] .name[_ngcontent-%COMP%] { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar[_ngcontent-%COMP%] > .ps-mono[_ngcontent-%COMP%] { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n\n.ps-gauge[_ngcontent-%COMP%] {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge[_ngcontent-%COMP%]::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge[_ngcontent-%COMP%] .g-val[_ngcontent-%COMP%] { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n\n.ps-callout[_ngcontent-%COMP%] { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 16px; margin-top: 1px; }\n\n\n.ps-stepper[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done[_ngcontent-%COMP%] { color: var(--mj-status-success-text); }\n.ps-step.done[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.ps-step.curr[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step[_ngcontent-%COMP%] .ln[_ngcontent-%COMP%] { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n\n.ps-flow[_ngcontent-%COMP%] {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node[_ngcontent-%COMP%] {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] .ps-tag[_ngcontent-%COMP%] { margin-left: auto; }\n.ps-node[_ngcontent-%COMP%] .nb[_ngcontent-%COMP%] { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] .k[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-node.src[_ngcontent-%COMP%] { border-left-color: var(--ps-node-source); }\n.ps-node.src[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-node.feat[_ngcontent-%COMP%] { border-left-color: var(--ps-node-feature); }\n.ps-node.feat[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-node.emb[_ngcontent-%COMP%] { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-node.target[_ngcontent-%COMP%] { border-left-color: var(--ps-node-target); }\n.ps-node.target[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-node.algo[_ngcontent-%COMP%] { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n.ps-node.output[_ngcontent-%COMP%] { border-left-color: var(--mj-status-success); }\n.ps-node.output[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-node.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node[_ngcontent-%COMP%] .port[_ngcontent-%COMP%] {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node[_ngcontent-%COMP%] .port.in[_ngcontent-%COMP%] { left: -6px; }\n.ps-node[_ngcontent-%COMP%] .port.out[_ngcontent-%COMP%] { right: -6px; }\nsvg.ps-edges[_ngcontent-%COMP%] { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges[_ngcontent-%COMP%] path[_ngcontent-%COMP%] { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n\n.ps-pchip[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-pchip.f[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-pchip.e[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-pchip.t[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-pchip.a[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n\n\n.ps-seg[_ngcontent-%COMP%] { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:last-child { border-right: none; }\n.ps-seg[_ngcontent-%COMP%] button.on[_ngcontent-%COMP%] { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n\n.ps-field[_ngcontent-%COMP%] { margin-bottom: 14px; }\n.ps-field[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input[_ngcontent-%COMP%] {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input[_ngcontent-%COMP%]:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n\n.ps-loading[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n\n.ps-empty[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty[_ngcontent-%COMP%] .ps-empty-ico[_ngcontent-%COMP%] {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n\n.ps-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal[_ngcontent-%COMP%] {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body[_ngcontent-%COMP%] { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body[_ngcontent-%COMP%] .ps-field[_ngcontent-%COMP%] { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot[_ngcontent-%COMP%] .ps-spacer[_ngcontent-%COMP%] { flex: 1; }", "\n\n\n\n\n.ps-pred-grid-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n\n.pg-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%] {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n\n.pg-view-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid[_ngcontent-%COMP%] {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n\n.pg-record-cell[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-name[_ngcontent-%COMP%] {\n text-decoration: underline;\n}\n\n.pg-record-open-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-open-icon[_ngcontent-%COMP%] {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high[_ngcontent-%COMP%], \n.pg-score-fill.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium[_ngcontent-%COMP%], \n.pg-score-fill.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low[_ngcontent-%COMP%], \n.pg-score-fill.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-score-val[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high[_ngcontent-%COMP%], \n.pg-score-val.badge-red[_ngcontent-%COMP%] { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium[_ngcontent-%COMP%], \n.pg-score-val.badge-amber[_ngcontent-%COMP%] { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low[_ngcontent-%COMP%], \n.pg-score-val.badge-green[_ngcontent-%COMP%] { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.pg-drivers-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n\n.pg-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n\n.pg-chart-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n\n.pg-histogram[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-bar[_ngcontent-%COMP%] {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active[_ngcontent-%COMP%] .pg-h-bar[_ngcontent-%COMP%] {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n.pg-h-tooltip[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-tooltip[_ngcontent-%COMP%] {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n\n.pg-detail-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-detail-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n\n.pg-trendline-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n.pg-delta-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.pg-chart-drilldown-section[_ngcontent-%COMP%] {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host[_ngcontent-%COMP%] {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}"], changeDetection: 0 });
2254
2258
  }
2255
2259
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PSPredictionsGridComponent, [{
2256
2260
  type: Component,
@@ -2262,7 +2266,8 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2262
2266
  MJViewToggleComponent,
2263
2267
  MjSlidePanelComponent,
2264
2268
  AgGridModule,
2265
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-pred-grid-host\" [style.height]=\"height\">\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-toolbar\">\n <div class=\"pg-toolbar-left\">\n <div class=\"pg-search-box\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n type=\"text\"\n class=\"pg-search-input\"\n placeholder=\"Filter records, outcome, factors...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\" />\n @if (searchText) {\n <button type=\"button\" class=\"pg-search-clear\" (click)=\"clearSearch()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n <div class=\"pg-tier-filters\">\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === 'all'\"\n (click)=\"setTier('all')\">\n All <span class=\"pg-count-pill\">({{ allRows.length | number }})</span>\n </button>\n @for (b of visibleBands; track b.key) {\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === b.key\"\n (click)=\"setTier(b.key)\">\n {{ b.label }} <span class=\"pg-count-pill\">({{ b.count | number }})</span>\n </button>\n }\n\n @if (selectedDecileIndex !== null) {\n <div class=\"pg-decile-pill\">\n <i class=\"fa-solid fa-filter\"></i>\n <span>Decile {{ selectedDecileLabel }}</span>\n <button type=\"button\" (click)=\"clearDecileFilter()\" title=\"Clear decile filter\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"pg-toolbar-right\">\n <mj-view-toggle\n [Options]=\"viewOptions\"\n [ActiveKey]=\"activeView\"\n (KeyChange)=\"onViewToggle($event)\">\n </mj-view-toggle>\n\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"allRows.length === 0\"\n (click)=\"exportCSV()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n </button>\n </div>\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAIN VIEW CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-view-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading predictions...\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"ps-load-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"ps-load-error-text\">\n <strong>Couldn't load predictions</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"reload()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else if (allRows.length === 0) {\n <div class=\"ps-empty\" style=\"padding: 32px\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-chart-line\"></i></span>\n <h3>No predictions available</h3>\n <p>Run this model from Models in Production or wait for the scheduled job to produce predictions.</p>\n </div>\n } @else {\n <!-- GRID VIEW -->\n @if (activeView === 'grid') {\n <ag-grid-angular\n class=\"pg-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n\n <div class=\"pg-footer\">\n <span>Showing <strong>{{ filteredRows.length }}</strong> of {{ allRows.length }} predictions</span>\n @if (selectedTier !== 'all' || searchText) {\n <span class=\"ps-muted\">Filtered by {{ selectedTier !== 'all' ? selectedTier + ' risk' : '' }}{{ searchText ? ' query \"' + searchText + '\"' : '' }}</span>\n }\n <span class=\"ps-muted\">Click any row to inspect details & score history</span>\n </div>\n }\n\n <!-- CHART VIEW -->\n @if (activeView === 'chart') {\n <div class=\"pg-chart-container\">\n <!-- KPI Summary Cards -->\n <div class=\"pg-chart-cards\">\n <div class=\"pg-chart-card total\">\n <span class=\"pg-chart-card-lbl\"><i class=\"fa-solid fa-users ps-muted\"></i> Scored Cohort</span>\n <span class=\"pg-chart-card-val\">{{ allRows.length | number }}</span>\n <span class=\"pg-chart-card-sub\">Total records</span>\n </div>\n @for (b of visibleBands; track b.key) {\n <div class=\"pg-chart-card\" [class]=\"'tier-' + b.key\" (click)=\"setTierAndGrid(b.key)\">\n <span class=\"pg-chart-card-lbl\">\n @if (b.icon) {\n <i class=\"fa-solid {{ b.icon }}\" [style.color]=\"getBadgeColorVar(b.badgeColor)\"></i>\n }\n {{ b.label }}\n </span>\n <span class=\"pg-chart-card-val\" [style.color]=\"getBadgeColorVar(b.badgeColor)\">\n {{ b.count | number }}\n </span>\n <span class=\"pg-chart-card-sub\">{{ b.pct }}% of cohort (avg {{ b.avgScoreFormatted }} {{ outcomeConfig.ScoreLabel }})</span>\n </div>\n }\n </div>\n\n <!-- Score Distribution Histogram -->\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-chart-simple ps-muted\"></i>\n <span>{{ outcomeConfig.ScoreLabel }} Distribution (10 Bins)</span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">Cohort Mean: <strong>{{ meanScoreFormatted }}</strong></span>\n @if (selectedDecileIndex !== null) {\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Clear Decile Filter\n </button>\n }\n </div>\n </div>\n\n <!-- Modern Interactive Flex Histogram -->\n <div class=\"pg-histogram\">\n <div class=\"pg-h-columns\">\n @for (b of histogramBins; track b.label) {\n <div\n class=\"pg-h-col\"\n [class.active]=\"selectedDecileIndex === b.idx\"\n [class.empty]=\"b.count === 0\"\n (click)=\"selectDecile(b.idx)\">\n\n <!-- Count label above bar -->\n <span class=\"pg-h-count\" [title]=\"b.count + ' records'\">\n {{ b.count > 0 ? (b.count | number) : '0' }}\n </span>\n\n <!-- Bar track & fill -->\n <div class=\"pg-h-bar-track\">\n <div\n class=\"pg-h-bar\"\n [style.height.px]=\"b.height\"\n [style.background]=\"b.color\">\n </div>\n </div>\n\n <!-- Footer labels -->\n <div class=\"pg-h-footer\">\n <span class=\"pg-h-range\">{{ b.shortLabel }}</span>\n <span class=\"pg-h-pct\">{{ b.pctFormatted }}</span>\n </div>\n\n <!-- Tooltip card -->\n <div class=\"pg-h-tooltip\">\n <div class=\"pg-h-tt-head\">{{ b.label }} {{ outcomeConfig.ScoreLabel }}</div>\n <div class=\"pg-h-tt-row\">\n <span class=\"pg-h-tt-val\">{{ b.count | number }} records</span>\n <span class=\"pg-h-tt-pct\">({{ b.pctFormatted }} of cohort)</span>\n </div>\n <div class=\"pg-h-tt-badge\" [style.color]=\"b.color\">{{ b.riskLabel }}</div>\n <div class=\"pg-h-tt-hint\">{{ selectedDecileIndex === b.idx ? 'Click to clear filter' : 'Click to filter grid' }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Predicted Class Breakdown (for Classification) -->\n @if (classBreakdown.length > 0) {\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <span><i class=\"fa-solid fa-layer-group ps-muted\"></i> Predicted Outcome Classes</span>\n </div>\n <div style=\"display:flex;height:24px;border-radius:var(--mj-radius-full);overflow:hidden;background:var(--mj-bg-surface-sunken);margin-bottom:8px\">\n @for (c of classBreakdown; track c.name) {\n <div\n [style.width.%]=\"c.pct\"\n [style.background]=\"c.color\"\n [title]=\"c.name + ': ' + c.count + ' (' + c.pct + '%)'\">\n </div>\n }\n </div>\n <div style=\"display:flex;gap:16px;flex-wrap:wrap\">\n @for (c of classBreakdown; track c.name) {\n <div style=\"display:flex;align-items:center;gap:6px;font-size:var(--mj-text-xs)\">\n <span [style.background]=\"c.color\" style=\"width:10px;height:10px;border-radius:2px;display:inline-block\"></span>\n <strong>{{ c.name }}</strong>\n <span class=\"ps-muted\">{{ c.count }} ({{ c.pct }}%)</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Segment Drilldown Grid Section \u2014 Only shown when a decile segment is selected -->\n @if (selectedDecileIndex !== null) {\n <div id=\"pg-drilldown-anchor\" class=\"pg-chart-section pg-chart-drilldown-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-table-list ps-muted\"></i>\n <span>\n Decile Drill-Down:\n <strong style=\"color:var(--mj-brand-primary)\">{{ selectedDecileLabel }}</strong>\n {{ outcomeConfig.ScoreLabel }}\n @if (histogramBins[selectedDecileIndex]) {\n <span class=\"ps-badge\" [style.color]=\"histogramBins[selectedDecileIndex].color\" style=\"margin-left:6px\">\n {{ histogramBins[selectedDecileIndex].riskLabel }}\n </span>\n }\n </span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">\n Showing <strong>{{ filteredRows.length | number }}</strong> of {{ allRows.length | number }} records\n </span>\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Show All Deciles\n </button>\n </div>\n </div>\n\n <!-- Drill-Down AG Grid -->\n <div class=\"pg-chart-grid-host\">\n <ag-grid-angular\n class=\"pg-grid pg-chart-ag-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"chartGridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onChartGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n </div>\n\n <div class=\"pg-drilldown-footer\">\n <span class=\"ps-muted\">Click any row to inspect explainability drivers and score history in the slide-in drawer</span>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE-IN DETAIL PANEL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (detailOpen && selectedRow) {\n <mj-slide-panel\n Mode=\"slide\"\n Title=\"Record Prediction & Score History\"\n [Resizable]=\"true\"\n [WidthPx]=\"drawerWidthPx\"\n (WidthChanged)=\"onDrawerWidthChanged($event)\"\n (Closed)=\"closeDetail()\">\n\n <div class=\"pg-detail-body\">\n <!-- Record header -->\n <div class=\"pg-detail-record-head\">\n <div class=\"pg-detail-record-info\">\n <h3>{{ selectedRow.recordName || selectedRow.recordId }}</h3>\n <div style=\"display:flex;align-items:center;gap:8px\">\n <span class=\"ps-badge blue\">{{ entityDisplayName || 'Entity Record' }}</span>\n <span class=\"ps-mono ps-small ps-muted\">{{ selectedRow.recordId }}</span>\n </div>\n </div>\n <div class=\"pg-detail-record-actions\" style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"drillThrough(selectedRow)\"\n title=\"Open record in Explorer\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open {{ entityDisplayName || 'Record' }}\n </button>\n @if (subjectEntityName && subjectRecordId) {\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n (click)=\"openSubjectRecord()\"\n title=\"Open subject record (e.g. Person, Account) in Explorer\">\n <i class=\"fa-solid fa-user\"></i> Open {{ subjectEntityName.replace('MJ_BizApps_Common: ', '').replace('MJ_BizApps_', '') }} ({{ subjectRecordName || 'Profile' }})\n </button>\n }\n </div>\n </div>\n\n <!-- Prediction Summary Card -->\n <div class=\"pg-detail-pred-card\">\n <div class=\"pg-detail-score-circle\" [class]=\"'badge-' + (selectedRow.badgeColor || 'gray')\">\n {{ selectedRow.scoreFormatted }}\n </div>\n <div class=\"pg-detail-meta\">\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.StatusLabel }}:</strong>\n <span class=\"ps-badge\" [class]=\"selectedRow.badgeColor || 'gray'\" style=\"margin-left:6px\">\n @if (selectedRow.icon) {\n <i class=\"fa-solid {{ selectedRow.icon }}\"></i>\n }\n {{ selectedRow.status || selectedRow.band }}\n </span>\n </div>\n @if (selectedRow.class) {\n <div class=\"pg-detail-meta-line\">\n <strong>Predicted Outcome:</strong>\n <span class=\"ps-badge\" [class]=\"getOutcomeBadgeClass(selectedRow.class)\">\n {{ selectedRow.class }}\n </span>\n </div>\n }\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.ScoreLabel }}:</strong>\n <span style=\"font-weight:700;color:var(--mj-text-primary)\">{{ selectedRow.scoreFormatted }}</span>\n </div>\n <div class=\"pg-detail-meta-sub\">\n Scored: {{ selectedRow.scoredAtDate ? (selectedRow.scoredAtDate | date:'medium') : '\u2014' }}\n </div>\n </div>\n </div>\n\n <!-- Explainability: Local Feature Drivers -->\n <div class=\"pg-detail-drivers-wrap\">\n <div class=\"ps-section-title\">\n <i class=\"fa-solid fa-lightbulb\" style=\"color:var(--mj-status-warning)\"></i> Key Decision Drivers (Explainability)\n </div>\n @if (!selectedRow.drivers || selectedRow.drivers.length === 0) {\n <div class=\"ps-small ps-muted\">No individual driver breakdown was recorded for this row.</div>\n } @else {\n <div class=\"pg-detail-drivers-list\">\n @for (d of selectedRow.drivers; track d.label) {\n <div class=\"pg-detail-driver-item\">\n <div class=\"pg-detail-driver-label\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"d.up\" [class.fa-arrow-down]=\"!d.up\" [style.color]=\"d.up ? 'var(--mj-status-error)' : 'var(--mj-status-success)'\"></i>\n {{ d.label }}\n </div>\n <span class=\"ps-badge\" [class]=\"d.up ? 'red' : 'green'\">\n {{ d.up ? 'Increases Risk' : 'Lowers Risk' }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Historical Trendline across Runs -->\n <div class=\"pg-trendline-wrap\">\n <div class=\"ps-section-title\" style=\"display:flex;align-items:center;justify-content:space-between\">\n <span><i class=\"fa-solid fa-clock-rotate-left ps-muted\"></i> Historical Score Trendline</span>\n <span class=\"ps-small ps-muted\">{{ historyPoints.length }} run{{ historyPoints.length === 1 ? '' : 's' }} recorded</span>\n </div>\n\n @if (historyLoading) {\n <mj-loading text=\"Loading score history...\" size=\"small\"></mj-loading>\n } @else if (historyPoints.length > 1) {\n <!-- Interactive SVG Trendline -->\n <svg class=\"pg-trendline-svg\" viewBox=\"0 0 540 160\" preserveAspectRatio=\"none\">\n <!-- Background grid lines -->\n <line x1=\"40\" y1=\"20\" x2=\"520\" y2=\"20\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"75\" x2=\"520\" y2=\"75\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"130\" x2=\"520\" y2=\"130\" stroke=\"var(--mj-border-default)\" />\n\n <!-- Y-axis labels -->\n <text x=\"32\" y=\"24\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">100%</text>\n <text x=\"32\" y=\"79\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">50%</text>\n <text x=\"32\" y=\"134\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">0%</text>\n\n <!-- Filled area under curve -->\n <polygon [attr.points]=\"trendlineAreaPoints\" fill=\"color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)\" />\n\n <!-- Trend line path -->\n <polyline [attr.points]=\"trendlineLinePoints\" fill=\"none\" stroke=\"var(--mj-brand-primary)\" stroke-width=\"2.5\" />\n\n <!-- Data points -->\n @for (p of trendlinePlotPoints; track p.runId) {\n <circle\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y\"\n r=\"5\"\n [attr.fill]=\"p.color\"\n stroke=\"var(--mj-bg-surface)\"\n stroke-width=\"2\">\n <title>{{ p.dateStr }}: {{ p.scoreFormatted }} ({{ p.class || 'No class' }})</title>\n </circle>\n <text\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y - 9\"\n font-size=\"10\"\n font-weight=\"700\"\n text-anchor=\"middle\"\n fill=\"var(--mj-text-primary)\">\n {{ p.scoreFormatted }}\n </text>\n }\n </svg>\n\n <!-- Runs Table -->\n <table class=\"pg-history-table\">\n <thead>\n <tr>\n <th>When</th>\n <th>Status</th>\n <th>Score</th>\n <th>Change</th>\n <th>Class</th>\n </tr>\n </thead>\n <tbody>\n @for (pt of historyPoints; track pt.runId) {\n <tr>\n <td>{{ pt.RunDate | date:'short' }}</td>\n <td><span class=\"ps-badge\" [class]=\"pt.status === 'Succeeded' ? 'green' : 'gray'\">{{ pt.status }}</span></td>\n <td><strong class=\"ps-mono\">{{ pt.ScoreFormatted }}</strong></td>\n <td>\n @if (pt.Delta == null) {\n <span class=\"pg-delta-pill neutral\">Baseline</span>\n } @else if (pt.Delta > 0.005) {\n <span class=\"pg-delta-pill up\"><i class=\"fa-solid fa-arrow-up\"></i> +{{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else if (pt.Delta < -0.005) {\n <span class=\"pg-delta-pill down\"><i class=\"fa-solid fa-arrow-down\"></i> {{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else {\n <span class=\"pg-delta-pill neutral\">0%</span>\n }\n </td>\n <td>{{ pt.class || '\u2014' }}</td>\n </tr>\n }\n </tbody>\n </table>\n } @else if (historyPoints.length === 1) {\n <div class=\"ps-small ps-muted\">\n This record has been scored once so far ({{ historyPoints[0].RunDate | date:'medium' }}). As more runs occur over time, the score trendline will track changes here.\n </div>\n } @else {\n <div class=\"ps-small ps-muted\">No historical runs found for this record.</div>\n }\n </div>\n </div>\n </mj-slide-panel>\n }\n</div>\n", styles: ["/* ============================================================================\n Predictive Studio \u2014 shared panel styles (design-token compliant)\n Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n so the class names are global within the PS dashboard subtree.\n No hardcoded colors except the intentional categorical node/algorithm palette\n (declared once as --ps-* custom props below) which must stay distinct across\n light/dark to remain readable as diagram accents.\n ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n data-visualization colors that must remain distinct regardless of theme\n (allowed exception #3 in the design-token rules). */\n.ps-panel {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n display: block;\n height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar + .ps-fbar { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar .track { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar > .ps-mono { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n/* gauge */\n.ps-gauge {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node .nh {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", "/* ============================================================================\n Predictive Studio \u2014 Unified Predictions Grid & Detail Panel styles\n Design-token compliant (all --mj-* semantic tokens).\n ============================================================================ */\n\n.ps-pred-grid-host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box i {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill button {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 GRID CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-view-container {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n/* AG Grid cell styling overrides */\n.pg-record-cell {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link:hover .pg-record-name {\n text-decoration: underline;\n}\n\n.pg-record-open-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link:hover .pg-record-open-icon {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high,\n.pg-score-fill.badge-red { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium,\n.pg-score-fill.badge-amber { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low,\n.pg-score-fill.badge-green { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray { background: var(--mj-text-muted); }\n\n.pg-score-val {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high,\n.pg-score-val.badge-red { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium,\n.pg-score-val.badge-amber { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low,\n.pg-score-val.badge-green { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray { color: var(--mj-text-muted); }\n\n.pg-drivers-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 FOOTER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART VIEW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MODERN HISTOGRAM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-histogram {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col:hover .pg-h-bar {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active .pg-h-bar {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* Tooltip card */\n.pg-h-tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col:hover .pg-h-tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE PANEL DETAIL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-detail-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info h3 {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high,\n.pg-detail-score-circle.badge-red { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium,\n.pg-detail-score-circle.badge-amber { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low,\n.pg-detail-score-circle.badge-green { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray { background: var(--mj-text-muted); }\n\n.pg-detail-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.pg-detail-drivers-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.pg-detail-driver-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-sm);\n}\n\n.pg-detail-driver-label {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TRENDLINE CHART & TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-trendline-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table th {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table td {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table tr:last-child td {\n border-bottom: none;\n}\n\n.pg-delta-pill {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART DRILLDOWN GRID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-drilldown-section {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}\n"] }]
2269
+ PSRowDriversComponent,
2270
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-pred-grid-host\" [style.height]=\"height\">\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-toolbar\">\n <div class=\"pg-toolbar-left\">\n <div class=\"pg-search-box\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n type=\"text\"\n class=\"pg-search-input\"\n placeholder=\"Filter records, outcome, factors...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\" />\n @if (searchText) {\n <button type=\"button\" class=\"pg-search-clear\" (click)=\"clearSearch()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n <div class=\"pg-tier-filters\">\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === 'all'\"\n (click)=\"setTier('all')\">\n All <span class=\"pg-count-pill\">({{ allRows.length | number }})</span>\n </button>\n @for (b of visibleBands; track b.key) {\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === b.key\"\n (click)=\"setTier(b.key)\">\n {{ b.label }} <span class=\"pg-count-pill\">({{ b.count | number }})</span>\n </button>\n }\n\n @if (selectedDecileIndex !== null) {\n <div class=\"pg-decile-pill\">\n <i class=\"fa-solid fa-filter\"></i>\n <span>Decile {{ selectedDecileLabel }}</span>\n <button type=\"button\" (click)=\"clearDecileFilter()\" title=\"Clear decile filter\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"pg-toolbar-right\">\n <mj-view-toggle\n [Options]=\"viewOptions\"\n [ActiveKey]=\"activeView\"\n (KeyChange)=\"onViewToggle($event)\">\n </mj-view-toggle>\n\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"allRows.length === 0\"\n (click)=\"exportCSV()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n </button>\n </div>\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAIN VIEW CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-view-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading predictions...\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"ps-load-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"ps-load-error-text\">\n <strong>Couldn't load predictions</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"reload()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else if (allRows.length === 0) {\n <div class=\"ps-empty\" style=\"padding: 32px\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-chart-line\"></i></span>\n <h3>No predictions available</h3>\n <p>Run this model from Models in Production or wait for the scheduled job to produce predictions.</p>\n </div>\n } @else {\n <!-- GRID VIEW -->\n @if (activeView === 'grid') {\n <ag-grid-angular\n class=\"pg-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n\n <div class=\"pg-footer\">\n <span>Showing <strong>{{ filteredRows.length }}</strong> of {{ allRows.length }} predictions</span>\n @if (selectedTier !== 'all' || searchText) {\n <span class=\"ps-muted\">Filtered by {{ SelectedTierLabel }}{{ searchText ? ' query \"' + searchText + '\"' : '' }}</span>\n }\n @if (DetailRowsCapped) {\n <span class=\"ps-muted\" data-testid=\"ps-predictions-capped\">Showing the first {{ MaxRunDetailRowsLabel }} predictions</span>\n }\n <span class=\"ps-muted\">Click any row to inspect details & score history</span>\n </div>\n }\n\n <!-- CHART VIEW -->\n @if (activeView === 'chart') {\n <div class=\"pg-chart-container\">\n <!-- KPI Summary Cards -->\n <div class=\"pg-chart-cards\">\n <div class=\"pg-chart-card total\">\n <span class=\"pg-chart-card-lbl\"><i class=\"fa-solid fa-users ps-muted\"></i> Scored Cohort</span>\n <span class=\"pg-chart-card-val\">{{ allRows.length | number }}</span>\n <span class=\"pg-chart-card-sub\">Total records</span>\n </div>\n @for (b of visibleBands; track b.key) {\n <div class=\"pg-chart-card\" [class]=\"'tier-' + b.key\" (click)=\"setTierAndGrid(b.key)\">\n <span class=\"pg-chart-card-lbl\">\n @if (b.icon) {\n <i class=\"fa-solid {{ b.icon }}\" [style.color]=\"getBadgeColorVar(b.badgeColor)\"></i>\n }\n {{ b.label }}\n </span>\n <span class=\"pg-chart-card-val\" [style.color]=\"getBadgeColorVar(b.badgeColor)\">\n {{ b.count | number }}\n </span>\n <span class=\"pg-chart-card-sub\">{{ b.pct }}% of cohort (avg {{ b.avgScoreFormatted }} {{ outcomeConfig.ScoreLabel }})</span>\n </div>\n }\n </div>\n\n <!-- Score Distribution Histogram -->\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-chart-simple ps-muted\"></i>\n <span>{{ outcomeConfig.ScoreLabel }} Distribution (10 Bins)</span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">Cohort Mean: <strong>{{ meanScoreFormatted }}</strong></span>\n @if (selectedDecileIndex !== null) {\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Clear Decile Filter\n </button>\n }\n </div>\n </div>\n\n <!-- Modern Interactive Flex Histogram -->\n <div class=\"pg-histogram\">\n <div class=\"pg-h-columns\">\n @for (b of histogramBins; track b.label) {\n <div\n class=\"pg-h-col\"\n [class.active]=\"selectedDecileIndex === b.idx\"\n [class.empty]=\"b.count === 0\"\n (click)=\"selectDecile(b.idx)\">\n\n <!-- Count label above bar -->\n <span class=\"pg-h-count\" [title]=\"b.count + ' records'\">\n {{ b.count > 0 ? (b.count | number) : '0' }}\n </span>\n\n <!-- Bar track & fill -->\n <div class=\"pg-h-bar-track\">\n <div\n class=\"pg-h-bar\"\n [style.height.px]=\"b.height\"\n [style.background]=\"b.color\">\n </div>\n </div>\n\n <!-- Footer labels -->\n <div class=\"pg-h-footer\">\n <span class=\"pg-h-range\">{{ b.shortLabel }}</span>\n <span class=\"pg-h-pct\">{{ b.pctFormatted }}</span>\n </div>\n\n <!-- Tooltip card -->\n <div class=\"pg-h-tooltip\">\n <div class=\"pg-h-tt-head\">{{ b.label }} {{ outcomeConfig.ScoreLabel }}</div>\n <div class=\"pg-h-tt-row\">\n <span class=\"pg-h-tt-val\">{{ b.count | number }} records</span>\n <span class=\"pg-h-tt-pct\">({{ b.pctFormatted }} of cohort)</span>\n </div>\n <div class=\"pg-h-tt-badge\" [style.color]=\"b.color\">{{ b.riskLabel }}</div>\n <div class=\"pg-h-tt-hint\">{{ selectedDecileIndex === b.idx ? 'Click to clear filter' : 'Click to filter grid' }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Predicted Class Breakdown (for Classification) -->\n @if (classBreakdown.length > 0) {\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <span><i class=\"fa-solid fa-layer-group ps-muted\"></i> Predicted Outcome Classes</span>\n </div>\n <div style=\"display:flex;height:24px;border-radius:var(--mj-radius-full);overflow:hidden;background:var(--mj-bg-surface-sunken);margin-bottom:8px\">\n @for (c of classBreakdown; track c.name) {\n <div\n [style.width.%]=\"c.pct\"\n [style.background]=\"c.color\"\n [title]=\"c.name + ': ' + c.count + ' (' + c.pct + '%)'\">\n </div>\n }\n </div>\n <div style=\"display:flex;gap:16px;flex-wrap:wrap\">\n @for (c of classBreakdown; track c.name) {\n <div style=\"display:flex;align-items:center;gap:6px;font-size:var(--mj-text-xs)\">\n <span [style.background]=\"c.color\" style=\"width:10px;height:10px;border-radius:2px;display:inline-block\"></span>\n <strong>{{ c.name }}</strong>\n <span class=\"ps-muted\">{{ c.count }} ({{ c.pct }}%)</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Segment Drilldown Grid Section \u2014 Only shown when a decile segment is selected -->\n @if (selectedDecileIndex !== null) {\n <div id=\"pg-drilldown-anchor\" class=\"pg-chart-section pg-chart-drilldown-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-table-list ps-muted\"></i>\n <span>\n Decile Drill-Down:\n <strong style=\"color:var(--mj-brand-primary)\">{{ selectedDecileLabel }}</strong>\n {{ outcomeConfig.ScoreLabel }}\n @if (histogramBins[selectedDecileIndex]) {\n <span class=\"ps-badge\" [style.color]=\"histogramBins[selectedDecileIndex].color\" style=\"margin-left:6px\">\n {{ histogramBins[selectedDecileIndex].riskLabel }}\n </span>\n }\n </span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">\n Showing <strong>{{ filteredRows.length | number }}</strong> of {{ allRows.length | number }} records\n </span>\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Show All Deciles\n </button>\n </div>\n </div>\n\n <!-- Drill-Down AG Grid -->\n <div class=\"pg-chart-grid-host\">\n <ag-grid-angular\n class=\"pg-grid pg-chart-ag-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"chartGridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onChartGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n </div>\n\n <div class=\"pg-drilldown-footer\">\n <span class=\"ps-muted\">Click any row to inspect explainability drivers and score history in the slide-in drawer</span>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE-IN DETAIL PANEL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (detailOpen && selectedRow) {\n <mj-slide-panel\n Mode=\"slide\"\n Title=\"Record Prediction & Score History\"\n [Resizable]=\"true\"\n [WidthPx]=\"drawerWidthPx\"\n (WidthChanged)=\"onDrawerWidthChanged($event)\"\n (Closed)=\"closeDetail()\">\n\n <div class=\"pg-detail-body\">\n <!-- Record header -->\n <div class=\"pg-detail-record-head\">\n <div class=\"pg-detail-record-info\">\n <h3>{{ selectedRow.recordName || selectedRow.recordId }}</h3>\n <div style=\"display:flex;align-items:center;gap:8px\">\n <span class=\"ps-badge blue\">{{ entityDisplayName || 'Entity Record' }}</span>\n <span class=\"ps-mono ps-small ps-muted\">{{ selectedRow.recordId }}</span>\n </div>\n </div>\n <div class=\"pg-detail-record-actions\" style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"drillThrough(selectedRow)\"\n title=\"Open record in Explorer\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open {{ entityDisplayName || 'Record' }}\n </button>\n @if (subjectEntityName && subjectRecordId) {\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n (click)=\"openSubjectRecord()\"\n title=\"Open subject record (e.g. Person, Account) in Explorer\">\n <i class=\"fa-solid fa-user\"></i> Open {{ subjectEntityName.replace('MJ_BizApps_Common: ', '').replace('MJ_BizApps_', '') }} ({{ subjectRecordName || 'Profile' }})\n </button>\n }\n </div>\n </div>\n\n <!-- Prediction Summary Card -->\n <div class=\"pg-detail-pred-card\">\n <div class=\"pg-detail-score-circle\" [class]=\"'badge-' + (selectedRow.badgeColor || 'gray')\">\n {{ selectedRow.scoreFormatted }}\n </div>\n <div class=\"pg-detail-meta\">\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.StatusLabel }}:</strong>\n <span class=\"ps-badge\" [class]=\"selectedRow.badgeColor || 'gray'\" style=\"margin-left:6px\">\n @if (selectedRow.icon) {\n <i class=\"fa-solid {{ selectedRow.icon }}\"></i>\n }\n {{ selectedRow.status || selectedRow.band }}\n </span>\n </div>\n @if (selectedRow.class) {\n <div class=\"pg-detail-meta-line\">\n <strong>Predicted Outcome:</strong>\n <span class=\"ps-badge\" [class]=\"getOutcomeBadgeClass(selectedRow.class)\">\n {{ selectedRow.class }}\n </span>\n </div>\n }\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.ScoreLabel }}:</strong>\n <span style=\"font-weight:700;color:var(--mj-text-primary)\">{{ selectedRow.scoreFormatted }}</span>\n </div>\n <div class=\"pg-detail-meta-sub\">\n Scored: {{ selectedRow.scoredAtDate ? (selectedRow.scoredAtDate | date:'medium') : '\u2014' }}\n </div>\n </div>\n </div>\n\n <!-- Explainability: Local Feature Drivers -->\n <div class=\"pg-detail-drivers-wrap\">\n <div class=\"ps-section-title\">\n <i class=\"fa-solid fa-lightbulb\" style=\"color:var(--mj-status-warning)\"></i> Factors behind this score (associations, not causes)\n </div>\n <ps-row-drivers [Drivers]=\"selectedRow.drivers\"></ps-row-drivers>\n </div>\n\n <!-- Historical Trendline across Runs -->\n <div class=\"pg-trendline-wrap\">\n <div class=\"ps-section-title\" style=\"display:flex;align-items:center;justify-content:space-between\">\n <span><i class=\"fa-solid fa-clock-rotate-left ps-muted\"></i> Historical Score Trendline</span>\n <span class=\"ps-small ps-muted\">{{ historyPoints.length }} run{{ historyPoints.length === 1 ? '' : 's' }} recorded</span>\n </div>\n\n @if (historyLoading) {\n <mj-loading text=\"Loading score history...\" size=\"small\"></mj-loading>\n } @else if (historyPoints.length > 1) {\n <!-- Interactive SVG Trendline -->\n <svg class=\"pg-trendline-svg\" viewBox=\"0 0 540 160\" preserveAspectRatio=\"none\">\n <!-- Background grid lines -->\n <line x1=\"40\" y1=\"20\" x2=\"520\" y2=\"20\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"75\" x2=\"520\" y2=\"75\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"130\" x2=\"520\" y2=\"130\" stroke=\"var(--mj-border-default)\" />\n\n <!-- Y-axis labels -->\n <text x=\"32\" y=\"24\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">100%</text>\n <text x=\"32\" y=\"79\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">50%</text>\n <text x=\"32\" y=\"134\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">0%</text>\n\n <!-- Filled area under curve -->\n <polygon [attr.points]=\"trendlineAreaPoints\" fill=\"color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)\" />\n\n <!-- Trend line path -->\n <polyline [attr.points]=\"trendlineLinePoints\" fill=\"none\" stroke=\"var(--mj-brand-primary)\" stroke-width=\"2.5\" />\n\n <!-- Data points -->\n @for (p of trendlinePlotPoints; track p.runId) {\n <circle\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y\"\n r=\"5\"\n [attr.fill]=\"p.color\"\n stroke=\"var(--mj-bg-surface)\"\n stroke-width=\"2\">\n <title>{{ p.dateStr }}: {{ p.scoreFormatted }} ({{ p.class || 'No class' }})</title>\n </circle>\n <text\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y - 9\"\n font-size=\"10\"\n font-weight=\"700\"\n text-anchor=\"middle\"\n fill=\"var(--mj-text-primary)\">\n {{ p.scoreFormatted }}\n </text>\n }\n </svg>\n\n <!-- Runs Table -->\n <table class=\"pg-history-table\">\n <thead>\n <tr>\n <th>When</th>\n <th>Status</th>\n <th>Score</th>\n <th>Change</th>\n <th>Class</th>\n </tr>\n </thead>\n <tbody>\n @for (pt of historyPoints; track pt.runId) {\n <tr>\n <td>{{ pt.RunDate | date:'short' }}</td>\n <td><span class=\"ps-badge\" [class]=\"pt.status === 'Succeeded' ? 'green' : 'gray'\">{{ pt.status }}</span></td>\n <td><strong class=\"ps-mono\">{{ pt.ScoreFormatted }}</strong></td>\n <td>\n @if (pt.Delta == null) {\n <span class=\"pg-delta-pill neutral\">Baseline</span>\n } @else if (pt.Delta > 0.005) {\n <span class=\"pg-delta-pill up\"><i class=\"fa-solid fa-arrow-up\"></i> +{{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else if (pt.Delta < -0.005) {\n <span class=\"pg-delta-pill down\"><i class=\"fa-solid fa-arrow-down\"></i> {{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else {\n <span class=\"pg-delta-pill neutral\">0%</span>\n }\n </td>\n <td>{{ pt.class || '\u2014' }}</td>\n </tr>\n }\n </tbody>\n </table>\n } @else if (historyPoints.length === 1) {\n <div class=\"ps-small ps-muted\">\n This record has been scored once so far ({{ historyPoints[0].RunDate | date:'medium' }}). As more runs occur over time, the score trendline will track changes here.\n </div>\n } @else {\n <div class=\"ps-small ps-muted\">No historical runs found for this record.</div>\n }\n </div>\n </div>\n </mj-slide-panel>\n }\n</div>\n", styles: ["/* ============================================================================\n Predictive Studio \u2014 shared panel styles (design-token compliant)\n Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n so the class names are global within the PS dashboard subtree.\n No hardcoded colors except the intentional categorical node/algorithm palette\n (declared once as --ps-* custom props below) which must stay distinct across\n light/dark to remain readable as diagram accents.\n ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n data-visualization colors that must remain distinct regardless of theme\n (allowed exception #3 in the design-token rules). */\n.ps-panel {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n display: block;\n height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar + .ps-fbar { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar .track { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar > .ps-mono { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n/* gauge */\n.ps-gauge {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node .nh {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", "/* ============================================================================\n Predictive Studio \u2014 Unified Predictions Grid & Detail Panel styles\n Design-token compliant (all --mj-* semantic tokens).\n ============================================================================ */\n\n.ps-pred-grid-host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box i {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill button {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 GRID CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-view-container {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n/* AG Grid cell styling overrides */\n.pg-record-cell {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link:hover .pg-record-name {\n text-decoration: underline;\n}\n\n.pg-record-open-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link:hover .pg-record-open-icon {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high,\n.pg-score-fill.badge-red { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium,\n.pg-score-fill.badge-amber { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low,\n.pg-score-fill.badge-green { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray { background: var(--mj-text-muted); }\n\n.pg-score-val {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high,\n.pg-score-val.badge-red { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium,\n.pg-score-val.badge-amber { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low,\n.pg-score-val.badge-green { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray { color: var(--mj-text-muted); }\n\n.pg-drivers-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 FOOTER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART VIEW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MODERN HISTOGRAM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-histogram {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col:hover .pg-h-bar {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active .pg-h-bar {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* Tooltip card */\n.pg-h-tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col:hover .pg-h-tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE PANEL DETAIL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-detail-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info h3 {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high,\n.pg-detail-score-circle.badge-red { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium,\n.pg-detail-score-circle.badge-amber { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low,\n.pg-detail-score-circle.badge-green { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray { background: var(--mj-text-muted); }\n\n.pg-detail-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TRENDLINE CHART & TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-trendline-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table th {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table td {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table tr:last-child td {\n border-bottom: none;\n}\n\n.pg-delta-pill {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART DRILLDOWN GRID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-drilldown-section {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}\n"] }]
2266
2271
  }], null, { modelId: [{
2267
2272
  type: Input
2268
2273
  }], RunId: [{
@@ -2283,6 +2288,10 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
2283
2288
  type: Input
2284
2289
  }], readOnly: [{
2285
2290
  type: Input
2291
+ }], RowsLoaded: [{
2292
+ type: Output
2293
+ }], RowsLoadFailed: [{
2294
+ type: Output
2286
2295
  }] }); })();
2287
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSPredictionsGridComponent, { className: "PSPredictionsGridComponent", filePath: "src/PredictiveStudio/components/ps-predictions-grid.component.ts", lineNumber: 151 }); })();
2296
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSPredictionsGridComponent, { className: "PSPredictionsGridComponent", filePath: "src/PredictiveStudio/components/ps-predictions-grid.component.ts", lineNumber: 168 }); })();
2288
2297
  //# sourceMappingURL=ps-predictions-grid.component.js.map