@edvak99/voice-receptionist-widget 1.1.12 → 1.1.13

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 (74) hide show
  1. package/README.md +23 -14
  2. package/fesm2022/{edvak99-voice-receptionist-widget-activities-page.component-CACfxM4x.mjs → edvak99-voice-receptionist-widget-activities-page.component-Br2Vi1Im.mjs} +3 -4
  3. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-Br2Vi1Im.mjs.map +1 -0
  4. package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-Dj9vw97B.mjs → edvak99-voice-receptionist-widget-analytics-page.component-CglgGV6H.mjs} +2 -3
  5. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CglgGV6H.mjs.map +1 -0
  6. package/fesm2022/edvak99-voice-receptionist-widget-api-log.util-C0TOKF1q.mjs.map +1 -1
  7. package/fesm2022/{edvak99-voice-receptionist-widget-api-logs-page.component-CwXaCPpV.mjs → edvak99-voice-receptionist-widget-api-logs-page.component-DPJiuNjk.mjs} +3 -4
  8. package/fesm2022/edvak99-voice-receptionist-widget-api-logs-page.component-DPJiuNjk.mjs.map +1 -0
  9. package/fesm2022/{edvak99-voice-receptionist-widget-api-logs-table.component-CEf4NPe5.mjs → edvak99-voice-receptionist-widget-api-logs-table.component-CiNc65dO.mjs} +2 -3
  10. package/fesm2022/edvak99-voice-receptionist-widget-api-logs-table.component-CiNc65dO.mjs.map +1 -0
  11. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-DEplWBbz.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-ENq2c-sm.mjs} +5 -7
  12. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-ENq2c-sm.mjs.map +1 -0
  13. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-page.component-Br9R0PQh.mjs → edvak99-voice-receptionist-widget-call-history-page.component-DoYJFpSa.mjs} +4 -5
  14. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DoYJFpSa.mjs.map +1 -0
  15. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-j1mY5wU0.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-GVg1g-Vq.mjs} +2 -3
  16. package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-GVg1g-Vq.mjs.map +1 -0
  17. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-DQ4TT_Su.mjs → edvak99-voice-receptionist-widget-call-review.service-WG30w6Jl.mjs} +2 -2
  18. package/fesm2022/edvak99-voice-receptionist-widget-call-review.service-WG30w6Jl.mjs.map +1 -0
  19. package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs.map +1 -1
  20. package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DPxQ-wst.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-B_EYljRs.mjs} +4 -5
  21. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-B_EYljRs.mjs.map +1 -0
  22. package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-BJs_TH8X.mjs.map +1 -1
  23. package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs.map +1 -1
  24. package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-B8yxY-7p.mjs +14 -0
  25. package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-B8yxY-7p.mjs.map +1 -0
  26. package/fesm2022/edvak99-voice-receptionist-widget-eds-search-field.component-OGRDvYBp.mjs.map +1 -1
  27. package/fesm2022/{edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs} +612 -8
  28. package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs.map +1 -0
  29. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs +74 -0
  30. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs.map +1 -0
  31. package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs} +5 -7
  32. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs.map +1 -0
  33. package/fesm2022/edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs.map +1 -1
  34. package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-B2koBFU3.mjs} +2 -3
  35. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-B2koBFU3.mjs.map +1 -0
  36. package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-YAvQ_XV6.mjs → edvak99-voice-receptionist-widget-settings-page.component-C6F-Hgmk.mjs} +2 -3
  37. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-C6F-Hgmk.mjs.map +1 -0
  38. package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-BojdiNNx.mjs} +2 -2
  39. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-BojdiNNx.mjs.map +1 -0
  40. package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-BIOGiTgM.mjs → edvak99-voice-receptionist-widget-tasks-page.component-Cf76XyCz.mjs} +3 -4
  41. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Cf76XyCz.mjs.map +1 -0
  42. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-DpF6y1go.mjs → edvak99-voice-receptionist-widget-wizard-page.component-BQTlz2F5.mjs} +2 -3
  43. package/fesm2022/edvak99-voice-receptionist-widget-wizard-page.component-BQTlz2F5.mjs.map +1 -0
  44. package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -339
  45. package/fesm2022/edvak99-voice-receptionist-widget.mjs.map +1 -1
  46. package/lib/models/ai-receptionist.types.d.ts +2 -0
  47. package/lib/models/api-dto.types.d.ts +2 -0
  48. package/lib/pages/live-calls-page/live-calls-page.component.d.ts +1 -4
  49. package/lib/pages/live-calls-page/live-calls-shell.component.d.ts +13 -0
  50. package/lib/services/live-calls-list.service.d.ts +2 -0
  51. package/lib/utils/call-history-display.util.d.ts +1 -0
  52. package/package.json +1 -1
  53. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CACfxM4x.mjs.map +0 -1
  54. package/fesm2022/edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs.map +0 -1
  55. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-Dj9vw97B.mjs.map +0 -1
  56. package/fesm2022/edvak99-voice-receptionist-widget-api-logs-page.component-CwXaCPpV.mjs.map +0 -1
  57. package/fesm2022/edvak99-voice-receptionist-widget-api-logs-table.component-CEf4NPe5.mjs.map +0 -1
  58. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-DEplWBbz.mjs.map +0 -1
  59. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Br9R0PQh.mjs.map +0 -1
  60. package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-j1mY5wU0.mjs.map +0 -1
  61. package/fesm2022/edvak99-voice-receptionist-widget-call-review.service-DQ4TT_Su.mjs.map +0 -1
  62. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DPxQ-wst.mjs.map +0 -1
  63. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs +0 -120
  64. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs.map +0 -1
  65. package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs +0 -130
  66. package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs.map +0 -1
  67. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs +0 -81
  68. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs.map +0 -1
  69. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs.map +0 -1
  70. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs.map +0 -1
  71. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-YAvQ_XV6.mjs.map +0 -1
  72. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs.map +0 -1
  73. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-BIOGiTgM.mjs.map +0 -1
  74. package/fesm2022/edvak99-voice-receptionist-widget-wizard-page.component-DpF6y1go.mjs.map +0 -1
