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

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 (293) hide show
  1. package/README.md +35 -0
  2. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +2 -2
  3. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -1
  4. package/dist/AI/components/analytics/realtime/realtime-management.component.d.ts.map +1 -1
  5. package/dist/AI/components/analytics/realtime/realtime-management.component.js +3 -1
  6. package/dist/AI/components/analytics/realtime/realtime-management.component.js.map +1 -1
  7. package/dist/AI/components/analytics/realtime/realtime-overview.component.d.ts +1 -1
  8. package/dist/AI/components/analytics/realtime/realtime-overview.component.js +3 -3
  9. package/dist/AI/components/analytics/realtime/realtime-overview.component.js.map +1 -1
  10. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts +6 -4
  11. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts.map +1 -1
  12. package/dist/AI/components/analytics/realtime/realtime-session-data.js +8 -2
  13. package/dist/AI/components/analytics/realtime/realtime-session-data.js.map +1 -1
  14. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
  15. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  16. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +21 -13
  17. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  18. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +1 -1
  19. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -1
  20. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -1
  21. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +1 -0
  22. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -1
  23. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
  24. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +1 -0
  25. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
  26. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  27. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1 -0
  28. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  29. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
  30. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  31. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +210 -57
  32. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  33. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
  34. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
  35. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
  36. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
  37. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  38. package/dist/AI/components/execution-monitoring.component.js +28 -16
  39. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  40. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
  41. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
  42. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +32 -8
  43. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
  44. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
  45. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  46. package/dist/AI/components/tags/tags-resource.component.js +18 -9
  47. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  48. package/dist/AI/components/vectors/sensitive-fields.d.ts +9 -4
  49. package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -1
  50. package/dist/AI/components/vectors/sensitive-fields.js +39 -14
  51. package/dist/AI/components/vectors/sensitive-fields.js.map +1 -1
  52. package/dist/AI/components/vectors/vector-document-rules.d.ts +13 -0
  53. package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -1
  54. package/dist/AI/components/vectors/vector-document-rules.js +14 -0
  55. package/dist/AI/components/vectors/vector-document-rules.js.map +1 -1
  56. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +34 -14
  57. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  58. package/dist/AI/components/vectors/vector-management-resource.component.js +134 -51
  59. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  60. package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
  61. package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
  62. package/dist/AI/components/vectors/vector-store-selection.js +57 -0
  63. package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
  64. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  65. package/dist/AI/services/ai-instrumentation.service.js +4 -2
  66. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  67. package/dist/Actions/action-result-code.d.ts +80 -0
  68. package/dist/Actions/action-result-code.d.ts.map +1 -0
  69. package/dist/Actions/action-result-code.js +163 -0
  70. package/dist/Actions/action-result-code.js.map +1 -0
  71. package/dist/Actions/components/actions-overview.component.d.ts +8 -0
  72. package/dist/Actions/components/actions-overview.component.d.ts.map +1 -1
  73. package/dist/Actions/components/actions-overview.component.js +12 -9
  74. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  75. package/dist/Actions/components/execution-monitoring.component.d.ts +29 -9
  76. package/dist/Actions/components/execution-monitoring.component.d.ts.map +1 -1
  77. package/dist/Actions/components/execution-monitoring.component.js +65 -42
  78. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  79. package/dist/Actions/components/explorer/action-card.component.d.ts.map +1 -1
  80. package/dist/Actions/components/explorer/action-card.component.js +5 -4
  81. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  82. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +198 -0
  83. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
  84. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +289 -0
  85. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
  86. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.d.ts +29 -0
  87. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.d.ts.map +1 -0
  88. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.js +666 -0
  89. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.js.map +1 -0
  90. package/dist/ChiefOfStaff/chief-of-staff-governance.component.d.ts +56 -0
  91. package/dist/ChiefOfStaff/chief-of-staff-governance.component.d.ts.map +1 -0
  92. package/dist/ChiefOfStaff/chief-of-staff-governance.component.js +515 -0
  93. package/dist/ChiefOfStaff/chief-of-staff-governance.component.js.map +1 -0
  94. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.d.ts +14 -0
  95. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.d.ts.map +1 -0
  96. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.js +39 -0
  97. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.js.map +1 -0
  98. package/dist/ChiefOfStaff/chief-of-staff-overview.component.d.ts +17 -0
  99. package/dist/ChiefOfStaff/chief-of-staff-overview.component.d.ts.map +1 -0
  100. package/dist/ChiefOfStaff/chief-of-staff-overview.component.js +485 -0
  101. package/dist/ChiefOfStaff/chief-of-staff-overview.component.js.map +1 -0
  102. package/dist/ChiefOfStaff/chief-of-staff-page-base.d.ts +139 -0
  103. package/dist/ChiefOfStaff/chief-of-staff-page-base.d.ts.map +1 -0
  104. package/dist/ChiefOfStaff/chief-of-staff-page-base.js +602 -0
  105. package/dist/ChiefOfStaff/chief-of-staff-page-base.js.map +1 -0
  106. package/dist/ChiefOfStaff/index.d.ts +6 -0
  107. package/dist/ChiefOfStaff/index.d.ts.map +1 -0
  108. package/dist/ChiefOfStaff/index.js +6 -0
  109. package/dist/ChiefOfStaff/index.js.map +1 -0
  110. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  111. package/dist/Communication/communication-logs-resource.component.js +2 -1
  112. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  113. package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
  114. package/dist/Communication/communication-monitor-resource.component.js +26 -21
  115. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  116. package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
  117. package/dist/Communication/communication-runs-resource.component.js +14 -13
  118. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  119. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  120. package/dist/ComponentStudio/component-studio-dashboard.component.js +1 -0
  121. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  122. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
  123. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +2 -1
  124. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
  125. package/dist/ComponentStudio/services/component-version.service.d.ts.map +1 -1
  126. package/dist/ComponentStudio/services/component-version.service.js +3 -0
  127. package/dist/ComponentStudio/services/component-version.service.js.map +1 -1
  128. package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
  129. package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
  130. package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
  131. package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
  132. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +45 -2
  133. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  134. package/dist/DataExplorer/data-explorer-dashboard.component.js +178 -55
  135. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  136. package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
  137. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  138. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  139. package/dist/DevTools/graphql-console.component.js +2 -2
  140. package/dist/DevTools/lazy-module-status.component.js +2 -2
  141. package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -1
  142. package/dist/FormBuilder/form-builder-resource.component.js +5 -0
  143. package/dist/FormBuilder/form-builder-resource.component.js.map +1 -1
  144. package/dist/Integration/components/connections/connections.component.js +2 -2
  145. package/dist/Integration/services/integration-data.service.d.ts +1 -1
  146. package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
  147. package/dist/Integration/services/integration-data.service.js +4 -3
  148. package/dist/Integration/services/integration-data.service.js.map +1 -1
  149. package/dist/Lists/components/lists-browse-resource.component.js +1 -1
  150. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  151. package/dist/Lists/components/lists-my-lists-resource.component.js +1 -1
  152. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  153. package/dist/LoginStudio/login-studio-resource.component.d.ts +10 -2
  154. package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -1
  155. package/dist/LoginStudio/login-studio-resource.component.js +111 -77
  156. package/dist/LoginStudio/login-studio-resource.component.js.map +1 -1
  157. package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
  158. package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
  159. package/dist/MCP/mcp-dashboard.component.js +118 -65
  160. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  161. package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
  162. package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
  163. package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
  164. package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
  165. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
  166. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
  167. package/dist/PredictiveStudio/components/ps-experiments.component.js +257 -521
  168. package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
  169. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
  170. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
  171. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +124 -251
  172. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
  173. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
  174. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  175. package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
  176. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  177. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
  178. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
  179. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +338 -326
  180. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
  181. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
  182. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
  183. package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
  184. package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
  185. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
  186. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
  187. package/dist/PredictiveStudio/engine/predictive-studio.engine.js +52 -2
  188. package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
  189. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
  190. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
  191. package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
  192. package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
  193. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
  194. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
  195. package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
  196. package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
  197. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
  198. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
  199. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +186 -103
  200. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
  201. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
  202. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
  203. package/dist/QueryBrowser/query-browser-resource.component.d.ts +26 -0
  204. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  205. package/dist/QueryBrowser/query-browser-resource.component.js +375 -252
  206. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  207. package/dist/UserRoutines/user-routines-resource.component.d.ts +8 -1
  208. package/dist/UserRoutines/user-routines-resource.component.d.ts.map +1 -1
  209. package/dist/UserRoutines/user-routines-resource.component.js +22 -4
  210. package/dist/UserRoutines/user-routines-resource.component.js.map +1 -1
  211. package/dist/VersionHistory/components/diff-resource.component.d.ts.map +1 -1
  212. package/dist/VersionHistory/components/diff-resource.component.js +1 -0
  213. package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
  214. package/dist/VideoStudio/components/vs-archetype-editor.component.d.ts +162 -0
  215. package/dist/VideoStudio/components/vs-archetype-editor.component.d.ts.map +1 -0
  216. package/dist/VideoStudio/components/vs-archetype-editor.component.js +1105 -0
  217. package/dist/VideoStudio/components/vs-archetype-editor.component.js.map +1 -0
  218. package/dist/VideoStudio/components/vs-audio-options.component.d.ts +27 -0
  219. package/dist/VideoStudio/components/vs-audio-options.component.d.ts.map +1 -0
  220. package/dist/VideoStudio/components/vs-audio-options.component.js +119 -0
  221. package/dist/VideoStudio/components/vs-audio-options.component.js.map +1 -0
  222. package/dist/VideoStudio/components/vs-copilot-panel.component.d.ts +105 -0
  223. package/dist/VideoStudio/components/vs-copilot-panel.component.d.ts.map +1 -0
  224. package/dist/VideoStudio/components/vs-copilot-panel.component.js +560 -0
  225. package/dist/VideoStudio/components/vs-copilot-panel.component.js.map +1 -0
  226. package/dist/VideoStudio/components/vs-production-brief.component.d.ts +163 -0
  227. package/dist/VideoStudio/components/vs-production-brief.component.d.ts.map +1 -0
  228. package/dist/VideoStudio/components/vs-production-brief.component.js +1054 -0
  229. package/dist/VideoStudio/components/vs-production-brief.component.js.map +1 -0
  230. package/dist/VideoStudio/components/vs-setup-health-card.component.d.ts +43 -0
  231. package/dist/VideoStudio/components/vs-setup-health-card.component.d.ts.map +1 -0
  232. package/dist/VideoStudio/components/vs-setup-health-card.component.js +412 -0
  233. package/dist/VideoStudio/components/vs-setup-health-card.component.js.map +1 -0
  234. package/dist/VideoStudio/components/vs-studio-slide-in.component.d.ts +73 -0
  235. package/dist/VideoStudio/components/vs-studio-slide-in.component.d.ts.map +1 -0
  236. package/dist/VideoStudio/components/vs-studio-slide-in.component.js +271 -0
  237. package/dist/VideoStudio/components/vs-studio-slide-in.component.js.map +1 -0
  238. package/dist/VideoStudio/index.d.ts +12 -0
  239. package/dist/VideoStudio/index.d.ts.map +1 -0
  240. package/dist/VideoStudio/index.js +12 -0
  241. package/dist/VideoStudio/index.js.map +1 -0
  242. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.d.ts +118 -0
  243. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.d.ts.map +1 -0
  244. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.js +964 -0
  245. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.js.map +1 -0
  246. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.d.ts +70 -0
  247. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.d.ts.map +1 -0
  248. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.js +600 -0
  249. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.js.map +1 -0
  250. package/dist/VideoStudio/resources/video-studio-productions-resource.component.d.ts +182 -0
  251. package/dist/VideoStudio/resources/video-studio-productions-resource.component.d.ts.map +1 -0
  252. package/dist/VideoStudio/resources/video-studio-productions-resource.component.js +1481 -0
  253. package/dist/VideoStudio/resources/video-studio-productions-resource.component.js.map +1 -0
  254. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.d.ts +102 -0
  255. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.d.ts.map +1 -0
  256. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.js +240 -0
  257. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.js.map +1 -0
  258. package/dist/VideoStudio/video-studio-agent-context.d.ts +495 -0
  259. package/dist/VideoStudio/video-studio-agent-context.d.ts.map +1 -0
  260. package/dist/VideoStudio/video-studio-agent-context.js +992 -0
  261. package/dist/VideoStudio/video-studio-agent-context.js.map +1 -0
  262. package/dist/ai-dashboards.module.d.ts +25 -21
  263. package/dist/ai-dashboards.module.d.ts.map +1 -1
  264. package/dist/ai-dashboards.module.js +25 -3
  265. package/dist/ai-dashboards.module.js.map +1 -1
  266. package/dist/module.d.ts +13 -12
  267. package/dist/module.d.ts.map +1 -1
  268. package/dist/module.js +7 -0
  269. package/dist/module.js.map +1 -1
  270. package/dist/public-api.d.ts +8 -0
  271. package/dist/public-api.d.ts.map +1 -1
  272. package/dist/public-api.js +10 -0
  273. package/dist/public-api.js.map +1 -1
  274. package/dist/shared/action-scheduled-job.d.ts.map +1 -1
  275. package/dist/shared/action-scheduled-job.js +2 -0
  276. package/dist/shared/action-scheduled-job.js.map +1 -1
  277. package/dist/video-studio-dashboards.module.d.ts +40 -0
  278. package/dist/video-studio-dashboards.module.d.ts.map +1 -0
  279. package/dist/video-studio-dashboards.module.js +159 -0
  280. package/dist/video-studio-dashboards.module.js.map +1 -0
  281. package/package.json +77 -71
  282. package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
  283. package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
  284. package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
  285. package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
  286. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
  287. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
  288. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
  289. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
  290. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
  291. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
  292. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
  293. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
