@forgeroute/ui 0.4.33 → 0.4.35

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.
@@ -4352,6 +4352,7 @@ i0.ɵɵngDeclareClassMetadata({
4352
4352
  }
4353
4353
  });
4354
4354
  let nextTooltipId = 0;
4355
+ let openTooltip = null;
4355
4356
  var TooltipDirective = class TooltipDirective {
4356
4357
  constructor() {
4357
4358
  this.uiTooltip = input("", ...ngDevMode ? [{ debugName: "uiTooltip" }] : /* istanbul ignore next */ []);
@@ -4359,12 +4360,18 @@ var TooltipDirective = class TooltipDirective {
4359
4360
  this.host = inject(ElementRef).nativeElement;
4360
4361
  this.doc = inject(DOCUMENT);
4361
4362
  this.bubble = null;
4363
+ this.previousDescribedBy = null;
4362
4364
  this.id = `ui-tooltip-${nextTooltipId++}`;
4363
4365
  inject(DestroyRef).onDestroy(() => this.hide());
4364
4366
  }
4365
4367
  show() {
4366
4368
  const text = this.uiTooltip();
4367
4369
  if (!text || this.bubble) return;
4370
+ openTooltip?.close();
4371
+ openTooltip = {
4372
+ owner: this,
4373
+ close: () => this.hide()
4374
+ };
4368
4375
  const el = this.doc.createElement("div");
4369
4376
  el.id = this.id;
4370
4377
  el.setAttribute("role", "tooltip");
@@ -4386,7 +4393,8 @@ var TooltipDirective = class TooltipDirective {
4386
4393
  });
4387
4394
  this.doc.body.appendChild(el);
4388
4395
  this.bubble = el;
4389
- this.host.setAttribute("aria-describedby", this.id);
4396
+ this.previousDescribedBy = this.host.getAttribute("aria-describedby");
4397
+ this.host.setAttribute("aria-describedby", this.previousDescribedBy ? `${this.previousDescribedBy} ${this.id}` : this.id);
4390
4398
  const r = this.host.getBoundingClientRect();
4391
4399
  const b = el.getBoundingClientRect();
4392
4400
  const gap = 6;
@@ -4399,9 +4407,13 @@ var TooltipDirective = class TooltipDirective {
4399
4407
  el.style.visibility = "visible";
4400
4408
  }
4401
4409
  hide() {
4402
- this.bubble?.remove();
4410
+ if (!this.bubble) return;
4411
+ this.bubble.remove();
4403
4412
  this.bubble = null;
4404
- this.host.removeAttribute("aria-describedby");
4413
+ if (openTooltip?.owner === this) openTooltip = null;
4414
+ if (this.previousDescribedBy) this.host.setAttribute("aria-describedby", this.previousDescribedBy);
4415
+ else this.host.removeAttribute("aria-describedby");
4416
+ this.previousDescribedBy = null;
4405
4417
  }
4406
4418
  static {
4407
4419
  this.ɵfac = i0.ɵɵngDeclareFactory({
@@ -18714,6 +18726,7 @@ var ToggleBadgeComponent = class ToggleBadgeComponent {
18714
18726
  this.label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
18715
18727
  this.active = input(false, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
18716
18728
  this.actions = input([], ...ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []);
18729
+ this.tooltip = input("", ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
18717
18730
  this.toggle = output();
18718
18731
  this.action = output();
18719
18732
  }
@@ -18755,6 +18768,13 @@ var ToggleBadgeComponent = class ToggleBadgeComponent {
18755
18768
  isSignal: true,
18756
18769
  isRequired: false,
18757
18770
  transformFunction: null
18771
+ },
18772
+ tooltip: {
18773
+ classPropertyName: "tooltip",
18774
+ publicName: "tooltip",
18775
+ isSignal: true,
18776
+ isRequired: false,
18777
+ transformFunction: null
18758
18778
  }
18759
18779
  },
18760
18780
  outputs: {
@@ -18764,12 +18784,12 @@ var ToggleBadgeComponent = class ToggleBadgeComponent {
18764
18784
  ngImport: i0,
18765
18785
  template: `
18766
18786
  <span class="tb" [class.active]="active()" [class.tb-has-actions]="actions().length > 0">
18767
- <button type="button" class="toggle-badge" [class.active]="active()" (click)="toggle.emit()">
18787
+ <button type="button" class="toggle-badge" [class.active]="active()" [uiTooltip]="tooltip()" (click)="toggle.emit()">
18768
18788
  <ng-content />
18769
18789
  {{ label() }}
18770
18790
  </button>
18771
18791
  @if (actions().length > 0) {
18772
- <span class="tb-actions" role="group" [attr.aria-label]="label() + ' actions'">
18792
+ <span class="tb-actions" role="group" [attr.aria-label]="(label() + ' actions').trim()">
18773
18793
  <span class="tb-divider" aria-hidden="true"></span>
18774
18794
  @for (a of actions(); track a.id) {
18775
18795
  <button type="button" class="tb-action" [disabled]="a.disabled ?? false" [attr.aria-label]="a.label" [uiTooltip]="a.tooltip || a.label"
@@ -18782,7 +18802,7 @@ var ToggleBadgeComponent = class ToggleBadgeComponent {
18782
18802
  </span>
18783
18803
  `,
18784
18804
  isInline: true,
18785
- styles: [":host{display:inline-flex}.tb{display:inline-flex;align-items:center;border-radius:999px;border:1px solid #e2e8f0;background:#fff;color:#64748b;transition:all .15s ease}.tb:hover{background:#f8fafc;border-color:#94a3b8}.tb.active{background:#1e293b;color:#fff;border-color:#1e293b}.toggle-badge{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:999px;border:none;background:transparent;font-size:.75rem;font-weight:500;color:inherit;cursor:pointer;font-family:inherit;line-height:1}.toggle-badge:focus-visible,.tb-action:focus-visible{outline:2px solid #60a5fa;outline-offset:2px}.tb-has-actions .toggle-badge{padding-right:6px}.tb-actions{display:inline-flex;align-items:center;gap:1px;padding-right:4px}.tb-divider{width:1px;height:12px;background:currentColor;opacity:.25;margin-right:3px}.tb-action{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:50%;background:transparent;color:inherit;cursor:pointer;opacity:.75;font-family:inherit;transition:background .15s ease,opacity .15s ease}.tb-action:hover:not(:disabled){opacity:1;background:#64748b2e}.tb.active .tb-action:hover:not(:disabled){background:#fff3}.tb-action:disabled{opacity:.35;cursor:not-allowed}@media(pointer:coarse){.tb-action{position:relative}.tb-action:after{content:\"\";position:absolute;inset:-12px}}\n"],
18805
+ styles: [":host{display:inline-flex}.tb{display:inline-flex;align-items:center;border-radius:999px;border:1px solid #e2e8f0;background:#fff;color:#64748b;transition:all .15s ease}.tb:hover{background:#f8fafc;border-color:#94a3b8}.tb.active{background:#1e293b;color:#fff;border-color:#1e293b}.toggle-badge{display:inline-flex;align-items:center;gap:5px;padding:var(--ui-toggle-badge-pad-y, 3px) var(--ui-toggle-badge-pad-x, 10px);border-radius:999px;border:none;background:transparent;font-size:.75rem;font-weight:500;color:inherit;cursor:pointer;font-family:inherit;line-height:1}.toggle-badge:focus-visible,.tb-action:focus-visible{outline:2px solid #60a5fa;outline-offset:2px}.tb-has-actions .toggle-badge{padding-right:6px}.tb-actions{display:inline-flex;align-items:center;gap:1px;padding-right:4px}.tb-divider{width:1px;height:12px;background:currentColor;opacity:.25;margin-right:3px}.tb-action{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:50%;background:transparent;color:inherit;cursor:pointer;opacity:.75;font-family:inherit;transition:background .15s ease,opacity .15s ease}.tb-action:hover:not(:disabled){opacity:1;background:#64748b2e}.tb.active .tb-action:hover:not(:disabled){background:#fff3}.tb-action:disabled{opacity:.35;cursor:not-allowed}@media(pointer:coarse){.tb-action{position:relative}.tb-action:after{content:\"\";position:absolute;inset:-12px}}\n"],
18786
18806
  dependencies: [{
18787
18807
  kind: "directive",
18788
18808
  type: TooltipDirective,
@@ -18807,12 +18827,12 @@ i0.ɵɵngDeclareClassMetadata({
18807
18827
  changeDetection: ChangeDetectionStrategy.OnPush,
18808
18828
  template: `
18809
18829
  <span class="tb" [class.active]="active()" [class.tb-has-actions]="actions().length > 0">
18810
- <button type="button" class="toggle-badge" [class.active]="active()" (click)="toggle.emit()">
18830
+ <button type="button" class="toggle-badge" [class.active]="active()" [uiTooltip]="tooltip()" (click)="toggle.emit()">
18811
18831
  <ng-content />
18812
18832
  {{ label() }}
18813
18833
  </button>
18814
18834
  @if (actions().length > 0) {
18815
- <span class="tb-actions" role="group" [attr.aria-label]="label() + ' actions'">
18835
+ <span class="tb-actions" role="group" [attr.aria-label]="(label() + ' actions').trim()">
18816
18836
  <span class="tb-divider" aria-hidden="true"></span>
18817
18837
  @for (a of actions(); track a.id) {
18818
18838
  <button type="button" class="tb-action" [disabled]="a.disabled ?? false" [attr.aria-label]="a.label" [uiTooltip]="a.tooltip || a.label"
@@ -18824,7 +18844,7 @@ i0.ɵɵngDeclareClassMetadata({
18824
18844
  }
18825
18845
  </span>
18826
18846
  `,
18827
- styles: [":host{display:inline-flex}.tb{display:inline-flex;align-items:center;border-radius:999px;border:1px solid #e2e8f0;background:#fff;color:#64748b;transition:all .15s ease}.tb:hover{background:#f8fafc;border-color:#94a3b8}.tb.active{background:#1e293b;color:#fff;border-color:#1e293b}.toggle-badge{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:999px;border:none;background:transparent;font-size:.75rem;font-weight:500;color:inherit;cursor:pointer;font-family:inherit;line-height:1}.toggle-badge:focus-visible,.tb-action:focus-visible{outline:2px solid #60a5fa;outline-offset:2px}.tb-has-actions .toggle-badge{padding-right:6px}.tb-actions{display:inline-flex;align-items:center;gap:1px;padding-right:4px}.tb-divider{width:1px;height:12px;background:currentColor;opacity:.25;margin-right:3px}.tb-action{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:50%;background:transparent;color:inherit;cursor:pointer;opacity:.75;font-family:inherit;transition:background .15s ease,opacity .15s ease}.tb-action:hover:not(:disabled){opacity:1;background:#64748b2e}.tb.active .tb-action:hover:not(:disabled){background:#fff3}.tb-action:disabled{opacity:.35;cursor:not-allowed}@media(pointer:coarse){.tb-action{position:relative}.tb-action:after{content:\"\";position:absolute;inset:-12px}}\n"]
18847
+ styles: [":host{display:inline-flex}.tb{display:inline-flex;align-items:center;border-radius:999px;border:1px solid #e2e8f0;background:#fff;color:#64748b;transition:all .15s ease}.tb:hover{background:#f8fafc;border-color:#94a3b8}.tb.active{background:#1e293b;color:#fff;border-color:#1e293b}.toggle-badge{display:inline-flex;align-items:center;gap:5px;padding:var(--ui-toggle-badge-pad-y, 3px) var(--ui-toggle-badge-pad-x, 10px);border-radius:999px;border:none;background:transparent;font-size:.75rem;font-weight:500;color:inherit;cursor:pointer;font-family:inherit;line-height:1}.toggle-badge:focus-visible,.tb-action:focus-visible{outline:2px solid #60a5fa;outline-offset:2px}.tb-has-actions .toggle-badge{padding-right:6px}.tb-actions{display:inline-flex;align-items:center;gap:1px;padding-right:4px}.tb-divider{width:1px;height:12px;background:currentColor;opacity:.25;margin-right:3px}.tb-action{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:50%;background:transparent;color:inherit;cursor:pointer;opacity:.75;font-family:inherit;transition:background .15s ease,opacity .15s ease}.tb-action:hover:not(:disabled){opacity:1;background:#64748b2e}.tb.active .tb-action:hover:not(:disabled){background:#fff3}.tb-action:disabled{opacity:.35;cursor:not-allowed}@media(pointer:coarse){.tb-action{position:relative}.tb-action:after{content:\"\";position:absolute;inset:-12px}}\n"]
18828
18848
  }]
18829
18849
  }],
18830
18850
  propDecorators: {
@@ -18852,6 +18872,14 @@ i0.ɵɵngDeclareClassMetadata({
18852
18872
  required: false
18853
18873
  }]
18854
18874
  }],
18875
+ tooltip: [{
18876
+ type: i0.Input,
18877
+ args: [{
18878
+ isSignal: true,
18879
+ alias: "tooltip",
18880
+ required: false
18881
+ }]
18882
+ }],
18855
18883
  toggle: [{
18856
18884
  type: i0.Output,
18857
18885
  args: ["toggle"]
@@ -20577,7 +20605,8 @@ var BulkMessagePanelComponent = class BulkMessagePanelComponent {
20577
20605
  inputs: [
20578
20606
  "label",
20579
20607
  "active",
20580
- "actions"
20608
+ "actions",
20609
+ "tooltip"
20581
20610
  ],
20582
20611
  outputs: ["toggle", "action"]
20583
20612
  },
@@ -42343,6 +42372,8 @@ const str = (v) => typeof v === "string" ? v : "";
42343
42372
  const SETUP_INTEGRATIONS = {
42344
42373
  quickbooks: {
42345
42374
  key: "quickbooks",
42375
+ letter: "Q",
42376
+ color: "#2ca01c",
42346
42377
  title: "QuickBooks Online",
42347
42378
  icon: "bank",
42348
42379
  description: "Sync commissions and expenses to your QuickBooks books.",
@@ -42355,6 +42386,8 @@ const SETUP_INTEGRATIONS = {
42355
42386
  },
42356
42387
  slack: {
42357
42388
  key: "slack",
42389
+ letter: "S",
42390
+ color: "#4a154b",
42358
42391
  title: "Slack",
42359
42392
  icon: "message",
42360
42393
  description: "Get new-lead and deal alerts in a Slack channel.",
@@ -42367,6 +42400,8 @@ const SETUP_INTEGRATIONS = {
42367
42400
  },
42368
42401
  twilio: {
42369
42402
  key: "twilio",
42403
+ letter: "T",
42404
+ color: "#f22f46",
42370
42405
  title: "Twilio (calls & texts)",
42371
42406
  icon: "call",
42372
42407
  description: "Get a business phone number for texting and calling clients.",
@@ -42379,6 +42414,8 @@ const SETUP_INTEGRATIONS = {
42379
42414
  },
42380
42415
  gmail: {
42381
42416
  key: "gmail",
42417
+ letter: "G",
42418
+ color: "#ea4335",
42382
42419
  title: "Gmail / Google Workspace",
42383
42420
  icon: "email",
42384
42421
  description: "Connect your Google account for two-way email sync.",
@@ -42392,6 +42429,8 @@ const SETUP_INTEGRATIONS = {
42392
42429
  },
42393
42430
  outlook: {
42394
42431
  key: "outlook",
42432
+ letter: "O",
42433
+ color: "#0078d4",
42395
42434
  title: "Outlook / Microsoft 365",
42396
42435
  icon: "email",
42397
42436
  description: "Connect your Microsoft account for two-way email sync.",
@@ -42405,6 +42444,8 @@ const SETUP_INTEGRATIONS = {
42405
42444
  },
42406
42445
  "google-calendar": {
42407
42446
  key: "google-calendar",
42447
+ letter: "G",
42448
+ color: "#4285f4",
42408
42449
  title: "Google Calendar",
42409
42450
  icon: "link",
42410
42451
  description: "Two-way sync with your Google Calendar.",
@@ -42418,6 +42459,8 @@ const SETUP_INTEGRATIONS = {
42418
42459
  },
42419
42460
  "outlook-calendar": {
42420
42461
  key: "outlook-calendar",
42462
+ letter: "O",
42463
+ color: "#0078d4",
42421
42464
  title: "Outlook Calendar",
42422
42465
  icon: "link",
42423
42466
  description: "Two-way sync with your Outlook / Microsoft 365 calendar.",
@@ -42618,7 +42661,8 @@ var SetupWizardComponent = class SetupWizardComponent {
42618
42661
  this.busy = signal(false, ...ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []);
42619
42662
  this.api = {
42620
42663
  saveAndContinue: () => this.saveAndContinue(),
42621
- busy: () => this.busy()
42664
+ busy: () => this.busy(),
42665
+ markCompleted: (...keys) => this.markStepsCompleted(keys)
42622
42666
  };
42623
42667
  this.error = signal("", ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
42624
42668
  this.areaCodeOpen = signal("", ...ngDevMode ? [{ debugName: "areaCodeOpen" }] : /* istanbul ignore next */ []);
@@ -42699,6 +42743,10 @@ var SetupWizardComponent = class SetupWizardComponent {
42699
42743
  this.skipped.update((s) => new Set(s).add(key));
42700
42744
  this.advanceFrom(key);
42701
42745
  }
42746
+ markStepsCompleted(keys) {
42747
+ const known = new Set(this.steps().map((s) => s.key));
42748
+ for (const key of keys) if (known.has(key)) this.markCompleted(key);
42749
+ }
42702
42750
  markCompleted(key) {
42703
42751
  this.completed.update((s) => new Set(s).add(key));
42704
42752
  this.skipped.update((s) => {
@@ -42925,6 +42973,9 @@ var SetupWizardComponent = class SetupWizardComponent {
42925
42973
  @if (headerTemplateFor(current().key); as ht) {
42926
42974
  <div card-header-action class="sw-header-action" data-testid="wizard-card-header-action"><ng-container [ngTemplateOutlet]="ht" [ngTemplateOutletContext]="{ $implicit: api }" /></div>
42927
42975
  }
42976
+ @if (current().kind !== 'custom' && templateFor(current().key); as extra) {
42977
+ <ng-container [ngTemplateOutlet]="extra" [ngTemplateOutletContext]="{ $implicit: api }" />
42978
+ }
42928
42979
  @switch (current().kind) {
42929
42980
  @case ('custom') {
42930
42981
  @if (templateFor(current().key); as tpl) { <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: api }" /> }
@@ -42956,22 +43007,21 @@ var SetupWizardComponent = class SetupWizardComponent {
42956
43007
  @case ('integrations') {
42957
43008
  <div class="sw-provider-grid">
42958
43009
  @for (it of current().integrations ?? []; track it.key) {
42959
- <ui-detail-card class="sw-integration" [attr.data-testid]="'integration-' + it.key" [title]="it.title" [uppercaseTitle]="false" [headingLevel]="current().cardTitle ? 4 : 3" [collapsible]="false"
42960
- headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)">
42961
- <span card-header-leading class="sw-int-icon" aria-hidden="true"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false"><path [attr.d]="iconD(it.icon ?? 'link')" /></svg></span>
42962
- @if (isConnected(it)) { <ui-badge card-header-action [label]="t().connected" variant="green" /> }
42963
- <p class="sw-int-detail">{{ detailFor(it) }}</p>
43010
+ <ui-detail-card class="sw-integration" [attr.data-testid]="'integration-' + it.key" [showHeader]="false" [fill]="true" [ariaLabel]="it.title">
43011
+ <div class="sw-int-row">
43012
+ <span class="sw-int-tile" [style.background]="it.color || '#64748b'" aria-hidden="true">@if (it.letter) { {{ it.letter }} } @else { <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false"><path [attr.d]="iconD(it.icon ?? 'link')" /></svg> }</span>
43013
+ <span class="sw-int-text">
43014
+ <span class="sw-int-title">{{ it.title }}</span>
43015
+ <span class="sw-int-detail">{{ detailFor(it) }}</span>
43016
+ </span>
43017
+ <ui-button variant="secondary" size="xs" [attr.data-testid]="'integration-pick-' + it.key" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">{{ isConnected(it) ? t().reconnect : t().connect }}</ui-button>
43018
+ </div>
42964
43019
  @if (areaCodeOpen() === it.key) {
42965
43020
  <div class="sw-area-code" [attr.data-testid]="'area-code-' + it.key">
42966
43021
  <ui-text-input [label]="areaCodeLabelFor(it)" [maxlength]="3" inputmode="numeric" [ngModel]="areaCode()" (ngModelChange)="areaCode.set($event ?? '')" [inputTestId]="'area-code-input-' + it.key" />
42967
43022
  <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ t().connect }}</ui-button>
42968
43023
  </div>
42969
43024
  }
42970
- <div card-footer class="sw-int-footer">
42971
- <ui-button variant="secondary" size="sm" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">
42972
- <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ isConnected(it) ? t().reconnect : t().connect }}
42973
- </ui-button>
42974
- </div>
42975
43025
  </ui-detail-card>
42976
43026
  }
42977
43027
  </div>
@@ -43006,7 +43056,7 @@ var SetupWizardComponent = class SetupWizardComponent {
43006
43056
  </div>
43007
43057
  `,
43008
43058
  isInline: true,
43009
- styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-int-icon{display:inline-flex;color:#2563eb}.sw-int-detail{margin:0;font-size:.875rem;line-height:1.5;color:#475569}.sw-int-footer{display:flex;justify-content:flex-end}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
43059
+ styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-int-row{display:flex;align-items:center;gap:12px}.sw-int-tile{width:36px;height:36px;border-radius:8px;color:#fff;font-size:1rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.sw-int-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.sw-int-title{font-size:.8125rem;font-weight:600;color:#1e293b;line-height:1.2}.sw-int-detail{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"],
43010
43060
  dependencies: [
43011
43061
  {
43012
43062
  kind: "directive",
@@ -43341,6 +43391,9 @@ i0.ɵɵngDeclareClassMetadata({
43341
43391
  @if (headerTemplateFor(current().key); as ht) {
43342
43392
  <div card-header-action class="sw-header-action" data-testid="wizard-card-header-action"><ng-container [ngTemplateOutlet]="ht" [ngTemplateOutletContext]="{ $implicit: api }" /></div>
43343
43393
  }
43394
+ @if (current().kind !== 'custom' && templateFor(current().key); as extra) {
43395
+ <ng-container [ngTemplateOutlet]="extra" [ngTemplateOutletContext]="{ $implicit: api }" />
43396
+ }
43344
43397
  @switch (current().kind) {
43345
43398
  @case ('custom') {
43346
43399
  @if (templateFor(current().key); as tpl) { <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: api }" /> }
@@ -43372,22 +43425,21 @@ i0.ɵɵngDeclareClassMetadata({
43372
43425
  @case ('integrations') {
43373
43426
  <div class="sw-provider-grid">
43374
43427
  @for (it of current().integrations ?? []; track it.key) {
43375
- <ui-detail-card class="sw-integration" [attr.data-testid]="'integration-' + it.key" [title]="it.title" [uppercaseTitle]="false" [headingLevel]="current().cardTitle ? 4 : 3" [collapsible]="false"
43376
- headerBackground="rgb(248, 250, 252)" footerBackground="rgb(248, 250, 252)">
43377
- <span card-header-leading class="sw-int-icon" aria-hidden="true"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false"><path [attr.d]="iconD(it.icon ?? 'link')" /></svg></span>
43378
- @if (isConnected(it)) { <ui-badge card-header-action [label]="t().connected" variant="green" /> }
43379
- <p class="sw-int-detail">{{ detailFor(it) }}</p>
43428
+ <ui-detail-card class="sw-integration" [attr.data-testid]="'integration-' + it.key" [showHeader]="false" [fill]="true" [ariaLabel]="it.title">
43429
+ <div class="sw-int-row">
43430
+ <span class="sw-int-tile" [style.background]="it.color || '#64748b'" aria-hidden="true">@if (it.letter) { {{ it.letter }} } @else { <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false"><path [attr.d]="iconD(it.icon ?? 'link')" /></svg> }</span>
43431
+ <span class="sw-int-text">
43432
+ <span class="sw-int-title">{{ it.title }}</span>
43433
+ <span class="sw-int-detail">{{ detailFor(it) }}</span>
43434
+ </span>
43435
+ <ui-button variant="secondary" size="xs" [attr.data-testid]="'integration-pick-' + it.key" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">{{ isConnected(it) ? t().reconnect : t().connect }}</ui-button>
43436
+ </div>
43380
43437
  @if (areaCodeOpen() === it.key) {
43381
43438
  <div class="sw-area-code" [attr.data-testid]="'area-code-' + it.key">
43382
43439
  <ui-text-input [label]="areaCodeLabelFor(it)" [maxlength]="3" inputmode="numeric" [ngModel]="areaCode()" (ngModelChange)="areaCode.set($event ?? '')" [inputTestId]="'area-code-input-' + it.key" />
43383
43440
  <ui-button variant="primary" size="sm" [loading]="busy()" [disabled]="!validAreaCode()" (click)="submitAreaCode(it)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ t().connect }}</ui-button>
43384
43441
  </div>
43385
43442
  }
43386
- <div card-footer class="sw-int-footer">
43387
- <ui-button variant="secondary" size="sm" [ariaLabel]="(isConnected(it) ? t().reconnect : t().connect) + ' ' + it.title" (click)="connect(it)">
43388
- <svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('link')" /></svg> {{ isConnected(it) ? t().reconnect : t().connect }}
43389
- </ui-button>
43390
- </div>
43391
43443
  </ui-detail-card>
43392
43444
  }
43393
43445
  </div>
@@ -43421,7 +43473,7 @@ i0.ɵɵngDeclareClassMetadata({
43421
43473
  </main>
43422
43474
  </div>
43423
43475
  `,
43424
- styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-int-icon{display:inline-flex;color:#2563eb}.sw-int-detail{margin:0;font-size:.875rem;line-height:1.5;color:#475569}.sw-int-footer{display:flex;justify-content:flex-end}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
43476
+ styles: [".sw-page{display:flex;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.sw-sidebar{width:260px;min-width:260px;background:#faf9f7;border-right:1px solid #e5e2dc;display:flex;flex-direction:column;justify-content:space-between;padding:28px 20px}.sw-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}.sw-brand-text{font-size:1.125rem;font-weight:700;color:#1e293b}.sw-step-nav{display:block}.sw-sidebar-bottom{margin-top:24px}.sw-progress-text{display:block;margin-top:8px;font-size:.75rem;color:#94a3b8}.sw-content{flex:1;min-width:0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.sw-content-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 32px;border-bottom:1px solid #f1f5f9}.sw-step-title{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.sw-step-content{max-width:780px;padding:16px 48px 60px}.sw-intro{margin-bottom:24px}.sw-step-number{font-size:1.25rem;font-weight:800;line-height:1}.sw-step-desc{font-size:.9375rem;color:#6b7280;line-height:1.5;margin:0 0 32px}.sw-hint{font-size:.8125rem;color:#94a3b8;margin:0 0 16px}.sw-import-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:28px}.sw-tag{font-size:.6875rem;font-weight:700;letter-spacing:1px;color:#6b7280}.sw-provider-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:8px}@media(max-width:768px){.sw-provider-grid{grid-template-columns:1fr}}.sw-provider-grid .sw-integration{margin-bottom:0}.sw-int-row{display:flex;align-items:center;gap:12px}.sw-int-tile{width:36px;height:36px;border-radius:8px;color:#fff;font-size:1rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.sw-int-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.sw-int-title{font-size:.8125rem;font-weight:600;color:#1e293b;line-height:1.2}.sw-int-detail{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.sw-area-code{display:flex;align-items:flex-end;gap:12px;margin-top:12px;max-width:320px}.sw-area-code ui-text-input{flex:1}.sw-content ui-alert{display:block;margin-bottom:16px}.sw-card{display:block}.sw-header-action{margin-left:auto;min-width:0;max-width:100%}.sw-step-actions{display:flex;justify-content:space-between;align-items:center}.sw-ico{flex-shrink:0;vertical-align:-2px}.sw-actions-right{display:flex;align-items:center;gap:16px}.sw-done{text-align:center;display:flex;flex-direction:column;align-items:center;max-width:none}.sw-done .sw-step-desc{max-width:480px}.sw-summary{display:block;width:100%;max-width:480px;margin-bottom:24px;text-align:left}.sw-done-hint{font-size:.8125rem;color:#9ca3af;margin-bottom:24px}@media(max-width:768px){.sw-page{flex-direction:column}.sw-sidebar{width:100%;min-width:unset;padding:16px}.sw-brand{margin-bottom:12px}.sw-sidebar-bottom{display:none}.sw-step-content{padding:12px 20px 40px}}\n"]
43425
43477
  }]
43426
43478
  }],
43427
43479
  ctorParameters: () => [],
@@ -43680,6 +43732,11 @@ const HEADING_OPTIONS = [
43680
43732
  label: "Heading 3"
43681
43733
  }
43682
43734
  ];
43735
+ const BLOCK_BASE_PADDING_PX = 12;
43736
+ function setEditorSpacing(el, spacing) {
43737
+ el.style.paddingTop = spacing ? `calc(${BLOCK_BASE_PADDING_PX}px + ${spacing})` : "";
43738
+ el.style.paddingBottom = spacing ? `calc(${BLOCK_BASE_PADDING_PX}px + ${spacing})` : "";
43739
+ }
43683
43740
  const SPACING_TABS = [
43684
43741
  {
43685
43742
  key: "none",
@@ -43736,16 +43793,15 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43736
43793
  constructor() {
43737
43794
  this.host = inject(ElementRef);
43738
43795
  this.injector = inject(Injector);
43739
- this.toast = inject(ToastService);
43740
43796
  this.template = input(null, ...ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []);
43741
43797
  this.categories = input([], ...ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []);
43742
43798
  this.categoryPlaceholder = input("Select category...", ...ngDevMode ? [{ debugName: "categoryPlaceholder" }] : /* istanbul ignore next */ []);
43743
43799
  this.assignmentOptions = input([], ...ngDevMode ? [{ debugName: "assignmentOptions" }] : /* istanbul ignore next */ []);
43744
43800
  this.featuredAssignmentKey = input(null, ...ngDevMode ? [{ debugName: "featuredAssignmentKey" }] : /* istanbul ignore next */ []);
43745
- this.assignmentsDescription = input("Assign this template to automated email triggers. When triggered, the system will send this template.", ...ngDevMode ? [{ debugName: "assignmentsDescription" }] : /* istanbul ignore next */ []);
43746
- this.textEnabled = input(false, ...ngDevMode ? [{ debugName: "textEnabled" }] : /* istanbul ignore next */ []);
43801
+ this.assignmentsDescription = input("Assign this template to at least one automated email trigger. When triggered, the system will send this template.", ...ngDevMode ? [{ debugName: "assignmentsDescription" }] : /* istanbul ignore next */ []);
43747
43802
  this.variableGroups = input(DEFAULT_EMAIL_TEMPLATE_VARIABLE_GROUPS, ...ngDevMode ? [{ debugName: "variableGroups" }] : /* istanbul ignore next */ []);
43748
43803
  this.blockGroups = input(DEFAULT_EMAIL_TEMPLATE_BLOCK_GROUPS, ...ngDevMode ? [{ debugName: "blockGroups" }] : /* istanbul ignore next */ []);
43804
+ this.heading = input("", ...ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []);
43749
43805
  this.namePlaceholder = input("e.g. Follow-Up — Friendly", ...ngDevMode ? [{ debugName: "namePlaceholder" }] : /* istanbul ignore next */ []);
43750
43806
  this.subjectPlaceholder = input("e.g. Following up on {{property_address}}", ...ngDevMode ? [{ debugName: "subjectPlaceholder" }] : /* istanbul ignore next */ []);
43751
43807
  this.systemNote = input("This is a built-in system template, so it can be viewed but not changed.", ...ngDevMode ? [{ debugName: "systemNote" }] : /* istanbul ignore next */ []);
@@ -43780,11 +43836,10 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43780
43836
  this.activeTo = signal("", ...ngDevMode ? [{ debugName: "activeTo" }] : /* istanbul ignore next */ []);
43781
43837
  this.videoId = signal(null, ...ngDevMode ? [{ debugName: "videoId" }] : /* istanbul ignore next */ []);
43782
43838
  this.videoTitle = signal(null, ...ngDevMode ? [{ debugName: "videoTitle" }] : /* istanbul ignore next */ []);
43783
- this.assignmentChannels = signal({}, ...ngDevMode ? [{ debugName: "assignmentChannels" }] : /* istanbul ignore next */ []);
43839
+ this.assignedKeys = signal([], ...ngDevMode ? [{ debugName: "assignedKeys" }] : /* istanbul ignore next */ []);
43784
43840
  this.assignmentState = computed(() => this.assignmentOptions().map((o) => ({
43785
43841
  ...o,
43786
- email: !!this.assignmentChannels()[o.key]?.email,
43787
- text: !!this.assignmentChannels()[o.key]?.text
43842
+ assigned: this.assignedKeys().includes(o.key)
43788
43843
  })), ...ngDevMode ? [{ debugName: "assignmentState" }] : /* istanbul ignore next */ []);
43789
43844
  this.blocks = signal([], ...ngDevMode ? [{ debugName: "blocks" }] : /* istanbul ignore next */ []);
43790
43845
  this.selectedBlockId = signal(null, ...ngDevMode ? [{ debugName: "selectedBlockId" }] : /* istanbul ignore next */ []);
@@ -43816,10 +43871,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43816
43871
  this.imageAlt = signal("", ...ngDevMode ? [{ debugName: "imageAlt" }] : /* istanbul ignore next */ []);
43817
43872
  this.showTestSendDialog = signal(false, ...ngDevMode ? [{ debugName: "showTestSendDialog" }] : /* istanbul ignore next */ []);
43818
43873
  this.testSendEmail = signal("", ...ngDevMode ? [{ debugName: "testSendEmail" }] : /* istanbul ignore next */ []);
43819
- this.showAssignmentConfig = signal(false, ...ngDevMode ? [{ debugName: "showAssignmentConfig" }] : /* istanbul ignore next */ []);
43820
- this.configTarget = signal(null, ...ngDevMode ? [{ debugName: "configTarget" }] : /* istanbul ignore next */ []);
43821
- this.configEmail = signal(false, ...ngDevMode ? [{ debugName: "configEmail" }] : /* istanbul ignore next */ []);
43822
- this.configText = signal(false, ...ngDevMode ? [{ debugName: "configText" }] : /* istanbul ignore next */ []);
43823
43874
  this.activeEditorTab = signal("edit", ...ngDevMode ? [{ debugName: "activeEditorTab" }] : /* istanbul ignore next */ []);
43824
43875
  this.activeRightTab = signal("blocks", ...ngDevMode ? [{ debugName: "activeRightTab" }] : /* istanbul ignore next */ []);
43825
43876
  this.blockSearch = signal("", ...ngDevMode ? [{ debugName: "blockSearch" }] : /* istanbul ignore next */ []);
@@ -43880,8 +43931,20 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43880
43931
  this.nameErrorShown = computed(() => this.nameTouched() || this.submitAttempted() ? this.nameError() : "", ...ngDevMode ? [{ debugName: "nameErrorShown" }] : /* istanbul ignore next */ []);
43881
43932
  this.subjectErrorShown = computed(() => this.subjectTouched() || this.submitAttempted() ? this.subjectError() : "", ...ngDevMode ? [{ debugName: "subjectErrorShown" }] : /* istanbul ignore next */ []);
43882
43933
  this.bodyErrorShown = computed(() => this.bodyEdited() || this.submitAttempted() ? this.bodyError() : "", ...ngDevMode ? [{ debugName: "bodyErrorShown" }] : /* istanbul ignore next */ []);
43883
- this.canSave = computed(() => !this.nameError() && !this.subjectError() && !this.bodyError() && !this.datesError(), ...ngDevMode ? [{ debugName: "canSave" }] : /* istanbul ignore next */ []);
43884
- this.saveDisabled = computed(() => !this.canWrite(), ...ngDevMode ? [{ debugName: "saveDisabled" }] : /* istanbul ignore next */ []);
43934
+ this.assignmentError = computed(() => this.assignmentOptions().length > 0 && !this.assignmentState().some((a) => a.assigned) ? "Assign this template to at least one automation." : "", ...ngDevMode ? [{ debugName: "assignmentError" }] : /* istanbul ignore next */ []);
43935
+ this.assignmentsTouched = signal(false, ...ngDevMode ? [{ debugName: "assignmentsTouched" }] : /* istanbul ignore next */ []);
43936
+ this.assignmentErrorShown = computed(() => this.assignmentsTouched() || this.submitAttempted() ? this.assignmentError() : "", ...ngDevMode ? [{ debugName: "assignmentErrorShown" }] : /* istanbul ignore next */ []);
43937
+ this.canSave = computed(() => !this.nameError() && !this.subjectError() && !this.bodyError() && !this.datesError() && !this.assignmentError(), ...ngDevMode ? [{ debugName: "canSave" }] : /* istanbul ignore next */ []);
43938
+ this.saveDisabled = computed(() => !this.canWrite() || !this.canSave(), ...ngDevMode ? [{ debugName: "saveDisabled" }] : /* istanbul ignore next */ []);
43939
+ this.saveHint = computed(() => {
43940
+ if (!this.canWrite() || this.canSave()) return "";
43941
+ const missing = [];
43942
+ if (this.nameError()) missing.push(this.name().trim() ? "a shorter name" : "a name");
43943
+ if (this.subjectError()) missing.push(this.subject().trim() ? "a shorter subject" : "a subject");
43944
+ if (this.bodyError()) missing.push(this.bodyHasContent() ? "a shorter message" : "a message");
43945
+ if (this.assignmentError()) missing.push("at least one assignment");
43946
+ return missing.length ? `Add ${missing.join(", ")} to save this template.` : this.datesError() || "Fix the highlighted fields to save this template.";
43947
+ }, ...ngDevMode ? [{ debugName: "saveHint" }] : /* istanbul ignore next */ []);
43885
43948
  this.normalizedLink = computed(() => {
43886
43949
  const url = this.linkUrl().trim();
43887
43950
  if (!url) return "";
@@ -43935,7 +43998,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43935
43998
  const block = current.find((b) => b.id === blockId);
43936
43999
  if (block !== void 0) {
43937
44000
  el.innerHTML = block.html;
43938
- if (block.spacing) el.style.padding = `${block.spacing} 0`;
44001
+ setEditorSpacing(el, block.spacing);
43939
44002
  this.initializedBlockIds.add(blockId);
43940
44003
  }
43941
44004
  }
@@ -43965,17 +44028,15 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43965
44028
  id: this.genId(),
43966
44029
  html: `<p>${EMAIL_TEMPLATE_START_TEXT}</p>`
43967
44030
  }] : this.htmlToBlocks(t.body ?? ""));
43968
- this.selectedBlockId.set(null);
43969
- this.blockSpacing.set("");
44031
+ this.selectedBlockId.set(this.blocks()[0]?.id ?? null);
44032
+ this.blockSpacing.set(this.blocks()[0]?.spacing ?? "");
43970
44033
  this.loadedBody.set(t?.id ? t.body ?? "" : null);
43971
44034
  this.bodyEdited.set(false);
43972
44035
  this.submitAttempted.set(false);
43973
44036
  this.nameTouched.set(false);
43974
44037
  this.subjectTouched.set(false);
43975
- this.assignmentChannels.set(Object.fromEntries((t?.assignments ?? []).map((c) => [c.key, {
43976
- email: !!c.email,
43977
- text: !!c.text
43978
- }])));
44038
+ this.assignedKeys.set([...t?.assignments ?? []]);
44039
+ this.assignmentsTouched.set(false);
43979
44040
  this.savedSnapshot.set(t?.id ? this.snapshot() : null);
43980
44041
  }
43981
44042
  onSave() {
@@ -43995,11 +44056,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
43995
44056
  activeFrom: !this.useAllYear() && this.activeFrom() ? this.activeFrom() : null,
43996
44057
  activeTo: !this.useAllYear() && this.activeTo() ? this.activeTo() : null,
43997
44058
  videoId: this.videoId(),
43998
- assignments: this.assignmentState().filter((a) => a.email || a.text).map((a) => ({
43999
- key: a.key,
44000
- email: a.email,
44001
- text: a.text
44002
- }))
44059
+ assignments: this.assignmentState().filter((a) => a.assigned).map((a) => a.key)
44003
44060
  });
44004
44061
  }
44005
44062
  snapshot() {
@@ -44323,7 +44380,7 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44323
44380
  const id = this.selectedBlockId();
44324
44381
  if (!id) return;
44325
44382
  const ref = this.editorFor(id);
44326
- if (ref) ref.nativeElement.style.padding = value ? `${value} 0` : "";
44383
+ if (ref) setEditorSpacing(ref.nativeElement, value);
44327
44384
  const block = this.blocks().find((b) => b.id === id);
44328
44385
  if (!block) return;
44329
44386
  const changed = (block.spacing ?? "") !== (value ?? "");
@@ -44422,27 +44479,10 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44422
44479
  categoryLabel(cat) {
44423
44480
  return formatCategoryLabel(cat);
44424
44481
  }
44425
- openAssignmentConfig(item) {
44482
+ toggleAssignment(item) {
44426
44483
  if (!this.canWrite()) return;
44427
- this.configTarget.set(item);
44428
- this.configEmail.set(item.email);
44429
- this.configText.set(item.text);
44430
- this.showAssignmentConfig.set(true);
44431
- }
44432
- saveAssignmentConfig() {
44433
- const target = this.configTarget();
44434
- if (!this.canWrite() || !target) return;
44435
- const email = this.configEmail();
44436
- const text = this.configText();
44437
- this.assignmentChannels.update((m) => ({
44438
- ...m,
44439
- [target.key]: {
44440
- email,
44441
- text
44442
- }
44443
- }));
44444
- this.showAssignmentConfig.set(false);
44445
- this.toast.show(`${target.name} automation configured`);
44484
+ this.assignedKeys.update((keys) => keys.includes(item.key) ? keys.filter((k) => k !== item.key) : [...keys, item.key]);
44485
+ this.assignmentsTouched.set(true);
44446
44486
  }
44447
44487
  isOpen(id) {
44448
44488
  return id === "v:" + (this.variableGroups()[0]?.name ?? "") !== this.toggledGroups().has(id);
@@ -44533,13 +44573,6 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44533
44573
  isRequired: false,
44534
44574
  transformFunction: null
44535
44575
  },
44536
- textEnabled: {
44537
- classPropertyName: "textEnabled",
44538
- publicName: "textEnabled",
44539
- isSignal: true,
44540
- isRequired: false,
44541
- transformFunction: null
44542
- },
44543
44576
  variableGroups: {
44544
44577
  classPropertyName: "variableGroups",
44545
44578
  publicName: "variableGroups",
@@ -44554,6 +44587,13 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44554
44587
  isRequired: false,
44555
44588
  transformFunction: null
44556
44589
  },
44590
+ heading: {
44591
+ classPropertyName: "heading",
44592
+ publicName: "heading",
44593
+ isSignal: true,
44594
+ isRequired: false,
44595
+ transformFunction: null
44596
+ },
44557
44597
  namePlaceholder: {
44558
44598
  classPropertyName: "namePlaceholder",
44559
44599
  publicName: "namePlaceholder",
@@ -44704,16 +44744,23 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44704
44744
  <div class="editor-page">
44705
44745
  <!-- Actions (outside the white panels) -->
44706
44746
  <div class="editor-actions">
44747
+ @if (heading()) {
44748
+ <h1 class="editor-heading" data-testid="editor-heading">{{ heading() }}</h1>
44749
+ }
44750
+ <div class="editor-actions-buttons">
44707
44751
  @if (canWrite() && testSendEnabled()) {
44708
44752
  <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
44709
44753
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
44710
44754
  Test Send
44711
44755
  </ui-button>
44712
44756
  }
44757
+ <span class="save-wrap" [uiTooltip]="saveHint()">
44713
44758
  <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
44714
44759
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
44715
44760
  Save Template
44716
44761
  </ui-button>
44762
+ </span>
44763
+ </div>
44717
44764
  </div>
44718
44765
  <ui-divider />
44719
44766
 
@@ -44761,28 +44808,26 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
44761
44808
  <!-- Assignments -->
44762
44809
  @if (assignmentOptions().length > 0) {
44763
44810
  <div class="assignments-section">
44764
- <h4 class="section-title">Assignments</h4>
44811
+ <h4 class="section-title">Assignments <span class="required" aria-hidden="true">*</span></h4>
44765
44812
  <p class="section-desc">{{ assignmentsDescription() }}</p>
44813
+ <ui-error [errorId]="idPrefix() + '-assignments-error'" [message]="assignmentErrorShown()" />
44766
44814
  <ui-search-input placeholder="Search..." ariaLabel="Search assignments" [(value)]="assignmentSearch" />
44767
44815
  @if (filteredAssignments().length === 0) {
44768
44816
  <ui-empty-state iconType="search" title="No assignments found" message="No assignments match your search." />
44769
44817
  }
44770
44818
  <div class="assignment-list" [hidden]="filteredAssignments().length === 0">
44771
44819
  @for (item of filteredAssignments(); track item.key) {
44772
- <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'button' : null" [attr.tabindex]="canWrite() ? 0 : null"
44773
- [attr.aria-label]="canWrite() ? 'Configure ' + item.name : null"
44774
- (click)="openAssignmentConfig(item)" (keydown.enter)="openAssignmentConfig(item); $event.preventDefault()" (keydown.space)="openAssignmentConfig(item); $event.preventDefault()">
44820
+ <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'switch' : null" [attr.tabindex]="canWrite() ? 0 : null"
44821
+ [attr.aria-checked]="canWrite() ? item.assigned : null" [attr.aria-label]="canWrite() ? item.name : null"
44822
+ (click)="toggleAssignment(item)" (keydown.enter)="toggleAssignment(item); $event.preventDefault()" (keydown.space)="toggleAssignment(item); $event.preventDefault()">
44775
44823
  <div class="assignment-text">
44776
44824
  <strong>{{ item.name }}</strong>
44777
44825
  <span>{{ item.description }}</span>
44778
44826
  </div>
44779
44827
  <div class="assignment-channels">
44780
- <span class="channel-badge" [class.active]="item.email" role="img" [attr.aria-label]="'Email ' + (item.email ? 'on' : 'off')">
44828
+ <span class="channel-badge" [class.active]="item.assigned" role="img" [attr.aria-label]="'Email ' + (item.assigned ? 'on' : 'off')">
44781
44829
  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
44782
44830
  </span>
44783
- <span class="channel-badge" [class.active]="item.text" [class.disabled]="!textEnabled()" role="img" [attr.aria-label]="'Text ' + (item.text ? 'on' : 'off')">
44784
- <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
44785
- </span>
44786
44831
  </div>
44787
44832
  </div>
44788
44833
  }
@@ -45064,8 +45109,10 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
45064
45109
  @for (v of group.variables; track v.key) {
45065
45110
  <button type="button" class="variable-item" (mousedown)="saveSelection()" (click)="insertVariable(v)">
45066
45111
  <span class="var-tag">{{ '{{' + v.key + '}}' }}</span>
45067
- <span class="var-label">{{ v.label }}</span>
45068
- <span class="var-example">{{ v.example }}</span>
45112
+ <span class="var-meta">
45113
+ <span class="var-label">{{ v.label }}</span>
45114
+ <span class="var-example">{{ v.example }}</span>
45115
+ </span>
45069
45116
  </button>
45070
45117
  }
45071
45118
  </div>
@@ -45157,31 +45204,9 @@ var EmailTemplateEditorComponent = class EmailTemplateEditorComponent {
45157
45204
  </ui-side-panel>
45158
45205
 
45159
45206
 
45160
- <!-- Assignment config -->
45161
- <ui-side-panel [wide]="true" [open]="showAssignmentConfig()" [title]="configTarget()?.name || 'Configure Automation'" primaryLabel="Save Configuration"
45162
- [primaryDisabled]="!configEmail() && !configText()" (closed)="showAssignmentConfig.set(false)" (primaryClick)="saveAssignmentConfig()">
45163
- @if (configTarget(); as target) {
45164
- <p class="config-desc">{{ target.description }}</p>
45165
- <hr class="config-divider" />
45166
- <div class="config-section">
45167
- <span class="config-section-label">EMAIL TEMPLATE</span>
45168
- <div class="config-field">
45169
- <span class="config-label">Assigned Template</span>
45170
- <div class="config-readonly">{{ name() || 'Current template' }}</div>
45171
- <span class="config-hint">This template will be used when this automation is triggered.</span>
45172
- </div>
45173
- </div>
45174
- <hr class="config-divider" />
45175
- <div class="config-section">
45176
- <span class="config-section-label">CHANNELS <span class="required" aria-hidden="true">*</span></span>
45177
- <ui-checkbox label="Email" [(checked)]="configEmail" />
45178
- <ui-checkbox label="Text (SMS)" [(checked)]="configText" [disabled]="!textEnabled()" [hint]="textEnabled() ? '' : '(not enabled)'" />
45179
- </div>
45180
- }
45181
- </ui-side-panel>
45182
45207
  `,
45183
45208
  isInline: true,
45184
- styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;flex:1;min-height:0;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:flex-end;align-items:center;gap:8px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;grid-template-rows:minmax(0,1fr);flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){:host{flex:none}.editor-page{flex:none;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;flex:none;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"],
45209
+ styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;flex:1;min-height:0;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:space-between;align-items:center;gap:8px 16px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.editor-heading{margin:0;font-size:1.25rem;font-weight:700;color:#1e293b;line-height:1.3;min-width:0}.save-wrap{display:inline-flex}.editor-actions-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;margin-left:auto}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;grid-template-rows:minmax(0,1fr);flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1 1 0;min-height:0;padding:16px 20px 24px;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{flex-shrink:0;position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{flex-shrink:0;height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-height:44px;padding:8px 12px 8px 28px;min-width:0;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{max-width:100%;overflow-wrap:anywhere;font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-meta{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;min-width:0;max-width:100%}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){:host{flex:none}.editor-page{flex:none;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;flex:none;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"],
45185
45210
  dependencies: [
45186
45211
  {
45187
45212
  kind: "ngmodule",
@@ -45501,16 +45526,23 @@ i0.ɵɵngDeclareClassMetadata({
45501
45526
  <div class="editor-page">
45502
45527
  <!-- Actions (outside the white panels) -->
45503
45528
  <div class="editor-actions">
45529
+ @if (heading()) {
45530
+ <h1 class="editor-heading" data-testid="editor-heading">{{ heading() }}</h1>
45531
+ }
45532
+ <div class="editor-actions-buttons">
45504
45533
  @if (canWrite() && testSendEnabled()) {
45505
45534
  <ui-button variant="secondary" size="sm" (click)="openTestSendDialog()">
45506
45535
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
45507
45536
  Test Send
45508
45537
  </ui-button>
45509
45538
  }
45539
+ <span class="save-wrap" [uiTooltip]="saveHint()">
45510
45540
  <ui-button variant="primary" size="sm" [loading]="saving()" [disabled]="saveDisabled()" (click)="onSave()">
45511
45541
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
45512
45542
  Save Template
45513
45543
  </ui-button>
45544
+ </span>
45545
+ </div>
45514
45546
  </div>
45515
45547
  <ui-divider />
45516
45548
 
@@ -45558,28 +45590,26 @@ i0.ɵɵngDeclareClassMetadata({
45558
45590
  <!-- Assignments -->
45559
45591
  @if (assignmentOptions().length > 0) {
45560
45592
  <div class="assignments-section">
45561
- <h4 class="section-title">Assignments</h4>
45593
+ <h4 class="section-title">Assignments <span class="required" aria-hidden="true">*</span></h4>
45562
45594
  <p class="section-desc">{{ assignmentsDescription() }}</p>
45595
+ <ui-error [errorId]="idPrefix() + '-assignments-error'" [message]="assignmentErrorShown()" />
45563
45596
  <ui-search-input placeholder="Search..." ariaLabel="Search assignments" [(value)]="assignmentSearch" />
45564
45597
  @if (filteredAssignments().length === 0) {
45565
45598
  <ui-empty-state iconType="search" title="No assignments found" message="No assignments match your search." />
45566
45599
  }
45567
45600
  <div class="assignment-list" [hidden]="filteredAssignments().length === 0">
45568
45601
  @for (item of filteredAssignments(); track item.key) {
45569
- <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'button' : null" [attr.tabindex]="canWrite() ? 0 : null"
45570
- [attr.aria-label]="canWrite() ? 'Configure ' + item.name : null"
45571
- (click)="openAssignmentConfig(item)" (keydown.enter)="openAssignmentConfig(item); $event.preventDefault()" (keydown.space)="openAssignmentConfig(item); $event.preventDefault()">
45602
+ <div class="assignment-item" [class.assignment-readonly]="!canWrite()" [attr.role]="canWrite() ? 'switch' : null" [attr.tabindex]="canWrite() ? 0 : null"
45603
+ [attr.aria-checked]="canWrite() ? item.assigned : null" [attr.aria-label]="canWrite() ? item.name : null"
45604
+ (click)="toggleAssignment(item)" (keydown.enter)="toggleAssignment(item); $event.preventDefault()" (keydown.space)="toggleAssignment(item); $event.preventDefault()">
45572
45605
  <div class="assignment-text">
45573
45606
  <strong>{{ item.name }}</strong>
45574
45607
  <span>{{ item.description }}</span>
45575
45608
  </div>
45576
45609
  <div class="assignment-channels">
45577
- <span class="channel-badge" [class.active]="item.email" role="img" [attr.aria-label]="'Email ' + (item.email ? 'on' : 'off')">
45610
+ <span class="channel-badge" [class.active]="item.assigned" role="img" [attr.aria-label]="'Email ' + (item.assigned ? 'on' : 'off')">
45578
45611
  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
45579
45612
  </span>
45580
- <span class="channel-badge" [class.active]="item.text" [class.disabled]="!textEnabled()" role="img" [attr.aria-label]="'Text ' + (item.text ? 'on' : 'off')">
45581
- <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
45582
- </span>
45583
45613
  </div>
45584
45614
  </div>
45585
45615
  }
@@ -45861,8 +45891,10 @@ i0.ɵɵngDeclareClassMetadata({
45861
45891
  @for (v of group.variables; track v.key) {
45862
45892
  <button type="button" class="variable-item" (mousedown)="saveSelection()" (click)="insertVariable(v)">
45863
45893
  <span class="var-tag">{{ '{{' + v.key + '}}' }}</span>
45864
- <span class="var-label">{{ v.label }}</span>
45865
- <span class="var-example">{{ v.example }}</span>
45894
+ <span class="var-meta">
45895
+ <span class="var-label">{{ v.label }}</span>
45896
+ <span class="var-example">{{ v.example }}</span>
45897
+ </span>
45866
45898
  </button>
45867
45899
  }
45868
45900
  </div>
@@ -45954,30 +45986,8 @@ i0.ɵɵngDeclareClassMetadata({
45954
45986
  </ui-side-panel>
45955
45987
 
45956
45988
 
45957
- <!-- Assignment config -->
45958
- <ui-side-panel [wide]="true" [open]="showAssignmentConfig()" [title]="configTarget()?.name || 'Configure Automation'" primaryLabel="Save Configuration"
45959
- [primaryDisabled]="!configEmail() && !configText()" (closed)="showAssignmentConfig.set(false)" (primaryClick)="saveAssignmentConfig()">
45960
- @if (configTarget(); as target) {
45961
- <p class="config-desc">{{ target.description }}</p>
45962
- <hr class="config-divider" />
45963
- <div class="config-section">
45964
- <span class="config-section-label">EMAIL TEMPLATE</span>
45965
- <div class="config-field">
45966
- <span class="config-label">Assigned Template</span>
45967
- <div class="config-readonly">{{ name() || 'Current template' }}</div>
45968
- <span class="config-hint">This template will be used when this automation is triggered.</span>
45969
- </div>
45970
- </div>
45971
- <hr class="config-divider" />
45972
- <div class="config-section">
45973
- <span class="config-section-label">CHANNELS <span class="required" aria-hidden="true">*</span></span>
45974
- <ui-checkbox label="Email" [(checked)]="configEmail" />
45975
- <ui-checkbox label="Text (SMS)" [(checked)]="configText" [disabled]="!textEnabled()" [hint]="textEnabled() ? '' : '(not enabled)'" />
45976
- </div>
45977
- }
45978
- </ui-side-panel>
45979
45989
  `,
45980
- styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;flex:1;min-height:0;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:flex-end;align-items:center;gap:8px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;grid-template-rows:minmax(0,1fr);flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1;padding:16px 20px 24px;overflow-y:auto;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;min-height:44px;padding:8px 12px 8px 28px;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){:host{flex:none}.editor-page{flex:none;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;flex:none;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"]
45990
+ styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0}.required{color:#ef4444;font-weight:400}.editor-page{display:flex;flex-direction:column;flex:1;min-height:0;background:#f8fafc;overflow:hidden}.editor-actions{display:flex;justify-content:space-between;align-items:center;gap:8px 16px;flex-wrap:wrap;padding:0 0 12px;flex-shrink:0}.editor-heading{margin:0;font-size:1.25rem;font-weight:700;color:#1e293b;line-height:1.3;min-width:0}.save-wrap{display:inline-flex}.editor-actions-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;margin-left:auto}.readonly-note{margin:0;padding:8px 16px;font-size:.8125rem;color:#92400e;background:#fffbeb;border-bottom:1px solid #fde68a}.readonly-note.system-note{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.editor-body{display:grid;grid-template-columns:340px minmax(0,1fr) 300px;grid-template-rows:minmax(0,1fr);flex:1;min-height:0;overflow:hidden}.panel-left{background:#fff;border-right:1px solid #e2e8f0;padding:24px;overflow-y:auto}.panel-title{font-size:1.0625rem;font-weight:700;color:#1e293b;margin:0 0 20px}.form-field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.form-row-dates{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px}.assignments-section{border-top:1px solid #e2e8f0;padding-top:20px;margin-top:16px}.section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 6px}.section-desc{font-size:.8125rem;color:#64748b;line-height:1.5;margin:0 0 12px}.assignment-list{max-height:340px;overflow-y:auto;margin-top:12px;border:1px solid #e2e8f0;border-radius:8px}.assignment-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid #f1f5f9;transition:background .1s}.assignment-item:last-child{border-bottom:none}.assignment-item:hover{background:#f8fafc}.assignment-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.assignment-item.assignment-readonly{cursor:default}.assignment-item.assignment-readonly:hover{background:transparent}.assignment-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.assignment-text strong{font-size:.8125rem;color:#1e293b}.assignment-text span{font-size:.75rem;color:#64748b}.assignment-channels{display:flex;gap:4px;flex-shrink:0}.channel-badge{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:4px;background:#f1f5f9;color:#94a3b8;transition:all .15s}.channel-badge.active{background:#3b82f6;color:#fff}.channel-badge.disabled{opacity:.4;cursor:not-allowed}.config-desc{font-size:.875rem;color:#64748b;line-height:1.5;margin:0}.config-divider{border:none;border-top:1px solid #e2e8f0;margin:20px 0}.config-section{display:flex;flex-direction:column;gap:12px}.config-section-label{font-size:.6875rem;font-weight:700;color:#3b82f6;text-transform:uppercase;letter-spacing:.04em}.config-field{display:flex;flex-direction:column;gap:6px}.config-field-mt{margin-top:16px}.config-label{font-size:.8125rem;font-weight:600;color:#1e293b}.config-readonly{padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;font-size:.875rem;color:#1e293b}.config-hint{font-size:.75rem;color:#64748b}.test-save-note{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fef3c7;border:1px solid #fcd34d;border-radius:8px;font-size:.8125rem;color:#92400e;margin-top:12px}.test-save-note svg{flex-shrink:0}.panel-center{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden}.editor-tabs{display:flex;gap:2px;padding:12px 20px 0;background:#fff;border-bottom:1px solid #e2e8f0;overflow-x:auto;-webkit-overflow-scrolling:touch}.editor-tab{display:flex;align-items:center;gap:6px;padding:10px 16px;border:1px solid #e2e8f0;border-bottom:none;border-radius:8px 8px 0 0;background:#f8fafc;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;white-space:nowrap}.editor-tab:hover{background:#fff;color:#1e293b}.editor-tab.active{background:#eff6ff;color:#3b82f6;border-color:#93c5fd}.editor-tab:focus-visible,.right-tab:focus-visible,.block-group-header:focus-visible,.variable-item:focus-visible,.add-block-btn:focus-visible,.block-item:focus-visible,.video-lib-item:focus-visible{outline:2px solid #3b82f6;outline-offset:-2px}.editor-toolbar{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border-bottom:1px solid #e2e8f0;flex-wrap:wrap}.toolbar-row-2{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 20px;background:#fff;border-bottom:1px solid #e2e8f0}.toolbar-group{display:flex;align-items:center;gap:2px;padding-right:8px;border-right:1px solid #e2e8f0}.toolbar-group:last-child{border-right:none;padding-right:0}.toolbar-select{display:block;min-width:96px}.toolbar-label{font-size:.75rem;font-weight:600;color:#64748b;white-space:nowrap;margin-right:6px}.hidden-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none;border:none;padding:0}.color-indicator{display:flex;flex-direction:column;align-items:center;gap:2px;color:#475569}.color-bar{display:block;width:16px;height:3px;border-radius:2px;border:1px solid rgba(0,0,0,.1)}.link-dialog{background:#fff;border-bottom:1px solid #e2e8f0;padding:12px 20px}.link-dialog-inner{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.link-dialog-title{font-size:.8125rem;font-weight:700;color:#1e293b;white-space:nowrap;padding-top:10px}.link-dialog-input{display:block;width:240px;max-width:100%}.link-dialog-actions{display:flex;gap:6px}.preview-frame{flex:1;display:flex;justify-content:center;padding:24px;overflow-y:auto;background:#f1f5f9}.preview-frame.mobile{align-items:flex-start}.preview-content{max-width:600px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:32px;min-height:400px;font-size:.9375rem;line-height:1.6;color:#1e293b;overflow-wrap:anywhere}.preview-content p{margin:0 0 8px}.mobile-shell{width:375px;max-width:100%;box-sizing:border-box;min-height:600px;border:2px solid #1e293b;border-radius:24px;padding:40px 12px 24px;background:#fff;box-shadow:0 8px 32px #0000001f}.mobile-shell .preview-content{border:none;border-radius:0;padding:16px;max-width:100%}.blocks-canvas{flex:1 1 0;min-height:0;padding:16px 20px 24px;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;background:#f1f5f9;display:flex;flex-direction:column}.block-wrapper{flex-shrink:0;position:relative;display:flex;align-items:flex-start;background:#fff;border:2px solid transparent;border-radius:8px;transition:border-color .15s,box-shadow .15s}.block-wrapper:hover,.block-wrapper.selected,.block-wrapper:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.block-wrapper:hover .block-drag-handle,.block-wrapper.selected .block-drag-handle,.block-wrapper:focus-within .block-drag-handle{opacity:1}.block-wrapper:hover .block-controls,.block-wrapper.selected .block-controls,.block-wrapper:focus-within .block-controls{opacity:1;pointer-events:all}.block-wrapper.dragging{opacity:.4}.block-drag-handle{flex-shrink:0;width:28px;display:flex;align-items:flex-start;justify-content:center;padding-top:14px;opacity:0;transition:opacity .15s;cursor:grab;color:#94a3b8}.block-drag-handle:active{cursor:grabbing}.block-content{flex:1;min-width:0;padding:12px 16px;outline:none;font-size:.9375rem;color:#1e293b;line-height:1.6;min-height:48px;overflow-wrap:anywhere}.block-content:empty:before{content:\"Click to edit...\";color:#94a3b8;font-style:italic;pointer-events:none}.block-content p{margin:0 0 8px}.block-content p:last-child{margin:0}.block-content h1,.block-content h2,.block-content h3{margin:8px 0 6px;color:#1e293b}.block-content a{color:#3b82f6}.block-content img{max-width:100%;border-radius:6px}.block-content ul,.block-content ol{padding-left:20px;margin:0 0 8px}.block-controls{position:absolute;top:6px;right:6px;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity .15s;background:#fff;border:1px solid #e2e8f0;border-radius:6px;padding:3px;box-shadow:0 2px 6px #00000014}@media(hover:none){.block-wrapper.selected .block-controls{opacity:1;pointer-events:all}}.drop-zone{flex-shrink:0;height:8px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:height .15s,background .15s;position:relative}.drop-zone-label{font-size:.75rem;font-weight:600;color:#3b82f6;opacity:0;transition:opacity .1s}.drop-zone.active{height:40px;background:#3b82f614;border:2px dashed #3b82f6}.drop-zone.active .drop-zone-label{opacity:1}.add-block-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;padding:12px;margin-top:8px;border:2px dashed #e2e8f0;border-radius:8px;background:none;font-size:.875rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:border-color .15s,color .15s,background .15s}.add-block-btn:hover{border-color:#3b82f6;color:#3b82f6;background:#3b82f60a}.panel-right{background:#fff;border-left:1px solid #e2e8f0;display:flex;flex-direction:column;min-height:0;min-width:0}.right-tabs{display:flex;border-bottom:1px solid #e2e8f0}.right-tab{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:12px;min-height:44px;border:none;background:none;font-size:.8125rem;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;border-bottom:2px solid transparent}.right-tab:hover{color:#1e293b}.right-tab.active{color:#3b82f6;background:#eff6ff;border-bottom-color:#3b82f6}.right-panel-body{flex:1;padding:20px;overflow-y:auto}.right-section-title{font-size:.9375rem;font-weight:700;color:#1e293b;margin:0 0 12px}.right-section-desc{font-size:.8125rem;color:#64748b;margin:0 0 16px;line-height:1.5}.right-section-hint{font-size:.8125rem;color:#64748b;margin:0 0 12px;line-height:1.5}.block-group{border-bottom:1px solid #f1f5f9}.block-group-header{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:12px 0;border:none;background:none;font-size:.875rem;font-weight:600;color:#1e293b;cursor:pointer;font-family:inherit;text-align:left}.block-group-header .chevron{transition:transform .2s;color:#94a3b8}.block-group-header .chevron.expanded{transform:rotate(90deg)}.block-group-header span:nth-of-type(1){flex:1}.block-count{font-size:.75rem;font-weight:600;color:#64748b;background:#f1f5f9;padding:2px 8px;border-radius:10px;margin-left:auto}.block-list,.variable-list{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.block-item{display:flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;min-height:44px;padding:8px 12px 8px 28px;font-size:.8125rem;color:#64748b;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit;-webkit-user-select:none;user-select:none}.block-item:hover{background:#f8fafc;color:#1e293b}.block-item-drag{color:#cbd5e1;flex-shrink:0;cursor:grab}.variable-item{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-height:44px;padding:8px 12px 8px 28px;min-width:0;border:none;background:none;cursor:pointer;text-align:left;border-radius:4px;font-family:inherit}.variable-item:hover{background:#f8fafc}.var-tag{max-width:100%;overflow-wrap:anywhere;font-size:.75rem;font-weight:600;color:#3b82f6;background:#3b82f614;padding:2px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.var-meta{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;min-width:0;max-width:100%}.var-label{font-size:.8125rem;color:#1e293b}.var-example{font-size:.75rem;color:#64748b;overflow-wrap:anywhere}.video-library-panel{padding:0}.video-library-panel .right-section-title,.video-library-panel .right-section-hint{padding:0 16px}.video-library-panel .right-section-title{padding-top:16px}.video-config-section{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-bottom:1px solid #f1f5f9}.video-config-section:last-of-type{border-bottom:none}.video-lib-list{display:flex;flex-direction:column;gap:2px;padding:8px 8px 16px}.video-lib-item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:8px;border:1px solid transparent;border-radius:8px;background:none;cursor:pointer;text-align:left;font-family:inherit;transition:background .15s,border-color .15s}.video-lib-item:hover{background:#f8fafc;border-color:#e2e8f0}.video-lib-item.selected{background:#eff6ff;border-color:#93c5fd}.vli-thumb{position:relative;flex-shrink:0;width:56px;height:40px;border-radius:6px;background:linear-gradient(135deg,#f1f5f9,#e2e8f0);display:flex;align-items:center;justify-content:center}.vli-dur{position:absolute;bottom:2px;right:3px;font-size:.625rem;font-weight:600;color:#fff;background:#000000a6;padding:1px 4px;border-radius:3px}.vli-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.vli-title{font-size:.8125rem;font-weight:600;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vli-cat{font-size:.75rem;color:#64748b}.vli-check{flex-shrink:0}.video-lib-loading{padding:8px}.video-lib-skeleton{display:flex;align-items:center;gap:10px;padding:8px;margin-bottom:4px}.vls-info{flex:1;display:flex;flex-direction:column;gap:6px}@media(max-width:1200px){.editor-body{grid-template-columns:280px minmax(0,1fr) 260px}}@media(max-width:900px){:host{flex:none}.editor-page{flex:none;min-height:100vh;min-height:100dvh;overflow:visible}.editor-body{display:flex;flex-direction:column;flex:none;overflow:visible}.panel-left{border-right:none;border-bottom:1px solid #e2e8f0;overflow:visible;padding:16px}.panel-center{overflow:visible;min-height:480px}.blocks-canvas{overflow:visible;min-height:320px}.panel-right{border-left:none;border-top:1px solid #e2e8f0}.right-panel-body{overflow:visible}.editor-toolbar,.toolbar-row-2,.link-dialog,.editor-tabs{padding-left:12px;padding-right:12px}.preview-frame{padding:12px}.preview-content{padding:16px}.form-row-dates{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"]
45981
45991
  }]
45982
45992
  }],
45983
45993
  ctorParameters: () => [],
@@ -46030,27 +46040,27 @@ i0.ɵɵngDeclareClassMetadata({
46030
46040
  required: false
46031
46041
  }]
46032
46042
  }],
46033
- textEnabled: [{
46043
+ variableGroups: [{
46034
46044
  type: i0.Input,
46035
46045
  args: [{
46036
46046
  isSignal: true,
46037
- alias: "textEnabled",
46047
+ alias: "variableGroups",
46038
46048
  required: false
46039
46049
  }]
46040
46050
  }],
46041
- variableGroups: [{
46051
+ blockGroups: [{
46042
46052
  type: i0.Input,
46043
46053
  args: [{
46044
46054
  isSignal: true,
46045
- alias: "variableGroups",
46055
+ alias: "blockGroups",
46046
46056
  required: false
46047
46057
  }]
46048
46058
  }],
46049
- blockGroups: [{
46059
+ heading: [{
46050
46060
  type: i0.Input,
46051
46061
  args: [{
46052
46062
  isSignal: true,
46053
- alias: "blockGroups",
46063
+ alias: "heading",
46054
46064
  required: false
46055
46065
  }]
46056
46066
  }],