@@ -0,0 +1,74 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router, ActivatedRoute } from '@angular/router';
4
+ import { L as LiveCallsListService, c as callerMetaLine, e as ageFromDob, i as isUnknownCaller, d as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs';
5
+ import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-BJs_TH8X.mjs';
6
+ import { E as EdsPulseDotComponent } from './edvak99-voice-receptionist-widget-eds-pulse-dot.component-B8yxY-7p.mjs';
7
+
8
+ class LiveCallsPageComponent {
9
+ constructor() {
10
+ this.router = inject(Router);
11
+ this.route = inject(ActivatedRoute);
12
+ this.liveCallsList = inject(LiveCallsListService);
13
+ this.calls = this.liveCallsList.calls;
14
+ this.loading = this.liveCallsList.loading;
15
+ this.error = this.liveCallsList.error;
16
+ this.emptyState = computed(() => {
17
+ if (this.calls().length > 0)
18
+ return null;
19
+ return {
20
+ title: 'No active calls right now',
21
+ detail: 'When a patient calls your practice, their conversation will appear here for real-time monitoring.',
22
+ icon: 'phone_disabled',
23
+ };
24
+ });
25
+ }
26
+ openMonitor(id) {
27
+ void this.router.navigate([id], { relativeTo: this.route.parent ?? this.route });
28
+ }
29
+ displayName(call) {
30
+ return this.isUnknown(call) ? 'Unknown Caller' : call.name.trim();
31
+ }
32
+ displayMeta(call) {
33
+ return callerMetaLine({
34
+ name: call.name,
35
+ matched: call.matched,
36
+ phone: call.phone,
37
+ dob: call.dob,
38
+ age: call.age ?? ageFromDob(call.dob),
39
+ gender: call.gender,
40
+ });
41
+ }
42
+ isUnknown(call) {
43
+ return isUnknownCaller(call.name, call.matched);
44
+ }
45
+ sentimentLabel(sentiment) {
46
+ const key = String(sentiment ?? 'neutral').toLowerCase();
47
+ switch (key) {
48
+ case 'calm':
49
+ return 'Calm';
50
+ case 'frustrated':
51
+ return 'Frustrated';
52
+ case 'urgent':
53
+ return 'Urgent';
54
+ case 'neutral':
55
+ default:
56
+ return 'Neutral';
57
+ }
58
+ }
59
+ avatarInitials(call) {
60
+ return this.isUnknown(call) ? '?' : call.initials || '?';
61
+ }
62
+ avatarTone(call) {
63
+ return this.isUnknown(call) ? 'gray' : 'brand';
64
+ }
65
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
66
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LiveCallsPageComponent, isStandalone: true, selector: "eds-live-calls-page", ngImport: i0, template: "<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading() && calls().length === 0) {\n <p class=\"eds-body-sm\">Loading live calls\u2026</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".live-calls-page__avatar ::ng-deep .eds-avatar{width:40px;height:40px;border-radius:10px;font-size:13px}.live-calls-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-calls-page__sentiment[data-sentiment=calm]{color:#16a34a}.live-calls-page__sentiment[data-sentiment=neutral]{color:#71717a}.live-calls-page__sentiment[data-sentiment=frustrated]{color:#d97706}.live-calls-page__sentiment[data-sentiment=urgent]{color:#dc2626}\n"], dependencies: [{ kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "shape", "gradient"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: EdsPulseDotComponent, selector: "eds-pulse-dot" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
67
+ }
68
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsPageComponent, decorators: [{
69
+ type: Component,
70
+ args: [{ selector: 'eds-live-calls-page', imports: [EdsAvatarComponent, EdsIconComponent, EdsPulseDotComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading() && calls().length === 0) {\n <p class=\"eds-body-sm\">Loading live calls\u2026</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".live-calls-page__avatar ::ng-deep .eds-avatar{width:40px;height:40px;border-radius:10px;font-size:13px}.live-calls-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-calls-page__sentiment[data-sentiment=calm]{color:#16a34a}.live-calls-page__sentiment[data-sentiment=neutral]{color:#71717a}.live-calls-page__sentiment[data-sentiment=frustrated]{color:#d97706}.live-calls-page__sentiment[data-sentiment=urgent]{color:#dc2626}\n"] }]
71
+ }] });
72
+
73
+ export { LiveCallsPageComponent };
74
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs","sources":["../../../src/lib/pages/live-calls-page/live-calls-page.component.ts","../../../src/lib/pages/live-calls-page/live-calls-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { LiveCall, Sentiment } from '../../models/ai-receptionist.types';\nimport { LiveCallsListService } from '../../services/live-calls-list.service';\nimport {\n ageFromDob,\n callerMetaLine,\n isUnknownCaller,\n} from '../../utils/call-history-display.util';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { EdsPulseDotComponent } from '../../ui/eds-pulse-dot.component';\n\n@Component({\n selector: 'eds-live-calls-page',\n imports: [EdsAvatarComponent, EdsIconComponent, EdsPulseDotComponent],\n templateUrl: './live-calls-page.component.html',\n styleUrl: './live-calls-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LiveCallsPageComponent {\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly liveCallsList = inject(LiveCallsListService);\n\n protected readonly calls = this.liveCallsList.calls;\n protected readonly loading = this.liveCallsList.loading;\n protected readonly error = this.liveCallsList.error;\n\n protected readonly emptyState = computed(() => {\n if (this.calls().length > 0) return null;\n return {\n title: 'No active calls right now',\n detail:\n 'When a patient calls your practice, their conversation will appear here for real-time monitoring.',\n icon: 'phone_disabled',\n };\n });\n\n protected openMonitor(id: string): void {\n void this.router.navigate([id], { relativeTo: this.route.parent ?? this.route });\n }\n\n protected displayName(call: LiveCall): string {\n return this.isUnknown(call) ? 'Unknown Caller' : call.name.trim();\n }\n\n protected displayMeta(call: LiveCall): string {\n return callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n });\n }\n\n protected isUnknown(call: LiveCall): boolean {\n return isUnknownCaller(call.name, call.matched);\n }\n\n protected sentimentLabel(sentiment: Sentiment | string | null | undefined): string {\n const key = String(sentiment ?? 'neutral').toLowerCase();\n switch (key) {\n case 'calm':\n return 'Calm';\n case 'frustrated':\n return 'Frustrated';\n case 'urgent':\n return 'Urgent';\n case 'neutral':\n default:\n return 'Neutral';\n }\n }\n\n protected avatarInitials(call: LiveCall): string {\n return this.isUnknown(call) ? '?' : call.initials || '?';\n }\n\n protected avatarTone(call: LiveCall): 'gray' | 'brand' {\n return this.isUnknown(call) ? 'gray' : 'brand';\n }\n}\n","<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading() && calls().length === 0) {\n <p class=\"eds-body-sm\">Loading live calls…</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
@@ -5,10 +5,8 @@ import { ActivatedRoute, RouterLink } from '@angular/router';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormsModule } from '@angular/forms';
7
7
  import { firstValueFrom } from 'rxjs';
8
- import { VOICE_RECEPTIONIST_CONFIG, EdsIconComponent, ToastService } from './edvak99-voice-receptionist-widget.mjs';
9
- import { e as resolveToolKey, f as resolveToolDisplayName, i as isUnknownCaller, A as AiReceptionistApiService, t as toolEventTrackKey, c as callerMetaLine, d as ageFromDob } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs';
10
- import { D as DashboardSocketService } from './edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs';
11
- import { C as CallRecordingPlayerComponent } from './edvak99-voice-receptionist-widget-call-recording-player.component-j1mY5wU0.mjs';
8
+ import { f as resolveToolKey, g as resolveToolDisplayName, D as DashboardSocketService, V as VOICE_RECEPTIONIST_CONFIG, i as isUnknownCaller, d as EdsIconComponent, A as AiReceptionistApiService, T as ToastService, t as toolEventTrackKey, c as callerMetaLine, e as ageFromDob } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs';
9
+ import { C as CallRecordingPlayerComponent } from './edvak99-voice-receptionist-widget-call-recording-player.component-GVg1g-Vq.mjs';
12
10
  import { Track, Room, RoomEvent, ConnectionState } from 'livekit-client';
13
11
  import { E as EdsElapsedPipe } from './edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs';
14
12
  import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-BJs_TH8X.mjs';
@@ -1040,7 +1038,7 @@ class LiveMonitorPageComponent {
1040
1038
  });
1041
1039
  }
1042
1040
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveMonitorPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1043
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LiveMonitorPageComponent, isStandalone: true, selector: "eds-live-monitor-page", ngImport: i0, template: "<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call\u2026</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"../live\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting\u2026\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call \u00B7 mic on' : 'On call \u00B7 mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary\u2026</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '\u2014' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n }\n }\n</div>\n", styles: [":host{display:block;height:calc(100vh - var(--eds-topbar-height, 0px));box-sizing:border-box}.live-monitor-page{box-sizing:border-box;color:var(--eds-text-primary, #18181b);background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__back:hover{background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__avatar ::ng-deep .eds-avatar{width:44px;height:44px;border-radius:10px;font-size:14px}.live-monitor-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-monitor-page__header-btn:disabled{opacity:.55;cursor:not-allowed}.live-monitor-page__header-btn--danger:hover:not(:disabled){background:#fef2f2}.live-monitor-page__header-btn--primary:hover:not(:disabled){background:#1d4ed8}.live-monitor-page__header-btn--ghost:hover:not(:disabled){background:var(--eds-bg-subtle, #f7f9fa)}.live-monitor-page__media-pill[data-mode=takeover][data-state=connected]{background:#eff6ff;border-color:#bfdbfe;color:#1d4ed8}.live-monitor-page__media-pill[data-mode=listen][data-state=connected]{background:#f0fdf4;border-color:#bbf7d0;color:#15803d}.live-monitor-page__duration--footer{margin-left:auto;font-size:16px}.live-monitor-page__grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(240px,3fr);gap:var(--eds-space-4);align-items:stretch}.live-monitor-page__orb{color:#fff;background:linear-gradient(135deg,var(--eds-brand-500),var(--eds-violet-500));animation:eds-breathe 3s ease-in-out infinite}.live-monitor-page__ring{position:absolute;width:36px;height:36px;top:calc(50% - 28px);left:50%;margin-left:-18px;border-radius:50%;border:1.5px solid var(--eds-brand-400);animation:eds-ring 2s ease-out infinite}.live-monitor-page__ring--2{animation-delay:1s}.live-monitor-page__orb-wrap[data-mode=transfer] .live-monitor-page__orb{background:linear-gradient(135deg,var(--eds-amber-400),var(--eds-violet-500))}.live-monitor-page__confidence[data-level=high]{color:#047857}.live-monitor-page__confidence[data-level=low]{color:#b45309}.live-monitor-page__sentiment-fill{transition:width .3s ease}.live-monitor-page__sentiment-fill[data-sentiment=frustrated],.live-monitor-page__sentiment-fill[data-sentiment=urgent]{background:var(--eds-red-500, #ef4444)}.live-monitor-page__sentiment-fill[data-sentiment=neutral]{background:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tools{list-style:none;margin:0;padding:0}.live-monitor-page__tools li{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;padding:8px 10px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1, #f4f4f5);border-left:2px solid var(--eds-border-default, #d4d4d8)}.live-monitor-page__tool-spin{animation:eds-spin 1s linear infinite;color:var(--eds-brand-500)}.live-monitor-page__tool--ok{border-left-color:var(--eds-green-500, #22c55e)}.live-monitor-page__tool--warn{border-left-color:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tool--error{border-left-color:var(--eds-red-500, #ef4444)}.live-monitor-page__tool--active{border-left-color:var(--eds-brand-500)}.live-monitor-page__tools-empty{border-left:none!important;background:transparent!important;padding:4px 0!important}@media(max-width:960px){:host{height:auto;min-height:calc(100vh - var(--eds-topbar-height, 0px))}.live-monitor-page{height:auto;overflow:visible}.live-monitor-page__grid{grid-template-columns:1fr}.live-monitor-page__sidebar{width:100%;max-width:none;height:auto}.live-monitor-page__orb-wrap{width:100%}.live-monitor-page__header-actions{width:100%;margin-left:0}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "shape", "gradient"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "pipe", type: EdsElapsedPipe, name: "edsElapsed" }, { kind: "component", type: LiveTranscriptPanelComponent, selector: "eds-live-transcript-panel", inputs: ["live", "paused", "humanTakeover", "showStaffInput", "staffMessage", "callerName", "callerMatched"], outputs: ["staffMessageChange", "sendMessage"] }, { kind: "component", type: CallRecordingPlayerComponent, selector: "eds-call-recording-player", inputs: ["callId"], outputs: ["currentTimeChange", "durationChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1041
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LiveMonitorPageComponent, isStandalone: true, selector: "eds-live-monitor-page", ngImport: i0, template: "<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call\u2026</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting\u2026\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call \u00B7 mic on' : 'On call \u00B7 mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary\u2026</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '\u2014' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <div class=\"flex flex-col items-start gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:calc(100vh - var(--eds-topbar-height, 0px));box-sizing:border-box}.live-monitor-page{box-sizing:border-box;color:var(--eds-text-primary, #18181b);background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__back:hover{background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__avatar ::ng-deep .eds-avatar{width:44px;height:44px;border-radius:10px;font-size:14px}.live-monitor-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-monitor-page__header-btn:disabled{opacity:.55;cursor:not-allowed}.live-monitor-page__header-btn--danger:hover:not(:disabled){background:#fef2f2}.live-monitor-page__header-btn--primary:hover:not(:disabled){background:#1d4ed8}.live-monitor-page__header-btn--ghost:hover:not(:disabled){background:var(--eds-bg-subtle, #f7f9fa)}.live-monitor-page__media-pill[data-mode=takeover][data-state=connected]{background:#eff6ff;border-color:#bfdbfe;color:#1d4ed8}.live-monitor-page__media-pill[data-mode=listen][data-state=connected]{background:#f0fdf4;border-color:#bbf7d0;color:#15803d}.live-monitor-page__duration--footer{margin-left:auto;font-size:16px}.live-monitor-page__grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(240px,3fr);gap:var(--eds-space-4);align-items:stretch}.live-monitor-page__orb{color:#fff;background:linear-gradient(135deg,var(--eds-brand-500),var(--eds-violet-500));animation:eds-breathe 3s ease-in-out infinite}.live-monitor-page__ring{position:absolute;width:36px;height:36px;top:calc(50% - 28px);left:50%;margin-left:-18px;border-radius:50%;border:1.5px solid var(--eds-brand-400);animation:eds-ring 2s ease-out infinite}.live-monitor-page__ring--2{animation-delay:1s}.live-monitor-page__orb-wrap[data-mode=transfer] .live-monitor-page__orb{background:linear-gradient(135deg,var(--eds-amber-400),var(--eds-violet-500))}.live-monitor-page__confidence[data-level=high]{color:#047857}.live-monitor-page__confidence[data-level=low]{color:#b45309}.live-monitor-page__sentiment-fill{transition:width .3s ease}.live-monitor-page__sentiment-fill[data-sentiment=frustrated],.live-monitor-page__sentiment-fill[data-sentiment=urgent]{background:var(--eds-red-500, #ef4444)}.live-monitor-page__sentiment-fill[data-sentiment=neutral]{background:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tools{list-style:none;margin:0;padding:0}.live-monitor-page__tools li{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;padding:8px 10px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1, #f4f4f5);border-left:2px solid var(--eds-border-default, #d4d4d8)}.live-monitor-page__tool-spin{animation:eds-spin 1s linear infinite;color:var(--eds-brand-500)}.live-monitor-page__tool--ok{border-left-color:var(--eds-green-500, #22c55e)}.live-monitor-page__tool--warn{border-left-color:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tool--error{border-left-color:var(--eds-red-500, #ef4444)}.live-monitor-page__tool--active{border-left-color:var(--eds-brand-500)}.live-monitor-page__tools-empty{border-left:none!important;background:transparent!important;padding:4px 0!important}@media(max-width:960px){:host{height:auto;min-height:calc(100vh - var(--eds-topbar-height, 0px))}.live-monitor-page{height:auto;overflow:visible}.live-monitor-page__grid{grid-template-columns:1fr}.live-monitor-page__sidebar{width:100%;max-width:none;height:auto}.live-monitor-page__orb-wrap{width:100%}.live-monitor-page__header-actions{width:100%;margin-left:0}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "shape", "gradient"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "pipe", type: EdsElapsedPipe, name: "edsElapsed" }, { kind: "component", type: LiveTranscriptPanelComponent, selector: "eds-live-transcript-panel", inputs: ["live", "paused", "humanTakeover", "showStaffInput", "staffMessage", "callerName", "callerMatched"], outputs: ["staffMessageChange", "sendMessage"] }, { kind: "component", type: CallRecordingPlayerComponent, selector: "eds-call-recording-player", inputs: ["callId"], outputs: ["currentTimeChange", "durationChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1044
1042
  }
1045
1043
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveMonitorPageComponent, decorators: [{
1046
1044
  type: Component,
@@ -1052,8 +1050,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
1052
1050
  EdsElapsedPipe,
1053
1051
  LiveTranscriptPanelComponent,
1054
1052
  CallRecordingPlayerComponent,
1055
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call\u2026</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"../live\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting\u2026\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call \u00B7 mic on' : 'On call \u00B7 mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary\u2026</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '\u2014' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n }\n }\n</div>\n", styles: [":host{display:block;height:calc(100vh - var(--eds-topbar-height, 0px));box-sizing:border-box}.live-monitor-page{box-sizing:border-box;color:var(--eds-text-primary, #18181b);background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__back:hover{background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__avatar ::ng-deep .eds-avatar{width:44px;height:44px;border-radius:10px;font-size:14px}.live-monitor-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-monitor-page__header-btn:disabled{opacity:.55;cursor:not-allowed}.live-monitor-page__header-btn--danger:hover:not(:disabled){background:#fef2f2}.live-monitor-page__header-btn--primary:hover:not(:disabled){background:#1d4ed8}.live-monitor-page__header-btn--ghost:hover:not(:disabled){background:var(--eds-bg-subtle, #f7f9fa)}.live-monitor-page__media-pill[data-mode=takeover][data-state=connected]{background:#eff6ff;border-color:#bfdbfe;color:#1d4ed8}.live-monitor-page__media-pill[data-mode=listen][data-state=connected]{background:#f0fdf4;border-color:#bbf7d0;color:#15803d}.live-monitor-page__duration--footer{margin-left:auto;font-size:16px}.live-monitor-page__grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(240px,3fr);gap:var(--eds-space-4);align-items:stretch}.live-monitor-page__orb{color:#fff;background:linear-gradient(135deg,var(--eds-brand-500),var(--eds-violet-500));animation:eds-breathe 3s ease-in-out infinite}.live-monitor-page__ring{position:absolute;width:36px;height:36px;top:calc(50% - 28px);left:50%;margin-left:-18px;border-radius:50%;border:1.5px solid var(--eds-brand-400);animation:eds-ring 2s ease-out infinite}.live-monitor-page__ring--2{animation-delay:1s}.live-monitor-page__orb-wrap[data-mode=transfer] .live-monitor-page__orb{background:linear-gradient(135deg,var(--eds-amber-400),var(--eds-violet-500))}.live-monitor-page__confidence[data-level=high]{color:#047857}.live-monitor-page__confidence[data-level=low]{color:#b45309}.live-monitor-page__sentiment-fill{transition:width .3s ease}.live-monitor-page__sentiment-fill[data-sentiment=frustrated],.live-monitor-page__sentiment-fill[data-sentiment=urgent]{background:var(--eds-red-500, #ef4444)}.live-monitor-page__sentiment-fill[data-sentiment=neutral]{background:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tools{list-style:none;margin:0;padding:0}.live-monitor-page__tools li{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;padding:8px 10px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1, #f4f4f5);border-left:2px solid var(--eds-border-default, #d4d4d8)}.live-monitor-page__tool-spin{animation:eds-spin 1s linear infinite;color:var(--eds-brand-500)}.live-monitor-page__tool--ok{border-left-color:var(--eds-green-500, #22c55e)}.live-monitor-page__tool--warn{border-left-color:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tool--error{border-left-color:var(--eds-red-500, #ef4444)}.live-monitor-page__tool--active{border-left-color:var(--eds-brand-500)}.live-monitor-page__tools-empty{border-left:none!important;background:transparent!important;padding:4px 0!important}@media(max-width:960px){:host{height:auto;min-height:calc(100vh - var(--eds-topbar-height, 0px))}.live-monitor-page{height:auto;overflow:visible}.live-monitor-page__grid{grid-template-columns:1fr}.live-monitor-page__sidebar{width:100%;max-width:none;height:auto}.live-monitor-page__orb-wrap{width:100%}.live-monitor-page__header-actions{width:100%;margin-left:0}}\n"] }]
1053
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call\u2026</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting\u2026\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call \u00B7 mic on' : 'On call \u00B7 mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary\u2026</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '\u2014' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <div class=\"flex flex-col items-start gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:calc(100vh - var(--eds-topbar-height, 0px));box-sizing:border-box}.live-monitor-page{box-sizing:border-box;color:var(--eds-text-primary, #18181b);background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__back:hover{background:var(--eds-surface-l1, #f4f4f5)}.live-monitor-page__avatar ::ng-deep .eds-avatar{width:44px;height:44px;border-radius:10px;font-size:14px}.live-monitor-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-monitor-page__header-btn:disabled{opacity:.55;cursor:not-allowed}.live-monitor-page__header-btn--danger:hover:not(:disabled){background:#fef2f2}.live-monitor-page__header-btn--primary:hover:not(:disabled){background:#1d4ed8}.live-monitor-page__header-btn--ghost:hover:not(:disabled){background:var(--eds-bg-subtle, #f7f9fa)}.live-monitor-page__media-pill[data-mode=takeover][data-state=connected]{background:#eff6ff;border-color:#bfdbfe;color:#1d4ed8}.live-monitor-page__media-pill[data-mode=listen][data-state=connected]{background:#f0fdf4;border-color:#bbf7d0;color:#15803d}.live-monitor-page__duration--footer{margin-left:auto;font-size:16px}.live-monitor-page__grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(240px,3fr);gap:var(--eds-space-4);align-items:stretch}.live-monitor-page__orb{color:#fff;background:linear-gradient(135deg,var(--eds-brand-500),var(--eds-violet-500));animation:eds-breathe 3s ease-in-out infinite}.live-monitor-page__ring{position:absolute;width:36px;height:36px;top:calc(50% - 28px);left:50%;margin-left:-18px;border-radius:50%;border:1.5px solid var(--eds-brand-400);animation:eds-ring 2s ease-out infinite}.live-monitor-page__ring--2{animation-delay:1s}.live-monitor-page__orb-wrap[data-mode=transfer] .live-monitor-page__orb{background:linear-gradient(135deg,var(--eds-amber-400),var(--eds-violet-500))}.live-monitor-page__confidence[data-level=high]{color:#047857}.live-monitor-page__confidence[data-level=low]{color:#b45309}.live-monitor-page__sentiment-fill{transition:width .3s ease}.live-monitor-page__sentiment-fill[data-sentiment=frustrated],.live-monitor-page__sentiment-fill[data-sentiment=urgent]{background:var(--eds-red-500, #ef4444)}.live-monitor-page__sentiment-fill[data-sentiment=neutral]{background:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tools{list-style:none;margin:0;padding:0}.live-monitor-page__tools li{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;padding:8px 10px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1, #f4f4f5);border-left:2px solid var(--eds-border-default, #d4d4d8)}.live-monitor-page__tool-spin{animation:eds-spin 1s linear infinite;color:var(--eds-brand-500)}.live-monitor-page__tool--ok{border-left-color:var(--eds-green-500, #22c55e)}.live-monitor-page__tool--warn{border-left-color:var(--eds-amber-400, #f59e0b)}.live-monitor-page__tool--error{border-left-color:var(--eds-red-500, #ef4444)}.live-monitor-page__tool--active{border-left-color:var(--eds-brand-500)}.live-monitor-page__tools-empty{border-left:none!important;background:transparent!important;padding:4px 0!important}@media(max-width:960px){:host{height:auto;min-height:calc(100vh - var(--eds-topbar-height, 0px))}.live-monitor-page{height:auto;overflow:visible}.live-monitor-page__grid{grid-template-columns:1fr}.live-monitor-page__sidebar{width:100%;max-width:none;height:auto}.live-monitor-page__orb-wrap{width:100%}.live-monitor-page__header-actions{width:100%;margin-left:0}}\n"] }]
1056
1054
  }], ctorParameters: () => [] });
