@compsych-ui-components/angular 7.0.46 → 7.0.47

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.
@@ -91,7 +91,7 @@ export class CardComponent {
91
91
  actionLeadingIcon = input('', ...(ngDevMode ? [{ debugName: "actionLeadingIcon" }] : /* istanbul ignore next */ []));
92
92
  /** Content: trailing Lucide icon name rendered inside the action pill. */
93
93
  actionTrailingIcon = input('', ...(ngDevMode ? [{ debugName: "actionTrailingIcon" }] : /* istanbul ignore next */ []));
94
- /** Content (`appearance="banner"`): disables the action button. */
94
+ /** Content: disables the action button. */
95
95
  actionDisabled = input(false, ...(ngDevMode ? [{ debugName: "actionDisabled" }] : /* istanbul ignore next */ []));
96
96
  /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */
97
97
  inlineIcon = input(false, ...(ngDevMode ? [{ debugName: "inlineIcon" }] : /* istanbul ignore next */ []));
@@ -206,7 +206,7 @@ export class CardComponent {
206
206
  return this.sanitizer.bypassSecurityTrustHtml(svg);
207
207
  }
208
208
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
209
- 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 }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, hideImage: { classPropertyName: "hideImage", publicName: "hideImage", 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 }, headlineDescription: { classPropertyName: "headlineDescription", publicName: "headlineDescription", isSignal: true, isRequired: false, transformFunction: null }, metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, actionLeadingIcon: { classPropertyName: "actionLeadingIcon", publicName: "actionLeadingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionTrailingIcon: { classPropertyName: "actionTrailingIcon", publicName: "actionTrailingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionDisabled: { classPropertyName: "actionDisabled", publicName: "actionDisabled", isSignal: true, isRequired: false, transformFunction: null }, inlineIcon: { classPropertyName: "inlineIcon", publicName: "inlineIcon", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, showGradient: { classPropertyName: "showGradient", publicName: "showGradient", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, darkBackground: { classPropertyName: "darkBackground", publicName: "darkBackground", 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 }, metricSize: { classPropertyName: "metricSize", publicName: "metricSize", 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", actionClick: "actionClick" }, 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--banner": "appearance() === 'banner'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "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()", "class.cmp-card--selected": "selected()", "class.cmp-card--no-gradient": "!showGradient()", "class.cmp-card--compact": "compact()", "class.cmp-card--metric-sm": "variant() === 'metric' && metricSize() === 'small'", "class.cmp-card--dark-bg": "darkBackground()", "class.cmp-card--hide-image": "hideImage()", "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 (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\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 fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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", 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;text-wrap:pretty}: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-variant)}: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-variant)}: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.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}: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--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.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--banner: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--selected,: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}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@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--banner){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--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.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--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--banner{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)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.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__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-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(--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)}.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--no-desc .ac__label{line-height:1}.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-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}: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)}: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--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .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--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .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)}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "compsych-card", inputs: ["variant", "appearance", "radius", "padding", "size", "interactive", "disabled", "selected", "imageSrc", "hideImage", "imagePosition", "icon", "category", "categoryStyle", "iconStyle", "title", "subtitle", "description", "headline", "headlineDescription", "metrics", "actionLabel", "actionLeadingIcon", "actionTrailingIcon", "actionDisabled", "inlineIcon", "showArrow", "showGradient", "compact", "darkBackground", "label", "trailingIcon", "orientation", "fullWidth", "metricSize", "value", "current", "headingLevel", "aria-label"], outputs: ["cardClick", "actionClick"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ButtonComponent, selector: "compsych-button", inputs: ["label", "variant", "size", "leadingIcon", "trailingIcon", "type", "ariaLabel", "iconOnly", "disabled", "loading", "fullWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
209
+ 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 }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, hideImage: { classPropertyName: "hideImage", publicName: "hideImage", 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 }, headlineDescription: { classPropertyName: "headlineDescription", publicName: "headlineDescription", isSignal: true, isRequired: false, transformFunction: null }, metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, actionLeadingIcon: { classPropertyName: "actionLeadingIcon", publicName: "actionLeadingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionTrailingIcon: { classPropertyName: "actionTrailingIcon", publicName: "actionTrailingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionDisabled: { classPropertyName: "actionDisabled", publicName: "actionDisabled", isSignal: true, isRequired: false, transformFunction: null }, inlineIcon: { classPropertyName: "inlineIcon", publicName: "inlineIcon", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, showGradient: { classPropertyName: "showGradient", publicName: "showGradient", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, darkBackground: { classPropertyName: "darkBackground", publicName: "darkBackground", 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 }, metricSize: { classPropertyName: "metricSize", publicName: "metricSize", 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", actionClick: "actionClick" }, 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--banner": "appearance() === 'banner'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "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()", "class.cmp-card--selected": "selected()", "class.cmp-card--no-gradient": "!showGradient()", "class.cmp-card--compact": "compact()", "class.cmp-card--metric-sm": "variant() === 'metric' && metricSize() === 'small'", "class.cmp-card--dark-bg": "darkBackground()", "class.cmp-card--hide-image": "hideImage()", "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 (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\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 fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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", 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;text-wrap:pretty}: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-variant)}: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-variant)}: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.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}: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--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.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--banner: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--selected,: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}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@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--banner){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--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.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--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--banner{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)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.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__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-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(--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)}.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--no-desc .ac__label{line-height:1}.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-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}: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)}: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--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .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--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .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)}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "compsych-card", inputs: ["variant", "appearance", "radius", "padding", "size", "interactive", "disabled", "selected", "imageSrc", "hideImage", "imagePosition", "icon", "category", "categoryStyle", "iconStyle", "title", "subtitle", "description", "headline", "headlineDescription", "metrics", "actionLabel", "actionLeadingIcon", "actionTrailingIcon", "actionDisabled", "inlineIcon", "showArrow", "showGradient", "compact", "darkBackground", "label", "trailingIcon", "orientation", "fullWidth", "metricSize", "value", "current", "headingLevel", "aria-label"], outputs: ["cardClick", "actionClick"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ButtonComponent, selector: "compsych-button", inputs: ["label", "variant", "size", "leadingIcon", "trailingIcon", "type", "ariaLabel", "iconOnly", "disabled", "loading", "fullWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
210
210
  }
211
211
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, decorators: [{
212
212
  type: Component,
@@ -247,6 +247,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
247
247
  '[style.border-width]': "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null",
248
248
  '(click)': 'onActivate()',
249
249
  '(keydown)': 'onKeyDown($event)',
250
- }, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\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 fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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", 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;text-wrap:pretty}: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-variant)}: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-variant)}: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.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}: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--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.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--banner: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--selected,: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}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@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--banner){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--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.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--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--banner{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)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.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__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-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(--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)}.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--no-desc .ac__label{line-height:1}.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-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}: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)}: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--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .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--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .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)}\n"] }]
250
+ }, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\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 fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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", 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;text-wrap:pretty}: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-variant)}: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-variant)}: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.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}: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--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.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--banner: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--selected,: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}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@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--banner){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--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.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--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--banner{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)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.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__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-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(--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)}.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--no-desc .ac__label{line-height:1}.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-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}: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)}: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--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .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--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .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)}\n"] }]
251
251
  }], 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 }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], imageSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageSrc", required: false }] }], hideImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideImage", 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 }] }], headlineDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "headlineDescription", required: false }] }], metrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "metrics", required: false }] }], actionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLabel", required: false }] }], actionLeadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLeadingIcon", required: false }] }], actionTrailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionTrailingIcon", required: false }] }], actionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionDisabled", required: false }] }], inlineIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineIcon", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], showGradient: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGradient", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], darkBackground: [{ type: i0.Input, args: [{ isSignal: true, alias: "darkBackground", 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 }] }], metricSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricSize", 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"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