@@ -612,11 +612,11 @@ function DataExplorerDashboardComponent_Conditional_15_Template(rf, ctx) { if (r
612
612
  function DataExplorerDashboardComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
613
613
  const _r27 = i0.ɵɵgetCurrentView();
614
614
  i0.ɵɵelementStart(0, "mj-view-workspace", 91);
615
- i0.ɵɵlistener("SelectedViewChange", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_SelectedViewChange_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("ViewSelected", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_ViewSelected_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("OpenViewInTabRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenViewInTabRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("OpenRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceOpenRecord($event)); })("OpenRelatedRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenRelatedRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecordRequested($event)); })("CreateNewRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_CreateNewRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecordRequested($event)); })("RecordSelected", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_RecordSelected_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordSelected($event)); })("AfterViewSave", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_AfterViewSave_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("AfterViewDelete", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_AfterViewDelete_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("FilterTextChanged", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_FilterTextChanged_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterTextChanged($event)); })("DataLoaded", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_DataLoaded_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("FilteredCountChanged", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_FilteredCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilteredCountChanged($event)); });
615
+ i0.ɵɵlistener("SelectedViewChange", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_SelectedViewChange_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("ViewSelected", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_ViewSelected_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("AlternateBaseViewChange", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_AlternateBaseViewChange_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnWorkspaceAlternateBaseViewChanged($event)); })("OpenViewInTabRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenViewInTabRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("OpenRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceOpenRecord($event)); })("OpenRelatedRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_OpenRelatedRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecordRequested($event)); })("CreateNewRecordRequested", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_CreateNewRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecordRequested($event)); })("RecordSelected", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_RecordSelected_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordSelected($event)); })("AfterViewSave", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_AfterViewSave_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("AfterViewDelete", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_AfterViewDelete_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("FilterTextChanged", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_FilterTextChanged_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterTextChanged($event)); })("DataLoaded", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_DataLoaded_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("FilteredCountChanged", function DataExplorerDashboardComponent_Conditional_16_Template_mj_view_workspace_FilteredCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilteredCountChanged($event)); });
616
616
  i0.ɵɵelementEnd();
617
617
  } if (rf & 2) {
618
618
  const ctx_r1 = i0.ɵɵnextContext();
619
- i0.ɵɵproperty("Entity", ctx_r1.selectedEntity)("AutoSaveView", true)("SelectedView", ctx_r1.selectedViewEntity)("FilterText", ctx_r1.debouncedFilterText)("SelectedRecordId", ctx_r1.state.selectedRecordId)("ViewerConfig", ctx_r1.viewerConfig);
619
+ i0.ɵɵproperty("Entity", ctx_r1.selectedEntity)("AutoSaveView", true)("SelectedView", ctx_r1.selectedViewEntity)("AlternateBaseView", ctx_r1.SelectedAlternateBaseView)("FilterText", ctx_r1.debouncedFilterText)("SelectedRecordId", ctx_r1.state.selectedRecordId)("ViewerConfig", ctx_r1.viewerConfig);
620
620
  } }
