@edvak99/voice-receptionist-widget 1.1.7 → 1.1.8

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 (52) hide show
  1. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CtaPoY1k.mjs +344 -0
  2. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CtaPoY1k.mjs.map +1 -0
  3. package/fesm2022/{edvak99-voice-receptionist-widget-ai-receptionist-api.service-DokIb-9r.mjs → edvak99-voice-receptionist-widget-ai-receptionist-api.service-CK6tM862.mjs} +2 -2
  4. package/fesm2022/{edvak99-voice-receptionist-widget-ai-receptionist-api.service-DokIb-9r.mjs.map → edvak99-voice-receptionist-widget-ai-receptionist-api.service-CK6tM862.mjs.map} +1 -1
  5. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CM5-vgzu.mjs +277 -0
  6. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CM5-vgzu.mjs.map +1 -0
  7. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-A-vx_M3l.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-BuNyPmhn.mjs} +11 -8
  8. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-BuNyPmhn.mjs.map +1 -0
  9. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B-99E9Rs.mjs +193 -0
  10. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B-99E9Rs.mjs.map +1 -0
  11. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-Pla2UgeZ.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-Cy9DGRci.mjs} +2 -2
  12. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-Pla2UgeZ.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-Cy9DGRci.mjs.map} +1 -1
  13. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Di7GLG9k.mjs → edvak99-voice-receptionist-widget-call-review.service-BAjx3n3v.mjs} +2 -2
  14. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Di7GLG9k.mjs.map → edvak99-voice-receptionist-widget-call-review.service-BAjx3n3v.mjs.map} +1 -1
  15. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-9ao09dEd.mjs +113 -0
  16. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-9ao09dEd.mjs.map +1 -0
  17. package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-socket.service-D2pelzu4.mjs → edvak99-voice-receptionist-widget-dashboard-socket.service-BuFQz1lN.mjs} +2 -2
  18. package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-socket.service-D2pelzu4.mjs.map → edvak99-voice-receptionist-widget-dashboard-socket.service-BuFQz1lN.mjs.map} +1 -1
  19. package/fesm2022/{edvak99-voice-receptionist-widget-eds-pulse-dot.component-Ig0Eoq1z.mjs → edvak99-voice-receptionist-widget-eds-pulse-dot.component-CQIqnrcs.mjs} +3 -3
  20. package/fesm2022/{edvak99-voice-receptionist-widget-eds-pulse-dot.component-Ig0Eoq1z.mjs.map → edvak99-voice-receptionist-widget-eds-pulse-dot.component-CQIqnrcs.mjs.map} +1 -1
  21. package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-BDtAQSyF.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-4LJuMn28.mjs} +3 -3
  22. package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-BDtAQSyF.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-4LJuMn28.mjs.map} +1 -1
  23. package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-7e1HY6sB.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-CJ7N-Jq6.mjs} +6 -6
  24. package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-7e1HY6sB.mjs.map → edvak99-voice-receptionist-widget-live-monitor-page.component-CJ7N-Jq6.mjs.map} +1 -1
  25. package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-2GHT8NT9.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-HJmMq0b6.mjs} +127 -3
  26. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-HJmMq0b6.mjs.map +1 -0
  27. package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-BwCz1dlx.mjs → edvak99-voice-receptionist-widget-settings-page.component-CspheAr8.mjs} +31 -6
  28. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-CspheAr8.mjs.map +1 -0
  29. package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-Mqo1UmfK.mjs → edvak99-voice-receptionist-widget-tasks-page.component-Dfz-_0Jz.mjs} +2 -2
  30. package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-Mqo1UmfK.mjs.map → edvak99-voice-receptionist-widget-tasks-page.component-Dfz-_0Jz.mjs.map} +1 -1
  31. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-DskeqJwB.mjs → edvak99-voice-receptionist-widget-wizard-page.component-BD4Zhp0Y.mjs} +2 -2
  32. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-DskeqJwB.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-BD4Zhp0Y.mjs.map} +1 -1
  33. package/fesm2022/edvak99-voice-receptionist-widget.mjs +12 -12
  34. package/lib/pages/activities-page/activities-page.component.d.ts +2 -0
  35. package/lib/pages/call-history-detail-page/call-history-detail-page.component.d.ts +4 -0
  36. package/lib/pages/dashboard-page/dashboard-page.component.d.ts +0 -3
  37. package/lib/pages/settings-page/settings-page.component.d.ts +4 -0
  38. package/package.json +1 -1
  39. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-4UrqnTE3.mjs +0 -306
  40. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-4UrqnTE3.mjs.map +0 -1
  41. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DUR5f5nc.mjs +0 -277
  42. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DUR5f5nc.mjs.map +0 -1
  43. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-A-vx_M3l.mjs.map +0 -1
  44. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-gROZVIt-.mjs +0 -193
  45. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-gROZVIt-.mjs.map +0 -1
  46. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-E30a8p3d.mjs +0 -439
  47. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-E30a8p3d.mjs.map +0 -1
  48. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs +0 -127
  49. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs.map +0 -1
  50. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-2GHT8NT9.mjs.map +0 -1
  51. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-BwCz1dlx.mjs.map +0 -1
  52. package/lib/components/outbound-dial-modal/outbound-dial-modal.component.d.ts +0 -63