252
252
  //# 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":"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","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\nimport { ButtonComponent } from '../button/button';\r\n\r\n/** A single metric item for the banner card's metric row. */\r\nexport interface BannerMetric {\r\n value: string | number;\r\n label?: string;\r\n /** Renders the metric in its primary-color \"current\" state. */\r\n current?: boolean;\r\n}\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/banner 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' | 'banner';\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/** Metric-card size. `medium` is the default (24px padding, headline-medium value); `small` is compact (16px padding, headline-small value). */\r\nexport type CardMetricSize = 'medium' | 'small';\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 / 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).\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; 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 / banner).\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, ButtonComponent, CardComponent],\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--banner]': \"appearance() === 'banner'\",\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--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 '[class.cmp-card--selected]': 'selected()',\r\n '[class.cmp-card--no-gradient]': '!showGradient()',\r\n '[class.cmp-card--compact]': 'compact()',\r\n '[class.cmp-card--metric-sm]': \"variant() === 'metric' && metricSize() === 'small'\",\r\n '[class.cmp-card--dark-bg]': 'darkBackground()',\r\n '[class.cmp-card--hide-image]': 'hideImage()',\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 /** Applies the focused (blue outline) appearance. Useful for action cards to indicate selection. */\r\n readonly selected = input<boolean>(false);\r\n /** Background image URL for `appearance=\"banner\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * Hides the background image on an `appearance=\"banner\"` card and replaces it\r\n * with a `--accent-primary-sys-primary-container` solid background.\r\n */\r\n readonly hideImage = input<boolean>(false);\r\n /**\r\n * `background-position` for the `banner` appearance media (e.g. `'85% 0'` for an\r\n * off-center image). Defaults to `'center'`.\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.\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.\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 display text for the headline layout. */\r\n readonly headline = input<string>('');\r\n /** Content (`appearance=\"banner\"`): supporting text rendered below the headline, in white-80. */\r\n readonly headlineDescription = input<string>('');\r\n /** Content (`appearance=\"banner\"`): metric cards rendered in a dark row below the headline description. */\r\n readonly metrics = input<BannerMetric[]>([]);\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: leading Lucide icon name rendered inside the action pill. */\r\n readonly actionLeadingIcon = input<string>('');\r\n /** Content: trailing Lucide icon name rendered inside the action pill. */\r\n readonly actionTrailingIcon = input<string>('');\r\n /** Content (`appearance=\"banner\"`): disables the action button. */\r\n readonly actionDisabled = input<boolean>(false);\r\n /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */\r\n readonly inlineIcon = input<boolean>(false);\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n /** Content (gradient): show the inner gradient panel background. Set to `false` to render a flat surface. */\r\n readonly showGradient = input<boolean>(true);\r\n /** Content: remove the fixed min-height so the card sizes to its content. */\r\n readonly compact = input<boolean>(false);\r\n /**\r\n * Renders the card on a dark surface: background becomes\r\n * `--transparent-neutral-sys-white-20` (closest token to rgba(255,255,255,0.16))\r\n * and text color becomes white.\r\n */\r\n readonly darkBackground = input<boolean>(false);\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: size variant. Defaults to `medium`. */\r\n readonly metricSize = input<CardMetricSize>('medium');\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 / 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 /** Emits when the banner card's action button is clicked. */\r\n readonly actionClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isBanner = computed(() => this.appearance() === 'banner');\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.isBanner() ? '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 this.metricSize() === 'small' ? 'sm' : 'lg'; // sm=16px, lg=24px\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 (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" /> }\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 fragment: renders <h2>–<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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"]}
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":"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","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\nimport { ButtonComponent } from '../button/button';\r\n\r\n/** A single metric item for the banner card's metric row. */\r\nexport interface BannerMetric {\r\n value: string | number;\r\n label?: string;\r\n /** Renders the metric in its primary-color \"current\" state. */\r\n current?: boolean;\r\n}\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/banner 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' | 'banner';\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/** Metric-card size. `medium` is the default (24px padding, headline-medium value); `small` is compact (16px padding, headline-small value). */\r\nexport type CardMetricSize = 'medium' | 'small';\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 / 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).\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; 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 / banner).\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, ButtonComponent, CardComponent],\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--banner]': \"appearance() === 'banner'\",\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--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 '[class.cmp-card--selected]': 'selected()',\r\n '[class.cmp-card--no-gradient]': '!showGradient()',\r\n '[class.cmp-card--compact]': 'compact()',\r\n '[class.cmp-card--metric-sm]': \"variant() === 'metric' && metricSize() === 'small'\",\r\n '[class.cmp-card--dark-bg]': 'darkBackground()',\r\n '[class.cmp-card--hide-image]': 'hideImage()',\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 /** Applies the focused (blue outline) appearance. Useful for action cards to indicate selection. */\r\n readonly selected = input<boolean>(false);\r\n /** Background image URL for `appearance=\"banner\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * Hides the background image on an `appearance=\"banner\"` card and replaces it\r\n * with a `--accent-primary-sys-primary-container` solid background.\r\n */\r\n readonly hideImage = input<boolean>(false);\r\n /**\r\n * `background-position` for the `banner` appearance media (e.g. `'85% 0'` for an\r\n * off-center image). Defaults to `'center'`.\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.\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.\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 display text for the headline layout. */\r\n readonly headline = input<string>('');\r\n /** Content (`appearance=\"banner\"`): supporting text rendered below the headline, in white-80. */\r\n readonly headlineDescription = input<string>('');\r\n /** Content (`appearance=\"banner\"`): metric cards rendered in a dark row below the headline description. */\r\n readonly metrics = input<BannerMetric[]>([]);\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: leading Lucide icon name rendered inside the action pill. */\r\n readonly actionLeadingIcon = input<string>('');\r\n /** Content: trailing Lucide icon name rendered inside the action pill. */\r\n readonly actionTrailingIcon = input<string>('');\r\n /** Content: disables the action button. */\r\n readonly actionDisabled = input<boolean>(false);\r\n /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */\r\n readonly inlineIcon = input<boolean>(false);\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n /** Content (gradient): show the inner gradient panel background. Set to `false` to render a flat surface. */\r\n readonly showGradient = input<boolean>(true);\r\n /** Content: remove the fixed min-height so the card sizes to its content. */\r\n readonly compact = input<boolean>(false);\r\n /**\r\n * Renders the card on a dark surface: background becomes\r\n * `--transparent-neutral-sys-white-20` (closest token to rgba(255,255,255,0.16))\r\n * and text color becomes white.\r\n */\r\n readonly darkBackground = input<boolean>(false);\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: size variant. Defaults to `medium`. */\r\n readonly metricSize = input<CardMetricSize>('medium');\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 / 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 /** Emits when the banner card's action button is clicked. */\r\n readonly actionClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isBanner = computed(() => this.appearance() === 'banner');\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.isBanner() ? '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 this.metricSize() === 'small' ? 'sm' : 'lg'; // sm=16px, lg=24px\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 (isBanner() && mediaUrl() && !hideImage()) {\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 (isBanner()) {\r\n <div class=\"cc cc--banner\">\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() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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 @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\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()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\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 }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\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\" [class.ac--no-desc]=\"!description()\">\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\" [class.ac--no-desc]=\"!description()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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--banner]=\"isBanner()\">\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\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()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\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 fragment: renders <h2>–<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-types.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown-types.ts"],"names":[],"mappings":"","sourcesContent":["/** Size variant of a `compsych-dropdown` (40 / 48 / 56px). Controls trigger height, padding, and font size. */\r\nexport type DropdownSize = 'sm' | 'md' | 'lg';\r\n\r\n/** Placement of the label relative to the trigger. `'top'` stacks it above (default); `'left'` sets it beside the trigger. */\r\nexport type DropdownLabelPosition = 'top' | 'left';\r\n\r\n/** A single selectable option in a `compsych-dropdown`. */\r\nexport interface DropdownOption {\r\n /** Value written to the bound form control / emitted by `valueChange`. */\r\n value: string;\r\n /** Text shown for the option in the panel and, when selected, in the trigger. */\r\n label: string;\r\n /** Prevents the option from being selected or focused. */\r\n disabled?: boolean;\r\n /** Optional secondary text shown after the label (drops to its own line when the row wraps). */\r\n supportingText?: string;\r\n /** Retones the option's label to `sys-error` (e.g. a destructive choice). */\r\n error?: boolean;\r\n /**\r\n * Per-option Lucide icon name, assigned from the design system's Icon Mapping\r\n * (use → glyph). Overrides the dropdown's `optionsLeadingIcon` default for this row.\r\n */\r\n icon?: string;\r\n}\r\n\r\n/** ARIA contract for a standalone `compsych-dropdown-menu`: an action `menu` or a select `listbox`. */\r\nexport type DropdownMenuKind = 'menu' | 'listbox';\r\n\r\n/** A single row in a standalone `compsych-dropdown-menu`. */\r\nexport interface DropdownMenuItem {\r\n /** Stable id emitted on select and matched against the listbox selection. Falls back to `label`. */\r\n id?: string;\r\n /** Row text. */\r\n label: string;\r\n /** Optional secondary text shown after the label (drops to its own line when the row wraps). */\r\n supportingText?: string;\r\n /** Prevents the row from being chosen or focused. */\r\n disabled?: boolean;\r\n /** Retones the row's label to `sys-error` (e.g. a destructive action). */\r\n error?: boolean;\r\n /**\r\n * Per-row Lucide icon name, assigned from the design system's Icon Mapping\r\n * (use → glyph). Overrides the menu's `leadingIcon` default for this row.\r\n */\r\n icon?: string;\r\n}\r\n"]}
1
+ {"version":3,"file":"dropdown-types.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown-types.ts"],"names":[],"mappings":"","sourcesContent":["/** Size variant of a `compsych-dropdown` (40 / 48 / 56px). Controls trigger height, padding, and font size. */\r\nexport type DropdownSize = 'sm' | 'md' | 'lg';\r\n\r\n/** Placement of the label relative to the trigger. `'top'` stacks it above (default); `'left'` sets it beside the trigger. */\r\nexport type DropdownLabelPosition = 'top' | 'left';\r\n\r\n/** A single selectable option in a `compsych-dropdown`. */\r\nexport interface DropdownOption {\r\n /** Value written to the bound form control / emitted by `valueChange`. */\r\n value: string;\r\n /** Text shown for the option in the panel and, when selected, in the trigger. */\r\n label: string;\r\n /** Prevents the option from being selected or focused. */\r\n disabled?: boolean;\r\n /** Optional secondary text shown after the label (drops to its own line when the row wraps). */\r\n supportingText?: string;\r\n /** Retones the option's label to `sys-error` (e.g. a destructive choice). */\r\n error?: boolean;\r\n /**\r\n * Per-option Lucide icon name, assigned from the design system's Icon Mapping\r\n * (use → glyph). Overrides the dropdown's `optionsLeadingIcon` default for this row.\r\n */\r\n icon?: string;\r\n /**\r\n * Raw, **trusted** SVG markup for a non-Lucide icon (e.g. a country flag from an\r\n * icon pack) rendered in place of `icon`. Takes precedence over `icon`. The string\r\n * is sanitized-bypassed and scaled to 20px wide, so only pass static/trusted SVG —\r\n * never untrusted user input.\r\n */\r\n iconSvg?: string;\r\n}\r\n\r\n/** ARIA contract for a standalone `compsych-dropdown-menu`: an action `menu` or a select `listbox`. */\r\nexport type DropdownMenuKind = 'menu' | 'listbox';\r\n\r\n/** A single row in a standalone `compsych-dropdown-menu`. */\r\nexport interface DropdownMenuItem {\r\n /** Stable id emitted on select and matched against the listbox selection. Falls back to `label`. */\r\n id?: string;\r\n /** Row text. */\r\n label: string;\r\n /** Optional secondary text shown after the label (drops to its own line when the row wraps). */\r\n supportingText?: string;\r\n /** Prevents the row from being chosen or focused. */\r\n disabled?: boolean;\r\n /** Retones the row's label to `sys-error` (e.g. a destructive action). */\r\n error?: boolean;\r\n /**\r\n * Per-row Lucide icon name, assigned from the design system's Icon Mapping\r\n * (use → glyph). Overrides the menu's `leadingIcon` default for this row.\r\n */\r\n icon?: string;\r\n}\r\n"]}
@@ -116,15 +116,46 @@ export class DropdownComponent {
116
116
  const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', '<svg width="20" height="20" ');
117
117
  return this.sanitizer.bypassSecurityTrustHtml(svg);
118
118
  }