621
621
  function DataExplorerDashboardComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
622
622
  const _r28 = i0.ɵɵgetCurrentView();
@@ -832,6 +832,11 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
832
832
  loadedRecords = [];
833
833
  // Currently selected view entity (for view data loading)
834
834
  SelectedViewEntity = null;
835
+ /**
836
+ * Optional semantic name of an alternate base view selected via deep link (`?abv=<Name>`)
837
+ * when no saved view is active.
838
+ */
839
+ SelectedAlternateBaseView = null;
835
840
  /** @deprecated Use {@link SelectedViewEntity}. */
836
841
  get selectedViewEntity() {
837
842
  return this.SelectedViewEntity;
@@ -950,6 +955,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
950
955
  // ========================================
951
956
  // Concept D: Application Groups + Search-First
952
957
  // ========================================
958
+ _filteredAppEntityGroupsCache = [];
959
+ _filteredAppEntityGroupsKey = '';
953
960
  /**
954
961
  * Get app entity groups filtered by current entityFilterText and homeViewMode.
955
962
  * When searching, auto-expands groups that contain matches.
@@ -957,9 +964,16 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
957
964
  get FilteredAppEntityGroups() {
958
965
  const filterText = this.EntityFilterText.toLowerCase().trim();
959
966
  const showFavoritesOnly = this.State.homeViewMode === 'favorites';
960
- return this.AppEntityGroups
961
- .map(group => this.filterGroupEntities(group, filterText, showFavoritesOnly))
962
- .filter(group => group.entities.length > 0);
967
+ const expandedSig = this.AppEntityGroups.map(g => `${g.applicationId}:${g.isExpanded ? 1 : 0}:${g.entities.length}`).join('|');
968
+ const favSig = showFavoritesOnly ? this.State.favoriteEntities.map(f => f.entityId).join(',') : '';
969
+ const key = `${filterText}::${showFavoritesOnly ? 1 : 0}::${expandedSig}::${favSig}`;
970
+ if (key !== this._filteredAppEntityGroupsKey) {
971
+ this._filteredAppEntityGroupsKey = key;
972
+ this._filteredAppEntityGroupsCache = this.AppEntityGroups
973
+ .map(group => this.filterGroupEntities(group, filterText, showFavoritesOnly))
974
+ .filter(group => group.entities.length > 0);
975
+ }
976
+ return this._filteredAppEntityGroupsCache;
963
977
  }
964
978
  /** @deprecated Use {@link FilteredAppEntityGroups}. */
965
979
  get filteredAppEntityGroups() {
@@ -985,35 +999,64 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
985
999
  isExpanded: filterText ? true : group.isExpanded
986
1000
  };
987
1001
  }
1002
+ _flatFilteredEntitiesCache = [];
1003
+ _flatFilteredEntitiesSource = null;
1004
+ _flatFilteredEntitiesKey = '';
988
1005
  /**
989
1006
  * Get a flat filtered entity list for single-application mode.
990
1007
  * Used when entityFilter.applicationId is set, bypassing app grouping.
991
1008
  */