@@ -3,7 +3,7 @@ import { inject, EventEmitter, signal, Output, Input, ChangeDetectionStrategy, C
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import { ActivatedRoute } from '@angular/router';
6
- import { A as AiReceptionistApiService, W as WELCOME_MESSAGE_MAX, n as buildAutoWelcomeTemplate, o as resolveWelcomePreview } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-DokIb-9r.mjs';
6
+ import { A as AiReceptionistApiService, W as WELCOME_MESSAGE_MAX, m as buildAutoWelcomeTemplate, n as resolveWelcomePreview } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-CK6tM862.mjs';
7
7
  import { ToastService, EdsButtonComponent, EdsIconComponent } from './edvak99-voice-receptionist-widget.mjs';
8
8
  import { M as ModalComponent } from './edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs';
9
9
  import { switchMap, catchError, of, tap, throwError, finalize } from 'rxjs';
@@ -679,6 +679,7 @@ class SettingsPageComponent {
679
679
  this.saved = signal(false);
680
680
  this.knowledgeTestOpen = signal(false);
681
681
  this.locations = signal([]);
682
+ this.locationsMenuOpen = signal(false);
682
683
  this.confirmOffOpen = signal(false);
683
684
  this.online = this.agentOnline.online;
684
685
  this.agentLoading = this.agentOnline.loading;
@@ -686,8 +687,6 @@ class SettingsPageComponent {
686
687
  this.tabs = [
687
688
  { id: 'general', label: 'Identity & Greetings' },
688
689
  { id: 'phone', label: 'Phone & Availability' },
689
- { id: 'scheduling', label: 'Scheduling Rules' },
690
- { id: 'outbound', label: 'Outbound Purpose' },
691
690
  { id: 'knowledge', label: 'Knowledge Base' },
692
691
  { id: 'transcripts', label: 'Data & Compliance' },
693
692
  { id: 'advanced', label: 'Advanced' },
@@ -730,6 +729,20 @@ class SettingsPageComponent {
730
729
  this.whatToSay = computed(() => String(this.settings()?.knowledge?.['whatToSay'] ?? ''));
731
730
  this.whatNotToSay = computed(() => String(this.settings()?.knowledge?.['whatNotToSay'] ?? ''));
732
731
  this.selectedLocationIds = computed(() => parseCsvList(this.settings()?.phone?.['locationIds']));
732
+ this.locationSummary = computed(() => {
733
+ const selected = this.selectedLocationIds();
734
+ const all = this.locations();
735
+ if (!all.length)
736
+ return 'No locations available';
737
+ if (!selected.length)
738
+ return 'Select locations';
739
+ const names = all.filter((l) => selected.includes(l.id)).map((l) => l.name);
740
+ if (!names.length)
741
+ return `${selected.length} selected`;
742
+ if (names.length <= 2)
743
+ return names.join(', ');
744
+ return `${names[0]}, ${names[1]} +${names.length - 2}`;
745
+ });
733
746
  this.selectedTone = computed(() => String(this.settings()?.general?.['tone'] ?? 'professional'));
734
747
  this.disclosureEnabled = computed(() => this.settings()?.transcripts?.['disclosureWarningEnabled'] !== false);
735
748
  this.disclosureText = computed(() => String(this.settings()?.transcripts?.['disclosureWarningText'] ?? DEFAULT_DISCLOSURE_WARNING));
@@ -777,6 +790,7 @@ class SettingsPageComponent {
777
790
  setTab(id) {
778
791
  if (this.isTabDisabled(id))
779
792
  return;
793
+ this.locationsMenuOpen.set(false);
780
794
  this.tab.set(id);
781
795
  }
782
796
  updateField(section, key, value) {
@@ -801,6 +815,17 @@ class SettingsPageComponent {
801
815
  setTone(tone) {
802
816
  this.updateField('general', 'tone', tone);
803
817
  }
818
+ toggleLocationsMenu() {
819
+ if (!this.locations().length)
820
+ return;
821
+ this.locationsMenuOpen.update((open) => !open);
822
+ }
823
+ onLocationsDocClick(event) {
824
+ const target = event.target;
825
+ if (!target?.closest('.settings-page__locations-dd')) {
826
+ this.locationsMenuOpen.set(false);
827
+ }
828
+ }
804
829
  toggleLocation(id) {
805
830
  const current = this.selectedLocationIds();
806
831
  const next = current.includes(id) ? current.filter((x) => x !== id) : [...current, id];
@@ -950,7 +975,7 @@ class SettingsPageComponent {
950
975
  }
951
976
  }
952
977
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SettingsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
953
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SettingsPageComponent, isStandalone: true, selector: "eds-settings-page", ngImport: i0, template: "<div class=\"eds-page settings-page\">\n <header class=\"mb-6 flex items-start justify-between gap-4\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"flex shrink-0 items-center gap-3\">\n @if (saved()) {\n <span class=\"text-sm font-medium text-green-500\">Saved</span>\n }\n <eds-button variant=\"primary\" [disabled]=\"saving()\" (click)=\"save()\">\n <eds-icon name=\"save\" [size]=\"18\" />\n {{ saving() ? 'Saving\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Loading settings\u2026</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout grid items-start gap-5\">\n <nav class=\"eds-card settings-page__sidebar sticky top-4 flex max-h-[calc(100vh-120px)] flex-col gap-1 overflow-y-auto p-2 shadow-sm\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item flex w-full cursor-pointer items-center justify-between gap-3 rounded-md border-none bg-transparent px-4 py-3 text-left text-sm font-medium leading-snug text-zinc-600\"\n [class.settings-page__nav-item--active]=\"tab() === t.id\"\n [class.settings-page__nav-item--disabled]=\"isTabDisabled(t.id)\"\n [disabled]=\"isTabDisabled(t.id)\"\n [attr.title]=\"isTabDisabled(t.id) ? 'This section is currently disabled' : null\"\n (click)=\"setTab(t.id)\"\n >\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"ml-auto text-xs font-medium uppercase tracking-wide text-zinc-400\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel min-h-96 px-8 py-7 shadow-sm\">\n <header class=\"mb-6 flex items-start justify-between gap-4 border-b border-zinc-200 pb-4\">\n <div class=\"min-w-0\">\n <h2 class=\"mb-2 m-0 text-xl font-medium tracking-tight text-zinc-700\">{{ sectionMeta().title }}</h2>\n @if (tab() !== 'knowledge' && tab() !== 'general' && tab() !== 'phone' && tab() !== 'transcripts') {\n <p class=\"m-0 max-w-2xl text-base leading-relaxed text-zinc-500\">{{ sectionMeta().description }}</p>\n }\n </div>\n @if (tab() === 'knowledge') {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"openTestCall()\">\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Test Call\n </eds-button>\n }\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"mb-5 flex items-center gap-3 rounded-md border border-zinc-200 bg-slate-50 px-4 py-3 text-sm leading-snug text-zinc-500\">\n <eds-icon name=\"lock\" [size]=\"18\" />\n These settings are managed by Edvak. Contact support to request changes.\n </p>\n }\n\n @if (tab() === 'knowledge') {\n <div class=\"flex max-w-4xl flex-col gap-7\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatToSay', $event)\"\n placeholder=\"Hours, parking, payment options, arrival instructions, emergencies\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What not to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatNotToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatNotToSay', $event)\"\n placeholder=\"Clinical advice, unverified prices, PHI, promises the practice cannot keep\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatNotToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n </div>\n } @else if (tab() === 'general') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Name <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"How the AI introduces itself on calls\" />\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'agentName')\"\n (ngModelChange)=\"updateField('general', 'agentName', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <div class=\"flex items-end gap-3\">\n <label class=\"settings-page__field min-w-0 flex-1 flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Voice <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"relative w-full\">\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'ttsVoiceId')\"\n (ngModelChange)=\"updateField('general', 'ttsVoiceId', $event)\"\n autocomplete=\"off\"\n >\n @for (v of voicePresets; track v.id) {\n <option [ngValue]=\"v.id\">{{ v.label }}</option>\n }\n </select>\n <eds-icon name=\"expand_more\" [size]=\"20\" class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500\" />\n </div>\n </label>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Tone</span>\n <div class=\"flex flex-wrap gap-2\" role=\"radiogroup\" aria-label=\"Tone\">\n @for (tone of toneOptions; track tone.value) {\n <button\n type=\"button\"\n class=\"settings-page__tone h-9 cursor-pointer rounded-full border border-transparent bg-slate-100 px-4 text-sm font-medium text-zinc-500\"\n [class.settings-page__tone--active]=\"selectedTone() === tone.value\"\n (click)=\"setTone(tone.value)\"\n >\n {{ tone.label }}\n </button>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Inbound Greetings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ welcomeMessage().length }}/{{ welcomeMax }}</span>\n <div class=\"mt-3 flex flex-wrap items-center gap-2\">\n <span class=\"text-sm text-zinc-500\">Variables</span>\n @for (v of greetingVariables; track v.key) {\n <button\n type=\"button\"\n class=\"settings-page__var-chip h-7 cursor-pointer rounded-full border border-zinc-200 bg-white px-3 text-xs font-medium text-zinc-700\"\n (click)=\"insertGreetingVariable(v.token)\"\n [title]=\"'Insert ' + v.token\"\n >\n {{ v.label }}\n </button>\n }\n </div>\n </label>\n </div>\n } @else if (tab() === 'phone') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Answer Mode <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"When the AI picks up inbound calls\" />\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'answerMode')\"\n (ngModelChange)=\"updateField('phone', 'answerMode', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of answerModeOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Phone Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'mainNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [ngModel]=\"fieldValue('phone', 'mainNumber')\"\n (ngModelChange)=\"updateField('phone', 'mainNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Transfer Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'transferNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [ngModel]=\"fieldValue('phone', 'transferNumber')\"\n (ngModelChange)=\"updateField('phone', 'transferNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Ringing Time Wait <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'ringTimeout')\"\n (ngModelChange)=\"selectNumberField('phone', 'ringTimeout', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of ringTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"event_available\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Create Follow-up Task</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n If no one answers in time, the agent auto-creates a high priority task.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n [attr.aria-pressed]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n (click)=\"updateField('phone', 'createFollowUpTask', !fieldValue('phone', 'createFollowUpTask'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Location Handled <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"settings-page__check-grid grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2 rounded-lg border border-zinc-300 bg-white p-3\" role=\"group\" aria-label=\"Locations handled\">\n @for (loc of locations(); track loc.id) {\n <label class=\"settings-page__check-item flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm text-zinc-700\">\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 accent-blue-600\"\n [checked]=\"selectedLocationIds().includes(loc.id)\"\n (change)=\"toggleLocation(loc.id)\"\n autocomplete=\"off\"\n />\n <span>{{ loc.name }}</span>\n </label>\n } @empty {\n <p class=\"m-0 p-3 text-sm text-zinc-500\">No locations available.</p>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Max AI Call Duration <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'maxCallDurationMin')\"\n (ngModelChange)=\"selectNumberField('phone', 'maxCallDurationMin', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of maxCallDurationOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Silence Timeout <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'silenceTimeoutSec')\"\n (ngModelChange)=\"selectNumberField('phone', 'silenceTimeoutSec', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of silenceTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n After-Hours Behaviour <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'afterHoursBehavior')\"\n (ngModelChange)=\"updateField('phone', 'afterHoursBehavior', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of afterHoursOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n </div>\n } @else if (tab() === 'transcripts') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Call Recordings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'recordingRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'recordingRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Transcripts <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'transcriptRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'transcriptRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Disclosure Warning</span>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"disclosureEnabled()\"\n [attr.aria-pressed]=\"disclosureEnabled()\"\n (click)=\"setDisclosureEnabled(!disclosureEnabled())\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n @if (disclosureEnabled()) {\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"disclosureMax\"\n [ngModel]=\"disclosureText()\"\n (ngModelChange)=\"updateDisclosureText($event)\"\n autocomplete=\"off\"\n ></textarea>\n }\n </div>\n </div>\n } @else if (tab() === 'advanced') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"smart_toy\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">\n @if (toggling()) {\n Updating\u2026\n } @else if (online() === true) {\n Agent online\n } @else if (online() === false) {\n Agent offline\n } @else {\n Status unknown\n }\n </span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n @if (online() === true) {\n AI receptionist is answering inbound calls.\n } @else if (online() === false) {\n AI is offline \u2014 calls go to the front desk.\n } @else {\n Checking agent status\u2026\n }\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"online() === true\"\n [disabled]=\"agentSwitchDisabled()\"\n [attr.aria-pressed]=\"online() === true\"\n (click)=\"onAgentToggleClick()\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2 settings-page__field--readonly\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Model version\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input settings-page__input--readonly w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('advanced', 'modelVersion')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__toggle-row settings-page__toggle-row--readonly col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Debug mode\n </span>\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">Verbose logging \u2014 contact Edvak to change.</span>\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [ngModel]=\"fieldValue('advanced', 'debugMode')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n </div>\n } @else {\n <div class=\"settings-page__fields grid grid-cols-2 gap-x-7 gap-y-5\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, +$event)\"\n autocomplete=\"off\"\n />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n }\n </label>\n }\n }\n </div>\n }\n </article>\n </div>\n }\n</div>\n\n<eds-knowledge-test-modal\n [open]=\"knowledgeTestOpen()\"\n [whatToSay]=\"whatToSay()\"\n [whatNotToSay]=\"whatNotToSay()\"\n [voiceId]=\"selectedVoiceId()\"\n (closed)=\"closeTestCall()\"\n/>\n\n@if (confirmOffOpen()) {\n <app-modal\n title=\"Turn off AI receptionist?\"\n subtitle=\"Inbound callers will be transferred to the front desk instead of the AI.\"\n maxWidth=\"480px\"\n (closed)=\"cancelConfirmOff()\"\n >\n <p class=\"mb-4 m-0 text-sm leading-normal text-zinc-500\">While offline, the AI will not answer calls. Callers are routed to the human receptionist.</p>\n <div class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"cancelConfirmOff()\">Cancel</eds-button>\n <eds-button variant=\"danger\" type=\"button\" [disabled]=\"toggling()\" (click)=\"confirmTurnOff()\">\n Turn off\n </eds-button>\n </div>\n </app-modal>\n}\n", styles: [".settings-page__layout{grid-template-columns:240px minmax(0,1fr)}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f7f9fa);color:var(--eds-text-primary, #41464c)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf1fe);color:var(--eds-text-brand, #2162f0)}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-text-tertiary, #767676)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-text-tertiary, #767676)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__textarea:focus,.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__tone--active{background:#fff;border-color:var(--eds-brand-600, #2162f0);color:var(--eds-brand-600, #2162f0)}.settings-page__var-chip:hover{border-color:var(--eds-brand-300, #94c5f9);color:var(--eds-brand-600, #2162f0)}.settings-page__check-item:hover{background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__switch{width:44px;height:26px;border-radius:999px;border:none;background:#cbd5e1;padding:3px;cursor:pointer;transition:background .15s ease}.settings-page__switch--on{background:var(--eds-brand-600, #2162f0)}.settings-page__switch:disabled{opacity:.55;cursor:not-allowed}.settings-page__switch-thumb{display:block;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px #0f172a33;transition:transform .15s ease}.settings-page__switch--on .settings-page__switch-thumb{transform:translate(18px)}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: KnowledgeTestModalComponent, selector: "eds-knowledge-test-modal", inputs: ["open", "whatToSay", "whatNotToSay", "voiceId"], outputs: ["closed"] }, { kind: "component", type: ModalComponent, selector: "app-modal", inputs: ["title", "subtitle", "maxWidth"], outputs: ["closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
978
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SettingsPageComponent, isStandalone: true, selector: "eds-settings-page", ngImport: i0, template: "<div class=\"eds-page settings-page\">\n <header class=\"mb-6 flex items-start justify-between gap-4\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"flex shrink-0 items-center gap-3\">\n @if (saved()) {\n <span class=\"text-sm font-medium text-green-500\">Saved</span>\n }\n <eds-button variant=\"primary\" [disabled]=\"saving()\" (click)=\"save()\">\n <eds-icon name=\"save\" [size]=\"18\" />\n {{ saving() ? 'Saving\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Loading settings\u2026</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout grid items-start gap-5\">\n <nav class=\"eds-card settings-page__sidebar sticky top-4 flex max-h-[calc(100vh-120px)] flex-col gap-1 overflow-y-auto p-2 shadow-sm\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item flex w-full cursor-pointer items-center justify-between gap-3 rounded-md border-none bg-transparent px-4 py-3 text-left text-sm font-medium leading-snug text-zinc-600\"\n [class.settings-page__nav-item--active]=\"tab() === t.id\"\n [class.settings-page__nav-item--disabled]=\"isTabDisabled(t.id)\"\n [disabled]=\"isTabDisabled(t.id)\"\n [attr.title]=\"isTabDisabled(t.id) ? 'This section is currently disabled' : null\"\n (click)=\"setTab(t.id)\"\n >\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"ml-auto text-xs font-medium uppercase tracking-wide text-zinc-400\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel min-h-96 px-8 py-7 shadow-sm\">\n <header class=\"mb-6 flex items-start justify-between gap-4 border-b border-zinc-200 pb-4\">\n <div class=\"min-w-0\">\n <h2 class=\"mb-2 m-0 text-xl font-medium tracking-tight text-zinc-700\">{{ sectionMeta().title }}</h2>\n @if (tab() !== 'knowledge' && tab() !== 'general' && tab() !== 'phone' && tab() !== 'transcripts') {\n <p class=\"m-0 max-w-2xl text-base leading-relaxed text-zinc-500\">{{ sectionMeta().description }}</p>\n }\n </div>\n @if (tab() === 'knowledge') {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"openTestCall()\">\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Test Call\n </eds-button>\n }\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"mb-5 flex items-center gap-3 rounded-md border border-zinc-200 bg-slate-50 px-4 py-3 text-sm leading-snug text-zinc-500\">\n <eds-icon name=\"lock\" [size]=\"18\" />\n These settings are managed by Edvak. Contact support to request changes.\n </p>\n }\n\n @if (tab() === 'knowledge') {\n <div class=\"flex max-w-4xl flex-col gap-7\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatToSay', $event)\"\n placeholder=\"Hours, parking, payment options, arrival instructions, emergencies\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What not to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatNotToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatNotToSay', $event)\"\n placeholder=\"Clinical advice, unverified prices, PHI, promises the practice cannot keep\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatNotToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n </div>\n } @else if (tab() === 'general') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Name <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"How the AI introduces itself on calls\" />\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'agentName')\"\n (ngModelChange)=\"updateField('general', 'agentName', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <div class=\"flex items-end gap-3\">\n <label class=\"settings-page__field min-w-0 flex-1 flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Voice <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"relative w-full\">\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'ttsVoiceId')\"\n (ngModelChange)=\"updateField('general', 'ttsVoiceId', $event)\"\n autocomplete=\"off\"\n >\n @for (v of voicePresets; track v.id) {\n <option [ngValue]=\"v.id\">{{ v.label }}</option>\n }\n </select>\n <eds-icon name=\"expand_more\" [size]=\"20\" class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500\" />\n </div>\n </label>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Tone</span>\n <div class=\"flex flex-wrap gap-2\" role=\"radiogroup\" aria-label=\"Tone\">\n @for (tone of toneOptions; track tone.value) {\n <button\n type=\"button\"\n class=\"settings-page__tone h-9 cursor-pointer rounded-full border border-transparent bg-slate-100 px-4 text-sm font-medium text-zinc-500\"\n [class.settings-page__tone--active]=\"selectedTone() === tone.value\"\n (click)=\"setTone(tone.value)\"\n >\n {{ tone.label }}\n </button>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Inbound Greetings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ welcomeMessage().length }}/{{ welcomeMax }}</span>\n <div class=\"mt-3 flex flex-wrap items-center gap-2\">\n <span class=\"text-sm text-zinc-500\">Variables</span>\n @for (v of greetingVariables; track v.key) {\n <button\n type=\"button\"\n class=\"settings-page__var-chip h-7 cursor-pointer rounded-full border border-zinc-200 bg-white px-3 text-xs font-medium text-zinc-700\"\n (click)=\"insertGreetingVariable(v.token)\"\n [title]=\"'Insert ' + v.token\"\n >\n {{ v.label }}\n </button>\n }\n </div>\n </label>\n </div>\n } @else if (tab() === 'phone') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Answer Mode <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"When the AI picks up inbound calls\" />\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'answerMode')\"\n (ngModelChange)=\"updateField('phone', 'answerMode', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of answerModeOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Phone Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'mainNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [ngModel]=\"fieldValue('phone', 'mainNumber')\"\n (ngModelChange)=\"updateField('phone', 'mainNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Transfer Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'transferNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [ngModel]=\"fieldValue('phone', 'transferNumber')\"\n (ngModelChange)=\"updateField('phone', 'transferNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Ringing Time Wait <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'ringTimeout')\"\n (ngModelChange)=\"selectNumberField('phone', 'ringTimeout', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of ringTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"event_available\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Create Follow-up Task</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n If no one answers in time, the agent auto-creates a high priority task.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n [attr.aria-pressed]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n (click)=\"updateField('phone', 'createFollowUpTask', !fieldValue('phone', 'createFollowUpTask'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Location Handled <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"settings-page__locations-dd relative\" (document:click)=\"onLocationsDocClick($event)\">\n <button\n type=\"button\"\n class=\"settings-page__input settings-page__select flex w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-left text-base leading-snug text-zinc-700\"\n [disabled]=\"locations().length === 0\"\n [attr.aria-expanded]=\"locationsMenuOpen()\"\n aria-haspopup=\"listbox\"\n aria-label=\"Locations handled\"\n (click)=\"$event.stopPropagation(); toggleLocationsMenu()\"\n >\n <span class=\"min-w-0 truncate\">{{ locationSummary() }}</span>\n <eds-icon name=\"expand_more\" [size]=\"18\" class=\"shrink-0 text-zinc-500\" />\n </button>\n @if (locationsMenuOpen()) {\n <ul\n class=\"absolute z-20 m-0 mt-1 max-h-56 w-full list-none overflow-auto rounded-md border border-zinc-200 bg-white p-1 shadow-md\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n >\n @for (loc of locations(); track loc.id) {\n <li role=\"option\" [attr.aria-selected]=\"selectedLocationIds().includes(loc.id)\">\n <label\n class=\"flex cursor-pointer items-center gap-2.5 rounded px-2.5 py-2 text-sm text-zinc-700 hover:bg-zinc-50\"\n >\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 accent-blue-600\"\n [checked]=\"selectedLocationIds().includes(loc.id)\"\n (change)=\"toggleLocation(loc.id)\"\n />\n <span class=\"min-w-0 truncate\">{{ loc.name }}</span>\n </label>\n </li>\n }\n </ul>\n }\n </div>\n @if (locations().length === 0) {\n <p class=\"m-0 text-sm text-zinc-500\">No locations available.</p>\n }\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Max AI Call Duration <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'maxCallDurationMin')\"\n (ngModelChange)=\"selectNumberField('phone', 'maxCallDurationMin', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of maxCallDurationOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Silence Timeout <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'silenceTimeoutSec')\"\n (ngModelChange)=\"selectNumberField('phone', 'silenceTimeoutSec', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of silenceTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n After-Hours Behaviour <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'afterHoursBehavior')\"\n (ngModelChange)=\"updateField('phone', 'afterHoursBehavior', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of afterHoursOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"border-t border-zinc-200 pt-5\">\n <h3 class=\"mb-4 m-0 text-base font-semibold text-zinc-700\">Scheduling Rules</h3>\n <div class=\"flex flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-1.5\">\n <span class=\"settings-page__field-label flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Minimum lead time (hours)\n </span>\n <input\n type=\"number\"\n min=\"0\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('scheduling', 'leadTimeHours')\"\n (ngModelChange)=\"updateField('scheduling', 'leadTimeHours', +$event)\"\n autocomplete=\"off\"\n />\n <span class=\"text-xs text-zinc-500\">Earliest bookable slot from now.</span>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-3.5 rounded-xl border border-zinc-200 bg-white p-3.5\">\n <eds-icon name=\"today\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Allow same-day booking</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n Let patients book appointments later today.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n [attr.aria-pressed]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n (click)=\"updateField('scheduling', 'allowSameDay', !fieldValue('scheduling', 'allowSameDay'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n </div>\n </div>\n </div>\n } @else if (tab() === 'transcripts') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Call Recordings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'recordingRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'recordingRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Transcripts <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'transcriptRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'transcriptRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Disclosure Warning</span>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"disclosureEnabled()\"\n [attr.aria-pressed]=\"disclosureEnabled()\"\n (click)=\"setDisclosureEnabled(!disclosureEnabled())\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n @if (disclosureEnabled()) {\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"disclosureMax\"\n [ngModel]=\"disclosureText()\"\n (ngModelChange)=\"updateDisclosureText($event)\"\n autocomplete=\"off\"\n ></textarea>\n }\n </div>\n </div>\n } @else if (tab() === 'advanced') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"smart_toy\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">\n @if (toggling()) {\n Updating\u2026\n } @else if (online() === true) {\n Agent online\n } @else if (online() === false) {\n Agent offline\n } @else {\n Status unknown\n }\n </span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n @if (online() === true) {\n AI receptionist is answering inbound calls.\n } @else if (online() === false) {\n AI is offline \u2014 calls go to the front desk.\n } @else {\n Checking agent status\u2026\n }\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"online() === true\"\n [disabled]=\"agentSwitchDisabled()\"\n [attr.aria-pressed]=\"online() === true\"\n (click)=\"onAgentToggleClick()\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2 settings-page__field--readonly\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Model version\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input settings-page__input--readonly w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('advanced', 'modelVersion')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__toggle-row settings-page__toggle-row--readonly col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Debug mode\n </span>\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">Verbose logging \u2014 contact Edvak to change.</span>\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [ngModel]=\"fieldValue('advanced', 'debugMode')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n </div>\n } @else {\n <div class=\"settings-page__fields grid grid-cols-2 gap-x-7 gap-y-5\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, +$event)\"\n autocomplete=\"off\"\n />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n }\n </label>\n }\n }\n </div>\n }\n </article>\n </div>\n }\n</div>\n\n<eds-knowledge-test-modal\n [open]=\"knowledgeTestOpen()\"\n [whatToSay]=\"whatToSay()\"\n [whatNotToSay]=\"whatNotToSay()\"\n [voiceId]=\"selectedVoiceId()\"\n (closed)=\"closeTestCall()\"\n/>\n\n@if (confirmOffOpen()) {\n <app-modal\n title=\"Turn off AI receptionist?\"\n subtitle=\"Inbound callers will be transferred to the front desk instead of the AI.\"\n maxWidth=\"480px\"\n (closed)=\"cancelConfirmOff()\"\n >\n <p class=\"mb-4 m-0 text-sm leading-normal text-zinc-500\">While offline, the AI will not answer calls. Callers are routed to the human receptionist.</p>\n <div class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"cancelConfirmOff()\">Cancel</eds-button>\n <eds-button variant=\"danger\" type=\"button\" [disabled]=\"toggling()\" (click)=\"confirmTurnOff()\">\n Turn off\n </eds-button>\n </div>\n </app-modal>\n}\n", styles: [".settings-page__layout{grid-template-columns:240px minmax(0,1fr)}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f7f9fa);color:var(--eds-text-primary, #41464c)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf1fe);color:var(--eds-text-brand, #2162f0)}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-text-tertiary, #767676)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-text-tertiary, #767676)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__textarea:focus,.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__tone--active{background:#fff;border-color:var(--eds-brand-600, #2162f0);color:var(--eds-brand-600, #2162f0)}.settings-page__var-chip:hover{border-color:var(--eds-brand-300, #94c5f9);color:var(--eds-brand-600, #2162f0)}.settings-page__check-item:hover{background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__switch{width:44px;height:26px;border-radius:999px;border:none;background:#cbd5e1;padding:3px;cursor:pointer;transition:background .15s ease}.settings-page__switch--on{background:var(--eds-brand-600, #2162f0)}.settings-page__switch:disabled{opacity:.55;cursor:not-allowed}.settings-page__switch-thumb{display:block;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px #0f172a33;transition:transform .15s ease}.settings-page__switch--on .settings-page__switch-thumb{transform:translate(18px)}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: KnowledgeTestModalComponent, selector: "eds-knowledge-test-modal", inputs: ["open", "whatToSay", "whatNotToSay", "voiceId"], outputs: ["closed"] }, { kind: "component", type: ModalComponent, selector: "app-modal", inputs: ["title", "subtitle", "maxWidth"], outputs: ["closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
954
979
  }
955
980
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SettingsPageComponent, decorators: [{
956
981
  type: Component,
@@ -960,8 +985,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
960
985
  EdsIconComponent,
961
986
  KnowledgeTestModalComponent,
962
987
  ModalComponent,
963
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page settings-page\">\n <header class=\"mb-6 flex items-start justify-between gap-4\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"flex shrink-0 items-center gap-3\">\n @if (saved()) {\n <span class=\"text-sm font-medium text-green-500\">Saved</span>\n }\n <eds-button variant=\"primary\" [disabled]=\"saving()\" (click)=\"save()\">\n <eds-icon name=\"save\" [size]=\"18\" />\n {{ saving() ? 'Saving\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Loading settings\u2026</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout grid items-start gap-5\">\n <nav class=\"eds-card settings-page__sidebar sticky top-4 flex max-h-[calc(100vh-120px)] flex-col gap-1 overflow-y-auto p-2 shadow-sm\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item flex w-full cursor-pointer items-center justify-between gap-3 rounded-md border-none bg-transparent px-4 py-3 text-left text-sm font-medium leading-snug text-zinc-600\"\n [class.settings-page__nav-item--active]=\"tab() === t.id\"\n [class.settings-page__nav-item--disabled]=\"isTabDisabled(t.id)\"\n [disabled]=\"isTabDisabled(t.id)\"\n [attr.title]=\"isTabDisabled(t.id) ? 'This section is currently disabled' : null\"\n (click)=\"setTab(t.id)\"\n >\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"ml-auto text-xs font-medium uppercase tracking-wide text-zinc-400\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel min-h-96 px-8 py-7 shadow-sm\">\n <header class=\"mb-6 flex items-start justify-between gap-4 border-b border-zinc-200 pb-4\">\n <div class=\"min-w-0\">\n <h2 class=\"mb-2 m-0 text-xl font-medium tracking-tight text-zinc-700\">{{ sectionMeta().title }}</h2>\n @if (tab() !== 'knowledge' && tab() !== 'general' && tab() !== 'phone' && tab() !== 'transcripts') {\n <p class=\"m-0 max-w-2xl text-base leading-relaxed text-zinc-500\">{{ sectionMeta().description }}</p>\n }\n </div>\n @if (tab() === 'knowledge') {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"openTestCall()\">\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Test Call\n </eds-button>\n }\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"mb-5 flex items-center gap-3 rounded-md border border-zinc-200 bg-slate-50 px-4 py-3 text-sm leading-snug text-zinc-500\">\n <eds-icon name=\"lock\" [size]=\"18\" />\n These settings are managed by Edvak. Contact support to request changes.\n </p>\n }\n\n @if (tab() === 'knowledge') {\n <div class=\"flex max-w-4xl flex-col gap-7\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatToSay', $event)\"\n placeholder=\"Hours, parking, payment options, arrival instructions, emergencies\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What not to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatNotToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatNotToSay', $event)\"\n placeholder=\"Clinical advice, unverified prices, PHI, promises the practice cannot keep\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatNotToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n </div>\n } @else if (tab() === 'general') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Name <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"How the AI introduces itself on calls\" />\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'agentName')\"\n (ngModelChange)=\"updateField('general', 'agentName', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <div class=\"flex items-end gap-3\">\n <label class=\"settings-page__field min-w-0 flex-1 flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Voice <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"relative w-full\">\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'ttsVoiceId')\"\n (ngModelChange)=\"updateField('general', 'ttsVoiceId', $event)\"\n autocomplete=\"off\"\n >\n @for (v of voicePresets; track v.id) {\n <option [ngValue]=\"v.id\">{{ v.label }}</option>\n }\n </select>\n <eds-icon name=\"expand_more\" [size]=\"20\" class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500\" />\n </div>\n </label>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Tone</span>\n <div class=\"flex flex-wrap gap-2\" role=\"radiogroup\" aria-label=\"Tone\">\n @for (tone of toneOptions; track tone.value) {\n <button\n type=\"button\"\n class=\"settings-page__tone h-9 cursor-pointer rounded-full border border-transparent bg-slate-100 px-4 text-sm font-medium text-zinc-500\"\n [class.settings-page__tone--active]=\"selectedTone() === tone.value\"\n (click)=\"setTone(tone.value)\"\n >\n {{ tone.label }}\n </button>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Inbound Greetings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ welcomeMessage().length }}/{{ welcomeMax }}</span>\n <div class=\"mt-3 flex flex-wrap items-center gap-2\">\n <span class=\"text-sm text-zinc-500\">Variables</span>\n @for (v of greetingVariables; track v.key) {\n <button\n type=\"button\"\n class=\"settings-page__var-chip h-7 cursor-pointer rounded-full border border-zinc-200 bg-white px-3 text-xs font-medium text-zinc-700\"\n (click)=\"insertGreetingVariable(v.token)\"\n [title]=\"'Insert ' + v.token\"\n >\n {{ v.label }}\n </button>\n }\n </div>\n </label>\n </div>\n } @else if (tab() === 'phone') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Answer Mode <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"When the AI picks up inbound calls\" />\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'answerMode')\"\n (ngModelChange)=\"updateField('phone', 'answerMode', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of answerModeOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Phone Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'mainNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [ngModel]=\"fieldValue('phone', 'mainNumber')\"\n (ngModelChange)=\"updateField('phone', 'mainNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Transfer Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'transferNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [ngModel]=\"fieldValue('phone', 'transferNumber')\"\n (ngModelChange)=\"updateField('phone', 'transferNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Ringing Time Wait <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'ringTimeout')\"\n (ngModelChange)=\"selectNumberField('phone', 'ringTimeout', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of ringTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"event_available\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Create Follow-up Task</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n If no one answers in time, the agent auto-creates a high priority task.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n [attr.aria-pressed]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n (click)=\"updateField('phone', 'createFollowUpTask', !fieldValue('phone', 'createFollowUpTask'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Location Handled <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"settings-page__check-grid grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2 rounded-lg border border-zinc-300 bg-white p-3\" role=\"group\" aria-label=\"Locations handled\">\n @for (loc of locations(); track loc.id) {\n <label class=\"settings-page__check-item flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm text-zinc-700\">\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 accent-blue-600\"\n [checked]=\"selectedLocationIds().includes(loc.id)\"\n (change)=\"toggleLocation(loc.id)\"\n autocomplete=\"off\"\n />\n <span>{{ loc.name }}</span>\n </label>\n } @empty {\n <p class=\"m-0 p-3 text-sm text-zinc-500\">No locations available.</p>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Max AI Call Duration <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'maxCallDurationMin')\"\n (ngModelChange)=\"selectNumberField('phone', 'maxCallDurationMin', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of maxCallDurationOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Silence Timeout <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'silenceTimeoutSec')\"\n (ngModelChange)=\"selectNumberField('phone', 'silenceTimeoutSec', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of silenceTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n After-Hours Behaviour <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'afterHoursBehavior')\"\n (ngModelChange)=\"updateField('phone', 'afterHoursBehavior', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of afterHoursOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n </div>\n } @else if (tab() === 'transcripts') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Call Recordings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'recordingRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'recordingRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Transcripts <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'transcriptRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'transcriptRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Disclosure Warning</span>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"disclosureEnabled()\"\n [attr.aria-pressed]=\"disclosureEnabled()\"\n (click)=\"setDisclosureEnabled(!disclosureEnabled())\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n @if (disclosureEnabled()) {\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"disclosureMax\"\n [ngModel]=\"disclosureText()\"\n (ngModelChange)=\"updateDisclosureText($event)\"\n autocomplete=\"off\"\n ></textarea>\n }\n </div>\n </div>\n } @else if (tab() === 'advanced') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"smart_toy\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">\n @if (toggling()) {\n Updating\u2026\n } @else if (online() === true) {\n Agent online\n } @else if (online() === false) {\n Agent offline\n } @else {\n Status unknown\n }\n </span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n @if (online() === true) {\n AI receptionist is answering inbound calls.\n } @else if (online() === false) {\n AI is offline \u2014 calls go to the front desk.\n } @else {\n Checking agent status\u2026\n }\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"online() === true\"\n [disabled]=\"agentSwitchDisabled()\"\n [attr.aria-pressed]=\"online() === true\"\n (click)=\"onAgentToggleClick()\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2 settings-page__field--readonly\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Model version\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input settings-page__input--readonly w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('advanced', 'modelVersion')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__toggle-row settings-page__toggle-row--readonly col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Debug mode\n </span>\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">Verbose logging \u2014 contact Edvak to change.</span>\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [ngModel]=\"fieldValue('advanced', 'debugMode')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n </div>\n } @else {\n <div class=\"settings-page__fields grid grid-cols-2 gap-x-7 gap-y-5\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, +$event)\"\n autocomplete=\"off\"\n />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n }\n </label>\n }\n }\n </div>\n }\n </article>\n </div>\n }\n</div>\n\n<eds-knowledge-test-modal\n [open]=\"knowledgeTestOpen()\"\n [whatToSay]=\"whatToSay()\"\n [whatNotToSay]=\"whatNotToSay()\"\n [voiceId]=\"selectedVoiceId()\"\n (closed)=\"closeTestCall()\"\n/>\n\n@if (confirmOffOpen()) {\n <app-modal\n title=\"Turn off AI receptionist?\"\n subtitle=\"Inbound callers will be transferred to the front desk instead of the AI.\"\n maxWidth=\"480px\"\n (closed)=\"cancelConfirmOff()\"\n >\n <p class=\"mb-4 m-0 text-sm leading-normal text-zinc-500\">While offline, the AI will not answer calls. Callers are routed to the human receptionist.</p>\n <div class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"cancelConfirmOff()\">Cancel</eds-button>\n <eds-button variant=\"danger\" type=\"button\" [disabled]=\"toggling()\" (click)=\"confirmTurnOff()\">\n Turn off\n </eds-button>\n </div>\n </app-modal>\n}\n", styles: [".settings-page__layout{grid-template-columns:240px minmax(0,1fr)}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f7f9fa);color:var(--eds-text-primary, #41464c)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf1fe);color:var(--eds-text-brand, #2162f0)}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-text-tertiary, #767676)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-text-tertiary, #767676)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__textarea:focus,.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__tone--active{background:#fff;border-color:var(--eds-brand-600, #2162f0);color:var(--eds-brand-600, #2162f0)}.settings-page__var-chip:hover{border-color:var(--eds-brand-300, #94c5f9);color:var(--eds-brand-600, #2162f0)}.settings-page__check-item:hover{background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__switch{width:44px;height:26px;border-radius:999px;border:none;background:#cbd5e1;padding:3px;cursor:pointer;transition:background .15s ease}.settings-page__switch--on{background:var(--eds-brand-600, #2162f0)}.settings-page__switch:disabled{opacity:.55;cursor:not-allowed}.settings-page__switch-thumb{display:block;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px #0f172a33;transition:transform .15s ease}.settings-page__switch--on .settings-page__switch-thumb{transform:translate(18px)}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"] }]
988
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page settings-page\">\n <header class=\"mb-6 flex items-start justify-between gap-4\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"flex shrink-0 items-center gap-3\">\n @if (saved()) {\n <span class=\"text-sm font-medium text-green-500\">Saved</span>\n }\n <eds-button variant=\"primary\" [disabled]=\"saving()\" (click)=\"save()\">\n <eds-icon name=\"save\" [size]=\"18\" />\n {{ saving() ? 'Saving\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Loading settings\u2026</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout grid items-start gap-5\">\n <nav class=\"eds-card settings-page__sidebar sticky top-4 flex max-h-[calc(100vh-120px)] flex-col gap-1 overflow-y-auto p-2 shadow-sm\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item flex w-full cursor-pointer items-center justify-between gap-3 rounded-md border-none bg-transparent px-4 py-3 text-left text-sm font-medium leading-snug text-zinc-600\"\n [class.settings-page__nav-item--active]=\"tab() === t.id\"\n [class.settings-page__nav-item--disabled]=\"isTabDisabled(t.id)\"\n [disabled]=\"isTabDisabled(t.id)\"\n [attr.title]=\"isTabDisabled(t.id) ? 'This section is currently disabled' : null\"\n (click)=\"setTab(t.id)\"\n >\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"ml-auto text-xs font-medium uppercase tracking-wide text-zinc-400\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel min-h-96 px-8 py-7 shadow-sm\">\n <header class=\"mb-6 flex items-start justify-between gap-4 border-b border-zinc-200 pb-4\">\n <div class=\"min-w-0\">\n <h2 class=\"mb-2 m-0 text-xl font-medium tracking-tight text-zinc-700\">{{ sectionMeta().title }}</h2>\n @if (tab() !== 'knowledge' && tab() !== 'general' && tab() !== 'phone' && tab() !== 'transcripts') {\n <p class=\"m-0 max-w-2xl text-base leading-relaxed text-zinc-500\">{{ sectionMeta().description }}</p>\n }\n </div>\n @if (tab() === 'knowledge') {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"openTestCall()\">\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Test Call\n </eds-button>\n }\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"mb-5 flex items-center gap-3 rounded-md border border-zinc-200 bg-slate-50 px-4 py-3 text-sm leading-snug text-zinc-500\">\n <eds-icon name=\"lock\" [size]=\"18\" />\n These settings are managed by Edvak. Contact support to request changes.\n </p>\n }\n\n @if (tab() === 'knowledge') {\n <div class=\"flex max-w-4xl flex-col gap-7\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatToSay', $event)\"\n placeholder=\"Hours, parking, payment options, arrival instructions, emergencies\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What not to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatNotToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatNotToSay', $event)\"\n placeholder=\"Clinical advice, unverified prices, PHI, promises the practice cannot keep\u2026\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatNotToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n </div>\n } @else if (tab() === 'general') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Name <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"How the AI introduces itself on calls\" />\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'agentName')\"\n (ngModelChange)=\"updateField('general', 'agentName', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <div class=\"flex items-end gap-3\">\n <label class=\"settings-page__field min-w-0 flex-1 flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Voice <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"relative w-full\">\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'ttsVoiceId')\"\n (ngModelChange)=\"updateField('general', 'ttsVoiceId', $event)\"\n autocomplete=\"off\"\n >\n @for (v of voicePresets; track v.id) {\n <option [ngValue]=\"v.id\">{{ v.label }}</option>\n }\n </select>\n <eds-icon name=\"expand_more\" [size]=\"20\" class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500\" />\n </div>\n </label>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Tone</span>\n <div class=\"flex flex-wrap gap-2\" role=\"radiogroup\" aria-label=\"Tone\">\n @for (tone of toneOptions; track tone.value) {\n <button\n type=\"button\"\n class=\"settings-page__tone h-9 cursor-pointer rounded-full border border-transparent bg-slate-100 px-4 text-sm font-medium text-zinc-500\"\n [class.settings-page__tone--active]=\"selectedTone() === tone.value\"\n (click)=\"setTone(tone.value)\"\n >\n {{ tone.label }}\n </button>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Inbound Greetings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ welcomeMessage().length }}/{{ welcomeMax }}</span>\n <div class=\"mt-3 flex flex-wrap items-center gap-2\">\n <span class=\"text-sm text-zinc-500\">Variables</span>\n @for (v of greetingVariables; track v.key) {\n <button\n type=\"button\"\n class=\"settings-page__var-chip h-7 cursor-pointer rounded-full border border-zinc-200 bg-white px-3 text-xs font-medium text-zinc-700\"\n (click)=\"insertGreetingVariable(v.token)\"\n [title]=\"'Insert ' + v.token\"\n >\n {{ v.label }}\n </button>\n }\n </div>\n </label>\n </div>\n } @else if (tab() === 'phone') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Answer Mode <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"When the AI picks up inbound calls\" />\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'answerMode')\"\n (ngModelChange)=\"updateField('phone', 'answerMode', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of answerModeOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Phone Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'mainNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [ngModel]=\"fieldValue('phone', 'mainNumber')\"\n (ngModelChange)=\"updateField('phone', 'mainNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Transfer Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'transferNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [ngModel]=\"fieldValue('phone', 'transferNumber')\"\n (ngModelChange)=\"updateField('phone', 'transferNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Ringing Time Wait <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'ringTimeout')\"\n (ngModelChange)=\"selectNumberField('phone', 'ringTimeout', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of ringTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"event_available\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Create Follow-up Task</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n If no one answers in time, the agent auto-creates a high priority task.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n [attr.aria-pressed]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n (click)=\"updateField('phone', 'createFollowUpTask', !fieldValue('phone', 'createFollowUpTask'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Location Handled <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"settings-page__locations-dd relative\" (document:click)=\"onLocationsDocClick($event)\">\n <button\n type=\"button\"\n class=\"settings-page__input settings-page__select flex w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-left text-base leading-snug text-zinc-700\"\n [disabled]=\"locations().length === 0\"\n [attr.aria-expanded]=\"locationsMenuOpen()\"\n aria-haspopup=\"listbox\"\n aria-label=\"Locations handled\"\n (click)=\"$event.stopPropagation(); toggleLocationsMenu()\"\n >\n <span class=\"min-w-0 truncate\">{{ locationSummary() }}</span>\n <eds-icon name=\"expand_more\" [size]=\"18\" class=\"shrink-0 text-zinc-500\" />\n </button>\n @if (locationsMenuOpen()) {\n <ul\n class=\"absolute z-20 m-0 mt-1 max-h-56 w-full list-none overflow-auto rounded-md border border-zinc-200 bg-white p-1 shadow-md\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n >\n @for (loc of locations(); track loc.id) {\n <li role=\"option\" [attr.aria-selected]=\"selectedLocationIds().includes(loc.id)\">\n <label\n class=\"flex cursor-pointer items-center gap-2.5 rounded px-2.5 py-2 text-sm text-zinc-700 hover:bg-zinc-50\"\n >\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 accent-blue-600\"\n [checked]=\"selectedLocationIds().includes(loc.id)\"\n (change)=\"toggleLocation(loc.id)\"\n />\n <span class=\"min-w-0 truncate\">{{ loc.name }}</span>\n </label>\n </li>\n }\n </ul>\n }\n </div>\n @if (locations().length === 0) {\n <p class=\"m-0 text-sm text-zinc-500\">No locations available.</p>\n }\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Max AI Call Duration <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'maxCallDurationMin')\"\n (ngModelChange)=\"selectNumberField('phone', 'maxCallDurationMin', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of maxCallDurationOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Silence Timeout <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'silenceTimeoutSec')\"\n (ngModelChange)=\"selectNumberField('phone', 'silenceTimeoutSec', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of silenceTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n After-Hours Behaviour <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'afterHoursBehavior')\"\n (ngModelChange)=\"updateField('phone', 'afterHoursBehavior', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of afterHoursOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"border-t border-zinc-200 pt-5\">\n <h3 class=\"mb-4 m-0 text-base font-semibold text-zinc-700\">Scheduling Rules</h3>\n <div class=\"flex flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-1.5\">\n <span class=\"settings-page__field-label flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Minimum lead time (hours)\n </span>\n <input\n type=\"number\"\n min=\"0\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('scheduling', 'leadTimeHours')\"\n (ngModelChange)=\"updateField('scheduling', 'leadTimeHours', +$event)\"\n autocomplete=\"off\"\n />\n <span class=\"text-xs text-zinc-500\">Earliest bookable slot from now.</span>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-3.5 rounded-xl border border-zinc-200 bg-white p-3.5\">\n <eds-icon name=\"today\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Allow same-day booking</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n Let patients book appointments later today.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n [attr.aria-pressed]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n (click)=\"updateField('scheduling', 'allowSameDay', !fieldValue('scheduling', 'allowSameDay'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n </div>\n </div>\n </div>\n } @else if (tab() === 'transcripts') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Call Recordings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'recordingRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'recordingRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Transcripts <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'transcriptRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'transcriptRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Disclosure Warning</span>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"disclosureEnabled()\"\n [attr.aria-pressed]=\"disclosureEnabled()\"\n (click)=\"setDisclosureEnabled(!disclosureEnabled())\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n @if (disclosureEnabled()) {\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"disclosureMax\"\n [ngModel]=\"disclosureText()\"\n (ngModelChange)=\"updateDisclosureText($event)\"\n autocomplete=\"off\"\n ></textarea>\n }\n </div>\n </div>\n } @else if (tab() === 'advanced') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"smart_toy\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">\n @if (toggling()) {\n Updating\u2026\n } @else if (online() === true) {\n Agent online\n } @else if (online() === false) {\n Agent offline\n } @else {\n Status unknown\n }\n </span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n @if (online() === true) {\n AI receptionist is answering inbound calls.\n } @else if (online() === false) {\n AI is offline \u2014 calls go to the front desk.\n } @else {\n Checking agent status\u2026\n }\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"online() === true\"\n [disabled]=\"agentSwitchDisabled()\"\n [attr.aria-pressed]=\"online() === true\"\n (click)=\"onAgentToggleClick()\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2 settings-page__field--readonly\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Model version\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input settings-page__input--readonly w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('advanced', 'modelVersion')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__toggle-row settings-page__toggle-row--readonly col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Debug mode\n </span>\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">Verbose logging \u2014 contact Edvak to change.</span>\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [ngModel]=\"fieldValue('advanced', 'debugMode')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n </div>\n } @else {\n <div class=\"settings-page__fields grid grid-cols-2 gap-x-7 gap-y-5\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, +$event)\"\n autocomplete=\"off\"\n />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n }\n </label>\n }\n }\n </div>\n }\n </article>\n </div>\n }\n</div>\n\n<eds-knowledge-test-modal\n [open]=\"knowledgeTestOpen()\"\n [whatToSay]=\"whatToSay()\"\n [whatNotToSay]=\"whatNotToSay()\"\n [voiceId]=\"selectedVoiceId()\"\n (closed)=\"closeTestCall()\"\n/>\n\n@if (confirmOffOpen()) {\n <app-modal\n title=\"Turn off AI receptionist?\"\n subtitle=\"Inbound callers will be transferred to the front desk instead of the AI.\"\n maxWidth=\"480px\"\n (closed)=\"cancelConfirmOff()\"\n >\n <p class=\"mb-4 m-0 text-sm leading-normal text-zinc-500\">While offline, the AI will not answer calls. Callers are routed to the human receptionist.</p>\n <div class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"cancelConfirmOff()\">Cancel</eds-button>\n <eds-button variant=\"danger\" type=\"button\" [disabled]=\"toggling()\" (click)=\"confirmTurnOff()\">\n Turn off\n </eds-button>\n </div>\n </app-modal>\n}\n", styles: [".settings-page__layout{grid-template-columns:240px minmax(0,1fr)}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f7f9fa);color:var(--eds-text-primary, #41464c)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf1fe);color:var(--eds-text-brand, #2162f0)}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-text-tertiary, #767676)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-text-tertiary, #767676)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__textarea:focus,.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__tone--active{background:#fff;border-color:var(--eds-brand-600, #2162f0);color:var(--eds-brand-600, #2162f0)}.settings-page__var-chip:hover{border-color:var(--eds-brand-300, #94c5f9);color:var(--eds-brand-600, #2162f0)}.settings-page__check-item:hover{background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__switch{width:44px;height:26px;border-radius:999px;border:none;background:#cbd5e1;padding:3px;cursor:pointer;transition:background .15s ease}.settings-page__switch--on{background:var(--eds-brand-600, #2162f0)}.settings-page__switch:disabled{opacity:.55;cursor:not-allowed}.settings-page__switch-thumb{display:block;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 3px #0f172a33;transition:transform .15s ease}.settings-page__switch--on .settings-page__switch-thumb{transform:translate(18px)}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"] }]
964
989
  }] });
965
990
 
966
991
  export { SettingsPageComponent };
967
- //# sourceMappingURL=edvak99-voice-receptionist-widget-settings-page.component-BwCz1dlx.mjs.map
992
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-settings-page.component-CspheAr8.mjs.map