@compsych-ui-components/angular 7.0.19 → 7.0.21

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.
@@ -50,6 +50,15 @@ export class ButtonComponent {
50
50
  get hostFullWidth() {
51
51
  return this.fullWidth;
52
52
  }
53
+ /**
54
+ * Marks the host non-interactive while disabled or loading. The inner `<button>` sets
55
+ * `pointer-events: none` when disabled, so without this a click lands on the host wrapper
56
+ * instead — firing any `(click)` a consumer bound on `<compsych-button>`. Blocking pointer
57
+ * events at the host too makes the disabled state honour its "non-interactive" contract.
58
+ */
59
+ get hostNonInteractive() {
60
+ return this.disabled || this.loading;
61
+ }
53
62
  /** Pre-sanitized icon markup, recomputed on input change (avoids re-sanitizing every CD cycle). */
54
63
  leadingIconSvg = null;
55
64
  trailingIconSvg = null;
@@ -150,7 +159,7 @@ export class ButtonComponent {
150
159
  animation.onfinish = () => ripple.remove();
151
160
  }
152
161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
153
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ButtonComponent, isStandalone: true, selector: "compsych-button", inputs: { label: "label", variant: "variant", size: "size", leadingIcon: "leadingIcon", trailingIcon: "trailingIcon", type: "type", ariaLabel: "ariaLabel", iconOnly: ["iconOnly", "iconOnly", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], loading: ["loading", "loading", booleanAttribute], fullWidth: ["fullWidth", "fullWidth", booleanAttribute] }, host: { properties: { "class.full-width": "this.hostFullWidth" } }, usesOnChanges: true, ngImport: i0, template: `
162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ButtonComponent, isStandalone: true, selector: "compsych-button", inputs: { label: "label", variant: "variant", size: "size", leadingIcon: "leadingIcon", trailingIcon: "trailingIcon", type: "type", ariaLabel: "ariaLabel", iconOnly: ["iconOnly", "iconOnly", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], loading: ["loading", "loading", booleanAttribute], fullWidth: ["fullWidth", "fullWidth", booleanAttribute] }, host: { properties: { "class.full-width": "this.hostFullWidth", "class.non-interactive": "this.hostNonInteractive" } }, usesOnChanges: true, ngImport: i0, template: `
154
163
  <button
155
164
  [class]="buttonClasses"
156
165
  [type]="type"
@@ -172,7 +181,7 @@ export class ButtonComponent {
172
181
  <span class="icon" aria-hidden="true" [innerHTML]="trailingIconSvg"></span>
173
182
  }
174
183
  </button>
175
- `, isInline: true, styles: [":host{display:inline-flex}:host(.full-width){display:flex;width:100%}.cmp-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;margin:0;border:none;border-radius:var(--border-radius-sys-radius-full);background:none;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;position:relative;overflow:hidden;appearance:none;-webkit-appearance:none;transition:box-shadow .15s ease}.cmp-btn.full-width{width:100%}.cmp-btn:before{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;opacity:0;transition:opacity .15s ease;pointer-events:none}.cmp-btn:hover:before{opacity:.08}.cmp-btn:active:before{opacity:.1}.cmp-btn.filled:hover:not(:disabled),.cmp-btn.danger:hover:not(:disabled){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.cmp-btn:focus-visible{outline:var(--border-width-sys-stroke-thick) solid var(--add-on-primary-fixed-sys-on-primary-fixed-variant);outline-offset:var(--border-width-sys-stroke-thick)}.cmp-btn:focus-visible:before{opacity:.12}.cmp-btn:disabled{pointer-events:none}.cmp-btn:disabled:not(.loading){cursor:not-allowed;background-color:var(--surface-surface-container-sys-surface-container-highest);color:var(--surface-surface-sys-on-surface);border-color:transparent;box-shadow:none;opacity:.48}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.text:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){background-color:transparent}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){border-color:var(--outline-sys-outline-variant)}.icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:0;-webkit-user-select:none;user-select:none;width:16px;height:16px}.cmp-btn.large .icon{width:20px;height:20px}.cmp-btn.xlarge .icon{width:24px;height:24px}.icon svg{width:100%;height:100%}.cmp-btn.icon-only{padding:0;aspect-ratio:1}.cmp-btn.icon-only.small{width:32px}.cmp-btn.icon-only.medium{width:40px}.cmp-btn.icon-only.large{width:48px}.cmp-btn.icon-only.xlarge{width:56px}.spinner{border:2px solid currentColor;border-right-color:transparent;border-radius:50%;box-sizing:border-box;animation:cmp-btn-spin 1s linear infinite}@keyframes cmp-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}.cmp-btn.small{gap:var(--spacing-padding-sys-padding-4);height:32px;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);font-family:var(--label-small-sys-font-family);font-size:var(--label-small-sys-font-size);font-weight:var(--label-small-sys-font-weight-emphasized);line-height:var(--label-small-sys-line-height);letter-spacing:var(--label-small-sys-tracking)}.cmp-btn.medium{gap:var(--spacing-padding-sys-padding-8);height:40px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-16);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking)}.cmp-btn.large{gap:var(--spacing-padding-sys-padding-8);height:48px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.xlarge{gap:var(--spacing-padding-sys-padding-12);height:56px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.filled{background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.cmp-btn.tonal{background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cmp-btn.outlined{background-color:transparent;color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cmp-btn.elevated{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);box-shadow:0 2px 4px #00000014,0 4px 16px var(--transparent-neutral-sys-black-10)}.cmp-btn.text{background-color:transparent;color:var(--surface-surface-sys-on-surface);padding-inline:0}.cmp-btn.danger{background-color:var(--error-sys-error);color:var(--error-sys-on-error)}.cmp-btn.danger-outlined{background-color:transparent;color:var(--error-sys-error);border:var(--border-width-sys-stroke-thin) solid var(--error-sys-error-container)}@media(forced-colors:active){.cmp-btn{border:1px solid ButtonText;forced-color-adjust:none}.cmp-btn.filled,.cmp-btn.tonal,.cmp-btn.danger{background:ButtonText;color:ButtonFace}.cmp-btn:focus-visible{outline:2px solid Highlight;outline-offset:2px}.cmp-btn:disabled:not(.loading){color:GrayText;border-color:GrayText;background:ButtonFace}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
184
+ `, isInline: true, styles: [":host{display:inline-flex}:host(.full-width){display:flex;width:100%}:host(.non-interactive){pointer-events:none}.cmp-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;margin:0;border:none;border-radius:var(--border-radius-sys-radius-full);background:none;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;position:relative;overflow:hidden;appearance:none;-webkit-appearance:none;transition:box-shadow .15s ease}.cmp-btn.full-width{width:100%}.cmp-btn:before{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;opacity:0;transition:opacity .15s ease;pointer-events:none}.cmp-btn:hover:before{opacity:.08}.cmp-btn:active:before{opacity:.1}.cmp-btn.filled:hover:not(:disabled),.cmp-btn.danger:hover:not(:disabled){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.cmp-btn:focus-visible{outline:var(--border-width-sys-stroke-thick) solid var(--add-on-primary-fixed-sys-on-primary-fixed-variant);outline-offset:var(--border-width-sys-stroke-thick)}.cmp-btn:focus-visible:before{opacity:.12}.cmp-btn:disabled{pointer-events:none}.cmp-btn:disabled:not(.loading){cursor:not-allowed;background-color:var(--surface-surface-container-sys-surface-container-highest);color:var(--surface-surface-sys-on-surface);border-color:transparent;box-shadow:none;opacity:.48}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.text:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){background-color:transparent}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){border-color:var(--outline-sys-outline-variant)}.icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:0;-webkit-user-select:none;user-select:none;width:16px;height:16px}.cmp-btn.large .icon{width:20px;height:20px}.cmp-btn.xlarge .icon{width:24px;height:24px}.icon svg{width:100%;height:100%}.cmp-btn.icon-only{padding:0;aspect-ratio:1}.cmp-btn.icon-only.small{width:32px}.cmp-btn.icon-only.medium{width:40px}.cmp-btn.icon-only.large{width:48px}.cmp-btn.icon-only.xlarge{width:56px}.spinner{border:2px solid currentColor;border-right-color:transparent;border-radius:50%;box-sizing:border-box;animation:cmp-btn-spin 1s linear infinite}@keyframes cmp-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}.cmp-btn.small{gap:var(--spacing-padding-sys-padding-4);height:32px;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);font-family:var(--label-small-sys-font-family);font-size:var(--label-small-sys-font-size);font-weight:var(--label-small-sys-font-weight-emphasized);line-height:var(--label-small-sys-line-height);letter-spacing:var(--label-small-sys-tracking)}.cmp-btn.medium{gap:var(--spacing-padding-sys-padding-8);height:40px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-16);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking)}.cmp-btn.large{gap:var(--spacing-padding-sys-padding-8);height:48px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.xlarge{gap:var(--spacing-padding-sys-padding-12);height:56px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.filled{background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.cmp-btn.tonal{background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cmp-btn.outlined{background-color:transparent;color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cmp-btn.elevated{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);box-shadow:0 2px 4px #00000014,0 4px 16px var(--transparent-neutral-sys-black-10)}.cmp-btn.text{background-color:transparent;color:var(--surface-surface-sys-on-surface);padding-inline:0}.cmp-btn.danger{background-color:var(--error-sys-error);color:var(--error-sys-on-error)}.cmp-btn.danger-outlined{background-color:transparent;color:var(--error-sys-error);border:var(--border-width-sys-stroke-thin) solid var(--error-sys-error-container)}@media(forced-colors:active){.cmp-btn{border:1px solid ButtonText;forced-color-adjust:none}.cmp-btn.filled,.cmp-btn.tonal,.cmp-btn.danger{background:ButtonText;color:ButtonFace}.cmp-btn:focus-visible{outline:2px solid Highlight;outline-offset:2px}.cmp-btn:disabled:not(.loading){color:GrayText;border-color:GrayText;background:ButtonFace}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
176
185
  }
177
186
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ButtonComponent, decorators: [{
178
187
  type: Component,
@@ -198,7 +207,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
198
207
  <span class="icon" aria-hidden="true" [innerHTML]="trailingIconSvg"></span>
199
208
  }
200
209
  </button>
201
- `, styles: [":host{display:inline-flex}:host(.full-width){display:flex;width:100%}.cmp-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;margin:0;border:none;border-radius:var(--border-radius-sys-radius-full);background:none;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;position:relative;overflow:hidden;appearance:none;-webkit-appearance:none;transition:box-shadow .15s ease}.cmp-btn.full-width{width:100%}.cmp-btn:before{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;opacity:0;transition:opacity .15s ease;pointer-events:none}.cmp-btn:hover:before{opacity:.08}.cmp-btn:active:before{opacity:.1}.cmp-btn.filled:hover:not(:disabled),.cmp-btn.danger:hover:not(:disabled){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.cmp-btn:focus-visible{outline:var(--border-width-sys-stroke-thick) solid var(--add-on-primary-fixed-sys-on-primary-fixed-variant);outline-offset:var(--border-width-sys-stroke-thick)}.cmp-btn:focus-visible:before{opacity:.12}.cmp-btn:disabled{pointer-events:none}.cmp-btn:disabled:not(.loading){cursor:not-allowed;background-color:var(--surface-surface-container-sys-surface-container-highest);color:var(--surface-surface-sys-on-surface);border-color:transparent;box-shadow:none;opacity:.48}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.text:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){background-color:transparent}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){border-color:var(--outline-sys-outline-variant)}.icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:0;-webkit-user-select:none;user-select:none;width:16px;height:16px}.cmp-btn.large .icon{width:20px;height:20px}.cmp-btn.xlarge .icon{width:24px;height:24px}.icon svg{width:100%;height:100%}.cmp-btn.icon-only{padding:0;aspect-ratio:1}.cmp-btn.icon-only.small{width:32px}.cmp-btn.icon-only.medium{width:40px}.cmp-btn.icon-only.large{width:48px}.cmp-btn.icon-only.xlarge{width:56px}.spinner{border:2px solid currentColor;border-right-color:transparent;border-radius:50%;box-sizing:border-box;animation:cmp-btn-spin 1s linear infinite}@keyframes cmp-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}.cmp-btn.small{gap:var(--spacing-padding-sys-padding-4);height:32px;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);font-family:var(--label-small-sys-font-family);font-size:var(--label-small-sys-font-size);font-weight:var(--label-small-sys-font-weight-emphasized);line-height:var(--label-small-sys-line-height);letter-spacing:var(--label-small-sys-tracking)}.cmp-btn.medium{gap:var(--spacing-padding-sys-padding-8);height:40px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-16);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking)}.cmp-btn.large{gap:var(--spacing-padding-sys-padding-8);height:48px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.xlarge{gap:var(--spacing-padding-sys-padding-12);height:56px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.filled{background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.cmp-btn.tonal{background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cmp-btn.outlined{background-color:transparent;color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cmp-btn.elevated{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);box-shadow:0 2px 4px #00000014,0 4px 16px var(--transparent-neutral-sys-black-10)}.cmp-btn.text{background-color:transparent;color:var(--surface-surface-sys-on-surface);padding-inline:0}.cmp-btn.danger{background-color:var(--error-sys-error);color:var(--error-sys-on-error)}.cmp-btn.danger-outlined{background-color:transparent;color:var(--error-sys-error);border:var(--border-width-sys-stroke-thin) solid var(--error-sys-error-container)}@media(forced-colors:active){.cmp-btn{border:1px solid ButtonText;forced-color-adjust:none}.cmp-btn.filled,.cmp-btn.tonal,.cmp-btn.danger{background:ButtonText;color:ButtonFace}.cmp-btn:focus-visible{outline:2px solid Highlight;outline-offset:2px}.cmp-btn:disabled:not(.loading){color:GrayText;border-color:GrayText;background:ButtonFace}}\n"] }]
210
+ `, styles: [":host{display:inline-flex}:host(.full-width){display:flex;width:100%}:host(.non-interactive){pointer-events:none}.cmp-btn{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;margin:0;border:none;border-radius:var(--border-radius-sys-radius-full);background:none;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;position:relative;overflow:hidden;appearance:none;-webkit-appearance:none;transition:box-shadow .15s ease}.cmp-btn.full-width{width:100%}.cmp-btn:before{content:\"\";position:absolute;inset:0;border-radius:inherit;background-color:currentColor;opacity:0;transition:opacity .15s ease;pointer-events:none}.cmp-btn:hover:before{opacity:.08}.cmp-btn:active:before{opacity:.1}.cmp-btn.filled:hover:not(:disabled),.cmp-btn.danger:hover:not(:disabled){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.cmp-btn:focus-visible{outline:var(--border-width-sys-stroke-thick) solid var(--add-on-primary-fixed-sys-on-primary-fixed-variant);outline-offset:var(--border-width-sys-stroke-thick)}.cmp-btn:focus-visible:before{opacity:.12}.cmp-btn:disabled{pointer-events:none}.cmp-btn:disabled:not(.loading){cursor:not-allowed;background-color:var(--surface-surface-container-sys-surface-container-highest);color:var(--surface-surface-sys-on-surface);border-color:transparent;box-shadow:none;opacity:.48}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.text:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){background-color:transparent}.cmp-btn.outlined:disabled:not(.loading),.cmp-btn.danger-outlined:disabled:not(.loading){border-color:var(--outline-sys-outline-variant)}.icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:0;-webkit-user-select:none;user-select:none;width:16px;height:16px}.cmp-btn.large .icon{width:20px;height:20px}.cmp-btn.xlarge .icon{width:24px;height:24px}.icon svg{width:100%;height:100%}.cmp-btn.icon-only{padding:0;aspect-ratio:1}.cmp-btn.icon-only.small{width:32px}.cmp-btn.icon-only.medium{width:40px}.cmp-btn.icon-only.large{width:48px}.cmp-btn.icon-only.xlarge{width:56px}.spinner{border:2px solid currentColor;border-right-color:transparent;border-radius:50%;box-sizing:border-box;animation:cmp-btn-spin 1s linear infinite}@keyframes cmp-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}.cmp-btn.small{gap:var(--spacing-padding-sys-padding-4);height:32px;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);font-family:var(--label-small-sys-font-family);font-size:var(--label-small-sys-font-size);font-weight:var(--label-small-sys-font-weight-emphasized);line-height:var(--label-small-sys-line-height);letter-spacing:var(--label-small-sys-tracking)}.cmp-btn.medium{gap:var(--spacing-padding-sys-padding-8);height:40px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-16);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking)}.cmp-btn.large{gap:var(--spacing-padding-sys-padding-8);height:48px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.xlarge{gap:var(--spacing-padding-sys-padding-12);height:56px;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-24);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.cmp-btn.filled{background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.cmp-btn.tonal{background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cmp-btn.outlined{background-color:transparent;color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cmp-btn.elevated{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);box-shadow:0 2px 4px #00000014,0 4px 16px var(--transparent-neutral-sys-black-10)}.cmp-btn.text{background-color:transparent;color:var(--surface-surface-sys-on-surface);padding-inline:0}.cmp-btn.danger{background-color:var(--error-sys-error);color:var(--error-sys-on-error)}.cmp-btn.danger-outlined{background-color:transparent;color:var(--error-sys-error);border:var(--border-width-sys-stroke-thin) solid var(--error-sys-error-container)}@media(forced-colors:active){.cmp-btn{border:1px solid ButtonText;forced-color-adjust:none}.cmp-btn.filled,.cmp-btn.tonal,.cmp-btn.danger{background:ButtonText;color:ButtonFace}.cmp-btn:focus-visible{outline:2px solid Highlight;outline-offset:2px}.cmp-btn:disabled:not(.loading){color:GrayText;border-color:GrayText;background:ButtonFace}}\n"] }]
202
211
  }], propDecorators: { label: [{
203
212
  type: Input
204
213
  }], variant: [{
@@ -228,5 +237,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
228
237
  }], hostFullWidth: [{
229
238
  type: HostBinding,
230
239
  args: ['class.full-width']
240
+ }], hostNonInteractive: [{
241
+ type: HostBinding,
242
+ args: ['class.non-interactive']
231
243
  }] } });