1057
1055
 
1058
1056
  export { LiveMonitorPageComponent };
1059
- //# sourceMappingURL=edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs.map
1057
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs","sources":["../../../src/lib/models/live-transcript.types.ts","../../../src/lib/services/live-transcript.service.ts","../../../src/lib/components/live-transcript-panel/live-transcript-panel.component.ts","../../../src/lib/components/live-transcript-panel/live-transcript-panel.component.html","../../../src/lib/services/staff-media.service.ts","../../../src/lib/pages/live-monitor-page/live-monitor-page.component.ts","../../../src/lib/pages/live-monitor-page/live-monitor-page.component.html"],"sourcesContent":["import { ToolEvent, TranscriptLine } from './ai-receptionist.types';\nimport { resolveToolDisplayName, resolveToolKey } from '../utils/tool-labels.util';\n\n/** Socket.io `new_chunk` payload from /dashboard namespace */\nexport interface TranscriptChunk {\n /** `staff` is a human agent speaking after a softphone takeover. */\n role: 'user' | 'assistant' | 'staff' | 'system';\n text: string;\n isFinal: boolean;\n timestamp: string;\n}\n\n/** Socket.io `call_event` payload — tools + lifecycle */\nexport interface CallEventStreamPayload {\n eventType: string;\n occurredAt: string;\n payload: Record<string, unknown>;\n}\n\nexport interface LiveTranscriptState {\n lines: TranscriptLine[];\n patientInterim: string | null;\n aiInterim: string | null;\n connected: boolean;\n error: string | null;\n}\n\nexport function mapChunkToLine(chunk: TranscriptChunk): TranscriptLine {\n const at = Date.parse(chunk.timestamp);\n return {\n who:\n chunk.role === 'staff'\n ? 'staff'\n : chunk.role === 'system'\n ? 'system'\n : chunk.role === 'assistant'\n ? 'ai'\n : 'patient',\n text: chunk.text,\n at: Number.isFinite(at) ? at : Date.now(),\n };\n}\n\nexport function formatEventTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n}\n\nexport function mapCallEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n const state = p['state'];\n const rawName = String(p['name'] ?? event.eventType.replace(/^tool_/, ''));\n const tech = String(p['tech'] ?? event.eventType);\n const key = resolveToolKey(\n p['key'] != null ? String(p['key']) : undefined,\n rawName,\n tech,\n );\n return {\n t: formatEventTime(event.occurredAt),\n key,\n name: resolveToolDisplayName(key, rawName),\n tech,\n result: String(p['result'] ?? ''),\n state:\n state === 'ok' || state === 'warn' || state === 'error' || state === 'active'\n ? state\n : 'ok',\n };\n}\n\nexport function mapLifecycleEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n return {\n t: formatEventTime(event.occurredAt),\n name: event.eventType.replace(/_/g, ' '),\n tech: event.eventType,\n result: String(p['detail'] ?? p['message'] ?? p['result'] ?? ''),\n state: 'ok',\n };\n}\n\nexport function isDuplicateTranscriptLine(lines: TranscriptLine[], line: TranscriptLine): boolean {\n return lines.some((l) => l.who === line.who && l.text.trim() === line.text.trim());\n}\n","import { Injectable, inject, signal } from '@angular/core';\n\nimport { VOICE_RECEPTIONIST_CONFIG } from '../config';\nimport { ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';\nimport {\n CallEventStreamPayload,\n isDuplicateTranscriptLine,\n mapCallEventToTool,\n mapChunkToLine,\n mapLifecycleEventToTool,\n TranscriptChunk,\n} from '../models/live-transcript.types';\nimport { DashboardSocketService } from './dashboard-socket.service';\n\n/**\n * Live call stream over shared Socket.io (`/dashboard` namespace).\n * REST seeds transcript/tools once; socket delivers `new_chunk` + `call_event`.\n */\n@Injectable({ providedIn: 'root' })\nexport class LiveTranscriptService {\n private readonly socket = inject(DashboardSocketService);\n private readonly config = inject(VOICE_RECEPTIONIST_CONFIG);\n\n readonly lines = signal<TranscriptLine[]>([]);\n readonly patientInterim = signal<string | null>(null);\n readonly aiInterim = signal<string | null>(null);\n readonly staffInterim = signal<string | null>(null);\n readonly tools = signal<ToolEvent[]>([]);\n readonly connected = this.socket.connected;\n readonly error = signal<string | null>(null);\n readonly callEnded = signal(false);\n readonly summaryRequested = signal(false);\n\n private activeCallId: string | null = null;\n private watching = false;\n private mockTimer: ReturnType<typeof setInterval> | null = null;\n private mockIndex = 0;\n\n private readonly chunkHandler = (chunk: TranscriptChunk) => this.handleChunk(chunk);\n private readonly eventHandler = (event: CallEventStreamPayload) => this.handleCallEvent(event);\n private readonly onSocketConnect = () => {\n if (this.activeCallId) {\n this.socket.emit('watch_call', { callId: this.activeCallId });\n }\n };\n\n seed(transcript: TranscriptLine[], toolEvents: ToolEvent[]): void {\n this.lines.set(transcript.map((line) => ({ ...line })));\n this.tools.set(toolEvents.map((tool) => ({ ...tool })));\n }\n\n watch(callId: string, live = true): void {\n const id = callId.trim();\n if (!id || !live) return;\n\n const switchingCall = this.activeCallId !== id;\n if (switchingCall) {\n this.unsubscribeSocketEvents();\n this.clearInterim();\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n this.activeCallId = id;\n } else if (this.watching) {\n return;\n }\n\n if (this.config.useMockApi) {\n this.watching = true;\n this.startMockStream(id);\n return;\n }\n\n if (!this.watching) {\n this.socket.acquire();\n this.socket.on('new_chunk', this.chunkHandler);\n this.socket.on('call_event', this.eventHandler);\n this.socket.onConnect(this.onSocketConnect);\n this.watching = true;\n }\n\n if (this.socket.connected()) {\n this.socket.emit('watch_call', { callId: id });\n }\n }\n\n stop(): void {\n this.activeCallId = null;\n this.unsubscribeSocketEvents();\n this.resetStreamState();\n }\n\n markCompleted(): void {\n this.callEnded.set(true);\n this.unsubscribeSocketEvents();\n this.clearInterim();\n }\n\n private unsubscribeSocketEvents(): void {\n this.stopMockStream();\n if (!this.watching) return;\n\n this.socket.off('new_chunk', this.chunkHandler);\n this.socket.off('call_event', this.eventHandler);\n this.socket.offConnect(this.onSocketConnect);\n this.socket.release();\n this.watching = false;\n }\n\n private handleChunk(chunk: TranscriptChunk): void {\n if (!chunk?.text?.trim()) return;\n\n if (chunk.role === 'user') {\n if (chunk.isFinal) {\n this.patientInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.patientInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.role === 'system') {\n this.appendLineIfNew(mapChunkToLine(chunk));\n return;\n }\n\n if (chunk.role === 'staff') {\n if (chunk.isFinal) {\n this.staffInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.staffInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.isFinal) {\n this.aiInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.aiInterim.set(chunk.text);\n }\n }\n\n private handleCallEvent(event: CallEventStreamPayload): void {\n if (!event?.eventType) return;\n\n if (event.eventType.startsWith('tool_')) {\n this.tools.update((prev) => [...prev, mapCallEventToTool(event)]);\n return;\n }\n\n if (event.eventType === 'call_completed') {\n this.markCompleted();\n return;\n }\n\n if (event.eventType === 'summary_generated') {\n this.summaryRequested.set(true);\n return;\n }\n\n this.tools.update((prev) => [...prev, mapLifecycleEventToTool(event)]);\n }\n\n private appendLineIfNew(line: TranscriptLine): void {\n this.lines.update((prev) => {\n if (isDuplicateTranscriptLine(prev, line)) return prev;\n return [...prev, line];\n });\n }\n\n private startMockStream(callId: string): void {\n this.stopMockStream();\n this.mockIndex = 0;\n\n const mockChunks: TranscriptChunk[] = [\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: false,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'assistant',\n text: 'Of course — I can help with that. Which provider would you prefer?',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n ];\n\n const mockEvents: CallEventStreamPayload[] = [\n {\n eventType: 'tool_check_doctor_availability',\n occurredAt: new Date().toISOString(),\n payload: {\n key: 'check_doctor_availability',\n name: 'Checked Doctor Availability',\n tech: 'tool_check_doctor_availability',\n result: 'Found 3 available time slots',\n state: 'ok',\n },\n },\n ];\n\n this.mockTimer = setInterval(() => {\n if (this.activeCallId !== callId) {\n this.stopMockStream();\n return;\n }\n if (this.mockIndex < mockChunks.length) {\n this.handleChunk(mockChunks[this.mockIndex]);\n this.mockIndex++;\n return;\n }\n if (this.mockIndex === mockChunks.length) {\n this.handleCallEvent(mockEvents[0]);\n this.mockIndex++;\n }\n }, 1500);\n }\n\n private stopMockStream(): void {\n if (this.mockTimer) {\n clearInterval(this.mockTimer);\n this.mockTimer = null;\n }\n }\n\n private clearInterim(): void {\n this.patientInterim.set(null);\n this.aiInterim.set(null);\n this.staffInterim.set(null);\n }\n\n private resetStreamState(): void {\n this.lines.set([]);\n this.tools.set([]);\n this.clearInterim();\n this.error.set(null);\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n }\n}\n","import {\n AfterViewChecked,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewChild,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { TranscriptWho } from '../../models/ai-receptionist.types';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { isUnknownCaller } from '../../utils/call-history-display.util';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-transcript-panel',\n imports: [FormsModule, EdsIconComponent],\n templateUrl: './live-transcript-panel.component.html',\n styleUrl: './live-transcript-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'flex h-full min-h-0 flex-1 flex-col max-[900px]:h-auto max-[900px]:max-h-none max-[900px]:min-h-[360px]',\n },\n})\nexport class LiveTranscriptPanelComponent implements AfterViewChecked {\n readonly live = input(true);\n readonly paused = input(false);\n readonly humanTakeover = input(false);\n readonly showStaffInput = input(false);\n readonly staffMessage = input('');\n /** Resolved patient display name from the live call. */\n readonly callerName = input<string | null>(null);\n /** Whether the caller was matched to a patient chart. */\n readonly callerMatched = input(false);\n readonly staffMessageChange = output<string>();\n readonly sendMessage = output<void>();\n\n private readonly stream = inject(LiveTranscriptService);\n\n @ViewChild('scrollHost') private scrollHost?: ElementRef<HTMLElement>;\n\n protected readonly lines = this.stream.lines;\n protected readonly patientInterim = this.stream.patientInterim;\n protected readonly aiInterim = this.stream.aiInterim;\n protected readonly staffInterim = this.stream.staffInterim;\n protected readonly connected = this.stream.connected;\n protected readonly error = this.stream.error;\n\n protected readonly callerLabel = computed(() => {\n const name = this.callerName()?.trim() ?? '';\n if (isUnknownCaller(name, this.callerMatched())) return 'Unknown caller';\n return name || 'Unknown caller';\n });\n\n private shouldScroll = false;\n\n constructor() {\n effect(() => {\n this.lines();\n this.patientInterim();\n this.aiInterim();\n this.staffInterim();\n this.requestScroll();\n });\n }\n\n ngAfterViewChecked(): void {\n if (this.shouldScroll && this.scrollHost) {\n const el = this.scrollHost.nativeElement;\n el.scrollTop = el.scrollHeight;\n this.shouldScroll = false;\n }\n }\n\n protected roleLabel(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'Ava · AI';\n case 'patient':\n return this.callerLabel();\n case 'staff':\n return 'Staff';\n default:\n return 'System';\n }\n }\n\n protected speakerIcon(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'graphic_eq';\n case 'staff':\n return 'support_agent';\n case 'patient':\n return 'person';\n default:\n return 'info';\n }\n }\n\n protected systemIcon(flag?: string): string {\n if (flag === 'verify') return 'verified_user';\n if (flag === 'fail' || flag === 'escalate') return 'bolt';\n return 'info';\n }\n\n protected onStaffInput(value: string): void {\n this.staffMessageChange.emit(value);\n }\n\n protected onSend(): void {\n this.sendMessage.emit();\n }\n\n private requestScroll(): void {\n this.shouldScroll = true;\n }\n}\n","<section class=\"flex h-full min-h-0 flex-1 flex-col rounded-xl border border-zinc-200 bg-white max-[900px]:h-auto max-[900px]:max-h-none max-[900px]:min-h-[360px]\" aria-labelledby=\"live-transcript-title\">\n <header class=\"flex shrink-0 items-center justify-between gap-3 border-b border-zinc-200 px-4 py-4\">\n <h2 id=\"live-transcript-title\" class=\"m-0 font-mono text-xs font-semibold uppercase tracking-wider text-zinc-500\">Live transcript</h2>\n </header>\n\n <div #scrollHost class=\"flex flex-1 flex-col gap-4 overflow-auto bg-zinc-50 p-4\" role=\"log\" aria-live=\"polite\">\n @for (line of lines(); track $index) {\n @if (line.who === 'system') {\n <div\n class=\"inline-flex max-w-[90%] items-center gap-2 self-center rounded-full border px-3 py-2 text-center text-xs font-medium eds-animate-fade-up\"\n [class]=\"line.flag === 'verify' ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : line.flag === 'fail' || line.flag === 'escalate' ? 'border-amber-200 bg-amber-50 text-amber-700' : 'border-zinc-200 bg-white text-zinc-600'\"\n >\n <eds-icon [name]=\"systemIcon(line.flag)\" [size]=\"14\" />\n <span>{{ line.text }}</span>\n </div>\n } @else {\n <article\n class=\"flex max-w-[72%] gap-3 eds-animate-fade-up\"\n [class]=\"line.who === 'patient' ? 'mr-auto self-start' : 'ml-auto flex-row-reverse self-end'\"\n >\n <div\n class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full\"\n [class]=\"line.who === 'ai' ? 'live-transcript-panel__avatar--ai text-white' : line.who === 'staff' ? 'border border-violet-200 bg-violet-50 text-violet-700' : 'bg-zinc-200 text-zinc-600'\"\n >\n <eds-icon [name]=\"speakerIcon(line.who)\" [size]=\"16\" />\n </div>\n <div\n class=\"flex min-w-0 flex-col gap-1\"\n [class]=\"line.who === 'patient' ? 'items-start' : 'items-end'\"\n >\n <span\n class=\"font-mono text-xs font-semibold tracking-wide\"\n [class]=\"line.who === 'ai' ? 'text-blue-600' : line.who === 'staff' ? 'text-violet-700' : 'text-zinc-400'\"\n >{{ roleLabel(line.who) }}</span>\n <div\n class=\"px-4 py-2\"\n [class]=\"line.who === 'patient' ? 'rounded-tl rounded-tr-xl rounded-br-xl rounded-bl-xl border border-zinc-200 bg-white' : line.who === 'staff' ? 'rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-violet-200 bg-violet-50' : 'rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-blue-200 bg-blue-50'\"\n >\n <p class=\"m-0 text-sm leading-snug\" [class]=\"line.who === 'staff' ? 'text-violet-900' : 'text-zinc-900'\">{{ line.text }}</p>\n </div>\n </div>\n </article>\n }\n }\n\n @if (patientInterim(); as interim) {\n <article class=\"mr-auto flex max-w-[72%] gap-3 self-start eds-animate-fade-up\">\n <div class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-zinc-200 text-zinc-600\">\n <eds-icon name=\"person\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-start gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-zinc-400\">{{ callerLabel() }} · listening</span>\n <div class=\"rounded-tl rounded-tr-xl rounded-br-xl rounded-bl-xl border border-zinc-200 bg-white px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-zinc-900\">{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (staffInterim(); as interim) {\n <article class=\"ml-auto flex max-w-[72%] flex-row-reverse gap-3 self-end eds-animate-fade-up\">\n <div class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-violet-200 bg-violet-50 text-violet-700\">\n <eds-icon name=\"support_agent\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-end gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-violet-700\">Staff · speaking</span>\n <div class=\"rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-violet-200 bg-violet-50 px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-violet-900\">{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (aiInterim(); as interim) {\n <article class=\"ml-auto flex max-w-[72%] flex-row-reverse gap-3 self-end eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar--ai flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-white\">\n <eds-icon name=\"graphic_eq\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-end gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-blue-600\">Ava · AI</span>\n <div class=\"rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-blue-200 bg-blue-50 px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-zinc-900\">{{ interim }}<span class=\"live-transcript-panel__caret\" aria-hidden=\"true\"></span></p>\n </div>\n </div>\n </article>\n }\n\n @if (lines().length === 0 && !patientInterim() && !aiInterim() && !staffInterim()) {\n <p class=\"m-0 px-3 py-8 text-center text-sm leading-snug text-zinc-500\">Waiting for conversation…</p>\n }\n </div>\n\n @if (showStaffInput()) {\n <footer class=\"flex shrink-0 gap-2 border-t border-zinc-200 bg-white p-3\">\n <input\n type=\"text\"\n class=\"h-9 flex-1 rounded-md border border-zinc-200 bg-white px-4 text-sm text-zinc-900 placeholder:text-zinc-400 focus:border-blue-500 focus:outline-none\"\n placeholder=\"Type to speak as staff…\"\n [ngModel]=\"staffMessage()\"\n (ngModelChange)=\"onStaffInput($event)\"\n (keyup.enter)=\"onSend()\"\n autocomplete=\"off\"\n />\n </footer>\n }\n</section>\n","import { Injectable, signal } from '@angular/core';\nimport {\n ConnectionState,\n RemoteParticipant,\n RemoteTrack,\n RemoteTrackPublication,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\n\nimport { StaffMediaJoinResult, StaffMediaMode } from '../models/staff-media.types';\n\nexport type StaffMediaConnectionState =\n | 'idle'\n | 'connecting'\n | 'connected'\n | 'disconnecting'\n | 'error';\n\nconst STAFF_IDENTITY_PREFIX = 'staff-';\n\n/**\n * Browser softphone for staff Listen / Take Over via LiveKit.\n * Secrets stay on the server — FE only uses short-lived clientToken + livekitUrl.\n *\n * Root-provided on purpose: the session must survive navigating away from the\n * Live Monitor page, otherwise switching dashboard tabs would drop the call.\n */\n@Injectable({ providedIn: 'root' })\nexport class StaffMediaService {\n readonly connectionState = signal<StaffMediaConnectionState>('idle');\n readonly mode = signal<StaffMediaMode | null>(null);\n readonly micEnabled = signal(false);\n readonly error = signal<string | null>(null);\n readonly activeCallId = signal<string | null>(null);\n /** False when the browser blocks autoplay — UI should offer an \"enable sound\" action. */\n readonly audioPlaybackAllowed = signal(true);\n /** True once remote caller audio is actually attached and playing. */\n readonly remoteAudioAttached = signal(false);\n\n private room: Room | null = null;\n private audioContainer: HTMLElement | null = null;\n private readonly attached = new Map<string, HTMLMediaElement[]>();\n\n get isConnected(): boolean {\n return this.connectionState() === 'connected';\n }\n\n /** True when a softphone session is live for this call, regardless of page. */\n isConnectedTo(callId: string): boolean {\n return this.isConnected && this.activeCallId() === callId;\n }\n\n /**\n * getUserMedia only exists in a secure context (https or localhost) and, inside an\n * iframe, requires allow=\"microphone\". Returns null when capture is possible.\n */\n microphoneBlockedReason(): string | null {\n if (typeof navigator === 'undefined') return 'Microphone is not available in this environment.';\n if (!navigator.mediaDevices?.getUserMedia) {\n const secure = typeof window !== 'undefined' && window.isSecureContext;\n return secure\n ? 'Microphone access is blocked by the browser. If the dashboard is embedded, the host page must allow microphone access.'\n : 'Microphone access needs a secure connection. Open the dashboard over https (or localhost) to talk to callers.';\n }\n return null;\n }\n\n async join(join: StaffMediaJoinResult): Promise<void> {\n if (join.provider && join.provider !== 'livekit') {\n throw new Error(`Unsupported media provider: ${join.provider}`);\n }\n if (!join.livekitUrl || !join.clientToken) {\n throw new Error('Missing LiveKit URL or client token from media/join');\n }\n if (join.mode === 'takeover') {\n const blocked = this.microphoneBlockedReason();\n if (blocked) throw new Error(blocked);\n }\n\n await this.disconnect();\n\n this.connectionState.set('connecting');\n this.error.set(null);\n this.mode.set(join.mode);\n this.activeCallId.set(join.callId || null);\n this.micEnabled.set(false);\n\n const room = new Room({\n adaptiveStream: true,\n dynacast: true,\n audioCaptureDefaults: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n room.on(RoomEvent.Disconnected, () => {\n if (this.room !== room) return;\n void this.cleanupLocal(false);\n this.connectionState.set('idle');\n this.mode.set(null);\n this.activeCallId.set(null);\n this.micEnabled.set(false);\n });\n\n room.on(RoomEvent.ConnectionStateChanged, (state: ConnectionState) => {\n if (this.room !== room) return;\n if (state === ConnectionState.Connected) {\n this.connectionState.set('connected');\n } else if (state === ConnectionState.Connecting || state === ConnectionState.Reconnecting) {\n this.connectionState.set('connecting');\n }\n });\n\n room.on(RoomEvent.AudioPlaybackStatusChanged, () => {\n if (this.room === room) {\n this.audioPlaybackAllowed.set(room.canPlaybackAudio);\n }\n });\n\n room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n room.on(RoomEvent.TrackUnsubscribed, this.onTrackUnsubscribed);\n room.on(RoomEvent.ParticipantDisconnected, this.onParticipantDisconnected);\n room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n\n try {\n this.room = room;\n this.ensureAudioContainer();\n await room.connect(join.livekitUrl, join.clientToken);\n\n // Publish mic only for takeover (listen stays receive-only).\n if (join.mode === 'takeover') {\n await this.enableMicrophone(true);\n }\n\n this.attachExistingRemoteTracks(room);\n await this.startAudioPlayback();\n this.connectionState.set('connected');\n } catch (err) {\n const message = this.friendlyError(err);\n this.error.set(message);\n this.connectionState.set('error');\n await this.cleanupLocal(true);\n this.mode.set(null);\n this.activeCallId.set(null);\n throw new Error(message);\n }\n }\n\n async setMicrophoneEnabled(enabled: boolean): Promise<void> {\n if (!this.room || this.connectionState() !== 'connected') return;\n if (this.mode() !== 'takeover' && enabled) {\n // Listen mode stays muted unless upgraded to takeover.\n return;\n }\n await this.enableMicrophone(enabled);\n }\n\n async toggleMicrophone(): Promise<void> {\n await this.setMicrophoneEnabled(!this.micEnabled());\n }\n\n /** Retry blocked autoplay — must be called from a user gesture. */\n async startAudioPlayback(): Promise<void> {\n const room = this.room;\n if (!room) return;\n try {\n await room.startAudio();\n this.audioPlaybackAllowed.set(true);\n } catch {\n this.audioPlaybackAllowed.set(room.canPlaybackAudio);\n }\n for (const elements of this.attached.values()) {\n for (const el of elements) {\n void el.play().catch(() => undefined);\n }\n }\n }\n\n async disconnect(): Promise<void> {\n if (!this.room && this.connectionState() === 'idle') return;\n this.connectionState.set('disconnecting');\n await this.cleanupLocal(true);\n this.connectionState.set('idle');\n this.mode.set(null);\n this.activeCallId.set(null);\n this.micEnabled.set(false);\n this.error.set(null);\n this.audioPlaybackAllowed.set(true);\n }\n\n private readonly onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (track.kind !== Track.Kind.Audio) return;\n\n // Never play another staff softphone back — that is a direct feedback loop\n // where the person taking over hears their own voice.\n if (this.isStaff(participant.identity)) {\n try {\n publication.setSubscribed(false);\n } catch {\n /* server may already have unsubscribed */\n }\n return;\n }\n\n const container = this.ensureAudioContainer();\n const element = track.attach();\n element.autoplay = true;\n element.setAttribute('playsinline', 'true');\n (element as HTMLAudioElement).volume = 1;\n container.appendChild(element);\n\n const key = publication.trackSid || track.sid || participant.identity;\n this.attached.set(key, [...(this.attached.get(key) ?? []), element]);\n this.remoteAudioAttached.set(true);\n void element.play().catch(() => {\n // Autoplay blocked — surfaced via the \"Enable sound\" action.\n this.audioPlaybackAllowed.set(false);\n });\n };\n\n private readonly onTrackUnsubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (track.kind !== Track.Kind.Audio) return;\n const key = publication.trackSid || track.sid || participant.identity;\n this.detachKey(key, track);\n };\n\n private readonly onParticipantDisconnected = (participant: RemoteParticipant): void => {\n for (const publication of participant.trackPublications.values()) {\n const key = publication.trackSid;\n if (key) this.detachKey(key);\n }\n };\n\n /** Staff tracks are dropped server-side as soon as they appear. */\n private readonly onTrackPublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (!this.isStaff(participant.identity)) return;\n try {\n publication.setSubscribed(false);\n } catch {\n /* nothing to unsubscribe */\n }\n };\n\n private attachExistingRemoteTracks(room: Room): void {\n for (const participant of room.remoteParticipants.values()) {\n for (const publication of participant.trackPublications.values()) {\n if (publication.track && publication.isSubscribed) {\n this.onTrackSubscribed(publication.track, publication, participant);\n }\n }\n }\n }\n\n private isStaff(identity?: string | null): boolean {\n return !!identity && identity.startsWith(STAFF_IDENTITY_PREFIX);\n }\n\n private detachKey(key: string, track?: RemoteTrack): void {\n const elements = this.attached.get(key);\n if (!elements) return;\n this.attached.delete(key);\n for (const el of elements) {\n try {\n track?.detach(el);\n } catch {\n /* already detached */\n }\n el.remove();\n }\n if (this.attached.size === 0) this.remoteAudioAttached.set(false);\n }\n\n private ensureAudioContainer(): HTMLElement {\n if (this.audioContainer?.isConnected) return this.audioContainer;\n const el = document.createElement('div');\n el.dataset['edsStaffAudio'] = 'true';\n el.style.position = 'fixed';\n el.style.width = '0';\n el.style.height = '0';\n el.style.overflow = 'hidden';\n document.body.appendChild(el);\n this.audioContainer = el;\n return el;\n }\n\n private async enableMicrophone(enabled: boolean): Promise<void> {\n const room = this.room;\n if (!room) return;\n await room.localParticipant.setMicrophoneEnabled(enabled);\n this.micEnabled.set(enabled);\n }\n\n private friendlyError(err: unknown): string {\n const name = (err as { name?: string } | null)?.name ?? '';\n if (name === 'NotAllowedError' || name === 'SecurityError') {\n return 'Microphone permission was denied. Allow microphone access and try again.';\n }\n if (name === 'NotFoundError' || name === 'OverconstrainedError') {\n return 'No microphone was found on this device.';\n }\n if (name === 'NotReadableError' || name === 'TrackStartError') {\n return 'Your microphone is in use by another app.';\n }\n const message = err instanceof Error ? err.message : '';\n if (message.includes('getUserMedia')) {\n return this.microphoneBlockedReason() ?? message;\n }\n return message || 'Failed to join the call audio.';\n }\n\n private async cleanupLocal(disconnectRoom: boolean): Promise<void> {\n const room = this.room;\n this.room = null;\n\n for (const key of [...this.attached.keys()]) {\n this.detachKey(key);\n }\n this.remoteAudioAttached.set(false);\n this.audioContainer?.remove();\n this.audioContainer = null;\n\n if (!room) return;\n try {\n await room.localParticipant.setMicrophoneEnabled(false);\n } catch {\n /* mic may never have been published */\n }\n try {\n if (disconnectRoom) {\n await room.disconnect(true);\n }\n room.removeAllListeners();\n } catch {\n /* already gone */\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\nimport { firstValueFrom } from 'rxjs';\n\nimport { LiveTranscriptPanelComponent } from '../../components/live-transcript-panel/live-transcript-panel.component';\nimport { CallRecordingPlayerComponent } from '../../components/call-recording-player/call-recording-player.component';\nimport {\n CallControlMode,\n LiveCall,\n Sentiment,\n} from '../../models/ai-receptionist.types';\nimport {\n CallControlChangedEvent,\n StaffMediaMode,\n} from '../../models/staff-media.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { DashboardSocketService } from '../../services/dashboard-socket.service';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { StaffMediaService } from '../../services/staff-media.service';\nimport { ToastService } from '../../shared/toast.service';\nimport {\n ageFromDob,\n callerMetaLine,\n isUnknownCaller,\n} from '../../utils/call-history-display.util';\nimport { toolEventTrackKey } from '../../utils/tool-labels.util';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-monitor-page',\n imports: [\n RouterLink,\n FormsModule,\n EdsAvatarComponent,\n EdsIconComponent,\n EdsElapsedPipe,\n LiveTranscriptPanelComponent,\n CallRecordingPlayerComponent,\n ],\n templateUrl: './live-monitor-page.component.html',\n styleUrl: './live-monitor-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LiveMonitorPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n private readonly stream = inject(LiveTranscriptService);\n private readonly staffMedia = inject(StaffMediaService);\n private readonly socket = inject(DashboardSocketService);\n private readonly toast = inject(ToastService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly call = signal<LiveCall | null>(null);\n protected readonly staffMessage = signal('');\n protected readonly loading = signal(true);\n protected readonly callId = signal('');\n protected readonly summary = signal<string | null>(null);\n protected readonly summaryLoading = signal(false);\n protected readonly mediaBusy = signal(false);\n\n protected readonly liveTools = this.stream.tools;\n protected readonly callEnded = this.stream.callEnded;\n protected readonly mediaState = this.staffMedia.connectionState;\n protected readonly mediaMode = this.staffMedia.mode;\n protected readonly micEnabled = this.staffMedia.micEnabled;\n protected readonly audioPlaybackAllowed = this.staffMedia.audioPlaybackAllowed;\n\n private summaryLoaded = false;\n private staffJoined = false;\n\n private readonly onControlChanged = (evt: CallControlChangedEvent): void => {\n if (!evt?.callId || evt.callId !== this.callId()) return;\n this.call.update((c) => {\n if (!c) return c;\n const handedOff = evt.aiHandedOff === true || c.aiHandedOff === true;\n const controlMode = (evt.controlMode as CallControlMode | null | undefined) ?? c.controlMode;\n const next: LiveCall = {\n ...c,\n controlMode,\n aiPaused: typeof evt.aiPaused === 'boolean' ? evt.aiPaused : c.aiPaused,\n aiHandedOff: handedOff,\n assigned: evt.assigned !== undefined ? evt.assigned : c.assigned,\n };\n if (controlMode === 'takeover' || handedOff) {\n next.status = 'takeover';\n } else if (controlMode === 'ai' || controlMode === 'listen') {\n if (c.status === 'takeover') next.status = 'ai';\n }\n return next;\n });\n };\n\n constructor() {\n effect(() => {\n if (this.stream.callEnded()) {\n void this.staffMedia.disconnect();\n this.staffJoined = false;\n this.loadCallMetadataOnce();\n }\n });\n\n effect(() => {\n if (this.stream.summaryRequested() && !this.summaryLoaded) {\n this.loadPostCallSummary();\n }\n });\n }\n\n ngOnInit(): void {\n this.socket.acquire();\n this.socket.on<CallControlChangedEvent>('call_control_changed', this.onControlChanged);\n\n this.route.paramMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {\n const id = params.get('id') ?? '';\n this.callId.set(id);\n // The softphone lives in a root service, so a session started earlier is still\n // running when this page is re-created.\n this.staffJoined = this.staffMedia.isConnectedTo(id);\n this.loading.set(true);\n this.summary.set(null);\n this.summaryLoaded = false;\n this.stream.stop();\n this.loadCallMetadata();\n });\n }\n\n /**\n * Leaving the page must never drop the caller. The LiveKit session is owned by the\n * root StaffMediaService and keeps running until End Call or an explicit leave.\n */\n ngOnDestroy(): void {\n this.socket.off('call_control_changed', this.onControlChanged);\n this.socket.release();\n this.stream.stop();\n }\n\n /** True when this page's call is the one the softphone is connected to. */\n protected isMediaForThisCall(): boolean {\n return this.staffMedia.activeCallId() === this.callId();\n }\n\n protected isTakeover(): boolean {\n if (this.mediaMode() === 'takeover' && this.isMediaForThisCall()) return true;\n const c = this.call();\n if (!c) return false;\n if (c.aiHandedOff) return true;\n if (c.controlMode === 'listen') return false;\n return c.controlMode === 'takeover' || c.status === 'takeover' || !!c.assigned;\n }\n\n /** After takeover the AI is gone for good — no resume path is offered. */\n protected isHandedOff(): boolean {\n return this.call()?.aiHandedOff === true || this.isTakeover();\n }\n\n protected isPaused(): boolean {\n const c = this.call();\n return c?.controlMode === 'paused' || !!c?.aiPaused;\n }\n\n protected isLive(): boolean {\n return !!this.call() && !this.callEnded();\n }\n\n protected confidenceLevel(confidence: number): 'high' | 'low' | 'mid' {\n if (confidence >= 70) return 'high';\n if (confidence < 50) return 'low';\n return 'mid';\n }\n\n protected sentimentPercent(sentiment: Sentiment): number {\n const map: Record<Sentiment, number> = {\n calm: 85,\n neutral: 60,\n frustrated: 35,\n urgent: 15,\n };\n return map[sentiment];\n }\n\n protected toolStateClass(state: string): string {\n return `live-monitor-page__tool--${state}`;\n }\n\n protected readonly toolTrackKey = toolEventTrackKey;\n\n protected isUnknownCaller(call: LiveCall): boolean {\n return isUnknownCaller(call.name, call.matched);\n }\n\n protected displayName(call: LiveCall): string {\n return this.isUnknownCaller(call) ? 'Unknown Caller' : call.name.trim();\n }\n\n protected profileInitials(call: LiveCall): string {\n return this.isUnknownCaller(call) ? '?' : call.initials || '?';\n }\n\n protected profileMeta(call: LiveCall): string {\n return callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n });\n }\n\n protected goalBadge(call: LiveCall): string | null {\n const raw = (call.goal || call.reason || '').trim();\n if (!raw) return null;\n return raw.replace(/[_-]+/g, ' ').toUpperCase();\n }\n\n protected takeover(): void {\n void this.joinMedia('takeover');\n }\n\n protected toggleMic(): void {\n void this.staffMedia.toggleMicrophone();\n }\n\n protected transfer(): void {\n this.api.postTransfer(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected endCall(): void {\n const id = this.callId();\n void this.staffMedia.disconnect().then(() => {\n this.staffJoined = false;\n this.api.postEnd(id).subscribe(() => {\n this.stream.markCompleted();\n this.loadCallMetadataOnce();\n this.loadPostCallSummary();\n });\n });\n }\n\n protected sendMessage(): void {\n const text = this.staffMessage().trim();\n if (!text) return;\n this.api.postMessage(this.callId(), text).subscribe(() => {\n this.staffMessage.set('');\n this.refreshMetadata();\n });\n }\n\n protected enableSound(): void {\n void this.staffMedia.startAudioPlayback();\n }\n\n private async joinMedia(mode: StaffMediaMode): Promise<void> {\n if (this.mediaBusy() || this.callEnded()) return;\n const id = this.callId();\n if (!id) return;\n\n // Check the mic before joining so a blocked browser never leaves the AI paused.\n if (mode === 'takeover' && !this.api.usesMockStreaming()) {\n const blocked = this.staffMedia.microphoneBlockedReason();\n if (blocked) {\n this.toast.show(blocked, 'error', 6000);\n return;\n }\n }\n\n this.mediaBusy.set(true);\n try {\n const { data } = await firstValueFrom(this.api.postMediaJoin(id, mode));\n this.applyJoinMetadata(data);\n\n if (!this.api.usesMockStreaming()) {\n await this.staffMedia.join(data);\n }\n this.staffJoined = true;\n this.toast.show(\n mode === 'takeover' ? 'You are on the call' : 'Listening to the call',\n 'success',\n );\n } catch (err) {\n const message =\n err instanceof Error ? err.message : `Failed to ${mode === 'takeover' ? 'take over' : 'listen'}`;\n this.toast.show(message, 'error');\n try {\n await this.staffMedia.disconnect();\n await firstValueFrom(this.api.postMediaLeave(id));\n } catch {\n /* ignore cleanup errors */\n }\n this.staffJoined = false;\n } finally {\n this.mediaBusy.set(false);\n }\n }\n\n /**\n * Disconnect LiveKit first, then tell the server to drop staff and restore AI.\n * Only valid in listen mode — a taken-over call stays with the human.\n * Does not hang up the patient.\n */\n private async leaveMedia(notifyServer: boolean): Promise<void> {\n const id = this.callId();\n const wasJoined = this.staffJoined || this.staffMedia.isConnectedTo(id);\n try {\n await this.staffMedia.disconnect();\n } catch {\n /* ignore */\n }\n this.staffJoined = false;\n\n if (!notifyServer || !wasJoined || !id || this.callEnded()) return;\n\n this.mediaBusy.set(true);\n try {\n await firstValueFrom(this.api.postResumeAi(id));\n this.call.update((c) =>\n c\n ? {\n ...c,\n status: c.status === 'takeover' ? 'ai' : c.status,\n controlMode: 'ai',\n assigned: null,\n aiPaused: false,\n }\n : c,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to resume AI';\n this.toast.show(message, 'error');\n } finally {\n this.mediaBusy.set(false);\n }\n }\n\n private applyJoinMetadata(data: {\n controlMode?: string | null;\n aiPaused?: boolean;\n aiHandedOff?: boolean;\n assigned?: string | null;\n mode: StaffMediaMode;\n }): void {\n this.call.update((c) => {\n if (!c) return c;\n const controlMode = (data.controlMode as CallControlMode) || data.mode;\n return {\n ...c,\n controlMode,\n aiPaused: typeof data.aiPaused === 'boolean' ? data.aiPaused : data.mode === 'takeover',\n aiHandedOff:\n data.aiHandedOff === true || data.mode === 'takeover' || c.aiHandedOff === true,\n assigned:\n data.assigned !== undefined && data.assigned !== null\n ? data.assigned\n : data.mode === 'takeover'\n ? c.assigned || 'You'\n : c.assigned,\n status: data.mode === 'takeover' ? 'takeover' : c.status,\n };\n });\n }\n\n /** Initial load — seeds transcript/tools from REST, then starts socket. */\n private loadCallMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n this.call.set(data);\n this.loading.set(false);\n if (data) {\n this.stream.seed(data.transcript, data.tools);\n if (!this.callEnded()) {\n this.stream.watch(id, true);\n }\n }\n });\n }\n\n /** Metadata-only refresh after staff actions — does not overwrite live transcript/tools. */\n private refreshMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) this.call.set(data);\n });\n }\n\n /** One-time metadata refresh after call ends (no socket). */\n private loadCallMetadataOnce(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) {\n this.call.set(data);\n }\n });\n }\n\n private loadPostCallSummary(): void {\n const id = this.callId();\n if (!id || this.summaryLoaded) return;\n this.summaryLoading.set(true);\n this.api.getCallSummary(id).subscribe(({ data }) => {\n this.summaryLoading.set(false);\n this.summaryLoaded = true;\n if (!data) return;\n this.summary.set(data.summary);\n this.stream.seed(data.transcript, data.tools);\n });\n }\n}\n","<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call…</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting…\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call · mic on' : 'On call · mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary…</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '—' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <div class=\"flex flex-col items-start gap-3\">\n <a routerLink=\"..\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n </div>\n }\n }\n</div>\n"],"names":[],"mappings":";;;;;;;;;;;;;AA2BM,SAAU,cAAc,CAAC,KAAsB,EAAA;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;IACtC,OAAO;AACL,QAAA,GAAG,EACD,KAAK,CAAC,IAAI,KAAK;AACb,cAAE;AACF,cAAE,KAAK,CAAC,IAAI,KAAK;AACf,kBAAE;AACF,kBAAE,KAAK,CAAC,IAAI,KAAK;AACf,sBAAE;AACF,sBAAE,SAAS;QACnB,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;KAC1C;AACH;AAEM,SAAU,eAAe,CAAC,GAAW,EAAA;IACzC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;AAC/C,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,MAAM,EAAE,SAAS;AACjB,QAAA,MAAM,EAAE,SAAS;AACjB,QAAA,MAAM,EAAE,KAAK;AACd,KAAA,CAAC;AACJ;AAEM,SAAU,kBAAkB,CAAC,KAA6B,EAAA;AAC9D,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO;AACvB,IAAA,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC1E,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC;AACjD,IAAA,MAAM,GAAG,GAAG,cAAc,CACxB,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,EAC/C,OAAO,EACP,IAAI,CACL;IACD,OAAO;AACL,QAAA,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC;QACpC,GAAG;AACH,QAAA,IAAI,EAAE,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC;QAC1C,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;AACjC,QAAA,KAAK,EACH,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AACnE,cAAE;AACF,cAAE,IAAI;KACX;AACH;AAEM,SAAU,uBAAuB,CAAC,KAA6B,EAAA;AACnE,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO;IACvB,OAAO;AACL,QAAA,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC;QACpC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;QACxC,IAAI,EAAE,KAAK,CAAC,SAAS;AACrB,QAAA,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;AAChE,QAAA,KAAK,EAAE,IAAI;KACZ;AACH;AAEM,SAAU,yBAAyB,CAAC,KAAuB,EAAE,IAAoB,EAAA;AACrF,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACpF;;AC1EA;;;AAGG;MAEU,qBAAqB,CAAA;AADlC,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACvC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,yBAAyB,CAAC;AAElD,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAmB,EAAE,CAAC;AACpC,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC5C,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAgB,IAAI,CAAC;AACvC,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC1C,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAc,EAAE,CAAC;AAC/B,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;AACjC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC;AACnC,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AACzB,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;QAEjC,IAAA,CAAA,YAAY,GAAkB,IAAI;QAClC,IAAA,CAAA,QAAQ,GAAG,KAAK;QAChB,IAAA,CAAA,SAAS,GAA0C,IAAI;QACvD,IAAA,CAAA,SAAS,GAAG,CAAC;AAEJ,QAAA,IAAA,CAAA,YAAY,GAAG,CAAC,KAAsB,KAAK,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAClE,QAAA,IAAA,CAAA,YAAY,GAAG,CAAC,KAA6B,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAC7E,IAAA,CAAA,eAAe,GAAG,MAAK;AACtC,YAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,gBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/D;AACF,QAAA,CAAC;AA6MF,IAAA;IA3MC,IAAI,CAAC,UAA4B,EAAE,UAAuB,EAAA;QACxD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;IACzD;AAEA,IAAA,KAAK,CAAC,MAAc,EAAE,IAAI,GAAG,IAAI,EAAA;AAC/B,QAAA,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI;YAAE;AAElB,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,KAAK,EAAE;QAC9C,IAAI,aAAa,EAAE;YACjB,IAAI,CAAC,uBAAuB,EAAE;YAC9B,IAAI,CAAC,YAAY,EAAE;AACnB,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;AAChC,YAAA,IAAI,CAAC,YAAY,GAAG,EAAE;QACxB;AAAO,aAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;YACxB;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AAC1B,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACpB,YAAA,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;YACxB;QACF;AAEA,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC;AAC3C,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACtB;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE;AAC3B,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAChD;IACF;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QACxB,IAAI,CAAC,uBAAuB,EAAE;QAC9B,IAAI,CAAC,gBAAgB,EAAE;IACzB;IAEA,aAAa,GAAA;AACX,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,uBAAuB,EAAE;QAC9B,IAAI,CAAC,YAAY,EAAE;IACrB;IAEQ,uBAAuB,GAAA;QAC7B,IAAI,CAAC,cAAc,EAAE;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;QAEpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC;AAC5C,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;AACrB,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK;IACvB;AAEQ,IAAA,WAAW,CAAC,KAAsB,EAAA;AACxC,QAAA,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;YAAE;AAE1B,QAAA,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE;AACzB,YAAA,IAAI,KAAK,CAAC,OAAO,EAAE;AACjB,gBAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC7B,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC7C;iBAAO;gBACL,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YACrC;YACA;QACF;AAEA,QAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;YAC3B,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC3C;QACF;AAEA,QAAA,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;AAC1B,YAAA,IAAI,KAAK,CAAC,OAAO,EAAE;AACjB,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC7C;iBAAO;gBACL,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YACnC;YACA;QACF;AAEA,QAAA,IAAI,KAAK,CAAC,OAAO,EAAE;AACjB,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YACxB,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC7C;aAAO;YACL,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QAChC;IACF;AAEQ,IAAA,eAAe,CAAC,KAA6B,EAAA;QACnD,IAAI,CAAC,KAAK,EAAE,SAAS;YAAE;QAEvB,IAAI,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;YACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;YACjE;QACF;AAEA,QAAA,IAAI,KAAK,CAAC,SAAS,KAAK,gBAAgB,EAAE;YACxC,IAAI,CAAC,aAAa,EAAE;YACpB;QACF;AAEA,QAAA,IAAI,KAAK,CAAC,SAAS,KAAK,mBAAmB,EAAE;AAC3C,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;YAC/B;QACF;QAEA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE;AAEQ,IAAA,eAAe,CAAC,IAAoB,EAAA;QAC1C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAI;AACzB,YAAA,IAAI,yBAAyB,CAAC,IAAI,EAAE,IAAI,CAAC;AAAE,gBAAA,OAAO,IAAI;AACtD,YAAA,OAAO,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC;AACxB,QAAA,CAAC,CAAC;IACJ;AAEQ,IAAA,eAAe,CAAC,MAAc,EAAA;QACpC,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,IAAI,CAAC,SAAS,GAAG,CAAC;AAElB,QAAA,MAAM,UAAU,GAAsB;AACpC,YAAA;AACE,gBAAA,IAAI,EAAE,MAAM;AACZ,gBAAA,IAAI,EAAE,wCAAwC;AAC9C,gBAAA,OAAO,EAAE,KAAK;AACd,gBAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACpC,aAAA;AACD,YAAA;AACE,gBAAA,IAAI,EAAE,MAAM;AACZ,gBAAA,IAAI,EAAE,wCAAwC;AAC9C,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACpC,aAAA;AACD,YAAA;AACE,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,IAAI,EAAE,oEAAoE;AAC1E,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACpC,aAAA;SACF;AAED,QAAA,MAAM,UAAU,GAA6B;AAC3C,YAAA;AACE,gBAAA,SAAS,EAAE,gCAAgC;AAC3C,gBAAA,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACpC,gBAAA,OAAO,EAAE;AACP,oBAAA,GAAG,EAAE,2BAA2B;AAChC,oBAAA,IAAI,EAAE,6BAA6B;AACnC,oBAAA,IAAI,EAAE,gCAAgC;AACtC,oBAAA,MAAM,EAAE,8BAA8B;AACtC,oBAAA,KAAK,EAAE,IAAI;AACZ,iBAAA;AACF,aAAA;SACF;AAED,QAAA,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,MAAK;AAChC,YAAA,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM,EAAE;gBAChC,IAAI,CAAC,cAAc,EAAE;gBACrB;YACF;YACA,IAAI,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE;gBACtC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC5C,IAAI,CAAC,SAAS,EAAE;gBAChB;YACF;YACA,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC,MAAM,EAAE;gBACxC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,CAAC,SAAS,EAAE;YAClB;QACF,CAAC,EAAE,IAAI,CAAC;IACV;IAEQ,cAAc,GAAA;AACpB,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7B,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACvB;IACF;IAEQ,YAAY,GAAA;AAClB,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7B,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;IAEQ,gBAAgB,GAAA;AACtB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AAClB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,EAAE;AACnB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;IAClC;+GArOW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAArB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,cADR,MAAM,EAAA,CAAA,CAAA;;4FACnB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBADjC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCWrB,4BAA4B,CAAA;AAgCvC,IAAA,WAAA,GAAA;AA/BS,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;AAClB,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;AACrB,QAAA,IAAA,CAAA,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC;AAC5B,QAAA,IAAA,CAAA,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC;AAC7B,QAAA,IAAA,CAAA,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC;;AAExB,QAAA,IAAA,CAAA,UAAU,GAAG,KAAK,CAAgB,IAAI,CAAC;;AAEvC,QAAA,IAAA,CAAA,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC;QAC5B,IAAA,CAAA,kBAAkB,GAAG,MAAM,EAAU;QACrC,IAAA,CAAA,WAAW,GAAG,MAAM,EAAQ;AAEpB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAIpC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;AACzB,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc;AAC3C,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;AACjC,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;AACvC,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;AACjC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;AAEzB,QAAA,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YAC5C,IAAI,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;AAAE,gBAAA,OAAO,gBAAgB;YACxE,OAAO,IAAI,IAAI,gBAAgB;AACjC,QAAA,CAAC,CAAC;QAEM,IAAA,CAAA,YAAY,GAAG,KAAK;QAG1B,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,KAAK,EAAE;YACZ,IAAI,CAAC,cAAc,EAAE;YACrB,IAAI,CAAC,SAAS,EAAE;YAChB,IAAI,CAAC,YAAY,EAAE;YACnB,IAAI,CAAC,aAAa,EAAE;AACtB,QAAA,CAAC,CAAC;IACJ;IAEA,kBAAkB,GAAA;QAChB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,UAAU,EAAE;AACxC,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa;AACxC,YAAA,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY;AAC9B,YAAA,IAAI,CAAC,YAAY,GAAG,KAAK;QAC3B;IACF;AAEU,IAAA,SAAS,CAAC,GAAkB,EAAA;QACpC,QAAQ,GAAG;AACT,YAAA,KAAK,IAAI;AACP,gBAAA,OAAO,UAAU;AACnB,YAAA,KAAK,SAAS;AACZ,gBAAA,OAAO,IAAI,CAAC,WAAW,EAAE;AAC3B,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,OAAO;AAChB,YAAA;AACE,gBAAA,OAAO,QAAQ;;IAErB;AAEU,IAAA,WAAW,CAAC,GAAkB,EAAA;QACtC,QAAQ,GAAG;AACT,YAAA,KAAK,IAAI;AACP,gBAAA,OAAO,YAAY;AACrB,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,eAAe;AACxB,YAAA,KAAK,SAAS;AACZ,gBAAA,OAAO,QAAQ;AACjB,YAAA;AACE,gBAAA,OAAO,MAAM;;IAEnB;AAEU,IAAA,UAAU,CAAC,IAAa,EAAA;QAChC,IAAI,IAAI,KAAK,QAAQ;AAAE,YAAA,OAAO,eAAe;AAC7C,QAAA,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU;AAAE,YAAA,OAAO,MAAM;AACzD,QAAA,OAAO,MAAM;IACf;AAEU,IAAA,YAAY,CAAC,KAAa,EAAA;AAClC,QAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC;IAEU,MAAM,GAAA;AACd,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;IACzB;IAEQ,aAAa,GAAA;AACnB,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;IAC1B;+GA5FW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA5B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,yGAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,YAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,YAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC7BzC,mkMA0GA,EAAA,MAAA,EAAA,CAAA,0QAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDrFY,WAAW,+mBAAE,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAQ5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAVxC,SAAS;+BACE,2BAA2B,EAAA,OAAA,EAC5B,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAA,eAAA,EAGvB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,KAAK,EAAE,yGAAyG;AACjH,qBAAA,EAAA,QAAA,EAAA,mkMAAA,EAAA,MAAA,EAAA,CAAA,0QAAA,CAAA,EAAA;wDAiBgC,UAAU,EAAA,CAAA;sBAA1C,SAAS;uBAAC,YAAY;;;AExBzB,MAAM,qBAAqB,GAAG,QAAQ;AAEtC;;;;;;AAMG;MAEU,iBAAiB,CAAA;AAD9B,IAAA,WAAA,GAAA;AAEW,QAAA,IAAA,CAAA,eAAe,GAAG,MAAM,CAA4B,MAAM,CAAC;AAC3D,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAwB,IAAI,CAAC;AAC1C,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;AAC1B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC;AACnC,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAgB,IAAI,CAAC;;AAE1C,QAAA,IAAA,CAAA,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC;;AAEnC,QAAA,IAAA,CAAA,mBAAmB,GAAG,MAAM,CAAC,KAAK,CAAC;QAEpC,IAAA,CAAA,IAAI,GAAgB,IAAI;QACxB,IAAA,CAAA,cAAc,GAAuB,IAAI;AAChC,QAAA,IAAA,CAAA,QAAQ,GAAG,IAAI,GAAG,EAA8B;QAuJhD,IAAA,CAAA,iBAAiB,GAAG,CACnC,KAAkB,EAClB,WAAmC,EACnC,WAA8B,KACtB;YACR,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK;gBAAE;;;YAIrC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE;AACtC,gBAAA,IAAI;AACF,oBAAA,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC;gBAClC;AAAE,gBAAA,MAAM;;gBAER;gBACA;YACF;AAEA,YAAA,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,EAAE;AAC7C,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE;AAC9B,YAAA,OAAO,CAAC,QAAQ,GAAG,IAAI;AACvB,YAAA,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC;AAC1C,YAAA,OAA4B,CAAC,MAAM,GAAG,CAAC;AACxC,YAAA,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC;AAE9B,YAAA,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,IAAI,WAAW,CAAC,QAAQ;YACrE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACpE,YAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;YAClC,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAK;;AAE7B,gBAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC;AACtC,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC;QAEgB,IAAA,CAAA,mBAAmB,GAAG,CACrC,KAAkB,EAClB,WAAmC,EACnC,WAA8B,KACtB;YACR,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK;gBAAE;AACrC,YAAA,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,IAAI,WAAW,CAAC,QAAQ;AACrE,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC;AAC5B,QAAA,CAAC;AAEgB,QAAA,IAAA,CAAA,yBAAyB,GAAG,CAAC,WAA8B,KAAU;YACpF,KAAK,MAAM,WAAW,IAAI,WAAW,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE;AAChE,gBAAA,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ;AAChC,gBAAA,IAAI,GAAG;AAAE,oBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAC9B;AACF,QAAA,CAAC;;AAGgB,QAAA,IAAA,CAAA,gBAAgB,GAAG,CAClC,WAAmC,EACnC,WAA8B,KACtB;YACR,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;gBAAE;AACzC,YAAA,IAAI;AACF,gBAAA,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC;YAClC;AAAE,YAAA,MAAM;;YAER;AACF,QAAA,CAAC;AA+FF,IAAA;AAlTC,IAAA,IAAI,WAAW,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,eAAe,EAAE,KAAK,WAAW;IAC/C;;AAGA,IAAA,aAAa,CAAC,MAAc,EAAA;QAC1B,OAAO,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE,KAAK,MAAM;IAC3D;AAEA;;;AAGG;IACH,uBAAuB,GAAA;QACrB,IAAI,OAAO,SAAS,KAAK,WAAW;AAAE,YAAA,OAAO,kDAAkD;AAC/F,QAAA,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE;YACzC,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,eAAe;AACtE,YAAA,OAAO;AACL,kBAAE;kBACA,+GAA+G;QACrH;AACA,QAAA,OAAO,IAAI;IACb;IAEA,MAAM,IAAI,CAAC,IAA0B,EAAA;QACnC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE;YAChD,MAAM,IAAI,KAAK,CAAC,CAAA,4BAAA,EAA+B,IAAI,CAAC,QAAQ,CAAA,CAAE,CAAC;QACjE;QACA,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACzC,YAAA,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;QACxE;AACA,QAAA,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;AAC5B,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,uBAAuB,EAAE;AAC9C,YAAA,IAAI,OAAO;AAAE,gBAAA,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC;QACvC;AAEA,QAAA,MAAM,IAAI,CAAC,UAAU,EAAE;AAEvB,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC;AACtC,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;AAC1C,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAE1B,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;AACpB,YAAA,cAAc,EAAE,IAAI;AACpB,YAAA,QAAQ,EAAE,IAAI;AACd,YAAA,oBAAoB,EAAE;AACpB,gBAAA,gBAAgB,EAAE,IAAI;AACtB,gBAAA,gBAAgB,EAAE,IAAI;AACtB,gBAAA,eAAe,EAAE,IAAI;AACtB,aAAA;AACF,SAAA,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,MAAK;AACnC,YAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;gBAAE;AACxB,YAAA,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;AAC7B,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;AAChC,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,sBAAsB,EAAE,CAAC,KAAsB,KAAI;AACnE,YAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;gBAAE;AACxB,YAAA,IAAI,KAAK,KAAK,eAAe,CAAC,SAAS,EAAE;AACvC,gBAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC;YACvC;AAAO,iBAAA,IAAI,KAAK,KAAK,eAAe,CAAC,UAAU,IAAI,KAAK,KAAK,eAAe,CAAC,YAAY,EAAE;AACzF,gBAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC;YACxC;AACF,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,0BAA0B,EAAE,MAAK;AACjD,YAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;gBACtB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC;YACtD;AACF,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,iBAAiB,CAAC;QAC1D,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,CAAC,mBAAmB,CAAC;QAC9D,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,uBAAuB,EAAE,IAAI,CAAC,yBAAyB,CAAC;QAC1E,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC;AAExD,QAAA,IAAI;AACF,YAAA,IAAI,CAAC,IAAI,GAAG,IAAI;YAChB,IAAI,CAAC,oBAAoB,EAAE;AAC3B,YAAA,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC;;AAGrD,YAAA,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;AAC5B,gBAAA,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACnC;AAEA,YAAA,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC;AACrC,YAAA,MAAM,IAAI,CAAC,kBAAkB,EAAE;AAC/B,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC;QACvC;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;AACvC,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvB,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;AACjC,YAAA,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;AAC7B,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,YAAA,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC;QAC1B;IACF;IAEA,MAAM,oBAAoB,CAAC,OAAgB,EAAA;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,KAAK,WAAW;YAAE;QAC1D,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,UAAU,IAAI,OAAO,EAAE;;YAEzC;QACF;AACA,QAAA,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;IACtC;AAEA,IAAA,MAAM,gBAAgB,GAAA;QACpB,MAAM,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;IACrD;;AAGA,IAAA,MAAM,kBAAkB,GAAA;AACtB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AACtB,QAAA,IAAI,CAAC,IAAI;YAAE;AACX,QAAA,IAAI;AACF,YAAA,MAAM,IAAI,CAAC,UAAU,EAAE;AACvB,YAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;QACrC;AAAE,QAAA,MAAM;YACN,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC;QACtD;QACA,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE;AAC7C,YAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;AACzB,gBAAA,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;YACvC;QACF;IACF;AAEA,IAAA,MAAM,UAAU,GAAA;QACd,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,KAAK,MAAM;YAAE;AACrD,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,eAAe,CAAC;AACzC,QAAA,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;AAC7B,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;AAChC,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,QAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;IACrC;AAkEQ,IAAA,0BAA0B,CAAC,IAAU,EAAA;QAC3C,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE;YAC1D,KAAK,MAAM,WAAW,IAAI,WAAW,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE;gBAChE,IAAI,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,YAAY,EAAE;oBACjD,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC;gBACrE;YACF;QACF;IACF;AAEQ,IAAA,OAAO,CAAC,QAAwB,EAAA;QACtC,OAAO,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC;IACjE;IAEQ,SAAS,CAAC,GAAW,EAAE,KAAmB,EAAA;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;AACvC,QAAA,IAAI,CAAC,QAAQ;YAAE;AACf,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;AACzB,QAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;AACzB,YAAA,IAAI;AACF,gBAAA,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;YACnB;AAAE,YAAA,MAAM;;YAER;YACA,EAAE,CAAC,MAAM,EAAE;QACb;AACA,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC;IACnE;IAEQ,oBAAoB,GAAA;AAC1B,QAAA,IAAI,IAAI,CAAC,cAAc,EAAE,WAAW;YAAE,OAAO,IAAI,CAAC,cAAc;QAChE,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AACxC,QAAA,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM;AACpC,QAAA,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO;AAC3B,QAAA,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG;AACpB,QAAA,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG;AACrB,QAAA,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ;AAC5B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;AAC7B,QAAA,IAAI,CAAC,cAAc,GAAG,EAAE;AACxB,QAAA,OAAO,EAAE;IACX;IAEQ,MAAM,gBAAgB,CAAC,OAAgB,EAAA;AAC7C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AACtB,QAAA,IAAI,CAAC,IAAI;YAAE;QACX,MAAM,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,OAAO,CAAC;AACzD,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC;IAC9B;AAEQ,IAAA,aAAa,CAAC,GAAY,EAAA;AAChC,QAAA,MAAM,IAAI,GAAI,GAAgC,EAAE,IAAI,IAAI,EAAE;QAC1D,IAAI,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,eAAe,EAAE;AAC1D,YAAA,OAAO,0EAA0E;QACnF;QACA,IAAI,IAAI,KAAK,eAAe,IAAI,IAAI,KAAK,sBAAsB,EAAE;AAC/D,YAAA,OAAO,yCAAyC;QAClD;QACA,IAAI,IAAI,KAAK,kBAAkB,IAAI,IAAI,KAAK,iBAAiB,EAAE;AAC7D,YAAA,OAAO,2CAA2C;QACpD;AACA,QAAA,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,EAAE;AACvD,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE;AACpC,YAAA,OAAO,IAAI,CAAC,uBAAuB,EAAE,IAAI,OAAO;QAClD;QACA,OAAO,OAAO,IAAI,gCAAgC;IACpD;IAEQ,MAAM,YAAY,CAAC,cAAuB,EAAA;AAChD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AACtB,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAEhB,QAAA,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE;AAC3C,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;QACrB;AACA,QAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC;AACnC,QAAA,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE;AAC7B,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAE1B,QAAA,IAAI,CAAC,IAAI;YAAE;AACX,QAAA,IAAI;YACF,MAAM,IAAI,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,KAAK,CAAC;QACzD;AAAE,QAAA,MAAM;;QAER;AACA,QAAA,IAAI;YACF,IAAI,cAAc,EAAE;AAClB,gBAAA,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAC7B;YACA,IAAI,CAAC,kBAAkB,EAAE;QAC3B;AAAE,QAAA,MAAM;;QAER;IACF;+GAhUW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cADJ,MAAM,EAAA,CAAA,CAAA;;4FACnB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MC2BrB,wBAAwB,CAAA;AAiDnC,IAAA,WAAA,GAAA;AAhDiB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAC9B,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC;AACtC,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACtC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACvC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;AAC5B,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE7B,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAkB,IAAI,CAAC;AACpC,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC;AACzB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AACnB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAgB,IAAI,CAAC;AACrC,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC;AAC9B,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AAEzB,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;AAC7B,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;AACjC,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,eAAe;AAC5C,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI;AAChC,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU;AACvC,QAAA,IAAA,CAAA,oBAAoB,GAAG,IAAI,CAAC,UAAU,CAAC,oBAAoB;QAEtE,IAAA,CAAA,aAAa,GAAG,KAAK;QACrB,IAAA,CAAA,WAAW,GAAG,KAAK;AAEV,QAAA,IAAA,CAAA,gBAAgB,GAAG,CAAC,GAA4B,KAAU;AACzE,YAAA,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE;gBAAE;YAClD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAI;AACrB,gBAAA,IAAI,CAAC,CAAC;AAAE,oBAAA,OAAO,CAAC;AAChB,gBAAA,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,KAAK,IAAI,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI;gBACpE,MAAM,WAAW,GAAI,GAAG,CAAC,WAAkD,IAAI,CAAC,CAAC,WAAW;AAC5F,gBAAA,MAAM,IAAI,GAAa;AACrB,oBAAA,GAAG,CAAC;oBACJ,WAAW;AACX,oBAAA,QAAQ,EAAE,OAAO,GAAG,CAAC,QAAQ,KAAK,SAAS,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;AACvE,oBAAA,WAAW,EAAE,SAAS;AACtB,oBAAA,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;iBACjE;AACD,gBAAA,IAAI,WAAW,KAAK,UAAU,IAAI,SAAS,EAAE;AAC3C,oBAAA,IAAI,CAAC,MAAM,GAAG,UAAU;gBAC1B;qBAAO,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,QAAQ,EAAE;AAC3D,oBAAA,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;AAAE,wBAAA,IAAI,CAAC,MAAM,GAAG,IAAI;gBACjD;AACA,gBAAA,OAAO,IAAI;AACb,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC;QA8FkB,IAAA,CAAA,YAAY,GAAG,iBAAiB;QA3FjD,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE;AAC3B,gBAAA,KAAK,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;AACjC,gBAAA,IAAI,CAAC,WAAW,GAAG,KAAK;gBACxB,IAAI,CAAC,oBAAoB,EAAE;YAC7B;AACF,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;gBACzD,IAAI,CAAC,mBAAmB,EAAE;YAC5B;AACF,QAAA,CAAC,CAAC;IACJ;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAA0B,sBAAsB,EAAE,IAAI,CAAC,gBAAgB,CAAC;QAEtF,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,KAAI;YACjF,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;AACjC,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;;;YAGnB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;AACpD,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,YAAA,IAAI,CAAC,aAAa,GAAG,KAAK;AAC1B,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAClB,IAAI,CAAC,gBAAgB,EAAE;AACzB,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACH,WAAW,GAAA;QACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,gBAAgB,CAAC;AAC9D,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;;IAGU,kBAAkB,GAAA;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE;IACzD;IAEU,UAAU,GAAA;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE,KAAK,UAAU,IAAI,IAAI,CAAC,kBAAkB,EAAE;AAAE,YAAA,OAAO,IAAI;AAC7E,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AACrB,QAAA,IAAI,CAAC,CAAC;AAAE,YAAA,OAAO,KAAK;QACpB,IAAI,CAAC,CAAC,WAAW;AAAE,YAAA,OAAO,IAAI;AAC9B,QAAA,IAAI,CAAC,CAAC,WAAW,KAAK,QAAQ;AAAE,YAAA,OAAO,KAAK;AAC5C,QAAA,OAAO,CAAC,CAAC,WAAW,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;IAChF;;IAGU,WAAW,GAAA;AACnB,QAAA,OAAO,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE;IAC/D;IAEU,QAAQ,GAAA;AAChB,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;QACrB,OAAO,CAAC,EAAE,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ;IACrD;IAEU,MAAM,GAAA;AACd,QAAA,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;IAC3C;AAEU,IAAA,eAAe,CAAC,UAAkB,EAAA;QAC1C,IAAI,UAAU,IAAI,EAAE;AAAE,YAAA,OAAO,MAAM;QACnC,IAAI,UAAU,GAAG,EAAE;AAAE,YAAA,OAAO,KAAK;AACjC,QAAA,OAAO,KAAK;IACd;AAEU,IAAA,gBAAgB,CAAC,SAAoB,EAAA;AAC7C,QAAA,MAAM,GAAG,GAA8B;AACrC,YAAA,IAAI,EAAE,EAAE;AACR,YAAA,OAAO,EAAE,EAAE;AACX,YAAA,UAAU,EAAE,EAAE;AACd,YAAA,MAAM,EAAE,EAAE;SACX;AACD,QAAA,OAAO,GAAG,CAAC,SAAS,CAAC;IACvB;AAEU,IAAA,cAAc,CAAC,KAAa,EAAA;QACpC,OAAO,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAE;IAC5C;AAIU,IAAA,eAAe,CAAC,IAAc,EAAA;QACtC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC;IACjD;AAEU,IAAA,WAAW,CAAC,IAAc,EAAA;AAClC,QAAA,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;IACzE;AAEU,IAAA,eAAe,CAAC,IAAc,EAAA;AACtC,QAAA,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,GAAG;IAChE;AAEU,IAAA,WAAW,CAAC,IAAc,EAAA;AAClC,QAAA,OAAO,cAAc,CAAC;YACpB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;YACrC,MAAM,EAAE,IAAI,CAAC,MAAM;AACpB,SAAA,CAAC;IACJ;AAEU,IAAA,SAAS,CAAC,IAAc,EAAA;AAChC,QAAA,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,IAAI,EAAE;AACnD,QAAA,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,IAAI;QACrB,OAAO,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;IACjD;IAEU,QAAQ,GAAA;AAChB,QAAA,KAAK,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACjC;IAEU,SAAS,GAAA;AACjB,QAAA,KAAK,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE;IACzC;IAEU,QAAQ,GAAA;QAChB,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;IAC9E;IAEU,OAAO,GAAA;AACf,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;QACxB,KAAK,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,MAAK;AAC1C,YAAA,IAAI,CAAC,WAAW,GAAG,KAAK;YACxB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,MAAK;AAClC,gBAAA,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;gBAC3B,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,mBAAmB,EAAE;AAC5B,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;IAEU,WAAW,GAAA;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;AACvC,QAAA,IAAI,CAAC,IAAI;YAAE;AACX,QAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,MAAK;AACvD,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,EAAE;AACxB,QAAA,CAAC,CAAC;IACJ;IAEU,WAAW,GAAA;AACnB,QAAA,KAAK,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE;IAC3C;IAEQ,MAAM,SAAS,CAAC,IAAoB,EAAA;QAC1C,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE;YAAE;AAC1C,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE;YAAE;;AAGT,QAAA,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,uBAAuB,EAAE;YACzD,IAAI,OAAO,EAAE;gBACX,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;gBACvC;YACF;QACF;AAEA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI;AACF,YAAA,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;AACvE,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAE5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE;gBACjC,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC;AACA,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,YAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CACb,IAAI,KAAK,UAAU,GAAG,qBAAqB,GAAG,uBAAuB,EACrE,SAAS,CACV;QACH;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,CAAA,UAAA,EAAa,IAAI,KAAK,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAA,CAAE;YAClG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;AACjC,YAAA,IAAI;AACF,gBAAA,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;gBAClC,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YACnD;AAAE,YAAA,MAAM;;YAER;AACA,YAAA,IAAI,CAAC,WAAW,GAAG,KAAK;QAC1B;gBAAU;AACR,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B;IACF;AAEA;;;;AAIG;IACK,MAAM,UAAU,CAAC,YAAqB,EAAA;AAC5C,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;AACvE,QAAA,IAAI;AACF,YAAA,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;QACpC;AAAE,QAAA,MAAM;;QAER;AACA,QAAA,IAAI,CAAC,WAAW,GAAG,KAAK;AAExB,QAAA,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE;YAAE;AAE5D,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI;YACF,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KACjB;AACE,kBAAE;AACE,oBAAA,GAAG,CAAC;AACJ,oBAAA,MAAM,EAAE,CAAC,CAAC,MAAM,KAAK,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM;AACjD,oBAAA,WAAW,EAAE,IAAI;AACjB,oBAAA,QAAQ,EAAE,IAAI;AACd,oBAAA,QAAQ,EAAE,KAAK;AAChB;kBACD,CAAC,CACN;QACH;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,qBAAqB;YAC1E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;QACnC;gBAAU;AACR,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B;IACF;AAEQ,IAAA,iBAAiB,CAAC,IAMzB,EAAA;QACC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAI;AACrB,YAAA,IAAI,CAAC,CAAC;AAAE,gBAAA,OAAO,CAAC;YAChB,MAAM,WAAW,GAAI,IAAI,CAAC,WAA+B,IAAI,IAAI,CAAC,IAAI;YACtE,OAAO;AACL,gBAAA,GAAG,CAAC;gBACJ,WAAW;gBACX,QAAQ,EAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU;AACvF,gBAAA,WAAW,EACT,IAAI,CAAC,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI;gBACjF,QAAQ,EACN,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK;sBAC7C,IAAI,CAAC;AACP,sBAAE,IAAI,CAAC,IAAI,KAAK;AACd,0BAAE,CAAC,CAAC,QAAQ,IAAI;0BACd,CAAC,CAAC,QAAQ;AAClB,gBAAA,MAAM,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC,MAAM;aACzD;AACH,QAAA,CAAC,CAAC;IACJ;;IAGQ,gBAAgB,GAAA;AACtB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AAC9C,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACvB,IAAI,IAAI,EAAE;AACR,gBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC;AAC7C,gBAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE;oBACrB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC;gBAC7B;YACF;AACF,QAAA,CAAC,CAAC;IACJ;;IAGQ,eAAe,GAAA;AACrB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AAC9C,YAAA,IAAI,IAAI;AAAE,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/B,QAAA,CAAC,CAAC;IACJ;;IAGQ,oBAAoB,GAAA;AAC1B,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;YAC9C,IAAI,IAAI,EAAE;AACR,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YACrB;AACF,QAAA,CAAC,CAAC;IACJ;IAEQ,mBAAmB,GAAA;AACzB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;AACxB,QAAA,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,aAAa;YAAE;AAC/B,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7B,QAAA,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AACjD,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9B,YAAA,IAAI,CAAC,aAAa,GAAG,IAAI;AACzB,YAAA,IAAI,CAAC,IAAI;gBAAE;YACX,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9B,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;+GA7WW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAxB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,wBAAwB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxDrC,kjUA+LA,EAAA,MAAA,EAAA,CAAA,85GAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDnJI,UAAU,mOACV,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAChB,cAAc,EAAA,IAAA,EAAA,YAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACd,4BAA4B,oOAC5B,4BAA4B,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,mBAAA,EAAA,gBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAMnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBAfpC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,EAAA,OAAA,EACxB;wBACP,UAAU;wBACV,WAAW;wBACX,kBAAkB;wBAClB,gBAAgB;wBAChB,cAAc;wBACd,4BAA4B;wBAC5B,4BAA4B;qBAC7B,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,kjUAAA,EAAA,MAAA,EAAA,CAAA,85GAAA,CAAA,EAAA;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/shared/modal.component.ts","../../../projects/voice-receptionist-widget/src/lib/shared/modal.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n HostListener,\n Input,\n Output,\n} from '@angular/core';\n\n/**\n * Lightweight, reusable modal shell.\n *\n * Renders a centered card on top of a dimmed backdrop. Closes on backdrop\n * click, ESC key, or via the close button. Slot the modal body using\n * <ng-content>.\n */\n@Component({\n selector: 'app-modal',\n standalone: true,\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ModalComponent {\n @Input({ required: true }) title!: string;\n @Input() subtitle?: string;\n @Input() maxWidth = '640px';\n @Output() readonly closed = new EventEmitter<void>();\n\n @HostListener('document:keydown.escape')\n onEscape(): void {\n this.closed.emit();\n }\n\n onBackdropClick(event: MouseEvent): void {\n if (event.target === event.currentTarget) {\n this.closed.emit();\n }\n }\n\n close(): void {\n this.closed.emit();\n }\n}\n","<div\n class=\"modal-backdrop fixed inset-0 z-[1000] flex items-center justify-center bg-[rgba(20,30,50,0.42)] p-6 backdrop-blur-[2px]\"\n (click)=\"onBackdropClick($event)\"\n role=\"presentation\"\n>\n <div\n class=\"modal-card flex w-full max-h-[calc(100vh-48px)] flex-col overflow-hidden rounded-[var(--eds-radius-lg)] border border-[var(--eds-color-border)] bg-[var(--eds-color-surface)] shadow-sm\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"title\"\n [style.max-width]=\"maxWidth\"\n >\n <header class=\"flex items-start justify-between gap-4 border-b border-[var(--eds-color-border)] px-6 pb-4 pt-5\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <h2 class=\"m-0 text-base font-semibold tracking-tight text-[var(--eds-color-text)]\">{{ title }}</h2>\n @if (subtitle) {\n <p class=\"m-0 text-[13px] text-[var(--eds-color-text-muted)]\">{{ subtitle }}</p>\n }\n </div>\n <button\n type=\"button\"\n class=\"inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--eds-radius-md)] border border-transparent bg-transparent text-[var(--eds-color-text-muted)] transition-colors duration-150 hover:bg-[var(--eds-color-surface-alt)] hover:text-[var(--eds-color-text)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--eds-color-primary)]\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </header>\n\n <div class=\"overflow-y-auto px-6 pb-6 pt-5\">\n <ng-content />\n </div>\n </div>\n</div>\n"],"names":[],"mappings":";;;AASA;;;;;;AAMG;MAQU,cAAc,CAAA;AAP3B,IAAA,WAAA,GAAA;QAUW,IAAA,CAAA,QAAQ,GAAG,OAAO;AACR,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAQ;AAgBrD,IAAA;IAbC,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;AAEA,IAAA,eAAe,CAAC,KAAiB,EAAA;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE;AACxC,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QACpB;IACF;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;+GAnBW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAd,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,cAAc,8OCvB3B,k7DAsCA,EAAA,MAAA,EAAA,CAAA,+QAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FDfa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAP1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,WAAW,EAAA,UAAA,EACT,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,k7DAAA,EAAA,MAAA,EAAA,CAAA,+QAAA,CAAA,EAAA;8BAGpB,KAAK,EAAA,CAAA;sBAA/B,KAAK;uBAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAChB,QAAQ,EAAA,CAAA;sBAAhB;gBACQ,QAAQ,EAAA,CAAA;sBAAhB;gBACkB,MAAM,EAAA,CAAA;sBAAxB;gBAGD,QAAQ,EAAA,CAAA;sBADP,YAAY;uBAAC,yBAAyB;;;;;"}
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs","sources":["../../../src/lib/shared/modal.component.ts","../../../src/lib/shared/modal.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n HostListener,\n Input,\n Output,\n} from '@angular/core';\n\n/**\n * Lightweight, reusable modal shell.\n *\n * Renders a centered card on top of a dimmed backdrop. Closes on backdrop\n * click, ESC key, or via the close button. Slot the modal body using\n * <ng-content>.\n */\n@Component({\n selector: 'app-modal',\n standalone: true,\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ModalComponent {\n @Input({ required: true }) title!: string;\n @Input() subtitle?: string;\n @Input() maxWidth = '640px';\n @Output() readonly closed = new EventEmitter<void>();\n\n @HostListener('document:keydown.escape')\n onEscape(): void {\n this.closed.emit();\n }\n\n onBackdropClick(event: MouseEvent): void {\n if (event.target === event.currentTarget) {\n this.closed.emit();\n }\n }\n\n close(): void {\n this.closed.emit();\n }\n}\n","<div\n class=\"modal-backdrop fixed inset-0 z-[1000] flex items-center justify-center bg-[rgba(20,30,50,0.42)] p-6 backdrop-blur-[2px]\"\n (click)=\"onBackdropClick($event)\"\n role=\"presentation\"\n>\n <div\n class=\"modal-card flex w-full max-h-[calc(100vh-48px)] flex-col overflow-hidden rounded-[var(--eds-radius-lg)] border border-[var(--eds-color-border)] bg-[var(--eds-color-surface)] shadow-sm\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"title\"\n [style.max-width]=\"maxWidth\"\n >\n <header class=\"flex items-start justify-between gap-4 border-b border-[var(--eds-color-border)] px-6 pb-4 pt-5\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <h2 class=\"m-0 text-base font-semibold tracking-tight text-[var(--eds-color-text)]\">{{ title }}</h2>\n @if (subtitle) {\n <p class=\"m-0 text-[13px] text-[var(--eds-color-text-muted)]\">{{ subtitle }}</p>\n }\n </div>\n <button\n type=\"button\"\n class=\"inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--eds-radius-md)] border border-transparent bg-transparent text-[var(--eds-color-text-muted)] transition-colors duration-150 hover:bg-[var(--eds-color-surface-alt)] hover:text-[var(--eds-color-text)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--eds-color-primary)]\"\n (click)=\"close()\"\n aria-label=\"Close dialog\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </header>\n\n <div class=\"overflow-y-auto px-6 pb-6 pt-5\">\n <ng-content />\n </div>\n </div>\n</div>\n"],"names":[],"mappings":";;;AASA;;;;;;AAMG;MAQU,cAAc,CAAA;AAP3B,IAAA,WAAA,GAAA;QAUW,IAAA,CAAA,QAAQ,GAAG,OAAO;AACR,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAQ;AAgBrD,IAAA;IAbC,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;AAEA,IAAA,eAAe,CAAC,KAAiB,EAAA;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE;AACxC,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QACpB;IACF;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;+GAnBW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAd,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,cAAc,8OCvB3B,k7DAsCA,EAAA,MAAA,EAAA,CAAA,+QAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FDfa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAP1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,WAAW,EAAA,UAAA,EACT,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,k7DAAA,EAAA,MAAA,EAAA,CAAA,+QAAA,CAAA,EAAA;8BAGpB,KAAK,EAAA,CAAA;sBAA/B,KAAK;uBAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAChB,QAAQ,EAAA,CAAA;sBAAhB;gBACQ,QAAQ,EAAA,CAAA;sBAAhB;gBACkB,MAAM,EAAA,CAAA;sBAAxB;gBAGD,QAAQ,EAAA,CAAA;sBADP,YAAY;uBAAC,yBAAyB;;;;;"}
@@ -1,10 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, EventEmitter, signal, ViewChild, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { RouterLink } from '@angular/router';
4
- import { A as AiReceptionistApiService, o as DEFAULT_PLACEHOLDERS } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs';
4
+ import { A as AiReceptionistApiService, s as DEFAULT_PLACEHOLDERS, E as EdsButtonComponent, l as EdsBadgeComponent, d as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormsModule } from '@angular/forms';
7
- import { EdsButtonComponent, EdsBadgeComponent, EdsIconComponent } from './edvak99-voice-receptionist-widget.mjs';
8
7
  import { M as ModalComponent } from './edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs';
9
8
 
10
9
  const REQUIRED_FIELD_OPTIONS = [
@@ -388,4 +387,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
388
387
  }] });
389
388
 
390
389
  export { OutboundPurposesPageComponent };
391
- //# sourceMappingURL=edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs.map
390
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-outbound-purposes-page.component-B2koBFU3.mjs.map