992
1009
  get FlatFilteredEntities() {
993
- let result = this.Entities;
994
- if (this.State.homeViewMode === 'favorites') {
995
- result = result.filter(e => this.IsEntityFavorited(e));
996
- }
997
1010
  const filterText = this.EntityFilterText.toLowerCase().trim();
998
- if (filterText) {
999
- result = result.filter(e => e.Name.toLowerCase().includes(filterText) ||
1000
- e.DisplayNameOrName.toLowerCase().includes(filterText) ||
1001
- (e.Description && e.Description.toLowerCase().includes(filterText)));
1011
+ const showFavoritesOnly = this.State.homeViewMode === 'favorites';
1012
+ const favSig = showFavoritesOnly ? this.State.favoriteEntities.map(f => f.entityId).join(',') : '';
1013
+ const key = `${filterText}::${showFavoritesOnly ? 1 : 0}::${favSig}`;
1014
+ if (this._flatFilteredEntitiesSource !== this.Entities || key !== this._flatFilteredEntitiesKey) {
1015
+ this._flatFilteredEntitiesSource = this.Entities;
1016
+ this._flatFilteredEntitiesKey = key;
1017
+ let result = this.Entities;
1018
+ if (showFavoritesOnly) {
1019
+ result = result.filter(e => this.IsEntityFavorited(e));
1020
+ }
1021
+ if (filterText) {
1022
+ result = result.filter(e => e.Name.toLowerCase().includes(filterText) ||
1023
+ e.DisplayNameOrName.toLowerCase().includes(filterText) ||
1024
+ (e.Description && e.Description.toLowerCase().includes(filterText)));
1025
+ }
1026
+ this._flatFilteredEntitiesCache = result;
1002
1027
  }
1003
- return result;
1028
+ return this._flatFilteredEntitiesCache;
1004
1029
  }
1005
1030
  /** @deprecated Use {@link FlatFilteredEntities}. */
1006
1031
  get flatFilteredEntities() {
1007
1032
  return this.FlatFilteredEntities;
1008
1033
  }
1009
1034
  /**
1010
- * Total count of entities matching current filters (across all groups or flat list)
1035
+ * Count of DISTINCT entities matching the current filters (across all groups, or the flat
1036
+ * list in single-application mode).
1037
+ *
1038
+ * Distinct is the whole point. `buildAppEntityGroups` deliberately assigns an entity to
1039
+ * EVERY application it belongs to, so summing `group.entities.length` counts a
1040
+ * multi-application entity once per application. On a stock install that made the header
1041
+ * read "2195 entities" while the sibling label eight lines up the page read
1042
+ * "2134 entities available" — two counts of the same set, on the same screen, differing by
1043
+ * the number of multi-app memberships. Neither number was wrong for what it measured; they
1044
+ * were measuring different things while claiming the same words.
1045
+ *
1046
+ * Both labels now count entities. Membership totals, if ever wanted, belong in a label that
1047
+ * says "memberships".
1011
1048
  */
1012
1049
  get FilteredEntityCount() {
1013
1050
  if (this.EntityFilter?.applicationId) {
1014
1051
  return this.FlatFilteredEntities.length;
1015
1052
  }
1016
- return this.FilteredAppEntityGroups.reduce((sum, g) => sum + g.entities.length, 0);
1053
+ const distinct = new Set();
1054
+ for (const group of this.FilteredAppEntityGroups) {
1055
+ for (const entity of group.entities) {
1056
+ distinct.add(entity.ID);
1057
+ }
1058
+ }
1059
+ return distinct.size;
1017
1060
  }
1018
1061
  /** @deprecated Use {@link FilteredEntityCount}. */
1019
1062
  get filteredEntityCount() {
@@ -1098,33 +1141,42 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1098
1141
  isQuickAccessSectionExpanded(sectionId) {
1099
1142
  return this.IsQuickAccessSectionExpanded(sectionId);
1100
1143
  }
1144
+ _uniqueRecentRecordEntitiesCache = [];
1145
+ _uniqueRecentRecordEntitiesSource = null;
1146
+ _uniqueRecentRecordEntitiesLength = -1;
1101
1147
  /**
1102
1148
  * Get unique entities from recent records for the filter strip.
1103
1149
  * Returns up to 5 entities, sorted by frequency in the recent records.
1104
1150
  */
1105
1151
  get UniqueRecentRecordEntities() {
1106
- const entityCounts = new Map();
1107
- for (const record of this.RecentRecords) {
1108
- const existing = entityCounts.get(record.entityId);
1109
- if (existing) {
1110
- existing.count++;
1111
- }
1112
- else {
1113
- entityCounts.set(record.entityId, {
1114
- entityId: record.entityId,
1115
- entityName: record.entityName,
1116
- count: 1
1117
- });
1152
+ if (this._uniqueRecentRecordEntitiesSource !== this.RecentRecords ||
1153
+ this._uniqueRecentRecordEntitiesLength !== this.RecentRecords.length) {
1154
+ this._uniqueRecentRecordEntitiesSource = this.RecentRecords;
1155
+ this._uniqueRecentRecordEntitiesLength = this.RecentRecords.length;
1156
+ const entityCounts = new Map();
1157
+ for (const record of this.RecentRecords) {
1158
+ const existing = entityCounts.get(record.entityId);
1159
+ if (existing) {
1160
+ existing.count++;
1161
+ }
1162
+ else {
1163
+ entityCounts.set(record.entityId, {
1164
+ entityId: record.entityId,
1165
+ entityName: record.entityName,
1166
+ count: 1
1167
+ });
1168
+ }
1118
1169
  }
1170
+ // Convert to array, sort by count (descending), take first 5
1171
+ this._uniqueRecentRecordEntitiesCache = Array.from(entityCounts.values())
1172
+ .sort((a, b) => b.count - a.count)
1173
+ .slice(0, 5)
1174
+ .map(e => ({
1175
+ ...e,
1176
+ icon: this.GetEntityIconById(e.entityId)
1177
+ }));
1119
1178
  }
1120
- // Convert to array, sort by count (descending), take first 5
1121
- return Array.from(entityCounts.values())
1122
- .sort((a, b) => b.count - a.count)
1123
- .slice(0, 5)
1124
- .map(e => ({
1125
- ...e,
1126
- icon: this.GetEntityIconById(e.entityId)
1127
- }));
1179
+ return this._uniqueRecentRecordEntitiesCache;
1128
1180
  }
1129
1181
  /** @deprecated Use {@link UniqueRecentRecordEntities}. */
1130
1182
  get uniqueRecentRecordEntities() {
@@ -1141,6 +1193,9 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1141
1193
  get showRecentRecordsEntityFilter() {
1142
1194
  return this.ShowRecentRecordsEntityFilter;
1143
1195
  }
1196
+ _filteredRecentRecordsCache = [];
1197
+ _filteredRecentRecordsSource = null;
1198
+ _filteredRecentRecordsFilter = null;
1144
1199
  /**
1145
1200
  * Get filtered recent records based on entity filter.
1146
1201
  */
@@ -1148,7 +1203,13 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1148
1203
  if (!this.RecentRecordsEntityFilter) {
1149
1204
  return this.RecentRecords;
1150
1205
  }
1151
- return this.RecentRecords.filter(r => r.entityId === this.RecentRecordsEntityFilter);
1206
+ if (this._filteredRecentRecordsSource !== this.RecentRecords ||
1207
+ this._filteredRecentRecordsFilter !== this.RecentRecordsEntityFilter) {
1208
+ this._filteredRecentRecordsSource = this.RecentRecords;
1209
+ this._filteredRecentRecordsFilter = this.RecentRecordsEntityFilter;
1210
+ this._filteredRecentRecordsCache = this.RecentRecords.filter(r => r.entityId === this.RecentRecordsEntityFilter);
1211
+ }
1212
+ return this._filteredRecentRecordsCache;
1152
1213
  }
1153
1214
  /** @deprecated Use {@link FilteredRecentRecords}. */
1154
1215
  get filteredRecentRecords() {
@@ -1320,12 +1381,24 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1320
1381
  // etc. without the template ever computing time during change detection. Updating the stored
1321
1382
  // field + running detectChanges here (rather than calling a Date.now()-based method from the
1322
1383
  // template binding) is what prevents the ExpressionChangedAfterItHasBeenCheckedError (NG0100).
1323
- this.recentTimeRefreshTimer = setInterval(() => {
1324
- if (this.RecentRecords.length > 0) {
1325
- this.refreshRecentRecordTimes();
1326
- this.cdr.detectChanges();
1327
- }
1328
- }, 30000);
1384
+ const startTimer = () => {
1385
+ this.recentTimeRefreshTimer = setInterval(() => {
1386
+ if (this.RecentRecords.length > 0 && this.refreshRecentRecordTimes()) {
1387
+ if (this.ngZone) {
1388
+ this.ngZone.run(() => this.cdr.detectChanges());
1389
+ }
1390
+ else {
1391
+ this.cdr.detectChanges();
1392
+ }
1393
+ }
1394
+ }, 30000);
1395
+ };
1396
+ if (this.ngZone) {
1397
+ this.ngZone.runOutsideAngular(startTimer);
1398
+ }
1399
+ else {
1400
+ startTimer();
1401
+ }
1329
1402
  // Subscribe to favorite records changes
1330
1403
  this.StateService.FavoriteRecords
1331
1404
  .pipe(takeUntil(this.destroy$))
@@ -2047,6 +2120,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2047
2120
  this.SelectedEntity = null;
2048
2121
  this.SelectedRecord = null;
2049
2122
  this.DetailPanelEntity = null;
2123
+ this.SelectedAlternateBaseView = null;
2050
2124
  this.StateService.selectEntity(null);
2051
2125
  this.StateService.closeDetailPanel();
2052
2126
  this.cdr.detectChanges();
@@ -2179,7 +2253,14 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2179
2253
  }
2180
2254
  }
2181
2255
  /**
2182
- * Load entity IDs associated with a specific application
2256
+ * Load entity IDs associated with a specific application.
2257
+ *
2258
+ * `IgnoreMaxRows` is required, not an optimization. This set is the membership
2259
+ * filter for the whole surface: an entity missing from it is not merely unlisted,
2260
+ * it is unreachable — the tree hides it and the search box cannot find it. Under
2261
+ * the default row cap an application with more than the cap's worth of entities
2262
+ * silently returns a truncated set, and the UI shows the truncation as fact with
2263
+ * nothing to indicate rows were dropped. Read every row or report nothing.
2183
2264
  */
2184
2265
  async loadApplicationEntityIds(applicationId) {
2185
2266
  this.applicationEntityIds.clear();
@@ -2187,7 +2268,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2187
2268
  const result = await rv.RunView({
2188
2269
  EntityName: 'MJ: Application Entities',
2189
2270
  ExtraFilter: `ApplicationID = '${applicationId}'`,
2190
- ResultType: 'entity_object'
2271
+ ResultType: 'entity_object',
2272
+ IgnoreMaxRows: true
2191
2273
  });
2192
2274
  if (result.Success && result.Results) {
2193
2275
  for (const appEntity of result.Results) {
@@ -2241,6 +2323,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2241
2323
  // state would leak into the new entity's query (e.g., ORDER BY FirstName on Groups).
2242
2324
  // The workspace resets its own view/grid state when its [Entity] input changes.
2243
2325
  this.SelectedViewEntity = null;
2326
+ this.SelectedAlternateBaseView = null;
2244
2327
  this.SelectedEntity = entity;
2245
2328
  this.reconcileViewModeForEntity(entity);
2246
2329
  this.StateService.selectEntity(entity.Name);
@@ -2297,6 +2380,9 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2297
2380
  */
2298
2381
  OnWorkspaceViewSelected(view) {
2299
2382
  this.SelectedViewEntity = view;
2383
+ if (view) {
2384
+ this.SelectedAlternateBaseView = null;
2385
+ }
2300
2386
  this.StateService.selectView(view?.ID ?? null);
2301
2387
  if (view && view.SmartFilterEnabled && view.SmartFilterPrompt) {
2302
2388
  this.StateService.setSmartFilterPrompt(view.SmartFilterPrompt);
@@ -2313,6 +2399,14 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2313
2399
  onWorkspaceViewSelected(view) {
2314
2400
  return this.OnWorkspaceViewSelected(view);
2315
2401
  }
2402
+ /**
2403
+ * Handle an Alternate Base View selection emitted by the workspace's view selector.
2404
+ */
2405
+ OnWorkspaceAlternateBaseViewChanged(abv) {
2406
+ this.SelectedAlternateBaseView = abv;
2407
+ this.pushCurrentStateToUrl();
2408
+ this.cdr.detectChanges();
2409
+ }
2316
2410
  /**
2317
2411
  * Handle the workspace's "open view in tab" request — route via NavigationService.
2318
2412
  */
@@ -2714,7 +2808,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2714
2808
  EntityName: entityName,
2715
2809
  ExtraFilter: CompositeKey.FromURLSegment(entityInfo, recordId).ToWhereClause(),
2716
2810
  ResultType: 'simple',
2717
- MaxRows: 1
2811
+ MaxRows: 1,
2812
+ SkipTotalRowCount: true
2718
2813
  });
2719
2814
  if (result.Success && result.Results.length > 0) {
2720
2815
  this.ngZone.run(() => {
@@ -2797,6 +2892,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2797
2892
  // Reset counts before setting entity to prevent stale data display
2798
2893
  this.resetRecordCounts();
2799
2894
  this.SelectedEntity = entity;
2895
+ this.SelectedAlternateBaseView = deepLink.abv || null;
2800
2896
  this.StateService.selectEntity(entity.Name);
2801
2897
  // Apply filter if specified (to smart filter state, not user search)
2802
2898
  if (deepLink.filter) {
@@ -2850,6 +2946,10 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2850
2946
  // ========================================
2851
2947
  // HELPERS
2852
2948
  // ========================================
2949
+ _allowedEntityNamesCache = null;
2950
+ _allowedEntityNamesFilterSource = null;
2951
+ _allowedEntityNamesEntitiesSource = null;
2952
+ _allowedEntityNamesEntitiesLen = -1;
2853
2953
  /**
2854
2954
  * Get the set of allowed entity names for filtering favorites/recents.
2855
2955
  * Returns null if no filter is active (all entities allowed).
@@ -2858,7 +2958,16 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2858
2958
  if (!this.EntityFilter) {
2859
2959
  return null;
2860
2960
  }
2861
- return new Set(this.Entities.map(e => e.Name));
2961
+ if (this._allowedEntityNamesFilterSource !== this.EntityFilter ||
2962
+ this._allowedEntityNamesEntitiesSource !== this.Entities ||
2963
+ this._allowedEntityNamesEntitiesLen !== this.Entities.length ||
2964
+ this._allowedEntityNamesCache === null) {
2965
+ this._allowedEntityNamesFilterSource = this.EntityFilter;
2966
+ this._allowedEntityNamesEntitiesSource = this.Entities;
2967
+ this._allowedEntityNamesEntitiesLen = this.Entities.length;
2968
+ this._allowedEntityNamesCache = new Set(this.Entities.map(e => e.Name));
2969
+ }
2970
+ return this._allowedEntityNamesCache;
2862
2971
  }
2863
2972
  /** @deprecated Use {@link AllowedEntityNames}. */
2864
2973
  get allowedEntityNames() {
@@ -2920,7 +3029,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2920
3029
  const record = params['record'] || null;
2921
3030
  const filterParam = params['filter'] || null;
2922
3031
  const viewId = params['viewId'] || null;
2923
- if (!entity && !record && !filterParam && !viewId) {
3032
+ const abv = params['abv'] || null;
3033
+ if (!entity && !record && !filterParam && !viewId && !abv) {
2924
3034
  return null;
2925
3035
  }
2926
3036
  // ViewTypeID-only: the active view type is persisted via UserView.ViewTypeID / per-user settings
@@ -2929,7 +3039,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2929
3039
  entity: entity || undefined,
2930
3040
  record: record || undefined,
2931
3041
  filter: filterParam || undefined,
2932
- viewId: viewId || undefined
3042
+ viewId: viewId || undefined,
3043
+ abv: abv || undefined
2933
3044
  };
2934
3045
  }
2935
3046
  /**
@@ -2977,7 +3088,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2977
3088
  entity: this.State.selectedEntityName || null,
2978
3089
  record: (this.State.selectedRecordId && hasEntity) ? this.State.selectedRecordId : null,
2979
3090
  filter: null, // Never in URL — filters live in saved views (DB), not query strings
2980
- viewId: hasViewId ? this.State.selectedViewId : null
3091
+ viewId: hasViewId ? this.State.selectedViewId : null,
3092
+ abv: (!hasViewId && hasEntity && this.SelectedAlternateBaseView) ? this.SelectedAlternateBaseView : null
2981
3093
  };
2982
3094
  this.UpdateQueryParams(queryParams);
2983
3095
  }
@@ -2992,6 +3104,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2992
3104
  const entity = this.Entities.find(e => e.Name.toLowerCase() === urlState.entity.toLowerCase());
2993
3105
  if (entity) {
2994
3106
  const entityChanged = this.SelectedEntity?.Name !== entity.Name;
3107
+ const previousAbv = this.SelectedAlternateBaseView;
3108
+ this.SelectedAlternateBaseView = urlState.viewId ? null : (urlState.abv || null);
2995
3109
  if (entityChanged) {
2996
3110
  // Entity changed - reset counts and select new entity
2997
3111
  this.resetRecordCounts();
@@ -3015,6 +3129,9 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3015
3129
  this.StateService.selectView(null);
3016
3130
  }
3017
3131
  }
3132
+ if (!entityChanged && previousAbv !== this.SelectedAlternateBaseView) {
3133
+ this.pushCurrentStateToUrl();
3134
+ }
3018
3135
  // Filters live in saved views (DB), never in URL query strings.
3019
3136
  // Clear smart filter on entity change when no specific view is selected.
3020
3137
  if (entityChanged && !urlState.viewId) {
@@ -3397,9 +3514,15 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3397
3514
  * record set loads and on a timer so the labels stay current.
3398
3515
  */
3399
3516
  refreshRecentRecordTimes() {
3517
+ let changed = false;
3400
3518
  for (const record of this.RecentRecords) {
3401
- record.relativeTime = this.formatRelativeTime(record.latestAt);
3519
+ const next = this.formatRelativeTime(record.latestAt);
3520
+ if (record.relativeTime !== next) {
3521
+ record.relativeTime = next;
3522
+ changed = true;
3523
+ }
3402
3524
  }
3525
+ return changed;
3403
3526
  }
3404
3527
  /**
3405
3528
  * Format relative time for display (e.g., "2 hours ago").
@@ -3459,7 +3582,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3459
3582
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.ViewWorkspaceRef = _t.first);
3460
3583
  } }, hostBindings: function DataExplorerDashboardComponent_HostBindings(rf, ctx) { if (rf & 1) {
3461
3584
  i0.ɵɵlistener("keydown", function DataExplorerDashboardComponent_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument);
3462
- } }, inputs: { EntityFilter: "EntityFilter", entityFilter: "entityFilter", DeepLink: "DeepLink", deepLink: "deepLink", ContextName: "ContextName", contextName: "contextName", ContextIcon: "ContextIcon", contextIcon: "contextIcon", InitialQueryParams: "InitialQueryParams", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 18, vars: 13, consts: [["filterInput", ""], [1, "data-explorer-container"], [1, "navigation-panel", 3, "collapsed", "width"], [1, "content-area"], [1, "breadcrumb-bar"], [1, "content-header"], [1, "header-left"], [1, "header-center"], [1, "smart-filter-container"], [1, "header-right"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "active"], ["role", "status", 1, "dx-moved-banner", 3, "panel-open"], [1, "content-body"], [1, "home-view-concept-d"], [3, "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel", 3, "width"], [1, "navigation-panel"], [3, "entitySelected", "toggleCollapse", "sectionToggled", "openRecord", "selectRecord", "expandAndFocus", "entities", "appEntityGroups", "selectedEntityName", "favorites", "recentItems", "collapsed", "allowedEntityNames", "favoritesSectionExpanded", "recentSectionExpanded", "entitiesSectionExpanded", "viewsSectionExpanded"], [1, "breadcrumb-item", 3, "click", "title"], [1, "breadcrumb-icon", 3, "class"], [1, "breadcrumb-label"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "breadcrumb-icon"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "entity-icon", 3, "class"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", "placeholder", "Filter records... (press / to focus)", 1, "smart-filter-input", 3, "input", "value"], [1, "clear-filter-btn"], [1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "qa-badge"], ["role", "status", 1, "dx-moved-banner"], ["aria-hidden", "true", 1, "fa-solid", "fa-gauge-high"], ["mjButton", "", "size", "sm", 3, "click"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "loading-state"], ["text", "Loading your data...", "size", "medium"], [1, "home-main-area"], [1, "search-hero"], [1, "search-hero-container"], [1, "fa-solid", "fa-magnifying-glass", "search-hero-icon"], ["type", "text", "placeholder", "Search your data...", 1, "search-hero-input", 3, "ngModelChange", "ngModel"], [1, "search-hero-clear"], [1, "search-hero-shortcut"], [1, "search-meta-row"], [1, "search-entity-count"], [1, "pill-toggle"], [1, "pill-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "entity-groups-area"], [1, "entity-item-grid"], ["Variant", "no-results", "Title", "No matches found", 3, "Message"], ["Icon", "fa-solid fa-database", "Title", "Nothing here yet", "Message", "This app doesn't have any data set up yet. An administrator can add data for you to explore here."], [1, "quick-access-panel"], [1, "qa-header"], [1, "qa-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "qa-body"], [3, "ExpandedChange", "Expanded"], ["mjAccordionTitle", ""], [1, "qa-item"], [1, "qa-empty"], [1, "search-hero-clear", 3, "click"], [1, "entity-item", 3, "title"], [1, "entity-item", 3, "click", "title"], [1, "entity-item-icon"], [1, "entity-item-text"], [1, "entity-item-name"], [1, "entity-item-desc"], [1, "entity-item-fav", 3, "click", "title"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-group-icon"], [1, "app-group-name"], [1, "app-group-count"], [1, "fa-solid", "fa-chevron-right", "app-group-chevron"], [1, "app-group-entities"], [1, "fa-solid", "fa-clock-rotate-left", "qa-section-icon"], [1, "mj-accordion-badge", "mj-accordion-badge--right"], [1, "qa-item", 3, "click"], [1, "qa-item-icon"], [1, "qa-item-info"], [1, "qa-item-name"], [1, "qa-item-meta"], [1, "qa-item-time"], [1, "fa-solid", "fa-table", "qa-section-icon"], [1, "fa-solid", "fa-star", "qa-section-icon", 2, "color", "var(--mj-status-warning)"], [3, "SelectedViewChange", "ViewSelected", "OpenViewInTabRequested", "OpenRecordRequested", "OpenRelatedRecordRequested", "CreateNewRecordRequested", "RecordSelected", "AfterViewSave", "AfterViewDelete", "FilterTextChanged", "DataLoaded", "FilteredCountChanged", "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel"], [3, "close", "openRecord", "navigateToRelated", "openRelatedRecord", "openForeignKeyRecord", "entity", "record"]], template: function DataExplorerDashboardComponent_Template(rf, ctx) { if (rf & 1) {
3585
+ } }, inputs: { EntityFilter: "EntityFilter", entityFilter: "entityFilter", DeepLink: "DeepLink", deepLink: "deepLink", ContextName: "ContextName", contextName: "contextName", ContextIcon: "ContextIcon", contextIcon: "contextIcon", InitialQueryParams: "InitialQueryParams", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 18, vars: 13, consts: [["filterInput", ""], [1, "data-explorer-container"], [1, "navigation-panel", 3, "collapsed", "width"], [1, "content-area"], [1, "breadcrumb-bar"], [1, "content-header"], [1, "header-left"], [1, "header-center"], [1, "smart-filter-container"], [1, "header-right"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "active"], ["role", "status", 1, "dx-moved-banner", 3, "panel-open"], [1, "content-body"], [1, "home-view-concept-d"], [3, "Entity", "AutoSaveView", "SelectedView", "AlternateBaseView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel", 3, "width"], [1, "navigation-panel"], [3, "entitySelected", "toggleCollapse", "sectionToggled", "openRecord", "selectRecord", "expandAndFocus", "entities", "appEntityGroups", "selectedEntityName", "favorites", "recentItems", "collapsed", "allowedEntityNames", "favoritesSectionExpanded", "recentSectionExpanded", "entitiesSectionExpanded", "viewsSectionExpanded"], [1, "breadcrumb-item", 3, "click", "title"], [1, "breadcrumb-icon", 3, "class"], [1, "breadcrumb-label"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "breadcrumb-icon"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "entity-icon", 3, "class"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", "placeholder", "Filter records... (press / to focus)", 1, "smart-filter-input", 3, "input", "value"], [1, "clear-filter-btn"], [1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "qa-badge"], ["role", "status", 1, "dx-moved-banner"], ["aria-hidden", "true", 1, "fa-solid", "fa-gauge-high"], ["mjButton", "", "size", "sm", 3, "click"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "loading-state"], ["text", "Loading your data...", "size", "medium"], [1, "home-main-area"], [1, "search-hero"], [1, "search-hero-container"], [1, "fa-solid", "fa-magnifying-glass", "search-hero-icon"], ["type", "text", "placeholder", "Search your data...", 1, "search-hero-input", 3, "ngModelChange", "ngModel"], [1, "search-hero-clear"], [1, "search-hero-shortcut"], [1, "search-meta-row"], [1, "search-entity-count"], [1, "pill-toggle"], [1, "pill-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "entity-groups-area"], [1, "entity-item-grid"], ["Variant", "no-results", "Title", "No matches found", 3, "Message"], ["Icon", "fa-solid fa-database", "Title", "Nothing here yet", "Message", "This app doesn't have any data set up yet. An administrator can add data for you to explore here."], [1, "quick-access-panel"], [1, "qa-header"], [1, "qa-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "qa-body"], [3, "ExpandedChange", "Expanded"], ["mjAccordionTitle", ""], [1, "qa-item"], [1, "qa-empty"], [1, "search-hero-clear", 3, "click"], [1, "entity-item", 3, "title"], [1, "entity-item", 3, "click", "title"], [1, "entity-item-icon"], [1, "entity-item-text"], [1, "entity-item-name"], [1, "entity-item-desc"], [1, "entity-item-fav", 3, "click", "title"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-group-icon"], [1, "app-group-name"], [1, "app-group-count"], [1, "fa-solid", "fa-chevron-right", "app-group-chevron"], [1, "app-group-entities"], [1, "fa-solid", "fa-clock-rotate-left", "qa-section-icon"], [1, "mj-accordion-badge", "mj-accordion-badge--right"], [1, "qa-item", 3, "click"], [1, "qa-item-icon"], [1, "qa-item-info"], [1, "qa-item-name"], [1, "qa-item-meta"], [1, "qa-item-time"], [1, "fa-solid", "fa-table", "qa-section-icon"], [1, "fa-solid", "fa-star", "qa-section-icon", 2, "color", "var(--mj-status-warning)"], [3, "SelectedViewChange", "ViewSelected", "AlternateBaseViewChange", "OpenViewInTabRequested", "OpenRecordRequested", "OpenRelatedRecordRequested", "CreateNewRecordRequested", "RecordSelected", "AfterViewSave", "AfterViewDelete", "FilterTextChanged", "DataLoaded", "FilteredCountChanged", "Entity", "AutoSaveView", "SelectedView", "AlternateBaseView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel"], [3, "close", "openRecord", "navigateToRelated", "openRelatedRecord", "openForeignKeyRecord", "entity", "record"]], template: function DataExplorerDashboardComponent_Template(rf, ctx) { if (rf & 1) {
3463
3586
  i0.ɵɵelementStart(0, "div", 1);
3464
3587
  i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_1_Template, 2, 16, "div", 2);
3465
3588
  i0.ɵɵelementStart(2, "div", 3);
@@ -3476,7 +3599,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3476
3599
  i0.ɵɵelementEnd()();
3477
3600
  i0.ɵɵconditionalCreate(13, DataExplorerDashboardComponent_Conditional_13_Template, 10, 2, "div", 11);
3478
3601
  i0.ɵɵelementStart(14, "div", 12);
3479
- i0.ɵɵconditionalCreate(15, DataExplorerDashboardComponent_Conditional_15_Template, 3, 1, "div", 13)(16, DataExplorerDashboardComponent_Conditional_16_Template, 1, 6, "mj-view-workspace", 14);
3602
+ i0.ɵɵconditionalCreate(15, DataExplorerDashboardComponent_Conditional_15_Template, 3, 1, "div", 13)(16, DataExplorerDashboardComponent_Conditional_16_Template, 1, 7, "mj-view-workspace", 14);
3480
3603
  i0.ɵɵelementEnd()();
3481
3604
  i0.ɵɵconditionalCreate(17, DataExplorerDashboardComponent_Conditional_17_Template, 2, 4, "div", 15);
3482
3605
  i0.ɵɵelementEnd();
@@ -3503,7 +3626,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3503
3626
  i0.ɵɵconditional(!ctx.selectedEntity ? 15 : 16);
3504
3627
  i0.ɵɵadvance(2);
3505
3628
  i0.ɵɵconditional(ctx.state.detailPanelOpen && ctx.selectedRecord ? 17 : -1);
3506
- } }, dependencies: [i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MJEmptyStateComponent, i4.MJAccordionPanelComponent, i4.MJAccordionTitleDirective, i4.MJButtonDirective, i5.EntityRecordDetailPanelComponent, i5.ViewWorkspaceComponent, i2.LoadingComponent, i6.NavigationPanelComponent, i7.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; \n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n display: flex;\n flex: 1 1 0%;\n overflow: hidden;\n \n\n\n\n\n\n\n\n isolation: isolate;\n position: relative; \n z-index: 3; \n}\n\n\n\n\n\n\n.dx-moved-banner[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 12px 24px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n font-size: 13px;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n.content-header.home-header[_ngcontent-%COMP%] + .dx-moved-banner[_ngcontent-%COMP%] {\n margin-top: 0;\n}\n\n\n.dx-moved-banner.panel-open[_ngcontent-%COMP%] {\n margin-right: 344px;\n}\n\n\n.dx-moved-banner[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1 1 200px;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-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.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px;\n right: 0;\n width: 320px;\n height: calc(100% - 60px);\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n \n .dx-moved-banner.panel-open[_ngcontent-%COMP%] {\n margin-right: 24px;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n \n .content-header[_ngcontent-%COMP%]:not(.home-header) + .dx-moved-banner[_ngcontent-%COMP%] {\n margin-left: 16px;\n margin-right: 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
3629
+ } }, dependencies: [i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MJEmptyStateComponent, i4.MJAccordionPanelComponent, i4.MJAccordionTitleDirective, i4.MJButtonDirective, i5.EntityRecordDetailPanelComponent, i5.ViewWorkspaceComponent, i2.LoadingComponent, i6.NavigationPanelComponent, i7.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n \n\n isolation: isolate;\n position: relative;\n z-index: 1;\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n display: flex;\n flex: 1 1 0%;\n overflow: hidden;\n \n\n\n\n\n position: relative;\n}\n\n\n\n\n\n\n.dx-moved-banner[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 12px 24px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n font-size: 13px;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n.content-header.home-header[_ngcontent-%COMP%] + .dx-moved-banner[_ngcontent-%COMP%] {\n margin-top: 0;\n}\n\n\n.dx-moved-banner.panel-open[_ngcontent-%COMP%] {\n margin-right: 344px;\n}\n\n\n.dx-moved-banner[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1 1 200px;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-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.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px;\n right: 0;\n width: 320px;\n height: calc(100% - 60px);\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n \n .dx-moved-banner.panel-open[_ngcontent-%COMP%] {\n margin-right: 24px;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n \n .content-header[_ngcontent-%COMP%]:not(.home-header) + .dx-moved-banner[_ngcontent-%COMP%] {\n margin-left: 16px;\n margin-right: 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
3507
3630
  trigger('slideInLeft', [
3508
3631
  transition(':enter', [
3509
3632
  style({ transform: 'translateX(-100%)', opacity: 0 }),
@@ -3531,7 +3654,7 @@ export { DataExplorerDashboardComponent };
3531
3654
  animate('200ms ease-in', style({ transform: 'translateX(-100%)', opacity: 0 }))
3532
3655
  ])
3533
3656
  ])
3534
- ], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View selector + view header now live inside mj-view-workspace (below). -->\n <!-- Add-to-List is now owned inside the grid plug-in renderer (it hosts its own dialog). -->\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} record types available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-type switcher AND all view-specific controls (timeline date/orientation/sort,\n map render mode, etc.) now live inside the plug-in renderers hosted by\n mj-view-workspace. Nothing view-type-specific lives in this header anymore. -->\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Dashboards moved banner: shows with or without a selected entity.\n panel-open makes room for the Quick Access panel, which shows only on the loaded home view. -->\n @if (ShowDashboardsMovedBanner) {\n <div class=\"dx-moved-banner\" role=\"status\"\n [class.panel-open]=\"State.quickAccessPanelOpen && !SelectedEntity && !IsLoadingEntities\">\n <i class=\"fa-solid fa-gauge-high\" aria-hidden=\"true\"></i>\n <span><b>Dashboards moved.</b> They now live in the Dashboards app.</span>\n <button mjButton size=\"sm\" (click)=\"OpenDashboardsApp()\">Open Dashboards</button>\n <button mjButton size=\"sm\" variant=\"flat\" (click)=\"DismissDashboardsMovedBanner()\">Got it</button>\n </div>\n }\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading your data...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search your data...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} record types\n @if (applicationCount > 0) {\n across {{ applicationCount }} apps\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Data\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <mj-empty-state Variant=\"no-results\"\n Title=\"No matches found\"\n [Message]=\"NoEntityResultsMessage\" />\n }\n @if (entities.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-database\"\n Title=\"Nothing here yet\"\n Message=\"This app doesn't have any data set up yet. An administrator can add data for you to explore here.\" />\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('recentRecords')\" (ExpandedChange)=\"toggleQuickAccessSection('recentRecords')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessRecentRecords.length }}</span>\n </ng-template>\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ getEntityDisplayName(record.entityName) }}</div>\n </div>\n <span class=\"qa-item-time\">{{ record.relativeTime }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </mj-accordion-panel>\n\n <!-- Recent Entities (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('recentEntities')\" (ExpandedChange)=\"toggleQuickAccessSection('recentEntities')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Record Types</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessRecentEntities.length }}</span>\n </ng-template>\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent record types</div>\n }\n </mj-accordion-panel>\n\n <!-- Favorite Records (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('favoriteRecords')\" (ExpandedChange)=\"toggleQuickAccessSection('favoriteRecords')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessFavoriteRecords.length }}</span>\n </ng-template>\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ getEntityDisplayName(record.entityName) }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </mj-accordion-panel>\n </div>\n </div>\n }\n </div>\n } @else {\n <!--\n mj-view-workspace owns the saved-view lifecycle (select / save / duplicate / rename /\n delete / revert / quick-save) and the inner data renderer. Every view type is now a\n self-contained plug-in: view-type-specific features (export / add-to-list / delete /\n grid-state / timeline + map controls) live INSIDE the plug-in renderers and no longer\n bubble through the workspace. The dashboard only handles navigation (open record / open\n related record / create new record) + the generic filter/data-load/count signals + URL\n and view-CRUD state sync. AutoSaveView=true \u2192 the workspace persists view CRUD itself.\n -->\n <mj-view-workspace\n [Entity]=\"selectedEntity\"\n [AutoSaveView]=\"true\"\n [SelectedView]=\"selectedViewEntity\"\n [FilterText]=\"debouncedFilterText\"\n [SelectedRecordId]=\"state.selectedRecordId\"\n [ViewerConfig]=\"viewerConfig\"\n (SelectedViewChange)=\"onWorkspaceViewSelected($event)\"\n (ViewSelected)=\"onWorkspaceViewSelected($event)\"\n (OpenViewInTabRequested)=\"onOpenInTabRequested($event)\"\n (OpenRecordRequested)=\"onWorkspaceOpenRecord($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\"\n (CreateNewRecordRequested)=\"onCreateNewRecordRequested($event)\"\n (RecordSelected)=\"onViewerRecordSelected($event)\"\n (AfterViewSave)=\"onWorkspaceViewSaved()\"\n (AfterViewDelete)=\"onWorkspaceViewSaved()\"\n (FilterTextChanged)=\"onFilterTextChanged($event)\"\n (DataLoaded)=\"onDataLoaded($event)\"\n (FilteredCountChanged)=\"onFilteredCountChanged($event)\">\n </mj-view-workspace>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View config panel, filter dialog, quick-save/duplicate/shared-view-warning dialogs\n now live inside mj-view-workspace (the saved-view lifecycle moved there).\n Export + Add-to-List dialogs now live inside the grid plug-in renderer (it hosts its own\n Generic dialogs), so they are no longer rendered at the dashboard level. -->\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; /* Above sibling .content-body so header dropdowns render on top of grid/map content */\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n display: flex;\n flex: 1 1 0%;\n overflow: hidden;\n /* Contain the body's stacking context. The view components inside (grid\n option menus, the map's Leaflet panes/toolbar, etc.) use z-index values up\n to ~1000; .content-header sits at z-index 2 (kept below the shell header \u2014\n see #2701). Without this, those body z-indices leak into the shared context\n and paint over the header's own dropdowns (view-selector, date-field).\n `isolation: isolate` flattens all body z-indices into one context beneath\n the header. Safe because modals + the detail panel render at the dashboard\n root (outside .content-body), so they still overlay everything. */\n isolation: isolate;\n position: relative; /* added */\n z-index: 3; /* added \u2014 higher than .content-header's z-index: 2 */\n}\n\n/* ============================================\n DASHBOARDS MOVED BANNER\n ============================================ */\n\n/* Sits between .content-header and .content-body in the .content-area column. Side margins line up with the header text. */\n.dx-moved-banner {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 12px 24px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n font-size: 13px;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* The home header has no bottom border and ends with its own padding. */\n.content-header.home-header + .dx-moved-banner {\n margin-top: 0;\n}\n\n/* The open Quick Access panel covers the right 320px, so the banner ends 24px before it. */\n.dx-moved-banner.panel-open {\n margin-right: 344px;\n}\n\n/* The text fills the free space. When less than 200px is free, the buttons go to a second line. */\n.dx-moved-banner span {\n flex: 1 1 200px;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 60px;\n right: 0;\n width: 320px;\n height: calc(100% - 60px);\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n\n /* The Quick Access panel covers the full width here, so the banner keeps its normal margin. */\n .dx-moved-banner.panel-open {\n margin-right: 24px;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n /* The entity header has 16px side padding here. The home header keeps 24px. */\n .content-header:not(.home-header) + .dx-moved-banner {\n margin-left: 16px;\n margin-right: 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
3657
+ ], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View selector + view header now live inside mj-view-workspace (below). -->\n <!-- Add-to-List is now owned inside the grid plug-in renderer (it hosts its own dialog). -->\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} record types available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-type switcher AND all view-specific controls (timeline date/orientation/sort,\n map render mode, etc.) now live inside the plug-in renderers hosted by\n mj-view-workspace. Nothing view-type-specific lives in this header anymore. -->\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Dashboards moved banner: shows with or without a selected entity.\n panel-open makes room for the Quick Access panel, which shows only on the loaded home view. -->\n @if (ShowDashboardsMovedBanner) {\n <div class=\"dx-moved-banner\" role=\"status\"\n [class.panel-open]=\"State.quickAccessPanelOpen && !SelectedEntity && !IsLoadingEntities\">\n <i class=\"fa-solid fa-gauge-high\" aria-hidden=\"true\"></i>\n <span><b>Dashboards moved.</b> They now live in the Dashboards app.</span>\n <button mjButton size=\"sm\" (click)=\"OpenDashboardsApp()\">Open Dashboards</button>\n <button mjButton size=\"sm\" variant=\"flat\" (click)=\"DismissDashboardsMovedBanner()\">Got it</button>\n </div>\n }\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading your data...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search your data...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} record types\n @if (applicationCount > 0) {\n across {{ applicationCount }} apps\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Data\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <mj-empty-state Variant=\"no-results\"\n Title=\"No matches found\"\n [Message]=\"NoEntityResultsMessage\" />\n }\n @if (entities.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-database\"\n Title=\"Nothing here yet\"\n Message=\"This app doesn't have any data set up yet. An administrator can add data for you to explore here.\" />\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('recentRecords')\" (ExpandedChange)=\"toggleQuickAccessSection('recentRecords')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessRecentRecords.length }}</span>\n </ng-template>\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ getEntityDisplayName(record.entityName) }}</div>\n </div>\n <span class=\"qa-item-time\">{{ record.relativeTime }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </mj-accordion-panel>\n\n <!-- Recent Entities (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('recentEntities')\" (ExpandedChange)=\"toggleQuickAccessSection('recentEntities')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Record Types</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessRecentEntities.length }}</span>\n </ng-template>\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent record types</div>\n }\n </mj-accordion-panel>\n\n <!-- Favorite Records (max 3) -->\n <mj-accordion-panel [Expanded]=\"isQuickAccessSectionExpanded('favoriteRecords')\" (ExpandedChange)=\"toggleQuickAccessSection('favoriteRecords')\">\n <ng-template mjAccordionTitle>\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ quickAccessFavoriteRecords.length }}</span>\n </ng-template>\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ getEntityDisplayName(record.entityName) }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </mj-accordion-panel>\n </div>\n </div>\n }\n </div>\n } @else {\n <!--\n mj-view-workspace owns the saved-view lifecycle (select / save / duplicate / rename /\n delete / revert / quick-save) and the inner data renderer. Every view type is now a\n self-contained plug-in: view-type-specific features (export / add-to-list / delete /\n grid-state / timeline + map controls) live INSIDE the plug-in renderers and no longer\n bubble through the workspace. The dashboard only handles navigation (open record / open\n related record / create new record) + the generic filter/data-load/count signals + URL\n and view-CRUD state sync. AutoSaveView=true \u2192 the workspace persists view CRUD itself.\n -->\n <mj-view-workspace\n [Entity]=\"selectedEntity\"\n [AutoSaveView]=\"true\"\n [SelectedView]=\"selectedViewEntity\"\n [AlternateBaseView]=\"SelectedAlternateBaseView\"\n [FilterText]=\"debouncedFilterText\"\n [SelectedRecordId]=\"state.selectedRecordId\"\n [ViewerConfig]=\"viewerConfig\"\n (SelectedViewChange)=\"onWorkspaceViewSelected($event)\"\n (ViewSelected)=\"onWorkspaceViewSelected($event)\"\n (AlternateBaseViewChange)=\"OnWorkspaceAlternateBaseViewChanged($event)\"\n (OpenViewInTabRequested)=\"onOpenInTabRequested($event)\"\n (OpenRecordRequested)=\"onWorkspaceOpenRecord($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\"\n (CreateNewRecordRequested)=\"onCreateNewRecordRequested($event)\"\n (RecordSelected)=\"onViewerRecordSelected($event)\"\n (AfterViewSave)=\"onWorkspaceViewSaved()\"\n (AfterViewDelete)=\"onWorkspaceViewSaved()\"\n (FilterTextChanged)=\"onFilterTextChanged($event)\"\n (DataLoaded)=\"onDataLoaded($event)\"\n (FilteredCountChanged)=\"onFilteredCountChanged($event)\">\n </mj-view-workspace>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View config panel, filter dialog, quick-save/duplicate/shared-view-warning dialogs\n now live inside mj-view-workspace (the saved-view lifecycle moved there).\n Export + Add-to-List dialogs now live inside the grid plug-in renderer (it hosts its own\n Generic dialogs), so they are no longer rendered at the dashboard level. -->\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n /* Isolate the navigation panel stacking context so its internal .collapse-toggle\n (z-index: 10) never leaks out above .content-body or full-screen dialogs. */\n isolation: isolate;\n position: relative;\n z-index: 1;\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n display: flex;\n flex: 1 1 0%;\n overflow: hidden;\n /* Intentionally no z-index or isolation here: .content-header sits at z-index: 2\n above normal body content, .dynamic-view-host isolates plug-in renderers such as\n Leaflet (whose internal controls reach z-index: 1000) at z-index: 1, and full-screen\n modal overlays (--mj-z-modal) hosted inside mj-view-workspace or mj-entity-data-grid\n can escape above .content-header without being trapped. */\n position: relative;\n}\n\n/* ============================================\n DASHBOARDS MOVED BANNER\n ============================================ */\n\n/* Sits between .content-header and .content-body in the .content-area column. Side margins line up with the header text. */\n.dx-moved-banner {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n margin: 12px 24px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n font-size: 13px;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* The home header has no bottom border and ends with its own padding. */\n.content-header.home-header + .dx-moved-banner {\n margin-top: 0;\n}\n\n/* The open Quick Access panel covers the right 320px, so the banner ends 24px before it. */\n.dx-moved-banner.panel-open {\n margin-right: 344px;\n}\n\n/* The text fills the free space. When less than 200px is free, the buttons go to a second line. */\n.dx-moved-banner span {\n flex: 1 1 200px;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 60px;\n right: 0;\n width: 320px;\n height: calc(100% - 60px);\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n\n /* The Quick Access panel covers the full width here, so the banner keeps its normal margin. */\n .dx-moved-banner.panel-open {\n margin-right: 24px;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n /* The entity header has 16px side padding here. The home header keeps 24px. */\n .content-header:not(.home-header) + .dx-moved-banner {\n margin-left: 16px;\n margin-right: 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
3535
3658
  }], () => [{ type: i1.ExplorerStateService }, { type: i0.ChangeDetectorRef }, { type: i2.RecentAccessService }, { type: i0.NgZone }], { FilterInputRef: [{
3536
3659
  type: ViewChild,
3537
3660
  args: ['filterInput']