119
- /** Cached option-icon SVG by Lucide name (stable reference so option rows don't re-render each cycle). */
120
- optionIconSvg(name) {
121
- const key = name ?? '';
122
- let svg = this.optionIconCache.get(key);
123
- if (!svg) {
124
- svg = this.buildIconSvg(key);
125
- this.optionIconCache.set(key, svg);
119
+ /**
120
+ * Scales trusted raw SVG (e.g. a flag) to 20px wide, preserving aspect ratio via its
121
+ * viewBox. Only the root `<svg>` tag's width/height are normalized — inner elements
122
+ * (rects/paths that draw the icon) keep their own dimensions.
123
+ */
124
+ buildRawIconSvg(svg) {
125
+ const sized = svg.replace(/<svg\b[^>]*>/, (openTag) => openTag.replace(/\s(?:width|height)="[^"]*"/g, '').replace('<svg', '<svg width="20"'));
126
+ return this.sanitizer.bypassSecurityTrustHtml(sized);
127
+ }
128
+ /**
129
+ * Resolves an icon to cached SafeHtml: a trusted raw `iconSvg` wins, else a Lucide
130
+ * `iconName`. Returns null when neither is set. Cached so rows keep a stable reference.
131
+ */
132
+ resolveIcon(iconSvg, iconName) {
133
+ if (iconSvg) {
134
+ const key = 'raw:' + iconSvg;
135
+ let svg = this.optionIconCache.get(key);
136
+ if (!svg) {
137
+ svg = this.buildRawIconSvg(iconSvg);
138
+ this.optionIconCache.set(key, svg);
139
+ }
140
+ return svg;
141
+ }
142
+ if (iconName) {
143
+ let svg = this.optionIconCache.get(iconName);
144
+ if (!svg) {
145
+ svg = this.buildIconSvg(iconName);
146
+ this.optionIconCache.set(iconName, svg);
147
+ }
148
+ return svg;
126
149
  }
127
- return svg;
150
+ return null;
151
+ }
152
+ /** Icon for an option row: its own `iconSvg`/`icon`, else the shared `optionsLeadingIcon`. */
153
+ optionIcon(option) {
154
+ return this.resolveIcon(option.iconSvg, option.icon ?? this.optionsLeadingIcon);
155
+ }
156
+ /** Icon in the trigger: the selected option's own icon (flag/glyph), else the fixed `leadingIcon`. */
157
+ get triggerIconSvg() {
158
+ return this.resolveIcon(this.selectedOption?.iconSvg, this.selectedOption?.icon) ?? this.leadingIconSvg;
128
159
  }
129
160
  get triggerId() {
130
161
  return this.id ?? this._autoId;
@@ -299,8 +330,8 @@ export class DropdownComponent {
299
330
  (click)="toggle()"
300
331
  (keydown)="onTriggerKeydown($event)"
301
332
  >
302
- @if (leadingIconSvg) {
303
- <span class="trigger-icon" aria-hidden="true" [innerHTML]="leadingIconSvg"></span>
333
+ @if (triggerIconSvg) {
334
+ <span class="trigger-icon" aria-hidden="true" [innerHTML]="triggerIconSvg"></span>
304
335
  }
305
336
  <span class="trigger-text">{{ triggerText }}</span>
306
337
  <span class="trigger-chevron" aria-hidden="true" [innerHTML]="chevronSvg"></span>
@@ -328,6 +359,7 @@ export class DropdownComponent {
328
359
  #listboxEl
329
360
  cdkListbox
330
361
  class="panel"
362
+ [class.sm]="size === 'sm'"
331
363
  [style.width.px]="overlayWidth"
332
364
  [id]="listboxId"
333
365
  [attr.aria-labelledby]="labelId"
@@ -338,8 +370,8 @@ export class DropdownComponent {
338
370
  @for (opt of options; track opt.value) {
339
371
  <li class="option" [class.error]="opt.error" [cdkOption]="opt.value" [cdkOptionDisabled]="!!opt.disabled">
340
372
  <span class="option-inner">
341
- @if (opt.icon || optionsLeadingIcon) {
342
- <span class="option-icon" aria-hidden="true" [innerHTML]="optionIconSvg(opt.icon || optionsLeadingIcon)"></span>
373
+ @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {
374
+ <span class="option-icon" aria-hidden="true" [innerHTML]="optionIcon(opt)"></span>
343
375
  }
344
376
  <span class="option-text">
345
377
  <span class="option-label">{{ opt.label }}</span>
@@ -352,7 +384,7 @@ export class DropdownComponent {
352
384
  }
353
385
  </ul>
354
386
  </ng-template>
355
- `, isInline: true, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{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);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{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)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"], dependencies: [{ kind: "directive", type: CdkListbox, selector: "[cdkListbox]", inputs: ["id", "tabindex", "cdkListboxValue", "cdkListboxMultiple", "cdkListboxDisabled", "cdkListboxUseActiveDescendant", "cdkListboxOrientation", "cdkListboxCompareWith", "cdkListboxNavigationWrapDisabled", "cdkListboxNavigatesDisabledOptions"], outputs: ["cdkListboxValueChange"], exportAs: ["cdkListbox"] }, { kind: "directive", type: CdkOption, selector: "[cdkOption]", inputs: ["id", "cdkOption", "cdkOptionTypeaheadLabel", "cdkOptionDisabled", "tabindex"], exportAs: ["cdkOption"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
387
+ `, isInline: true, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{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);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{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)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"], dependencies: [{ kind: "directive", type: CdkListbox, selector: "[cdkListbox]", inputs: ["id", "tabindex", "cdkListboxValue", "cdkListboxMultiple", "cdkListboxDisabled", "cdkListboxUseActiveDescendant", "cdkListboxOrientation", "cdkListboxCompareWith", "cdkListboxNavigationWrapDisabled", "cdkListboxNavigatesDisabledOptions"], outputs: ["cdkListboxValueChange"], exportAs: ["cdkListbox"] }, { kind: "directive", type: CdkOption, selector: "[cdkOption]", inputs: ["id", "cdkOption", "cdkOptionTypeaheadLabel", "cdkOptionDisabled", "tabindex"], exportAs: ["cdkOption"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
356
388
  }
357
389
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DropdownComponent, decorators: [{
358
390
  type: Component,
@@ -389,8 +421,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
389
421
  (click)="toggle()"
390
422
  (keydown)="onTriggerKeydown($event)"
391
423
  >
392
- @if (leadingIconSvg) {
393
- <span class="trigger-icon" aria-hidden="true" [innerHTML]="leadingIconSvg"></span>
424
+ @if (triggerIconSvg) {
425
+ <span class="trigger-icon" aria-hidden="true" [innerHTML]="triggerIconSvg"></span>
394
426
  }
395
427
  <span class="trigger-text">{{ triggerText }}</span>
396
428
  <span class="trigger-chevron" aria-hidden="true" [innerHTML]="chevronSvg"></span>
@@ -418,6 +450,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
418
450
  #listboxEl
419
451
  cdkListbox
420
452
  class="panel"
453
+ [class.sm]="size === 'sm'"
421
454
  [style.width.px]="overlayWidth"
422
455
  [id]="listboxId"
423
456
  [attr.aria-labelledby]="labelId"
@@ -428,8 +461,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
428
461
  @for (opt of options; track opt.value) {
429
462
  <li class="option" [class.error]="opt.error" [cdkOption]="opt.value" [cdkOptionDisabled]="!!opt.disabled">
430
463
  <span class="option-inner">
431
- @if (opt.icon || optionsLeadingIcon) {
432
- <span class="option-icon" aria-hidden="true" [innerHTML]="optionIconSvg(opt.icon || optionsLeadingIcon)"></span>
464
+ @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {
465
+ <span class="option-icon" aria-hidden="true" [innerHTML]="optionIcon(opt)"></span>
433
466
  }
434
467
  <span class="option-text">
435
468
  <span class="option-label">{{ opt.label }}</span>
@@ -442,7 +475,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
442
475
  }
443
476
  </ul>
444
477
  </ng-template>
445
- `, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{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);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{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)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"] }]
478
+ `, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{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);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{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)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"] }]
446
479
  }], ctorParameters: () => [], propDecorators: { triggerBtn: [{
447
480
  type: ViewChild,
448
481
  args: ['triggerBtn']
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n Output,\r\n ViewChild,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\r\nimport { CdkListbox, CdkOption, ListboxValueChangeEvent } from '@angular/cdk/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition } from '@angular/cdk/overlay';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { DropdownLabelPosition, DropdownOption, DropdownSize } from './dropdown-types';\r\n\r\nlet nextId = 0;\r\n\r\n/**\r\n * A labelled single-select dropdown built on the CDK Listbox (`@angular/cdk/listbox`)\r\n * and CDK Overlay. The trigger renders the closed field (label, placeholder/selected\r\n * value and chevron); the options open in an overlay panel with full keyboard support\r\n * (arrow keys, Home/End, typeahead) provided by the CDK listbox.\r\n *\r\n * Implements `ControlValueAccessor` so it works with both reactive forms\r\n * (`formControlName`, `[formControl]`) and template-driven forms (`ngModel`). The error\r\n * visual state is driven automatically by the bound `FormControl`'s validity once the\r\n * field has been touched, and can also be set explicitly via the `error` input.\r\n */\r\n@Component({\r\n selector: 'compsych-dropdown',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin],\r\n template: `\r\n <div [class]=\"wrapperClasses\">\r\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\r\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\r\n {{ label }}\r\n @if (isRequired) {\r\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\r\n }\r\n </label>\r\n </div>\r\n\r\n <button\r\n #triggerBtn\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n type=\"button\"\r\n class=\"trigger\"\r\n [id]=\"triggerId\"\r\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\r\n [class.error]=\"hasError\"\r\n [class.open]=\"isOpen\"\r\n [disabled]=\"disabled\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"isOpen\"\r\n [attr.aria-controls]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\r\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\r\n [attr.aria-required]=\"isRequired ? 'true' : null\"\r\n [attr.aria-describedby]=\"describedBy\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n >\r\n @if (leadingIconSvg) {\r\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"leadingIconSvg\"></span>\r\n }\r\n <span class=\"trigger-text\">{{ triggerText }}</span>\r\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\r\n </button>\r\n\r\n @if (displayedSupportingText) {\r\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\r\n {{ displayedSupportingText }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen\"\r\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\r\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\r\n [cdkConnectedOverlayViewportMargin]=\"8\"\r\n (overlayOutsideClick)=\"close()\"\r\n (attach)=\"onPanelAttach()\"\r\n (detach)=\"close()\"\r\n >\r\n <ul\r\n #listboxEl\r\n cdkListbox\r\n class=\"panel\"\r\n [style.width.px]=\"overlayWidth\"\r\n [id]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId\"\r\n [cdkListboxValue]=\"listboxValue\"\r\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\r\n (keydown)=\"onListboxKeydown($event)\"\r\n >\r\n @for (opt of options; track opt.value) {\r\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\r\n <span class=\"option-inner\">\r\n @if (opt.icon || optionsLeadingIcon) {\r\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIconSvg(opt.icon || optionsLeadingIcon)\"></span>\r\n }\r\n <span class=\"option-text\">\r\n <span class=\"option-label\">{{ opt.label }}</span>\r\n @if (opt.supportingText) {\r\n <span class=\"option-support\">{{ opt.supportingText }}</span>\r\n }\r\n </span>\r\n </span>\r\n </li>\r\n }\r\n </ul>\r\n </ng-template>\r\n `,\r\n styleUrl: './dropdown.css',\r\n})\r\nexport class DropdownComponent implements ControlValueAccessor, OnChanges {\r\n private readonly _autoId = `cmp-dropdown-${++nextId}`;\r\n private readonly cdr = inject(ChangeDetectorRef);\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private _onChange: (value: string) => void = () => {};\r\n private _onTouched: () => void = () => {};\r\n\r\n /** Injected when the component is used inside a reactive or template-driven form. */\r\n protected readonly ngControl: NgControl | null;\r\n\r\n constructor() {\r\n const ctrl = inject(NgControl, { optional: true, self: true });\r\n if (ctrl) ctrl.valueAccessor = this;\r\n this.ngControl = ctrl;\r\n this.chevronSvg = this.buildIconSvg('chevron-down');\r\n }\r\n\r\n @ViewChild('triggerBtn') private triggerBtn?: ElementRef<HTMLButtonElement>;\r\n @ViewChild('listboxEl') private listboxEl?: ElementRef<HTMLUListElement>;\r\n\r\n /** Label displayed above the trigger. */\r\n @Input() label = '';\r\n /** Text shown in the trigger when no option is selected. */\r\n @Input() placeholder = '';\r\n /** Currently selected value. When used in a form, the form controls the value. */\r\n @Input() value = '';\r\n /** Selectable options rendered in the overlay panel. */\r\n @Input() options: DropdownOption[] = [];\r\n /** Size variant — controls height, padding, and font size. Defaults to `'md'`. */\r\n @Input() size: DropdownSize = 'md';\r\n /** Native `id` attribute for the trigger. Auto-generated if omitted. */\r\n @Input() id?: string;\r\n /**\r\n * Id(s) of external elements that describe the field, space-separated.\r\n * Forwarded to `aria-describedby` on the trigger.\r\n */\r\n @Input() ariaDescribedBy?: string;\r\n /** Text displayed below the trigger. Shown in red when in error state. */\r\n @Input() supportingText = '';\r\n /**\r\n * Static error text shown in red when in error state. Used when the dropdown is\r\n * outside a form (with `[error]=\"true\"`). When inside a form, prefer `errorMessages`.\r\n */\r\n @Input() errorMessage = '';\r\n /**\r\n * Map of Angular validator error keys to display strings. The component reads\r\n * `ngControl.errors` to determine which validator failed and shows the matching\r\n * message in red below the trigger. Example: `{ required: 'Please choose an option' }`\r\n */\r\n @Input() errorMessages: Record<string, string> = {};\r\n /**\r\n * Adds a blue asterisk after the label. When used in a form, this is set\r\n * automatically if the bound `FormControl` has `Validators.required`.\r\n * Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) required = false;\r\n /**\r\n * Applies the error visual state (red border) explicitly. When used in a form,\r\n * the error state is driven automatically from the `FormControl`'s validity once\r\n * the field is touched — this input is only needed outside of forms. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) error = false;\r\n /** Disables the dropdown. When used in a form, also responds to `FormControl.disable()`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /** Visually hides the label while keeping it accessible to screen readers. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) hideLabel = false;\r\n /** Places the label above the trigger (`'top'`, default) or beside it (`'left'`). */\r\n @Input() labelPosition: DropdownLabelPosition = 'top';\r\n /**\r\n * Renders the label as the trigger's own resting text instead of a separate\r\n * label above/beside it — e.g. the trigger reads \"I want to\" until an option\r\n * is chosen. No visible external label is shown, but the `label` is still\r\n * exposed to assistive tech (a screen-reader-only `<label>` + `aria-labelledby`),\r\n * so the field is announced as a properly labelled combobox. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) inlineLabel = false;\r\n /** Lucide icon name rendered inside the trigger, before the displayed value/placeholder (e.g. `'globe'`). */\r\n @Input() leadingIcon?: string;\r\n /** Default Lucide icon shown before every option's label; each option's own `icon` (from the Icon Mapping) overrides it. */\r\n @Input() optionsLeadingIcon?: string;\r\n\r\n /** Emits the newly selected value whenever the user picks an option. */\r\n @Output() readonly valueChange = new EventEmitter<string>();\r\n /** Emitted when the overlay panel opens. */\r\n @Output() readonly opened = new EventEmitter<void>();\r\n /** Emitted when the overlay panel closes. */\r\n @Output() readonly closed = new EventEmitter<void>();\r\n\r\n protected readonly chevronSvg: SafeHtml;\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n private readonly optionIconCache = new Map<string, SafeHtml>();\r\n\r\n protected isOpen = false;\r\n protected overlayWidth = 0;\r\n protected readonly overlayPositions: ConnectedPosition[] = [\r\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },\r\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },\r\n ];\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n }\r\n\r\n private buildIconSvg(name: string): SafeHtml {\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', '<svg width=\"20\" height=\"20\" ');\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /** Cached option-icon SVG by Lucide name (stable reference so option rows don't re-render each cycle). */\r\n protected optionIconSvg(name: string | undefined): SafeHtml {\r\n const key = name ?? '';\r\n let svg = this.optionIconCache.get(key);\r\n if (!svg) {\r\n svg = this.buildIconSvg(key);\r\n this.optionIconCache.set(key, svg);\r\n }\r\n return svg;\r\n }\r\n\r\n get triggerId(): string {\r\n return this.id ?? this._autoId;\r\n }\r\n\r\n get labelId(): string {\r\n return this.triggerId + '-label';\r\n }\r\n\r\n get listboxId(): string {\r\n return this.triggerId + '-listbox';\r\n }\r\n\r\n get selectedOption(): DropdownOption | undefined {\r\n return this.options.find((o) => o.value === this.value);\r\n }\r\n\r\n /**\r\n * Resting text shown in the trigger: the selected option's label, else the\r\n * `label` in inline-label mode (so the label reads as the field's own text),\r\n * else the placeholder.\r\n */\r\n get triggerText(): string {\r\n return this.selectedOption?.label || (this.inlineLabel ? this.label : this.placeholder);\r\n }\r\n\r\n /** Value array bound to the CDK listbox (single-select, so 0 or 1 entry). */\r\n get listboxValue(): readonly string[] {\r\n return this.value ? [this.value] : [];\r\n }\r\n\r\n /** True when the bound FormControl is invalid and touched, or when `error` is explicitly set. */\r\n get hasError(): boolean {\r\n return this.error || !!(this.ngControl?.invalid && this.ngControl.touched);\r\n }\r\n\r\n /** True when `required` is set explicitly, or when the bound FormControl has Validators.required. */\r\n get isRequired(): boolean {\r\n return this.required || !!this.ngControl?.control?.hasValidator(Validators.required);\r\n }\r\n\r\n private get activeErrorMessage(): string {\r\n const errors = this.ngControl?.errors;\r\n if (!errors) return '';\r\n for (const key of Object.keys(errors)) {\r\n if (this.errorMessages[key]) return this.errorMessages[key];\r\n }\r\n return '';\r\n }\r\n\r\n get displayedSupportingText(): string {\r\n if (this.hasError) {\r\n return this.activeErrorMessage || this.errorMessage || this.supportingText;\r\n }\r\n return this.supportingText;\r\n }\r\n\r\n get describedBy(): string | null {\r\n const parts: string[] = [];\r\n if (this.ariaDescribedBy) parts.push(this.ariaDescribedBy);\r\n if (this.supportingText || this.errorMessage || Object.keys(this.errorMessages).length) {\r\n parts.push(this.triggerId + '-supporting');\r\n }\r\n return parts.length ? parts.join(' ') : null;\r\n }\r\n\r\n get wrapperClasses(): string {\r\n return ['cmp-dropdown', this.size, this.disabled ? 'disabled' : '', this.labelPosition === 'left' ? 'label-left' : '']\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // ── Open / close ──────────────────────────────────────────────────────────\r\n\r\n protected toggle(): void {\r\n if (this.isOpen) {\r\n this.close(true);\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n protected open(): void {\r\n if (this.disabled || this.isOpen) return;\r\n this.overlayWidth = this.triggerBtn?.nativeElement.offsetWidth ?? 0;\r\n this.isOpen = true;\r\n this.opened.emit();\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected close(refocus = false): void {\r\n if (!this.isOpen) return;\r\n this.isOpen = false;\r\n this._onTouched();\r\n this.closed.emit();\r\n if (refocus) {\r\n setTimeout(() => this.triggerBtn?.nativeElement.focus());\r\n }\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected onPanelAttach(): void {\r\n setTimeout(() => this.listboxEl?.nativeElement.focus());\r\n }\r\n\r\n // ── Keyboard ──────────────────────────────────────────────────────────────\r\n\r\n protected onTriggerKeydown(event: KeyboardEvent): void {\r\n if (this.disabled) return;\r\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && !this.isOpen) {\r\n event.preventDefault();\r\n this.open();\r\n } else if (event.key === 'Escape' && this.isOpen) {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Escape') {\r\n event.preventDefault();\r\n this.close(true);\r\n } else if (event.key === 'Tab') {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxValueChange(event: ListboxValueChangeEvent<string>): void {\r\n const next = event.value[0] ?? '';\r\n this.value = next;\r\n this._onChange(next);\r\n this.valueChange.emit(next);\r\n this.close(true);\r\n }\r\n\r\n // ── ControlValueAccessor ────────────────────────────────────────────────────\r\n\r\n writeValue(value: string | null): void {\r\n this.value = value ?? '';\r\n this.cdr.markForCheck();\r\n }\r\n\r\n registerOnChange(fn: (value: string) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n /** Called by Angular when the bound FormControl is programmatically disabled or enabled. */\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.cdr.markForCheck();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n Output,\r\n ViewChild,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\r\nimport { CdkListbox, CdkOption, ListboxValueChangeEvent } from '@angular/cdk/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition } from '@angular/cdk/overlay';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { DropdownLabelPosition, DropdownOption, DropdownSize } from './dropdown-types';\r\n\r\nlet nextId = 0;\r\n\r\n/**\r\n * A labelled single-select dropdown built on the CDK Listbox (`@angular/cdk/listbox`)\r\n * and CDK Overlay. The trigger renders the closed field (label, placeholder/selected\r\n * value and chevron); the options open in an overlay panel with full keyboard support\r\n * (arrow keys, Home/End, typeahead) provided by the CDK listbox.\r\n *\r\n * Implements `ControlValueAccessor` so it works with both reactive forms\r\n * (`formControlName`, `[formControl]`) and template-driven forms (`ngModel`). The error\r\n * visual state is driven automatically by the bound `FormControl`'s validity once the\r\n * field has been touched, and can also be set explicitly via the `error` input.\r\n */\r\n@Component({\r\n selector: 'compsych-dropdown',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin],\r\n template: `\r\n <div [class]=\"wrapperClasses\">\r\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\r\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\r\n {{ label }}\r\n @if (isRequired) {\r\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\r\n }\r\n </label>\r\n </div>\r\n\r\n <button\r\n #triggerBtn\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n type=\"button\"\r\n class=\"trigger\"\r\n [id]=\"triggerId\"\r\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\r\n [class.error]=\"hasError\"\r\n [class.open]=\"isOpen\"\r\n [disabled]=\"disabled\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"isOpen\"\r\n [attr.aria-controls]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\r\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\r\n [attr.aria-required]=\"isRequired ? 'true' : null\"\r\n [attr.aria-describedby]=\"describedBy\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n >\r\n @if (triggerIconSvg) {\r\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"triggerIconSvg\"></span>\r\n }\r\n <span class=\"trigger-text\">{{ triggerText }}</span>\r\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\r\n </button>\r\n\r\n @if (displayedSupportingText) {\r\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\r\n {{ displayedSupportingText }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen\"\r\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\r\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\r\n [cdkConnectedOverlayViewportMargin]=\"8\"\r\n (overlayOutsideClick)=\"close()\"\r\n (attach)=\"onPanelAttach()\"\r\n (detach)=\"close()\"\r\n >\r\n <ul\r\n #listboxEl\r\n cdkListbox\r\n class=\"panel\"\r\n [class.sm]=\"size === 'sm'\"\r\n [style.width.px]=\"overlayWidth\"\r\n [id]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId\"\r\n [cdkListboxValue]=\"listboxValue\"\r\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\r\n (keydown)=\"onListboxKeydown($event)\"\r\n >\r\n @for (opt of options; track opt.value) {\r\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\r\n <span class=\"option-inner\">\r\n @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {\r\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIcon(opt)\"></span>\r\n }\r\n <span class=\"option-text\">\r\n <span class=\"option-label\">{{ opt.label }}</span>\r\n @if (opt.supportingText) {\r\n <span class=\"option-support\">{{ opt.supportingText }}</span>\r\n }\r\n </span>\r\n </span>\r\n </li>\r\n }\r\n </ul>\r\n </ng-template>\r\n `,\r\n styleUrl: './dropdown.css',\r\n})\r\nexport class DropdownComponent implements ControlValueAccessor, OnChanges {\r\n private readonly _autoId = `cmp-dropdown-${++nextId}`;\r\n private readonly cdr = inject(ChangeDetectorRef);\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private _onChange: (value: string) => void = () => {};\r\n private _onTouched: () => void = () => {};\r\n\r\n /** Injected when the component is used inside a reactive or template-driven form. */\r\n protected readonly ngControl: NgControl | null;\r\n\r\n constructor() {\r\n const ctrl = inject(NgControl, { optional: true, self: true });\r\n if (ctrl) ctrl.valueAccessor = this;\r\n this.ngControl = ctrl;\r\n this.chevronSvg = this.buildIconSvg('chevron-down');\r\n }\r\n\r\n @ViewChild('triggerBtn') private triggerBtn?: ElementRef<HTMLButtonElement>;\r\n @ViewChild('listboxEl') private listboxEl?: ElementRef<HTMLUListElement>;\r\n\r\n /** Label displayed above the trigger. */\r\n @Input() label = '';\r\n /** Text shown in the trigger when no option is selected. */\r\n @Input() placeholder = '';\r\n /** Currently selected value. When used in a form, the form controls the value. */\r\n @Input() value = '';\r\n /** Selectable options rendered in the overlay panel. */\r\n @Input() options: DropdownOption[] = [];\r\n /** Size variant — controls height, padding, and font size. Defaults to `'md'`. */\r\n @Input() size: DropdownSize = 'md';\r\n /** Native `id` attribute for the trigger. Auto-generated if omitted. */\r\n @Input() id?: string;\r\n /**\r\n * Id(s) of external elements that describe the field, space-separated.\r\n * Forwarded to `aria-describedby` on the trigger.\r\n */\r\n @Input() ariaDescribedBy?: string;\r\n /** Text displayed below the trigger. Shown in red when in error state. */\r\n @Input() supportingText = '';\r\n /**\r\n * Static error text shown in red when in error state. Used when the dropdown is\r\n * outside a form (with `[error]=\"true\"`). When inside a form, prefer `errorMessages`.\r\n */\r\n @Input() errorMessage = '';\r\n /**\r\n * Map of Angular validator error keys to display strings. The component reads\r\n * `ngControl.errors` to determine which validator failed and shows the matching\r\n * message in red below the trigger. Example: `{ required: 'Please choose an option' }`\r\n */\r\n @Input() errorMessages: Record<string, string> = {};\r\n /**\r\n * Adds a blue asterisk after the label. When used in a form, this is set\r\n * automatically if the bound `FormControl` has `Validators.required`.\r\n * Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) required = false;\r\n /**\r\n * Applies the error visual state (red border) explicitly. When used in a form,\r\n * the error state is driven automatically from the `FormControl`'s validity once\r\n * the field is touched — this input is only needed outside of forms. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) error = false;\r\n /** Disables the dropdown. When used in a form, also responds to `FormControl.disable()`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /** Visually hides the label while keeping it accessible to screen readers. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) hideLabel = false;\r\n /** Places the label above the trigger (`'top'`, default) or beside it (`'left'`). */\r\n @Input() labelPosition: DropdownLabelPosition = 'top';\r\n /**\r\n * Renders the label as the trigger's own resting text instead of a separate\r\n * label above/beside it — e.g. the trigger reads \"I want to\" until an option\r\n * is chosen. No visible external label is shown, but the `label` is still\r\n * exposed to assistive tech (a screen-reader-only `<label>` + `aria-labelledby`),\r\n * so the field is announced as a properly labelled combobox. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) inlineLabel = false;\r\n /** Lucide icon name rendered inside the trigger, before the displayed value/placeholder (e.g. `'globe'`). */\r\n @Input() leadingIcon?: string;\r\n /** Default Lucide icon shown before every option's label; each option's own `icon` (from the Icon Mapping) overrides it. */\r\n @Input() optionsLeadingIcon?: string;\r\n\r\n /** Emits the newly selected value whenever the user picks an option. */\r\n @Output() readonly valueChange = new EventEmitter<string>();\r\n /** Emitted when the overlay panel opens. */\r\n @Output() readonly opened = new EventEmitter<void>();\r\n /** Emitted when the overlay panel closes. */\r\n @Output() readonly closed = new EventEmitter<void>();\r\n\r\n protected readonly chevronSvg: SafeHtml;\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n private readonly optionIconCache = new Map<string, SafeHtml>();\r\n\r\n protected isOpen = false;\r\n protected overlayWidth = 0;\r\n protected readonly overlayPositions: ConnectedPosition[] = [\r\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },\r\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },\r\n ];\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n }\r\n\r\n private buildIconSvg(name: string): SafeHtml {\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', '<svg width=\"20\" height=\"20\" ');\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /**\r\n * Scales trusted raw SVG (e.g. a flag) to 20px wide, preserving aspect ratio via its\r\n * viewBox. Only the root `<svg>` tag's width/height are normalized — inner elements\r\n * (rects/paths that draw the icon) keep their own dimensions.\r\n */\r\n private buildRawIconSvg(svg: string): SafeHtml {\r\n const sized = svg.replace(/<svg\\b[^>]*>/, (openTag) =>\r\n openTag.replace(/\\s(?:width|height)=\"[^\"]*\"/g, '').replace('<svg', '<svg width=\"20\"')\r\n );\r\n return this.sanitizer.bypassSecurityTrustHtml(sized);\r\n }\r\n\r\n /**\r\n * Resolves an icon to cached SafeHtml: a trusted raw `iconSvg` wins, else a Lucide\r\n * `iconName`. Returns null when neither is set. Cached so rows keep a stable reference.\r\n */\r\n private resolveIcon(iconSvg: string | undefined, iconName: string | undefined): SafeHtml | null {\r\n if (iconSvg) {\r\n const key = 'raw:' + iconSvg;\r\n let svg = this.optionIconCache.get(key);\r\n if (!svg) {\r\n svg = this.buildRawIconSvg(iconSvg);\r\n this.optionIconCache.set(key, svg);\r\n }\r\n return svg;\r\n }\r\n if (iconName) {\r\n let svg = this.optionIconCache.get(iconName);\r\n if (!svg) {\r\n svg = this.buildIconSvg(iconName);\r\n this.optionIconCache.set(iconName, svg);\r\n }\r\n return svg;\r\n }\r\n return null;\r\n }\r\n\r\n /** Icon for an option row: its own `iconSvg`/`icon`, else the shared `optionsLeadingIcon`. */\r\n protected optionIcon(option: DropdownOption): SafeHtml | null {\r\n return this.resolveIcon(option.iconSvg, option.icon ?? this.optionsLeadingIcon);\r\n }\r\n\r\n /** Icon in the trigger: the selected option's own icon (flag/glyph), else the fixed `leadingIcon`. */\r\n get triggerIconSvg(): SafeHtml | null {\r\n return this.resolveIcon(this.selectedOption?.iconSvg, this.selectedOption?.icon) ?? this.leadingIconSvg;\r\n }\r\n\r\n get triggerId(): string {\r\n return this.id ?? this._autoId;\r\n }\r\n\r\n get labelId(): string {\r\n return this.triggerId + '-label';\r\n }\r\n\r\n get listboxId(): string {\r\n return this.triggerId + '-listbox';\r\n }\r\n\r\n get selectedOption(): DropdownOption | undefined {\r\n return this.options.find((o) => o.value === this.value);\r\n }\r\n\r\n /**\r\n * Resting text shown in the trigger: the selected option's label, else the\r\n * `label` in inline-label mode (so the label reads as the field's own text),\r\n * else the placeholder.\r\n */\r\n get triggerText(): string {\r\n return this.selectedOption?.label || (this.inlineLabel ? this.label : this.placeholder);\r\n }\r\n\r\n /** Value array bound to the CDK listbox (single-select, so 0 or 1 entry). */\r\n get listboxValue(): readonly string[] {\r\n return this.value ? [this.value] : [];\r\n }\r\n\r\n /** True when the bound FormControl is invalid and touched, or when `error` is explicitly set. */\r\n get hasError(): boolean {\r\n return this.error || !!(this.ngControl?.invalid && this.ngControl.touched);\r\n }\r\n\r\n /** True when `required` is set explicitly, or when the bound FormControl has Validators.required. */\r\n get isRequired(): boolean {\r\n return this.required || !!this.ngControl?.control?.hasValidator(Validators.required);\r\n }\r\n\r\n private get activeErrorMessage(): string {\r\n const errors = this.ngControl?.errors;\r\n if (!errors) return '';\r\n for (const key of Object.keys(errors)) {\r\n if (this.errorMessages[key]) return this.errorMessages[key];\r\n }\r\n return '';\r\n }\r\n\r\n get displayedSupportingText(): string {\r\n if (this.hasError) {\r\n return this.activeErrorMessage || this.errorMessage || this.supportingText;\r\n }\r\n return this.supportingText;\r\n }\r\n\r\n get describedBy(): string | null {\r\n const parts: string[] = [];\r\n if (this.ariaDescribedBy) parts.push(this.ariaDescribedBy);\r\n if (this.supportingText || this.errorMessage || Object.keys(this.errorMessages).length) {\r\n parts.push(this.triggerId + '-supporting');\r\n }\r\n return parts.length ? parts.join(' ') : null;\r\n }\r\n\r\n get wrapperClasses(): string {\r\n return ['cmp-dropdown', this.size, this.disabled ? 'disabled' : '', this.labelPosition === 'left' ? 'label-left' : '']\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // ── Open / close ──────────────────────────────────────────────────────────\r\n\r\n protected toggle(): void {\r\n if (this.isOpen) {\r\n this.close(true);\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n protected open(): void {\r\n if (this.disabled || this.isOpen) return;\r\n this.overlayWidth = this.triggerBtn?.nativeElement.offsetWidth ?? 0;\r\n this.isOpen = true;\r\n this.opened.emit();\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected close(refocus = false): void {\r\n if (!this.isOpen) return;\r\n this.isOpen = false;\r\n this._onTouched();\r\n this.closed.emit();\r\n if (refocus) {\r\n setTimeout(() => this.triggerBtn?.nativeElement.focus());\r\n }\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected onPanelAttach(): void {\r\n setTimeout(() => this.listboxEl?.nativeElement.focus());\r\n }\r\n\r\n // ── Keyboard ──────────────────────────────────────────────────────────────\r\n\r\n protected onTriggerKeydown(event: KeyboardEvent): void {\r\n if (this.disabled) return;\r\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && !this.isOpen) {\r\n event.preventDefault();\r\n this.open();\r\n } else if (event.key === 'Escape' && this.isOpen) {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Escape') {\r\n event.preventDefault();\r\n this.close(true);\r\n } else if (event.key === 'Tab') {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxValueChange(event: ListboxValueChangeEvent<string>): void {\r\n const next = event.value[0] ?? '';\r\n this.value = next;\r\n this._onChange(next);\r\n this.valueChange.emit(next);\r\n this.close(true);\r\n }\r\n\r\n // ── ControlValueAccessor ────────────────────────────────────────────────────\r\n\r\n writeValue(value: string | null): void {\r\n this.value = value ?? '';\r\n this.cdr.markForCheck();\r\n }\r\n\r\n registerOnChange(fn: (value: string) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n /** Called by Angular when the bound FormControl is programmatically disabled or enabled. */\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.cdr.markForCheck();\r\n }\r\n}\r\n"]}
@@ -120,7 +120,7 @@ export declare class CardComponent {
120
120
  readonly actionLeadingIcon: import("@angular/core").InputSignal<string>;
121
121
  /** Content: trailing Lucide icon name rendered inside the action pill. */
122
122
  readonly actionTrailingIcon: import("@angular/core").InputSignal<string>;
123
- /** Content (`appearance="banner"`): disables the action button. */
123
+ /** Content: disables the action button. */
124
124
  readonly actionDisabled: import("@angular/core").InputSignal<boolean>;
125
125
  /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */
126
126
  readonly inlineIcon: import("@angular/core").InputSignal<boolean>;
@@ -179,9 +179,9 @@ export declare class CardComponent {
179
179
  */
180
180
  readonly effectiveHeadingLevel: import("@angular/core").Signal<CardHeadingLevel | undefined>;
181
181
  /** Base Card Item plain-icon glyph size by `size` (48 md, 32 sm, 24 xs). */
182
- readonly basicIconSize: import("@angular/core").Signal<24 | 32 | 48>;
182
+ readonly basicIconSize: import("@angular/core").Signal<32 | 24 | 48>;
183
183
  /** Base Card Item arrow glyph size by `size` (24 md, 20 sm/xs). */
184
- readonly basicArrowSize: import("@angular/core").Signal<20 | 24>;
184
+ readonly basicArrowSize: import("@angular/core").Signal<24 | 20>;
185
185
  /** CSS `url(...)` for the media layer, or null when no image is set. */
186
186
  readonly mediaUrl: import("@angular/core").Signal<string | null>;
187
187
  /** Padding resolved per variant; `basic` honors the `padding` input. */
@@ -19,6 +19,13 @@ export interface DropdownOption {
19
19
  * (use → glyph). Overrides the dropdown's `optionsLeadingIcon` default for this row.
20
20
  */
21
21
  icon?: string;
22
+ /**
23
+ * Raw, **trusted** SVG markup for a non-Lucide icon (e.g. a country flag from an
24
+ * icon pack) rendered in place of `icon`. Takes precedence over `icon`. The string
25
+ * is sanitized-bypassed and scaled to 20px wide, so only pass static/trusted SVG —
26
+ * never untrusted user input.
27
+ */
28
+ iconSvg?: string;
22
29
  }
23
30
  /** ARIA contract for a standalone `compsych-dropdown-menu`: an action `menu` or a select `listbox`. */
24
31
  export type DropdownMenuKind = 'menu' | 'listbox';
@@ -101,8 +101,21 @@ export declare class DropdownComponent implements ControlValueAccessor, OnChange
101
101
  protected readonly overlayPositions: ConnectedPosition[];
102
102
  ngOnChanges(): void;
103
103
  private buildIconSvg;
104
- /** Cached option-icon SVG by Lucide name (stable reference so option rows don't re-render each cycle). */
105
- protected optionIconSvg(name: string | undefined): SafeHtml;
104
+ /**
105
+ * Scales trusted raw SVG (e.g. a flag) to 20px wide, preserving aspect ratio via its
106
+ * viewBox. Only the root `<svg>` tag's width/height are normalized — inner elements
107
+ * (rects/paths that draw the icon) keep their own dimensions.
108
+ */
109
+ private buildRawIconSvg;
110
+ /**
111
+ * Resolves an icon to cached SafeHtml: a trusted raw `iconSvg` wins, else a Lucide
112
+ * `iconName`. Returns null when neither is set. Cached so rows keep a stable reference.
113
+ */
114
+ private resolveIcon;
115
+ /** Icon for an option row: its own `iconSvg`/`icon`, else the shared `optionsLeadingIcon`. */
116
+ protected optionIcon(option: DropdownOption): SafeHtml | null;
117
+ /** Icon in the trigger: the selected option's own icon (flag/glyph), else the fixed `leadingIcon`. */
118
+ get triggerIconSvg(): SafeHtml | null;
106
119
  get triggerId(): string;
107
120
  get labelId(): string;
108
121
  get listboxId(): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compsych-ui-components/angular",
3
- "version": "7.0.46",
3
+ "version": "7.0.47",
4
4
  "description": "Angular UI components for compsych",
5
5
  "publishConfig": {
6
6
  "access": "public",