232
244
  //# sourceMappingURL=button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/button/button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n HostBinding,\r\n Input,\r\n OnChanges,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\n\r\n/** Visual style of a `compsych-button`. Controls color, border, and elevation. */\r\nexport type ButtonVariant =\r\n | 'filled'\r\n | 'tonal'\r\n | 'outlined'\r\n | 'elevated'\r\n | 'text'\r\n | 'danger'\r\n | 'danger-outlined';\r\n\r\n/** Button dimensions — controls height, padding, font size, and icon size. */\r\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\r\n\r\n/** Native button behaviour. `'submit'`/`'reset'` make the component a real form control. */\r\nexport type ButtonType = 'button' | 'submit' | 'reset';\r\n\r\n/** Icon pixel size per button size (per design: sm/md 16, lg 20, xl 24). */\r\nconst ICON_SIZE_BY_BUTTON_SIZE: Record<ButtonSize, number> = {\r\n small: 16,\r\n medium: 16,\r\n large: 20,\r\n xlarge: 24,\r\n};\r\n\r\n/**\r\n * A themeable button that renders a native `<button>` element, so it is fully\r\n * form-submittable and keyboard/screen-reader accessible out of the box. Icons\r\n * are Lucide glyphs (matching the rest of the library); a button may carry a\r\n * leading icon, a trailing icon, or both.\r\n */\r\n@Component({\r\n selector: 'compsych-button',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <button\r\n [class]=\"buttonClasses\"\r\n [type]=\"type\"\r\n [disabled]=\"disabled || loading\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n [attr.aria-label]=\"computedAriaLabel\"\r\n (pointerdown)=\"onPointerDown($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n >\r\n @if (loading) {\r\n <span class=\"icon spinner\" aria-hidden=\"true\"></span>\r\n } @else if (leadingIcon) {\r\n <span class=\"icon\" aria-hidden=\"true\" [innerHTML]=\"leadingIconSvg\"></span>\r\n }\r\n @if (!iconOnly) {\r\n <span class=\"label\">{{ label }}<ng-content /></span>\r\n }\r\n @if (trailingIcon && !iconOnly) {\r\n <span class=\"icon\" aria-hidden=\"true\" [innerHTML]=\"trailingIconSvg\"></span>\r\n }\r\n </button>\r\n `,\r\n styleUrl: './button.css',\r\n})\r\nexport class ButtonComponent implements OnChanges {\r\n private readonly sanitizer = inject(DomSanitizer);\r\n\r\n /** Text label rendered on the button. */\r\n @Input() label = '';\r\n /** Visual style of the button. Defaults to `'filled'`. */\r\n @Input() variant: ButtonVariant = 'filled';\r\n /** Button dimensions — controls height, padding, font size, and icon size. Defaults to `'small'`. */\r\n @Input() size: ButtonSize = 'small';\r\n /** Lucide icon name shown before the label (e.g. `'house'`). Swapped for a spinner when loading. */\r\n @Input() leadingIcon?: string;\r\n /** Lucide icon name shown after the label (e.g. `'chevron-right'`). Can be combined with `leadingIcon`. */\r\n @Input() trailingIcon?: string;\r\n /** Native button type. Use `'submit'` inside a `<form>` to submit it. Defaults to `'button'`. */\r\n @Input() type: ButtonType = 'button';\r\n /**\r\n * Accessible name. Required for icon-only buttons since the icon is decorative.\r\n * When `iconOnly` or `loading` is set and this is omitted, `label` is used.\r\n */\r\n @Input() ariaLabel?: string;\r\n\r\n /** Hides the label and renders a square icon-only button. Uses `leadingIcon`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) iconOnly = false;\r\n /** Disables the button — non-interactive and rendered in a neutral grey. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /**\r\n * Loading state. Swaps the leading icon for a spinner and suppresses activation\r\n * (native `disabled` blocks click/keyboard), while keeping the label and exposing\r\n * `aria-busy=\"true\"`. Retains the variant's colours. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) loading = false;\r\n /** Stretches the button to the full width of its container. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) fullWidth = false;\r\n\r\n /** Mirrors `fullWidth` onto the host so it can stretch. */\r\n @HostBinding('class.full-width') get hostFullWidth(): boolean {\r\n return this.fullWidth;\r\n }\r\n\r\n /** Pre-sanitized icon markup, recomputed on input change (avoids re-sanitizing every CD cycle). */\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n protected trailingIconSvg: SafeHtml | null = null;\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n this.trailingIconSvg = this.trailingIcon ? this.buildIconSvg(this.trailingIcon) : null;\r\n }\r\n\r\n /** Space-separated class list applied to the inner native button. */\r\n get buttonClasses(): string {\r\n return [\r\n 'cmp-btn',\r\n this.variant,\r\n this.size,\r\n this.iconOnly ? 'icon-only' : '',\r\n this.loading ? 'loading' : '',\r\n this.fullWidth ? 'full-width' : '',\r\n ]\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n /** Resolves the accessible name. Icon-only buttons have no visible text, so they fall back to `label`. */\r\n get computedAriaLabel(): string | null {\r\n if (this.ariaLabel) {\r\n return this.ariaLabel;\r\n }\r\n // Loading keeps the visible label, so only icon-only needs an explicit name here.\r\n return this.iconOnly ? this.label || null : null;\r\n }\r\n\r\n /**\r\n * Looks up a Lucide icon by name and injects an explicit width/height so the SVG\r\n * renders at the correct size when injected via `[innerHTML]` (Angular's CSS\r\n * encapsulation does not reach dynamically injected content).\r\n */\r\n private buildIconSvg(name: string): SafeHtml {\r\n const size = ICON_SIZE_BY_BUTTON_SIZE[this.size];\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /** M3 pressed ripple: pointer-down spawns a ripple at the pointer position. */\r\n onPointerDown(event: PointerEvent): void {\r\n if (this.disabled || this.loading || event.button !== 0) {\r\n return;\r\n }\r\n const host = event.currentTarget as HTMLElement;\r\n const rect = host.getBoundingClientRect();\r\n const x = event.clientX - rect.left;\r\n const y = event.clientY - rect.top;\r\n this.spawnRipple(host, x, y, this.farthestCornerDiameter(rect, x, y));\r\n }\r\n\r\n /** M3 pressed ripple: keyboard activation (Enter/Space) spawns a centered ripple. */\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (this.disabled || this.loading || event.repeat) {\r\n return;\r\n }\r\n if (event.key !== 'Enter' && event.key !== ' ') {\r\n return;\r\n }\r\n const host = event.currentTarget as HTMLElement;\r\n const rect = host.getBoundingClientRect();\r\n this.spawnRipple(host, rect.width / 2, rect.height / 2, Math.hypot(rect.width, rect.height));\r\n }\r\n\r\n /** Diameter that reaches the farthest corner from (x, y), so the ripple always covers the button. */\r\n private farthestCornerDiameter(rect: DOMRect, x: number, y: number): number {\r\n const corners: Array<[number, number]> = [\r\n [0, 0],\r\n [rect.width, 0],\r\n [0, rect.height],\r\n [rect.width, rect.height],\r\n ];\r\n const maxRadius = Math.max(...corners.map(([cx, cy]) => Math.hypot(cx - x, cy - y)));\r\n return maxRadius * 2;\r\n }\r\n\r\n /**\r\n * Spawns an expanding ripple circle. Created imperatively with inline styles and\r\n * animated via the Web Animations API — Angular's emulated encapsulation does not\r\n * reach dynamically created nodes, so it cannot rely on the component stylesheet.\r\n */\r\n private spawnRipple(host: HTMLElement, x: number, y: number, diameter: number): void {\r\n if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {\r\n return;\r\n }\r\n const ripple = document.createElement('span');\r\n Object.assign(ripple.style, {\r\n position: 'absolute',\r\n borderRadius: '50%',\r\n backgroundColor: 'currentColor',\r\n pointerEvents: 'none',\r\n width: `${diameter}px`,\r\n height: `${diameter}px`,\r\n left: `${x - diameter / 2}px`,\r\n top: `${y - diameter / 2}px`,\r\n } as Partial<CSSStyleDeclaration>);\r\n host.appendChild(ripple);\r\n const animation = ripple.animate(\r\n [\r\n { transform: 'scale(0)', opacity: '0.16' },\r\n { transform: 'scale(1)', opacity: '0' },\r\n ],\r\n { duration: 450, easing: 'ease-out' },\r\n );\r\n animation.onfinish = () => ripple.remove();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/button/button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n HostBinding,\r\n Input,\r\n OnChanges,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\n\r\n/** Visual style of a `compsych-button`. Controls color, border, and elevation. */\r\nexport type ButtonVariant =\r\n | 'filled'\r\n | 'tonal'\r\n | 'outlined'\r\n | 'elevated'\r\n | 'text'\r\n | 'danger'\r\n | 'danger-outlined';\r\n\r\n/** Button dimensions — controls height, padding, font size, and icon size. */\r\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\r\n\r\n/** Native button behaviour. `'submit'`/`'reset'` make the component a real form control. */\r\nexport type ButtonType = 'button' | 'submit' | 'reset';\r\n\r\n/** Icon pixel size per button size (per design: sm/md 16, lg 20, xl 24). */\r\nconst ICON_SIZE_BY_BUTTON_SIZE: Record<ButtonSize, number> = {\r\n small: 16,\r\n medium: 16,\r\n large: 20,\r\n xlarge: 24,\r\n};\r\n\r\n/**\r\n * A themeable button that renders a native `<button>` element, so it is fully\r\n * form-submittable and keyboard/screen-reader accessible out of the box. Icons\r\n * are Lucide glyphs (matching the rest of the library); a button may carry a\r\n * leading icon, a trailing icon, or both.\r\n */\r\n@Component({\r\n selector: 'compsych-button',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <button\r\n [class]=\"buttonClasses\"\r\n [type]=\"type\"\r\n [disabled]=\"disabled || loading\"\r\n [attr.aria-busy]=\"loading ? 'true' : null\"\r\n [attr.aria-label]=\"computedAriaLabel\"\r\n (pointerdown)=\"onPointerDown($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n >\r\n @if (loading) {\r\n <span class=\"icon spinner\" aria-hidden=\"true\"></span>\r\n } @else if (leadingIcon) {\r\n <span class=\"icon\" aria-hidden=\"true\" [innerHTML]=\"leadingIconSvg\"></span>\r\n }\r\n @if (!iconOnly) {\r\n <span class=\"label\">{{ label }}<ng-content /></span>\r\n }\r\n @if (trailingIcon && !iconOnly) {\r\n <span class=\"icon\" aria-hidden=\"true\" [innerHTML]=\"trailingIconSvg\"></span>\r\n }\r\n </button>\r\n `,\r\n styleUrl: './button.css',\r\n})\r\nexport class ButtonComponent implements OnChanges {\r\n private readonly sanitizer = inject(DomSanitizer);\r\n\r\n /** Text label rendered on the button. */\r\n @Input() label = '';\r\n /** Visual style of the button. Defaults to `'filled'`. */\r\n @Input() variant: ButtonVariant = 'filled';\r\n /** Button dimensions — controls height, padding, font size, and icon size. Defaults to `'small'`. */\r\n @Input() size: ButtonSize = 'small';\r\n /** Lucide icon name shown before the label (e.g. `'house'`). Swapped for a spinner when loading. */\r\n @Input() leadingIcon?: string;\r\n /** Lucide icon name shown after the label (e.g. `'chevron-right'`). Can be combined with `leadingIcon`. */\r\n @Input() trailingIcon?: string;\r\n /** Native button type. Use `'submit'` inside a `<form>` to submit it. Defaults to `'button'`. */\r\n @Input() type: ButtonType = 'button';\r\n /**\r\n * Accessible name. Required for icon-only buttons since the icon is decorative.\r\n * When `iconOnly` or `loading` is set and this is omitted, `label` is used.\r\n */\r\n @Input() ariaLabel?: string;\r\n\r\n /** Hides the label and renders a square icon-only button. Uses `leadingIcon`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) iconOnly = false;\r\n /** Disables the button — non-interactive and rendered in a neutral grey. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /**\r\n * Loading state. Swaps the leading icon for a spinner and suppresses activation\r\n * (native `disabled` blocks click/keyboard), while keeping the label and exposing\r\n * `aria-busy=\"true\"`. Retains the variant's colours. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) loading = false;\r\n /** Stretches the button to the full width of its container. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) fullWidth = false;\r\n\r\n /** Mirrors `fullWidth` onto the host so it can stretch. */\r\n @HostBinding('class.full-width') get hostFullWidth(): boolean {\r\n return this.fullWidth;\r\n }\r\n\r\n /**\r\n * Marks the host non-interactive while disabled or loading. The inner `<button>` sets\r\n * `pointer-events: none` when disabled, so without this a click lands on the host wrapper\r\n * instead — firing any `(click)` a consumer bound on `<compsych-button>`. Blocking pointer\r\n * events at the host too makes the disabled state honour its \"non-interactive\" contract.\r\n */\r\n @HostBinding('class.non-interactive') get hostNonInteractive(): boolean {\r\n return this.disabled || this.loading;\r\n }\r\n\r\n /** Pre-sanitized icon markup, recomputed on input change (avoids re-sanitizing every CD cycle). */\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n protected trailingIconSvg: SafeHtml | null = null;\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n this.trailingIconSvg = this.trailingIcon ? this.buildIconSvg(this.trailingIcon) : null;\r\n }\r\n\r\n /** Space-separated class list applied to the inner native button. */\r\n get buttonClasses(): string {\r\n return [\r\n 'cmp-btn',\r\n this.variant,\r\n this.size,\r\n this.iconOnly ? 'icon-only' : '',\r\n this.loading ? 'loading' : '',\r\n this.fullWidth ? 'full-width' : '',\r\n ]\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n /** Resolves the accessible name. Icon-only buttons have no visible text, so they fall back to `label`. */\r\n get computedAriaLabel(): string | null {\r\n if (this.ariaLabel) {\r\n return this.ariaLabel;\r\n }\r\n // Loading keeps the visible label, so only icon-only needs an explicit name here.\r\n return this.iconOnly ? this.label || null : null;\r\n }\r\n\r\n /**\r\n * Looks up a Lucide icon by name and injects an explicit width/height so the SVG\r\n * renders at the correct size when injected via `[innerHTML]` (Angular's CSS\r\n * encapsulation does not reach dynamically injected content).\r\n */\r\n private buildIconSvg(name: string): SafeHtml {\r\n const size = ICON_SIZE_BY_BUTTON_SIZE[this.size];\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /** M3 pressed ripple: pointer-down spawns a ripple at the pointer position. */\r\n onPointerDown(event: PointerEvent): void {\r\n if (this.disabled || this.loading || event.button !== 0) {\r\n return;\r\n }\r\n const host = event.currentTarget as HTMLElement;\r\n const rect = host.getBoundingClientRect();\r\n const x = event.clientX - rect.left;\r\n const y = event.clientY - rect.top;\r\n this.spawnRipple(host, x, y, this.farthestCornerDiameter(rect, x, y));\r\n }\r\n\r\n /** M3 pressed ripple: keyboard activation (Enter/Space) spawns a centered ripple. */\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (this.disabled || this.loading || event.repeat) {\r\n return;\r\n }\r\n if (event.key !== 'Enter' && event.key !== ' ') {\r\n return;\r\n }\r\n const host = event.currentTarget as HTMLElement;\r\n const rect = host.getBoundingClientRect();\r\n this.spawnRipple(host, rect.width / 2, rect.height / 2, Math.hypot(rect.width, rect.height));\r\n }\r\n\r\n /** Diameter that reaches the farthest corner from (x, y), so the ripple always covers the button. */\r\n private farthestCornerDiameter(rect: DOMRect, x: number, y: number): number {\r\n const corners: Array<[number, number]> = [\r\n [0, 0],\r\n [rect.width, 0],\r\n [0, rect.height],\r\n [rect.width, rect.height],\r\n ];\r\n const maxRadius = Math.max(...corners.map(([cx, cy]) => Math.hypot(cx - x, cy - y)));\r\n return maxRadius * 2;\r\n }\r\n\r\n /**\r\n * Spawns an expanding ripple circle. Created imperatively with inline styles and\r\n * animated via the Web Animations API — Angular's emulated encapsulation does not\r\n * reach dynamically created nodes, so it cannot rely on the component stylesheet.\r\n */\r\n private spawnRipple(host: HTMLElement, x: number, y: number, diameter: number): void {\r\n if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {\r\n return;\r\n }\r\n const ripple = document.createElement('span');\r\n Object.assign(ripple.style, {\r\n position: 'absolute',\r\n borderRadius: '50%',\r\n backgroundColor: 'currentColor',\r\n pointerEvents: 'none',\r\n width: `${diameter}px`,\r\n height: `${diameter}px`,\r\n left: `${x - diameter / 2}px`,\r\n top: `${y - diameter / 2}px`,\r\n } as Partial<CSSStyleDeclaration>);\r\n host.appendChild(ripple);\r\n const animation = ripple.animate(\r\n [\r\n { transform: 'scale(0)', opacity: '0.16' },\r\n { transform: 'scale(1)', opacity: '0' },\r\n ],\r\n { duration: 450, easing: 'ease-out' },\r\n );\r\n animation.onfinish = () => ripple.remove();\r\n }\r\n}\r\n"]}
@@ -85,6 +85,8 @@ export class CardComponent {
85
85
  trailingIcon = input('arrow-up-right', ...(ngDevMode ? [{ debugName: "trailingIcon" }] : /* istanbul ignore next */ []));
86
86
  /** Action: layout orientation. */
87
87
  orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
88
+ /** Action: stretch the card to 100% of its container width. */
89
+ fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : /* istanbul ignore next */ []));
88
90
  // ── Metric variant ──────────────────────────────────────
89
91
  /** Metric: the prominent value. */
90
92
  value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -171,7 +173,7 @@ export class CardComponent {
171
173
  return this.sanitizer.bypassSecurityTrustHtml(svg);
172
174
  }
173
175
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
174
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardComponent, isStandalone: true, selector: "compsych-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, imagePosition: { classPropertyName: "imagePosition", publicName: "imagePosition", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, categoryStyle: { classPropertyName: "categoryStyle", publicName: "categoryStyle", isSignal: true, isRequired: false, transformFunction: null }, iconStyle: { classPropertyName: "iconStyle", publicName: "iconStyle", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, headline: { classPropertyName: "headline", publicName: "headline", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, trailingIcon: { classPropertyName: "trailingIcon", publicName: "trailingIcon", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick" }, host: { listeners: { "click": "onActivate()", "keydown": "onKeyDown($event)" }, properties: { "class.cmp-card--outlined": "appearance() === 'outlined'", "class.cmp-card--filled": "appearance() === 'filled'", "class.cmp-card--gradient": "appearance() === 'gradient'", "class.cmp-card--image": "appearance() === 'image'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "class.cmp-card--hero": "variant() === 'content' && !!headline()", "class.cmp-card--metric": "variant() === 'metric'", "class.cmp-card--current": "variant() === 'metric' && current()", "class.cmp-card--radius-md": "radius() === 'md'", "class.cmp-card--radius-lg": "radius() === 'lg'", "class.cmp-card--radius-xl": "radius() === 'xl'", "class.cmp-card--pad-none": "effectivePadding() === 'none'", "class.cmp-card--pad-sm": "effectivePadding() === 'sm'", "class.cmp-card--pad-md": "effectivePadding() === 'md'", "class.cmp-card--pad-lg": "effectivePadding() === 'lg'", "class.cmp-card--pad-xl": "effectivePadding() === 'xl'", "class.cmp-card--interactive": "interactive()", "class.cmp-card--disabled": "disabled()", "attr.role": "interactive() ? 'button' : null", "attr.tabindex": "interactive() && !disabled() ? 0 : null", "attr.aria-label": "ariaLabel() ?? null", "attr.aria-disabled": "disabled() || null", "attr.aria-pressed": "interactive() && variant() === 'metric' ? current() : null", "style.border-color": "variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null", "style.border-width": "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null" }, classAttribute: "cmp-card" }, hostDirectives: [{ directive: i1.RippleDirective }], ngImport: i0, template: "@if (isImage() && mediaUrl()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (headline()) {\r\n <!-- Hero (image/filled): icon top-left, eyebrow + display headline + action bottom. -->\r\n <div class=\"cc cc--hero\" [class.cc--image]=\"isImage()\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n @if (icon()) {\r\n @if (isImage()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"cc__img-foot\">\r\n <div class=\"cc__hero-text\">\r\n @if (title()) { <p class=\"cc__eyebrow\">{{ title() }}</p> }\r\n <ng-container [ngTemplateOutlet]=\"headlineTpl\" />\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (isImage()) {\r\n <div class=\"cc cc--image\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || description()) {\r\n <div class=\"cc__hero-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"cc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else {\r\n <!-- With-icon content card (Figma 59444:2263): a full-width light-blue\r\n icon banner over a gray category eyebrow + title + body, with the\r\n text distributed top/bottom. Default for outlined/filled content. -->\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--image]=\"isImage()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button bc__button--end\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else if (isImage()) {\r\n <!-- md image base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--image\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragments: render a real <h2>\u2013<h6> when `headingLevel` is set, else the\r\n original <p>/<span>. Shared across layouts so semantics stay consistent and the\r\n cc__title / cc__headline / ac__label styling is unchanged. -->\r\n<ng-template #titleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"cc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"cc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"cc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"cc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"cc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #headlineTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__headline\">{{ headline() }}</h2> }\r\n @case (3) { <h3 class=\"cc__headline\">{{ headline() }}</h3> }\r\n @case (4) { <h4 class=\"cc__headline\">{{ headline() }}</h4> }\r\n @case (5) { <h5 class=\"cc__headline\">{{ headline() }}</h5> }\r\n @case (6) { <h6 class=\"cc__headline\">{{ headline() }}</h6> }\r\n @default { <p class=\"cc__headline\">{{ headline() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #bcTitleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"bc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"bc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"bc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"bc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"bc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"bc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--image{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .14s ease-out,border-color .14s ease-out,border-width .14s ease-out}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .14s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--image:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--hero):not(.cc--image){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--filled .cc__button{border-color:transparent}.cc--image{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--hero{border-radius:var(--border-radius-sys-radius-xl)}.cc--hero{position:relative;display:flex;flex-direction:column;flex:1 1 auto;justify-content:flex-end;gap:var(--spacing-padding-sys-padding-24);min-height:22.5rem;padding:var(--spacing-padding-sys-padding-48)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc--hero>.cc__media-icon{margin-bottom:auto}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__img-foot--end{justify-content:flex-end}.cc__hero-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__eyebrow{margin:0;font-family:var(--title-large-sys-font-family);font-size:var(--title-large-sys-font-size);line-height:var(--title-large-sys-line-height);letter-spacing:var(--title-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__headline{margin:0;font-family:var(--display-large-sys-font-family);font-size:var(--display-large-sys-font-size);line-height:var(--display-large-sys-line-height);font-weight:var(--display-large-sys-font-weight);letter-spacing:var(--display-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__button--solid{align-self:flex-end;flex-shrink:0;border-color:transparent;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);box-shadow:0 .125rem .25rem #0000000f,0 .125rem .5rem #0000000a}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__button--solid{align-self:flex-start}}.cc--image .cc__title,.cc--image .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--image .cc__subtitle,.cc--image .cc__desc{color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);white-space:nowrap}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--image{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--image .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--image .bc--row .bc__title,:host.cmp-card--image .bc--row .bc__icon,:host.cmp-card--image .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc__button--end{align-self:flex-end}.bc--promo.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}:host.cmp-card--filled .bc__button{border-color:transparent}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
176
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardComponent, isStandalone: true, selector: "compsych-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, imagePosition: { classPropertyName: "imagePosition", publicName: "imagePosition", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, categoryStyle: { classPropertyName: "categoryStyle", publicName: "categoryStyle", isSignal: true, isRequired: false, transformFunction: null }, iconStyle: { classPropertyName: "iconStyle", publicName: "iconStyle", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, headline: { classPropertyName: "headline", publicName: "headline", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, trailingIcon: { classPropertyName: "trailingIcon", publicName: "trailingIcon", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick" }, host: { listeners: { "click": "onActivate()", "keydown": "onKeyDown($event)" }, properties: { "class.cmp-card--outlined": "appearance() === 'outlined'", "class.cmp-card--filled": "appearance() === 'filled'", "class.cmp-card--gradient": "appearance() === 'gradient'", "class.cmp-card--image": "appearance() === 'image'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "class.cmp-card--hero": "variant() === 'content' && !!headline()", "class.cmp-card--metric": "variant() === 'metric'", "class.cmp-card--current": "variant() === 'metric' && current()", "class.cmp-card--radius-md": "radius() === 'md'", "class.cmp-card--radius-lg": "radius() === 'lg'", "class.cmp-card--radius-xl": "radius() === 'xl'", "class.cmp-card--pad-none": "effectivePadding() === 'none'", "class.cmp-card--pad-sm": "effectivePadding() === 'sm'", "class.cmp-card--pad-md": "effectivePadding() === 'md'", "class.cmp-card--pad-lg": "effectivePadding() === 'lg'", "class.cmp-card--pad-xl": "effectivePadding() === 'xl'", "style.width": "fullWidth() ? '100%' : null", "class.cmp-card--interactive": "interactive()", "class.cmp-card--disabled": "disabled()", "attr.role": "interactive() ? 'button' : null", "attr.tabindex": "interactive() && !disabled() ? 0 : null", "attr.aria-label": "ariaLabel() ?? null", "attr.aria-disabled": "disabled() || null", "attr.aria-pressed": "interactive() && variant() === 'metric' ? current() : null", "style.border-color": "variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null", "style.border-width": "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null" }, classAttribute: "cmp-card" }, hostDirectives: [{ directive: i1.RippleDirective }], ngImport: i0, template: "@if (isImage() && mediaUrl()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (headline()) {\r\n <!-- Hero (image/filled): icon top-left, eyebrow + display headline + action bottom. -->\r\n <div class=\"cc cc--hero\" [class.cc--image]=\"isImage()\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n @if (icon()) {\r\n @if (isImage()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"cc__img-foot\">\r\n <div class=\"cc__hero-text\">\r\n @if (title()) { <p class=\"cc__eyebrow\">{{ title() }}</p> }\r\n <ng-container [ngTemplateOutlet]=\"headlineTpl\" />\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (isImage()) {\r\n <div class=\"cc cc--image\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || description()) {\r\n <div class=\"cc__hero-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"cc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else {\r\n <!-- With-icon content card (Figma 59444:2263): a full-width light-blue\r\n icon banner over a gray category eyebrow + title + body, with the\r\n text distributed top/bottom. Default for outlined/filled content. -->\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--image]=\"isImage()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button bc__button--end\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else if (isImage()) {\r\n <!-- md image base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--image\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragments: render a real <h2>\u2013<h6> when `headingLevel` is set, else the\r\n original <p>/<span>. Shared across layouts so semantics stay consistent and the\r\n cc__title / cc__headline / ac__label styling is unchanged. -->\r\n<ng-template #titleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"cc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"cc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"cc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"cc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"cc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #headlineTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__headline\">{{ headline() }}</h2> }\r\n @case (3) { <h3 class=\"cc__headline\">{{ headline() }}</h3> }\r\n @case (4) { <h4 class=\"cc__headline\">{{ headline() }}</h4> }\r\n @case (5) { <h5 class=\"cc__headline\">{{ headline() }}</h5> }\r\n @case (6) { <h6 class=\"cc__headline\">{{ headline() }}</h6> }\r\n @default { <p class=\"cc__headline\">{{ headline() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #bcTitleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"bc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"bc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"bc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"bc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"bc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"bc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--image{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .14s ease-out,border-color .14s ease-out,border-width .14s ease-out}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .14s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--image:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--hero):not(.cc--image){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--filled .cc__button{border-color:transparent}.cc--image{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--hero{border-radius:var(--border-radius-sys-radius-xl)}.cc--hero{position:relative;display:flex;flex-direction:column;flex:1 1 auto;justify-content:flex-end;gap:var(--spacing-padding-sys-padding-24);min-height:22.5rem;padding:var(--spacing-padding-sys-padding-48)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc--hero>.cc__media-icon{margin-bottom:auto}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__img-foot--end{justify-content:flex-end}.cc__hero-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__eyebrow{margin:0;font-family:var(--title-large-sys-font-family);font-size:var(--title-large-sys-font-size);line-height:var(--title-large-sys-line-height);letter-spacing:var(--title-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__headline{margin:0;font-family:var(--display-large-sys-font-family);font-size:var(--display-large-sys-font-size);line-height:var(--display-large-sys-line-height);font-weight:var(--display-large-sys-font-weight);letter-spacing:var(--display-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__button--solid{align-self:flex-end;flex-shrink:0;border-color:transparent;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);box-shadow:0 .125rem .25rem #0000000f,0 .125rem .5rem #0000000a}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__button--solid{align-self:flex-start}}.cc--image .cc__title,.cc--image .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--image .cc__subtitle,.cc--image .cc__desc{color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);white-space:nowrap}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--image{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--image .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--image .bc--row .bc__title,:host.cmp-card--image .bc--row .bc__icon,:host.cmp-card--image .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc__button--end{align-self:flex-end}.bc--promo.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}:host.cmp-card--filled .bc__button{border-color:transparent}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
175
177
  }
176
178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, decorators: [{
177
179
  type: Component,
@@ -195,6 +197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
195
197
  '[class.cmp-card--pad-md]': "effectivePadding() === 'md'",
196
198
  '[class.cmp-card--pad-lg]': "effectivePadding() === 'lg'",
197
199
  '[class.cmp-card--pad-xl]': "effectivePadding() === 'xl'",
200
+ '[style.width]': "fullWidth() ? '100%' : null",
198
201
  '[class.cmp-card--interactive]': 'interactive()',
199
202
  '[class.cmp-card--disabled]': 'disabled()',
200
203
  '[attr.role]': "interactive() ? 'button' : null",
@@ -207,5 +210,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
207
210
  '(click)': 'onActivate()',
208
211
  '(keydown)': 'onKeyDown($event)',
209
212
  }, template: "@if (isImage() && mediaUrl()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (headline()) {\r\n <!-- Hero (image/filled): icon top-left, eyebrow + display headline + action bottom. -->\r\n <div class=\"cc cc--hero\" [class.cc--image]=\"isImage()\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n @if (icon()) {\r\n @if (isImage()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"cc__img-foot\">\r\n <div class=\"cc__hero-text\">\r\n @if (title()) { <p class=\"cc__eyebrow\">{{ title() }}</p> }\r\n <ng-container [ngTemplateOutlet]=\"headlineTpl\" />\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (isImage()) {\r\n <div class=\"cc cc--image\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || description()) {\r\n <div class=\"cc__hero-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"cc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else {\r\n <!-- With-icon content card (Figma 59444:2263): a full-width light-blue\r\n icon banner over a gray category eyebrow + title + body, with the\r\n text distributed top/bottom. Default for outlined/filled content. -->\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--image]=\"isImage()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button bc__button--end\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else if (isImage()) {\r\n <!-- md image base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--image\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragments: render a real <h2>\u2013<h6> when `headingLevel` is set, else the\r\n original <p>/<span>. Shared across layouts so semantics stay consistent and the\r\n cc__title / cc__headline / ac__label styling is unchanged. -->\r\n<ng-template #titleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"cc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"cc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"cc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"cc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"cc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #headlineTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__headline\">{{ headline() }}</h2> }\r\n @case (3) { <h3 class=\"cc__headline\">{{ headline() }}</h3> }\r\n @case (4) { <h4 class=\"cc__headline\">{{ headline() }}</h4> }\r\n @case (5) { <h5 class=\"cc__headline\">{{ headline() }}</h5> }\r\n @case (6) { <h6 class=\"cc__headline\">{{ headline() }}</h6> }\r\n @default { <p class=\"cc__headline\">{{ headline() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #bcTitleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"bc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"bc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"bc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"bc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"bc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"bc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--image{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .14s ease-out,border-color .14s ease-out,border-width .14s ease-out}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .14s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--image:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--hero):not(.cc--image){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--filled .cc__button{border-color:transparent}.cc--image{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--hero{border-radius:var(--border-radius-sys-radius-xl)}.cc--hero{position:relative;display:flex;flex-direction:column;flex:1 1 auto;justify-content:flex-end;gap:var(--spacing-padding-sys-padding-24);min-height:22.5rem;padding:var(--spacing-padding-sys-padding-48)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc--hero>.cc__media-icon{margin-bottom:auto}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__img-foot--end{justify-content:flex-end}.cc__hero-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__eyebrow{margin:0;font-family:var(--title-large-sys-font-family);font-size:var(--title-large-sys-font-size);line-height:var(--title-large-sys-line-height);letter-spacing:var(--title-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__headline{margin:0;font-family:var(--display-large-sys-font-family);font-size:var(--display-large-sys-font-size);line-height:var(--display-large-sys-line-height);font-weight:var(--display-large-sys-font-weight);letter-spacing:var(--display-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}.cc__button--solid{align-self:flex-end;flex-shrink:0;border-color:transparent;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);box-shadow:0 .125rem .25rem #0000000f,0 .125rem .5rem #0000000a}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__button--solid{align-self:flex-start}}.cc--image .cc__title,.cc--image .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--image .cc__subtitle,.cc--image .cc__desc{color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__button{align-self:flex-start;display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-32);border-radius:var(--border-radius-sys-radius-full);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);white-space:nowrap}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--image{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--image .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--image .bc--row .bc__title,:host.cmp-card--image .bc--row .bc__icon,:host.cmp-card--image .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc__button--end{align-self:flex-end}.bc--promo.bc--image .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--image .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--image .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}:host.cmp-card--filled .bc__button{border-color:transparent}\n"] }]
210
- }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], imageSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageSrc", required: false }] }], imagePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "imagePosition", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], category: [{ type: i0.Input, args: [{ isSignal: true, alias: "category", required: false }] }], categoryStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryStyle", required: false }] }], iconStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconStyle", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], headline: [{ type: i0.Input, args: [{ isSignal: true, alias: "headline", required: false }] }], actionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLabel", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], trailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIcon", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }] } });
213
+ }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], imageSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageSrc", required: false }] }], imagePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "imagePosition", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], category: [{ type: i0.Input, args: [{ isSignal: true, alias: "category", required: false }] }], categoryStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryStyle", required: false }] }], iconStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconStyle", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], headline: [{ type: i0.Input, args: [{ isSignal: true, alias: "headline", required: false }] }], actionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLabel", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], trailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIcon", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }] } });
211
214
  //# sourceMappingURL=card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/card-base/card.ts","../../../../../../packages/angular/src/lib/card-base/card.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,MAAM,EACN,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;;;AA8BrD;;;;;;;;;;;;;;;;;;;;GAoBG;AA0CH,MAAM,OAAO,aAAa;IACxB,2DAA2D;IAC3D,0DAA0D;IACjD,OAAO,GAAG,KAAK,CAAc,OAAO,8EAAC,CAAC;IAC/C,iDAAiD;IACxC,UAAU,GAAG,KAAK,CAAiB,UAAU,iFAAC,CAAC;IACxD,oDAAoD;IAC3C,MAAM,GAAG,KAAK,CAAa,IAAI,6EAAC,CAAC;IAC1C,2EAA2E;IAClE,OAAO,GAAG,KAAK,CAAc,IAAI,8EAAC,CAAC;IAC5C,4EAA4E;IACnE,IAAI,GAAG,KAAK,CAAW,IAAI,2EAAC,CAAC;IACtC,kFAAkF;IACzE,WAAW,GAAG,KAAK,CAAU,KAAK,kFAAC,CAAC;IAC7C,yCAAyC;IAChC,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC,CAAC;IAC1C,qDAAqD;IAC5C,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;OAGG;IACM,aAAa,GAAG,KAAK,CAAS,QAAQ,oFAAC,CAAC;IAEjD,2DAA2D;IAC3D,8DAA8D;IACrD,IAAI,GAAG,KAAK,CAAS,EAAE,2EAAC,CAAC;IAClC,mCAAmC;IAC1B,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;;OAIG;IACM,aAAa,GAAG,KAAK,CAAoB,MAAM,oFAAC,CAAC;IAC1D;;;;OAIG;IACM,SAAS,GAAG,KAAK,CAAgB,SAAS,gFAAC,CAAC;IACrD,sBAAsB;IACb,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,yBAAyB;IAChB,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,8CAA8C;IACrC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,yEAAyE;IAChE,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,iDAAiD;IACxC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,4DAA4D;IACnD,SAAS,GAAG,KAAK,CAAU,IAAI,gFAAC,CAAC;IAE1C,2DAA2D;IAC3D,oCAAoC;IAC3B,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,wDAAwD;IAC/C,YAAY,GAAG,KAAK,CAAS,gBAAgB,mFAAC,CAAC;IACxD,kCAAkC;IACzB,WAAW,GAAG,KAAK,CAAkB,YAAY,kFAAC,CAAC;IAE5D,2DAA2D;IAC3D,mCAAmC;IAC1B,KAAK,GAAG,KAAK,CAAkB,EAAE,4EAAC,CAAC;IAC5C,8DAA8D;IACrD,OAAO,GAAG,KAAK,CAAU,KAAK,8EAAC,CAAC;IAEzC,2DAA2D;IAC3D;;;;;;OAMG;IACM,YAAY,GAAG,KAAK,CAA+B,SAAS,mFAAC,CAAC;IACvE;;;;;OAKG;IACM,SAAS,GAAG,KAAK,CAAqB,SAAS,iFAAI,KAAK,EAAE,YAAY,GAAG,CAAC;IAEnF,wEAAwE;IAC/D,SAAS,GAAG,MAAM,EAAQ,CAAC;IAEnB,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAEzC,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,OAAO,8EAAC,CAAC;IAEjE;;;;OAIG;IACM,qBAAqB,GAAG,QAAQ,CAAC,GAAG,EAAE,CAC7C,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,4FACrD,CAAC;IAEF,4EAA4E;IACnE,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,oFAAC,CAAC;IACtG,mEAAmE;IAC1D,cAAc,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,qFAAC,CAAC;IAE3E,wEAAwE;IAC/D,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,+EAAC,CAAC;IAEH,wEAAwE;IAC/D,gBAAgB,GAAG,QAAQ,CAAc,GAAG,EAAE;QACrD,QAAQ,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACvB,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3D,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,CAAC,wCAAwC;YACvD,KAAK,OAAO;gBACV,OAAO,MAAM,CAAC,CAAC,gEAAgE;YACjF,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,CAAC,yCAAyC;YACxD;gBACE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC,uFAAC,CAAC;IAEH;QACE,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,SAAS,CAAC,KAAoB;QAC5B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO;QACzB,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;YAAE,OAAO;QACvD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,4DAA4D;IAC5D,OAAO,CAAC,IAAY,EAAE,IAAY,EAAE,WAAW,GAAG,IAAI;QACpD,IAAI,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,IAAI,aAAa,IAAI,IAAI,CAAC,CAAC;QACrE,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;YACxB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,iBAAiB,WAAW,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;wGA5JU,aAAa;4FAAb,aAAa,+qKCxG1B,g6ZA+QA,kxrBD5MY,gBAAgB;;4FAqCf,aAAa;kBAzCzB,SAAS;+BACE,eAAe,cACb,IAAI,mBACC,uBAAuB,CAAC,MAAM,WACtC,CAAC,gBAAgB,CAAC,kBACX,CAAC,eAAe,CAAC,QAG3B;wBACJ,KAAK,EAAE,UAAU;wBACjB,4BAA4B,EAAE,6BAA6B;wBAC3D,0BAA0B,EAAE,2BAA2B;wBACvD,4BAA4B,EAAE,6BAA6B;wBAC3D,yBAAyB,EAAE,0BAA0B;wBACrD,2BAA2B,EAAE,yBAAyB;wBACtD,yBAAyB,EAAE,uBAAuB;wBAClD,uBAAuB,EAAE,uCAAuC;wBAChE,wBAAwB,EAAE,yCAAyC;wBACnE,0BAA0B,EAAE,wBAAwB;wBACpD,2BAA2B,EAAE,qCAAqC;wBAClE,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,4BAA4B,EAAE,+BAA+B;wBAC7D,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,+BAA+B,EAAE,eAAe;wBAChD,4BAA4B,EAAE,YAAY;wBAC1C,aAAa,EAAE,iCAAiC;wBAChD,iBAAiB,EAAE,yCAAyC;wBAC5D,mBAAmB,EAAE,qBAAqB;wBAC1C,sBAAsB,EAAE,oBAAoB;wBAC5C,qBAAqB,EAAE,4DAA4D;wBACnF,sBAAsB,EAAE,kFAAkF;wBAC1G,sBAAsB,EAAE,qFAAqF;wBAC7G,SAAS,EAAE,cAAc;wBACzB,WAAW,EAAE,mBAAmB;qBACjC","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { RippleDirective } from './ripple.directive';\r\n\r\n/**\r\n * Card type — selects the projected/laid-out content. Mirrors the library's `variant` pattern.\r\n * `basic` is the Figma \"cards\" section (the \"Card Item\" family: icon + arrow +\r\n * title/subtitle, sized, across the outlined/filled/gradient/image surfaces) —\r\n * distinct from the `content` category tiles.\r\n */\r\nexport type CardVariant = 'basic' | 'content' | 'action' | 'metric';\r\n/** Visual surface treatment. Mirrors the Figma \"Card Item\" Style property. */\r\nexport type CardAppearance = 'outlined' | 'filled' | 'gradient' | 'image';\r\n/** Corner radius token: `md` (12px), `lg` (16px), `xl` (24px). */\r\nexport type CardRadius = 'md' | 'lg' | 'xl';\r\n/** Inner padding token (used by `variant=\"basic\"`; typed variants size themselves). */\r\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl';\r\n/** Action-card layout. */\r\nexport type CardOrientation = 'horizontal' | 'vertical';\r\n/** Base Card Item size (Figma \"Size\" property). Drives layout + type scale. */\r\nexport type CardSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs';\r\n/** Heading level for the title / hero headline / action label (screen-reader heading semantics). */\r\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\r\n/** How the content-variant category renders: trailing pill (`chip`) or leading plain-text `label`. */\r\nexport type CardCategoryStyle = 'chip' | 'label';\r\n/**\r\n * Content-variant icon badge treatment:\r\n * - `primary` — white icon on a filled primary (blue) circle (default, unchanged).\r\n * - `neutral` — dark (on-surface) icon on a white circle with a thin outline.\r\n */\r\nexport type CardIconStyle = 'primary' | 'neutral';\r\n\r\n/**\r\n * Card — the single Cards component for the ComPsych Design System.\r\n *\r\n * Figma: Core Components — \"Cards\" (file VFBn7KCDy3FSIlvhNo3ylq, 1117:9829).\r\n *\r\n * One component, switched by `variant` (like Accordion's `variant`):\r\n * - `basic` — a bare surface; project your own content.\r\n * - `content` — icon badge / image, category chip, title, subtitle, description,\r\n * action pill, arrow; hero (`headline`) layout.\r\n * - `action` — compact interactive row (icon · label/description · arrow); horizontal/vertical.\r\n * - `metric` — centered value + label; `current` (selected) state.\r\n *\r\n * `appearance` is the orthogonal surface skin (outlined / filled / gradient / image).\r\n * When `interactive`, the whole card is a button (role/tabindex/keyboard) with the\r\n * hover / focus / pressed ripple. All values are sys design tokens.\r\n *\r\n * <compsych-card variant=\"content\" appearance=\"gradient\" icon=\"circle-play\"\r\n * category=\"Video\" title=\"Mindful breathing\" actionLabel=\"Watch\" [interactive]=\"true\" />\r\n * <compsych-card variant=\"metric\" value=\"24\" label=\"Sessions\" [current]=\"true\" [interactive]=\"true\" />\r\n * <compsych-card>Projected content</compsych-card>\r\n */\r\n@Component({\r\n selector: 'compsych-card',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [NgTemplateOutlet],\r\n hostDirectives: [RippleDirective],\r\n templateUrl: './card.html',\r\n styleUrl: './card.css',\r\n host: {\r\n class: 'cmp-card',\r\n '[class.cmp-card--outlined]': \"appearance() === 'outlined'\",\r\n '[class.cmp-card--filled]': \"appearance() === 'filled'\",\r\n '[class.cmp-card--gradient]': \"appearance() === 'gradient'\",\r\n '[class.cmp-card--image]': \"appearance() === 'image'\",\r\n '[class.cmp-card--content]': \"variant() === 'content'\",\r\n '[class.cmp-card--basic]': \"variant() === 'basic'\",\r\n '[attr.data-card-size]': \"variant() === 'basic' ? size() : null\",\r\n '[class.cmp-card--hero]': \"variant() === 'content' && !!headline()\",\r\n '[class.cmp-card--metric]': \"variant() === 'metric'\",\r\n '[class.cmp-card--current]': \"variant() === 'metric' && current()\",\r\n '[class.cmp-card--radius-md]': \"radius() === 'md'\",\r\n '[class.cmp-card--radius-lg]': \"radius() === 'lg'\",\r\n '[class.cmp-card--radius-xl]': \"radius() === 'xl'\",\r\n '[class.cmp-card--pad-none]': \"effectivePadding() === 'none'\",\r\n '[class.cmp-card--pad-sm]': \"effectivePadding() === 'sm'\",\r\n '[class.cmp-card--pad-md]': \"effectivePadding() === 'md'\",\r\n '[class.cmp-card--pad-lg]': \"effectivePadding() === 'lg'\",\r\n '[class.cmp-card--pad-xl]': \"effectivePadding() === 'xl'\",\r\n '[class.cmp-card--interactive]': 'interactive()',\r\n '[class.cmp-card--disabled]': 'disabled()',\r\n '[attr.role]': \"interactive() ? 'button' : null\",\r\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\r\n '[attr.aria-label]': 'ariaLabel() ?? null',\r\n '[attr.aria-disabled]': 'disabled() || null',\r\n '[attr.aria-pressed]': \"interactive() && variant() === 'metric' ? current() : null\",\r\n '[style.border-color]': \"variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null\",\r\n '[style.border-width]': \"variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null\",\r\n '(click)': 'onActivate()',\r\n '(keydown)': 'onKeyDown($event)',\r\n },\r\n})\r\nexport class CardComponent {\r\n // ── Surface (all variants) ──────────────────────────────\r\n /** Card type. Defaults to `basic` (projected content). */\r\n readonly variant = input<CardVariant>('basic');\r\n /** Surface treatment. Defaults to `outlined`. */\r\n readonly appearance = input<CardAppearance>('outlined');\r\n /** Corner radius token. Defaults to `lg` (16px). */\r\n readonly radius = input<CardRadius>('lg');\r\n /** Inner padding for `variant=\"basic\"`. Typed variants size themselves. */\r\n readonly padding = input<CardPadding>('lg');\r\n /** Card Item size (`variant=\"basic\"`): xl/lg/md/sm/xs. Defaults to `md`. */\r\n readonly size = input<CardSize>('md');\r\n /** Whole-card click target: adds role/tabindex, hover/press states and ripple. */\r\n readonly interactive = input<boolean>(false);\r\n /** Disabled visual + non-interactive. */\r\n readonly disabled = input<boolean>(false);\r\n /** Background image URL for `appearance=\"image\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * `background-position` for the `image` appearance media (e.g. `'85% 0'` for an\r\n * off-center hero). Defaults to `'center'` — unchanged from before.\r\n */\r\n readonly imagePosition = input<string>('center');\r\n\r\n // ── Content variant ─────────────────────────────────────\r\n /** Lucide icon name (content badge / action leading icon). */\r\n readonly icon = input<string>('');\r\n /** Content: category chip text. */\r\n readonly category = input<string>('');\r\n /**\r\n * Content: how the category renders — `'chip'` (default) as the trailing pill,\r\n * or `'label'` as a leading plain-text label beside the icon. Opt-in; default\r\n * keeps the existing chip.\r\n */\r\n readonly categoryStyle = input<CardCategoryStyle>('chip');\r\n /**\r\n * Content: icon badge treatment — `'primary'` (default) is a white icon on a\r\n * filled primary (blue) circle; `'neutral'` is a dark icon on a white circle\r\n * with a thin outline. Opt-in; default keeps the existing primary badge.\r\n */\r\n readonly iconStyle = input<CardIconStyle>('primary');\r\n /** Content: title. */\r\n readonly title = input<string>('');\r\n /** Content: subtitle. */\r\n readonly subtitle = input<string>('');\r\n /** Content/action: supporting description. */\r\n readonly description = input<string>('');\r\n /** Content: large hero display text (switches to the XL hero layout). */\r\n readonly headline = input<string>('');\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n\r\n // ── Action variant ──────────────────────────────────────\r\n /** Action/metric: primary label. */\r\n readonly label = input<string>('');\r\n /** Action: trailing Lucide icon (horizontal layout). */\r\n readonly trailingIcon = input<string>('arrow-up-right');\r\n /** Action: layout orientation. */\r\n readonly orientation = input<CardOrientation>('horizontal');\r\n\r\n // ── Metric variant ──────────────────────────────────────\r\n /** Metric: the prominent value. */\r\n readonly value = input<string | number>('');\r\n /** Metric: selected/current state (primary border + text). */\r\n readonly current = input<boolean>(false);\r\n\r\n // ── Accessibility ───────────────────────────────────────\r\n /**\r\n * Opts the title / hero headline / action label into a heading in the\r\n * accessibility tree via `role=\"heading\"` + `aria-level`, so consumers that\r\n * replace real headings keep heading semantics and screen-reader heading\r\n * navigation (WCAG 1.3.1). Omit (default) to render as plain text — no visual\r\n * or behavioral change for existing usages.\r\n */\r\n readonly headingLevel = input<CardHeadingLevel | undefined>(undefined);\r\n /**\r\n * Accessible name for an `interactive` card (which is a `role=\"button\"`).\r\n * Required for image-only / icon-only interactive cards that have no text, and\r\n * useful to give text-heavy cards a concise name instead of their full content.\r\n * Bind as `aria-label`.\r\n */\r\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\r\n\r\n /** Emits on click / Enter / Space when interactive and not disabled. */\r\n readonly cardClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isImage = computed(() => this.appearance() === 'image');\r\n\r\n /**\r\n * Heading level actually applied. Suppressed when the whole card is interactive\r\n * (`role=\"button\"`), since a heading nested in a button isn't exposed as a\r\n * heading — the two would conflict.\r\n */\r\n readonly effectiveHeadingLevel = computed(() =>\r\n this.interactive() ? undefined : this.headingLevel(),\r\n );\r\n\r\n /** Base Card Item plain-icon glyph size by `size` (48 md, 32 sm, 24 xs). */\r\n readonly basicIconSize = computed(() => (this.size() === 'sm' ? 32 : this.size() === 'xs' ? 24 : 48));\r\n /** Base Card Item arrow glyph size by `size` (24 md, 20 sm/xs). */\r\n readonly basicArrowSize = computed(() => (this.size() === 'md' ? 24 : 20));\r\n\r\n /** CSS `url(...)` for the media layer, or null when no image is set. */\r\n readonly mediaUrl = computed(() => {\r\n const src = this.imageSrc();\r\n return src ? `url(\"${src}\")` : null;\r\n });\r\n\r\n /** Padding resolved per variant; `basic` honors the `padding` input. */\r\n readonly effectivePadding = computed<CardPadding>(() => {\r\n switch (this.variant()) {\r\n case 'content':\r\n return this.isImage() || this.headline() ? 'none' : 'sm';\r\n case 'action':\r\n return 'lg'; // 24px — Figma action card (60017:8036)\r\n case 'basic':\r\n return 'none'; // .bc controls its own padding per style (Figma Base Card Item)\r\n case 'metric':\r\n return 'lg'; // 24px — Figma metric card (60024:10073)\r\n default:\r\n return this.padding();\r\n }\r\n });\r\n\r\n constructor() {\r\n effect(() => {\r\n this.ripple.suppressed = !this.interactive() || this.disabled();\r\n });\r\n }\r\n\r\n onActivate(): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n this.cardClick.emit();\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n if (event.repeat) return;\r\n if (event.key !== 'Enter' && event.key !== ' ') return;\r\n event.preventDefault();\r\n this.cardClick.emit();\r\n }\r\n\r\n /** Renders a sized/weighted Lucide SVG for template use. */\r\n iconSvg(name: string, size: number, strokeWidth = 1.75): SafeHtml {\r\n let svg = LUCIDE_ICONS[name] ?? '';\r\n svg = svg.replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n if (strokeWidth !== 1.5) {\r\n svg = svg.replace('stroke-width=\"1.5\"', `stroke-width=\"${strokeWidth}\"`);\r\n }\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n}\r\n","@if (isImage() && mediaUrl()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (headline()) {\r\n <!-- Hero (image/filled): icon top-left, eyebrow + display headline + action bottom. -->\r\n <div class=\"cc cc--hero\" [class.cc--image]=\"isImage()\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n @if (icon()) {\r\n @if (isImage()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"cc__img-foot\">\r\n <div class=\"cc__hero-text\">\r\n @if (title()) { <p class=\"cc__eyebrow\">{{ title() }}</p> }\r\n <ng-container [ngTemplateOutlet]=\"headlineTpl\" />\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (isImage()) {\r\n <div class=\"cc cc--image\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || description()) {\r\n <div class=\"cc__hero-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"cc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else {\r\n <!-- With-icon content card (Figma 59444:2263): a full-width light-blue\r\n icon banner over a gray category eyebrow + title + body, with the\r\n text distributed top/bottom. Default for outlined/filled content. -->\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row — icon · title · arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--image]=\"isImage()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button bc__button--end\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else if (isImage()) {\r\n <!-- md image base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--image\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragments: render a real <h2>–<h6> when `headingLevel` is set, else the\r\n original <p>/<span>. Shared across layouts so semantics stay consistent and the\r\n cc__title / cc__headline / ac__label styling is unchanged. -->\r\n<ng-template #titleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"cc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"cc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"cc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"cc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"cc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #headlineTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__headline\">{{ headline() }}</h2> }\r\n @case (3) { <h3 class=\"cc__headline\">{{ headline() }}</h3> }\r\n @case (4) { <h4 class=\"cc__headline\">{{ headline() }}</h4> }\r\n @case (5) { <h5 class=\"cc__headline\">{{ headline() }}</h5> }\r\n @case (6) { <h6 class=\"cc__headline\">{{ headline() }}</h6> }\r\n @default { <p class=\"cc__headline\">{{ headline() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #bcTitleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"bc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"bc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"bc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"bc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"bc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"bc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n"]}
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/card-base/card.ts","../../../../../../packages/angular/src/lib/card-base/card.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,MAAM,EACN,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;;;AA8BrD;;;;;;;;;;;;;;;;;;;;GAoBG;AA2CH,MAAM,OAAO,aAAa;IACxB,2DAA2D;IAC3D,0DAA0D;IACjD,OAAO,GAAG,KAAK,CAAc,OAAO,8EAAC,CAAC;IAC/C,iDAAiD;IACxC,UAAU,GAAG,KAAK,CAAiB,UAAU,iFAAC,CAAC;IACxD,oDAAoD;IAC3C,MAAM,GAAG,KAAK,CAAa,IAAI,6EAAC,CAAC;IAC1C,2EAA2E;IAClE,OAAO,GAAG,KAAK,CAAc,IAAI,8EAAC,CAAC;IAC5C,4EAA4E;IACnE,IAAI,GAAG,KAAK,CAAW,IAAI,2EAAC,CAAC;IACtC,kFAAkF;IACzE,WAAW,GAAG,KAAK,CAAU,KAAK,kFAAC,CAAC;IAC7C,yCAAyC;IAChC,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC,CAAC;IAC1C,qDAAqD;IAC5C,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;OAGG;IACM,aAAa,GAAG,KAAK,CAAS,QAAQ,oFAAC,CAAC;IAEjD,2DAA2D;IAC3D,8DAA8D;IACrD,IAAI,GAAG,KAAK,CAAS,EAAE,2EAAC,CAAC;IAClC,mCAAmC;IAC1B,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;;OAIG;IACM,aAAa,GAAG,KAAK,CAAoB,MAAM,oFAAC,CAAC;IAC1D;;;;OAIG;IACM,SAAS,GAAG,KAAK,CAAgB,SAAS,gFAAC,CAAC;IACrD,sBAAsB;IACb,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,yBAAyB;IAChB,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,8CAA8C;IACrC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,yEAAyE;IAChE,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,iDAAiD;IACxC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,4DAA4D;IACnD,SAAS,GAAG,KAAK,CAAU,IAAI,gFAAC,CAAC;IAE1C,2DAA2D;IAC3D,oCAAoC;IAC3B,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,wDAAwD;IAC/C,YAAY,GAAG,KAAK,CAAS,gBAAgB,mFAAC,CAAC;IACxD,kCAAkC;IACzB,WAAW,GAAG,KAAK,CAAkB,YAAY,kFAAC,CAAC;IAC5D,+DAA+D;IACtD,SAAS,GAAG,KAAK,CAAU,KAAK,gFAAC,CAAC;IAE3C,2DAA2D;IAC3D,mCAAmC;IAC1B,KAAK,GAAG,KAAK,CAAkB,EAAE,4EAAC,CAAC;IAC5C,8DAA8D;IACrD,OAAO,GAAG,KAAK,CAAU,KAAK,8EAAC,CAAC;IAEzC,2DAA2D;IAC3D;;;;;;OAMG;IACM,YAAY,GAAG,KAAK,CAA+B,SAAS,mFAAC,CAAC;IACvE;;;;;OAKG;IACM,SAAS,GAAG,KAAK,CAAqB,SAAS,iFAAI,KAAK,EAAE,YAAY,GAAG,CAAC;IAEnF,wEAAwE;IAC/D,SAAS,GAAG,MAAM,EAAQ,CAAC;IAEnB,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAEzC,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,OAAO,8EAAC,CAAC;IAEjE;;;;OAIG;IACM,qBAAqB,GAAG,QAAQ,CAAC,GAAG,EAAE,CAC7C,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,4FACrD,CAAC;IAEF,4EAA4E;IACnE,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,oFAAC,CAAC;IACtG,mEAAmE;IAC1D,cAAc,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,qFAAC,CAAC;IAE3E,wEAAwE;IAC/D,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,+EAAC,CAAC;IAEH,wEAAwE;IAC/D,gBAAgB,GAAG,QAAQ,CAAc,GAAG,EAAE;QACrD,QAAQ,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACvB,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3D,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,CAAC,wCAAwC;YACvD,KAAK,OAAO;gBACV,OAAO,MAAM,CAAC,CAAC,gEAAgE;YACjF,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,CAAC,yCAAyC;YACxD;gBACE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC,uFAAC,CAAC;IAEH;QACE,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,SAAS,CAAC,KAAoB;QAC5B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO;QACzB,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;YAAE,OAAO;QACvD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,4DAA4D;IAC5D,OAAO,CAAC,IAAY,EAAE,IAAY,EAAE,WAAW,GAAG,IAAI;QACpD,IAAI,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,IAAI,aAAa,IAAI,IAAI,CAAC,CAAC;QACrE,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;YACxB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,iBAAiB,WAAW,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;wGA9JU,aAAa;4FAAb,aAAa,i2KCzG1B,g6ZA+QA,kxrBD5MY,gBAAgB;;4FAsCf,aAAa;kBA1CzB,SAAS;+BACE,eAAe,cACb,IAAI,mBACC,uBAAuB,CAAC,MAAM,WACtC,CAAC,gBAAgB,CAAC,kBACX,CAAC,eAAe,CAAC,QAG3B;wBACJ,KAAK,EAAE,UAAU;wBACjB,4BAA4B,EAAE,6BAA6B;wBAC3D,0BAA0B,EAAE,2BAA2B;wBACvD,4BAA4B,EAAE,6BAA6B;wBAC3D,yBAAyB,EAAE,0BAA0B;wBACrD,2BAA2B,EAAE,yBAAyB;wBACtD,yBAAyB,EAAE,uBAAuB;wBAClD,uBAAuB,EAAE,uCAAuC;wBAChE,wBAAwB,EAAE,yCAAyC;wBACnE,0BAA0B,EAAE,wBAAwB;wBACpD,2BAA2B,EAAE,qCAAqC;wBAClE,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,4BAA4B,EAAE,+BAA+B;wBAC7D,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,eAAe,EAAE,6BAA6B;wBAC9C,+BAA+B,EAAE,eAAe;wBAChD,4BAA4B,EAAE,YAAY;wBAC1C,aAAa,EAAE,iCAAiC;wBAChD,iBAAiB,EAAE,yCAAyC;wBAC5D,mBAAmB,EAAE,qBAAqB;wBAC1C,sBAAsB,EAAE,oBAAoB;wBAC5C,qBAAqB,EAAE,4DAA4D;wBACnF,sBAAsB,EAAE,kFAAkF;wBAC1G,sBAAsB,EAAE,qFAAqF;wBAC7G,SAAS,EAAE,cAAc;wBACzB,WAAW,EAAE,mBAAmB;qBACjC","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { RippleDirective } from './ripple.directive';\r\n\r\n/**\r\n * Card type — selects the projected/laid-out content. Mirrors the library's `variant` pattern.\r\n * `basic` is the Figma \"cards\" section (the \"Card Item\" family: icon + arrow +\r\n * title/subtitle, sized, across the outlined/filled/gradient/image surfaces) —\r\n * distinct from the `content` category tiles.\r\n */\r\nexport type CardVariant = 'basic' | 'content' | 'action' | 'metric';\r\n/** Visual surface treatment. Mirrors the Figma \"Card Item\" Style property. */\r\nexport type CardAppearance = 'outlined' | 'filled' | 'gradient' | 'image';\r\n/** Corner radius token: `md` (12px), `lg` (16px), `xl` (24px). */\r\nexport type CardRadius = 'md' | 'lg' | 'xl';\r\n/** Inner padding token (used by `variant=\"basic\"`; typed variants size themselves). */\r\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl';\r\n/** Action-card layout. */\r\nexport type CardOrientation = 'horizontal' | 'vertical';\r\n/** Base Card Item size (Figma \"Size\" property). Drives layout + type scale. */\r\nexport type CardSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs';\r\n/** Heading level for the title / hero headline / action label (screen-reader heading semantics). */\r\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\r\n/** How the content-variant category renders: trailing pill (`chip`) or leading plain-text `label`. */\r\nexport type CardCategoryStyle = 'chip' | 'label';\r\n/**\r\n * Content-variant icon badge treatment:\r\n * - `primary` — white icon on a filled primary (blue) circle (default, unchanged).\r\n * - `neutral` — dark (on-surface) icon on a white circle with a thin outline.\r\n */\r\nexport type CardIconStyle = 'primary' | 'neutral';\r\n\r\n/**\r\n * Card — the single Cards component for the ComPsych Design System.\r\n *\r\n * Figma: Core Components — \"Cards\" (file VFBn7KCDy3FSIlvhNo3ylq, 1117:9829).\r\n *\r\n * One component, switched by `variant` (like Accordion's `variant`):\r\n * - `basic` — a bare surface; project your own content.\r\n * - `content` — icon badge / image, category chip, title, subtitle, description,\r\n * action pill, arrow; hero (`headline`) layout.\r\n * - `action` — compact interactive row (icon · label/description · arrow); horizontal/vertical.\r\n * - `metric` — centered value + label; `current` (selected) state.\r\n *\r\n * `appearance` is the orthogonal surface skin (outlined / filled / gradient / image).\r\n * When `interactive`, the whole card is a button (role/tabindex/keyboard) with the\r\n * hover / focus / pressed ripple. All values are sys design tokens.\r\n *\r\n * <compsych-card variant=\"content\" appearance=\"gradient\" icon=\"circle-play\"\r\n * category=\"Video\" title=\"Mindful breathing\" actionLabel=\"Watch\" [interactive]=\"true\" />\r\n * <compsych-card variant=\"metric\" value=\"24\" label=\"Sessions\" [current]=\"true\" [interactive]=\"true\" />\r\n * <compsych-card>Projected content</compsych-card>\r\n */\r\n@Component({\r\n selector: 'compsych-card',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [NgTemplateOutlet],\r\n hostDirectives: [RippleDirective],\r\n templateUrl: './card.html',\r\n styleUrl: './card.css',\r\n host: {\r\n class: 'cmp-card',\r\n '[class.cmp-card--outlined]': \"appearance() === 'outlined'\",\r\n '[class.cmp-card--filled]': \"appearance() === 'filled'\",\r\n '[class.cmp-card--gradient]': \"appearance() === 'gradient'\",\r\n '[class.cmp-card--image]': \"appearance() === 'image'\",\r\n '[class.cmp-card--content]': \"variant() === 'content'\",\r\n '[class.cmp-card--basic]': \"variant() === 'basic'\",\r\n '[attr.data-card-size]': \"variant() === 'basic' ? size() : null\",\r\n '[class.cmp-card--hero]': \"variant() === 'content' && !!headline()\",\r\n '[class.cmp-card--metric]': \"variant() === 'metric'\",\r\n '[class.cmp-card--current]': \"variant() === 'metric' && current()\",\r\n '[class.cmp-card--radius-md]': \"radius() === 'md'\",\r\n '[class.cmp-card--radius-lg]': \"radius() === 'lg'\",\r\n '[class.cmp-card--radius-xl]': \"radius() === 'xl'\",\r\n '[class.cmp-card--pad-none]': \"effectivePadding() === 'none'\",\r\n '[class.cmp-card--pad-sm]': \"effectivePadding() === 'sm'\",\r\n '[class.cmp-card--pad-md]': \"effectivePadding() === 'md'\",\r\n '[class.cmp-card--pad-lg]': \"effectivePadding() === 'lg'\",\r\n '[class.cmp-card--pad-xl]': \"effectivePadding() === 'xl'\",\r\n '[style.width]': \"fullWidth() ? '100%' : null\",\r\n '[class.cmp-card--interactive]': 'interactive()',\r\n '[class.cmp-card--disabled]': 'disabled()',\r\n '[attr.role]': \"interactive() ? 'button' : null\",\r\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\r\n '[attr.aria-label]': 'ariaLabel() ?? null',\r\n '[attr.aria-disabled]': 'disabled() || null',\r\n '[attr.aria-pressed]': \"interactive() && variant() === 'metric' ? current() : null\",\r\n '[style.border-color]': \"variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null\",\r\n '[style.border-width]': \"variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null\",\r\n '(click)': 'onActivate()',\r\n '(keydown)': 'onKeyDown($event)',\r\n },\r\n})\r\nexport class CardComponent {\r\n // ── Surface (all variants) ──────────────────────────────\r\n /** Card type. Defaults to `basic` (projected content). */\r\n readonly variant = input<CardVariant>('basic');\r\n /** Surface treatment. Defaults to `outlined`. */\r\n readonly appearance = input<CardAppearance>('outlined');\r\n /** Corner radius token. Defaults to `lg` (16px). */\r\n readonly radius = input<CardRadius>('lg');\r\n /** Inner padding for `variant=\"basic\"`. Typed variants size themselves. */\r\n readonly padding = input<CardPadding>('lg');\r\n /** Card Item size (`variant=\"basic\"`): xl/lg/md/sm/xs. Defaults to `md`. */\r\n readonly size = input<CardSize>('md');\r\n /** Whole-card click target: adds role/tabindex, hover/press states and ripple. */\r\n readonly interactive = input<boolean>(false);\r\n /** Disabled visual + non-interactive. */\r\n readonly disabled = input<boolean>(false);\r\n /** Background image URL for `appearance=\"image\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * `background-position` for the `image` appearance media (e.g. `'85% 0'` for an\r\n * off-center hero). Defaults to `'center'` — unchanged from before.\r\n */\r\n readonly imagePosition = input<string>('center');\r\n\r\n // ── Content variant ─────────────────────────────────────\r\n /** Lucide icon name (content badge / action leading icon). */\r\n readonly icon = input<string>('');\r\n /** Content: category chip text. */\r\n readonly category = input<string>('');\r\n /**\r\n * Content: how the category renders — `'chip'` (default) as the trailing pill,\r\n * or `'label'` as a leading plain-text label beside the icon. Opt-in; default\r\n * keeps the existing chip.\r\n */\r\n readonly categoryStyle = input<CardCategoryStyle>('chip');\r\n /**\r\n * Content: icon badge treatment — `'primary'` (default) is a white icon on a\r\n * filled primary (blue) circle; `'neutral'` is a dark icon on a white circle\r\n * with a thin outline. Opt-in; default keeps the existing primary badge.\r\n */\r\n readonly iconStyle = input<CardIconStyle>('primary');\r\n /** Content: title. */\r\n readonly title = input<string>('');\r\n /** Content: subtitle. */\r\n readonly subtitle = input<string>('');\r\n /** Content/action: supporting description. */\r\n readonly description = input<string>('');\r\n /** Content: large hero display text (switches to the XL hero layout). */\r\n readonly headline = input<string>('');\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n\r\n // ── Action variant ──────────────────────────────────────\r\n /** Action/metric: primary label. */\r\n readonly label = input<string>('');\r\n /** Action: trailing Lucide icon (horizontal layout). */\r\n readonly trailingIcon = input<string>('arrow-up-right');\r\n /** Action: layout orientation. */\r\n readonly orientation = input<CardOrientation>('horizontal');\r\n /** Action: stretch the card to 100% of its container width. */\r\n readonly fullWidth = input<boolean>(false);\r\n\r\n // ── Metric variant ──────────────────────────────────────\r\n /** Metric: the prominent value. */\r\n readonly value = input<string | number>('');\r\n /** Metric: selected/current state (primary border + text). */\r\n readonly current = input<boolean>(false);\r\n\r\n // ── Accessibility ───────────────────────────────────────\r\n /**\r\n * Opts the title / hero headline / action label into a heading in the\r\n * accessibility tree via `role=\"heading\"` + `aria-level`, so consumers that\r\n * replace real headings keep heading semantics and screen-reader heading\r\n * navigation (WCAG 1.3.1). Omit (default) to render as plain text — no visual\r\n * or behavioral change for existing usages.\r\n */\r\n readonly headingLevel = input<CardHeadingLevel | undefined>(undefined);\r\n /**\r\n * Accessible name for an `interactive` card (which is a `role=\"button\"`).\r\n * Required for image-only / icon-only interactive cards that have no text, and\r\n * useful to give text-heavy cards a concise name instead of their full content.\r\n * Bind as `aria-label`.\r\n */\r\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\r\n\r\n /** Emits on click / Enter / Space when interactive and not disabled. */\r\n readonly cardClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isImage = computed(() => this.appearance() === 'image');\r\n\r\n /**\r\n * Heading level actually applied. Suppressed when the whole card is interactive\r\n * (`role=\"button\"`), since a heading nested in a button isn't exposed as a\r\n * heading — the two would conflict.\r\n */\r\n readonly effectiveHeadingLevel = computed(() =>\r\n this.interactive() ? undefined : this.headingLevel(),\r\n );\r\n\r\n /** Base Card Item plain-icon glyph size by `size` (48 md, 32 sm, 24 xs). */\r\n readonly basicIconSize = computed(() => (this.size() === 'sm' ? 32 : this.size() === 'xs' ? 24 : 48));\r\n /** Base Card Item arrow glyph size by `size` (24 md, 20 sm/xs). */\r\n readonly basicArrowSize = computed(() => (this.size() === 'md' ? 24 : 20));\r\n\r\n /** CSS `url(...)` for the media layer, or null when no image is set. */\r\n readonly mediaUrl = computed(() => {\r\n const src = this.imageSrc();\r\n return src ? `url(\"${src}\")` : null;\r\n });\r\n\r\n /** Padding resolved per variant; `basic` honors the `padding` input. */\r\n readonly effectivePadding = computed<CardPadding>(() => {\r\n switch (this.variant()) {\r\n case 'content':\r\n return this.isImage() || this.headline() ? 'none' : 'sm';\r\n case 'action':\r\n return 'lg'; // 24px — Figma action card (60017:8036)\r\n case 'basic':\r\n return 'none'; // .bc controls its own padding per style (Figma Base Card Item)\r\n case 'metric':\r\n return 'lg'; // 24px — Figma metric card (60024:10073)\r\n default:\r\n return this.padding();\r\n }\r\n });\r\n\r\n constructor() {\r\n effect(() => {\r\n this.ripple.suppressed = !this.interactive() || this.disabled();\r\n });\r\n }\r\n\r\n onActivate(): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n this.cardClick.emit();\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n if (event.repeat) return;\r\n if (event.key !== 'Enter' && event.key !== ' ') return;\r\n event.preventDefault();\r\n this.cardClick.emit();\r\n }\r\n\r\n /** Renders a sized/weighted Lucide SVG for template use. */\r\n iconSvg(name: string, size: number, strokeWidth = 1.75): SafeHtml {\r\n let svg = LUCIDE_ICONS[name] ?? '';\r\n svg = svg.replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n if (strokeWidth !== 1.5) {\r\n svg = svg.replace('stroke-width=\"1.5\"', `stroke-width=\"${strokeWidth}\"`);\r\n }\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n}\r\n","@if (isImage() && mediaUrl()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (headline()) {\r\n <!-- Hero (image/filled): icon top-left, eyebrow + display headline + action bottom. -->\r\n <div class=\"cc cc--hero\" [class.cc--image]=\"isImage()\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n @if (icon()) {\r\n @if (isImage()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"cc__img-foot\">\r\n <div class=\"cc__hero-text\">\r\n @if (title()) { <p class=\"cc__eyebrow\">{{ title() }}</p> }\r\n <ng-container [ngTemplateOutlet]=\"headlineTpl\" />\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (isImage()) {\r\n <div class=\"cc cc--image\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || description()) {\r\n <div class=\"cc__hero-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <span class=\"cc__button cc__button--solid\">{{ actionLabel() }}</span>\r\n } @else if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"cc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else {\r\n <!-- With-icon content card (Figma 59444:2263): a full-width light-blue\r\n icon banner over a gray category eyebrow + title + body, with the\r\n text distributed top/bottom. Default for outlined/filled content. -->\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\">\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"titleTpl\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row — icon · title · arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--image]=\"isImage()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button bc__button--end\">{{ actionLabel() }}</span> }\r\n </div>\r\n } @else if (isImage()) {\r\n <!-- md image base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--image\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"bcTitleTpl\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <span class=\"bc__button\">{{ actionLabel() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragments: render a real <h2>–<h6> when `headingLevel` is set, else the\r\n original <p>/<span>. Shared across layouts so semantics stay consistent and the\r\n cc__title / cc__headline / ac__label styling is unchanged. -->\r\n<ng-template #titleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"cc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"cc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"cc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"cc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"cc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #headlineTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"cc__headline\">{{ headline() }}</h2> }\r\n @case (3) { <h3 class=\"cc__headline\">{{ headline() }}</h3> }\r\n @case (4) { <h4 class=\"cc__headline\">{{ headline() }}</h4> }\r\n @case (5) { <h5 class=\"cc__headline\">{{ headline() }}</h5> }\r\n @case (6) { <h6 class=\"cc__headline\">{{ headline() }}</h6> }\r\n @default { <p class=\"cc__headline\">{{ headline() }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #bcTitleTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"bc__title\">{{ title() }}</h2> }\r\n @case (3) { <h3 class=\"bc__title\">{{ title() }}</h3> }\r\n @case (4) { <h4 class=\"bc__title\">{{ title() }}</h4> }\r\n @case (5) { <h5 class=\"bc__title\">{{ title() }}</h5> }\r\n @case (6) { <h6 class=\"bc__title\">{{ title() }}</h6> }\r\n @default { <p class=\"bc__title\">{{ title() }}</p> }\r\n }\r\n</ng-template>\r\n"]}
@@ -46,6 +46,13 @@ export declare class ButtonComponent implements OnChanges {
46
46
  fullWidth: boolean;
47
47
  /** Mirrors `fullWidth` onto the host so it can stretch. */
48
48
  get hostFullWidth(): boolean;
49
+ /**
50
+ * Marks the host non-interactive while disabled or loading. The inner `<button>` sets
51
+ * `pointer-events: none` when disabled, so without this a click lands on the host wrapper
52
+ * instead — firing any `(click)` a consumer bound on `<compsych-button>`. Blocking pointer
53
+ * events at the host too makes the disabled state honour its "non-interactive" contract.
54
+ */
55
+ get hostNonInteractive(): boolean;
49
56
  /** Pre-sanitized icon markup, recomputed on input change (avoids re-sanitizing every CD cycle). */
50
57
  protected leadingIconSvg: SafeHtml | null;
51
58
  protected trailingIconSvg: SafeHtml | null;
@@ -105,6 +105,8 @@ export declare class CardComponent {
105
105
  readonly trailingIcon: import("@angular/core").InputSignal<string>;
106
106
  /** Action: layout orientation. */
107
107
  readonly orientation: import("@angular/core").InputSignal<CardOrientation>;
108
+ /** Action: stretch the card to 100% of its container width. */
109
+ readonly fullWidth: import("@angular/core").InputSignal<boolean>;
108
110
  /** Metric: the prominent value. */
109
111
  readonly value: import("@angular/core").InputSignal<string | number>;
110
112
  /** Metric: selected/current state (primary border + text). */
@@ -149,5 +151,5 @@ export declare class CardComponent {
149
151
  /** Renders a sized/weighted Lucide SVG for template use. */
150
152
  iconSvg(name: string, size: number, strokeWidth?: number): SafeHtml;
151
153
  static ɵfac: i0.ɵɵFactoryDeclaration<CardComponent, never>;
152
- static ɵcmp: i0.ɵɵComponentDeclaration<CardComponent, "compsych-card", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; "radius": { "alias": "radius"; "required": false; "isSignal": true; }; "padding": { "alias": "padding"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "imageSrc": { "alias": "imageSrc"; "required": false; "isSignal": true; }; "imagePosition": { "alias": "imagePosition"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "category": { "alias": "category"; "required": false; "isSignal": true; }; "categoryStyle": { "alias": "categoryStyle"; "required": false; "isSignal": true; }; "iconStyle": { "alias": "iconStyle"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "headline": { "alias": "headline"; "required": false; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "showArrow": { "alias": "showArrow"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "trailingIcon": { "alias": "trailingIcon"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "current": { "alias": "current"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, ["*"], true, [{ directive: typeof i1.RippleDirective; inputs: {}; outputs: {}; }]>;
154
+ static ɵcmp: i0.ɵɵComponentDeclaration<CardComponent, "compsych-card", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "appearance": { "alias": "appearance"; "required": false; "isSignal": true; }; "radius": { "alias": "radius"; "required": false; "isSignal": true; }; "padding": { "alias": "padding"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "imageSrc": { "alias": "imageSrc"; "required": false; "isSignal": true; }; "imagePosition": { "alias": "imagePosition"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "category": { "alias": "category"; "required": false; "isSignal": true; }; "categoryStyle": { "alias": "categoryStyle"; "required": false; "isSignal": true; }; "iconStyle": { "alias": "iconStyle"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "subtitle": { "alias": "subtitle"; "required": false; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; "headline": { "alias": "headline"; "required": false; "isSignal": true; }; "actionLabel": { "alias": "actionLabel"; "required": false; "isSignal": true; }; "showArrow": { "alias": "showArrow"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "trailingIcon": { "alias": "trailingIcon"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "current": { "alias": "current"; "required": false; "isSignal": true; }; "headingLevel": { "alias": "headingLevel"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, ["*"], true, [{ directive: typeof i1.RippleDirective; inputs: {}; outputs: {}; }]>;
153
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compsych-ui-components/angular",
3
- "version": "7.0.19",
3
+ "version": "7.0.21",
4
4
  "description": "Angular UI components for compsych",
5
5
  "publishConfig": {
6
6
  "access": "public",