@foxeltech/angular-ui 0.7.124 → 0.7.133

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.
@@ -2581,11 +2581,11 @@ class ButtonComponent {
2581
2581
  this.clicked.emit();
2582
2582
  }
2583
2583
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2584
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ButtonComponent, isStandalone: true, selector: "fx-ui-button", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, buttonVariant: { classPropertyName: "buttonVariant", publicName: "buttonVariant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\n [class]=\"class()\"\n [ngClass]=\"{\n 'fx-btn--icon': !!icon && !label,\n 'btn-default': buttonVariant() === 'default',\n 'btn-primary': buttonVariant() === 'primary',\n 'btn-success': buttonVariant() === 'success',\n 'btn-cta': buttonVariant() === 'cta',\n 'btn-alternative': buttonVariant() === 'alternative',\n }\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"onClick()\"\n>\n @if (loading()) {\n <div class=\"flex w-full items-center justify-center\" aria-hidden=\"true\">\n <svg\n [attr.fill]=\"\n buttonVariant() !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'\n \"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_lo66\"\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_z0Or\"\n begin=\"spinner_lo66.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_JsnR\"\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_Aguh\"\n begin=\"spinner_JsnR.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_hSjk\"\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_UHR2\"\n begin=\"spinner_hSjk.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate\n id=\"spinner_4v5M\"\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_OLMs\"\n begin=\"spinner_4v5M.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n </circle>\n </svg>\n </div>\n } @else {\n <ng-container>\n <div class=\"flex items-center justify-center gap-small\">\n @if (icon) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"16\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <!-- text-box: optical centering \u2014 Archivo's leading floats ink up otherwise -->\n <div class=\"[text-box:trim-both_cap_alphabetic]\">{{ label }}</div>\n }\n </div>\n </ng-container>\n }\n</button>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2584
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ButtonComponent, isStandalone: true, selector: "fx-ui-button", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, buttonVariant: { classPropertyName: "buttonVariant", publicName: "buttonVariant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: false, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\n [class]=\"class()\"\n [ngClass]=\"{\n 'fx-btn--icon': !!icon && !label,\n 'btn-default': buttonVariant() === 'default',\n 'btn-primary': buttonVariant() === 'primary',\n 'btn-success': buttonVariant() === 'success',\n 'btn-cta': buttonVariant() === 'cta',\n 'btn-alternative': buttonVariant() === 'alternative',\n }\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"onClick()\"\n>\n <!-- Loading keeps the LABEL, as the sign-in button does: a button that\n swaps its text for a spinner collapses to a stub, and the row jumps.\n The ring is that button's `.li-spin`, in the foreground the variant\n already uses for its icon so it reads on a coloured ground. -->\n <!-- 6px, the reference button's own gap; `gap-small` is 4px. -->\n <div class=\"flex items-center justify-center gap-[6px]\">\n @if (loading()) {\n <span\n class=\"fx-btn__spin\"\n aria-hidden=\"true\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></span>\n } @else if (icon) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"13\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <!-- text-box: optical centering \u2014 Archivo's leading floats ink up otherwise -->\n <div class=\"[text-box:trim-both_cap_alphabetic]\">{{ label }}</div>\n }\n </div>\n</button>\n", styles: ["@charset \"UTF-8\";.fx-btn__spin{display:inline-block;width:12px;height:12px;flex:0 0 auto;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.9;animation:fx-btn-spin .8s linear infinite}@keyframes fx-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.fx-btn__spin{animation:none}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2585
2585
  }
2586
2586
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ButtonComponent, decorators: [{
2587
2587
  type: Component,
2588
- args: [{ selector: 'fx-ui-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, HeroIconComponent], template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\n [class]=\"class()\"\n [ngClass]=\"{\n 'fx-btn--icon': !!icon && !label,\n 'btn-default': buttonVariant() === 'default',\n 'btn-primary': buttonVariant() === 'primary',\n 'btn-success': buttonVariant() === 'success',\n 'btn-cta': buttonVariant() === 'cta',\n 'btn-alternative': buttonVariant() === 'alternative',\n }\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"onClick()\"\n>\n @if (loading()) {\n <div class=\"flex w-full items-center justify-center\" aria-hidden=\"true\">\n <svg\n [attr.fill]=\"\n buttonVariant() !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'\n \"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"4\" cy=\"12\" r=\"0\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_lo66\"\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_z0Or\"\n begin=\"spinner_lo66.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"4\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_JsnR\"\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_Aguh\"\n begin=\"spinner_JsnR.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"12\" cy=\"12\" r=\"3\">\n <animate\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_hSjk\"\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_UHR2\"\n begin=\"spinner_hSjk.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n </circle>\n <circle cx=\"20\" cy=\"12\" r=\"3\">\n <animate\n id=\"spinner_4v5M\"\n begin=\"0;spinner_z0Or.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"3;0\"\n fill=\"freeze\"\n />\n <animate\n id=\"spinner_OLMs\"\n begin=\"spinner_4v5M.end\"\n attributeName=\"cx\"\n dur=\"0.001s\"\n values=\"20;4\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_OLMs.end\"\n attributeName=\"r\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"0;3\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_UHR2.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"4;12\"\n fill=\"freeze\"\n />\n <animate\n begin=\"spinner_Aguh.end\"\n attributeName=\"cx\"\n calcMode=\"spline\"\n dur=\"0.5s\"\n keySplines=\".36,.6,.31,1\"\n values=\"12;20\"\n fill=\"freeze\"\n />\n </circle>\n </svg>\n </div>\n } @else {\n <ng-container>\n <div class=\"flex items-center justify-center gap-small\">\n @if (icon) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"16\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <!-- text-box: optical centering \u2014 Archivo's leading floats ink up otherwise -->\n <div class=\"[text-box:trim-both_cap_alphabetic]\">{{ label }}</div>\n }\n </div>\n </ng-container>\n }\n</button>\n" }]
2588
+ args: [{ selector: 'fx-ui-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, HeroIconComponent], template: "<button\n [attr.type]=\"type()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"loading() || null\"\n [class]=\"class()\"\n [ngClass]=\"{\n 'fx-btn--icon': !!icon && !label,\n 'btn-default': buttonVariant() === 'default',\n 'btn-primary': buttonVariant() === 'primary',\n 'btn-success': buttonVariant() === 'success',\n 'btn-cta': buttonVariant() === 'cta',\n 'btn-alternative': buttonVariant() === 'alternative',\n }\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"onClick()\"\n>\n <!-- Loading keeps the LABEL, as the sign-in button does: a button that\n swaps its text for a spinner collapses to a stub, and the row jumps.\n The ring is that button's `.li-spin`, in the foreground the variant\n already uses for its icon so it reads on a coloured ground. -->\n <!-- 6px, the reference button's own gap; `gap-small` is 4px. -->\n <div class=\"flex items-center justify-center gap-[6px]\">\n @if (loading()) {\n <span\n class=\"fx-btn__spin\"\n aria-hidden=\"true\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></span>\n } @else if (icon) {\n <fx-ui-hero-icon\n [icon]=\"icon\"\n [size]=\"13\"\n class=\"flex\"\n [ngClass]=\"{\n 'text-text-inverse': buttonVariant() === 'default',\n 'text-text-primary': buttonVariant() === 'alternative',\n 'text-accent-contrast': buttonVariant() === 'primary',\n 'text-surface': buttonVariant() === 'success',\n 'text-white': buttonVariant() === 'cta',\n }\"\n ></fx-ui-hero-icon>\n }\n @if (label) {\n <!-- text-box: optical centering \u2014 Archivo's leading floats ink up otherwise -->\n <div class=\"[text-box:trim-both_cap_alphabetic]\">{{ label }}</div>\n }\n </div>\n</button>\n", styles: ["@charset \"UTF-8\";.fx-btn__spin{display:inline-block;width:12px;height:12px;flex:0 0 auto;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.9;animation:fx-btn-spin .8s linear infinite}@keyframes fx-btn-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.fx-btn__spin{animation:none}}\n"] }]
2589
2589
  }], propDecorators: { label: [{
2590
2590
  type: Input
2591
2591
  }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], buttonVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonVariant", required: false }] }], icon: [{
@@ -4147,7 +4147,7 @@ class DrawerComponent {
4147
4147
  return this.isExpanded ? 'expanded' : 'collapsed';
4148
4148
  }
4149
4149
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DrawerComponent, deps: [{ token: i2$1.Router }], target: i0.ɵɵFactoryTarget.Component });
4150
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DrawerComponent, isStandalone: true, selector: "fx-ui-drawer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, footerItems: { classPropertyName: "footerItems", publicName: "footerItems", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: false, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: false, isRequired: false, transformFunction: null }, logoText: { classPropertyName: "logoText", publicName: "logoText", isSignal: false, isRequired: false, transformFunction: null }, logoSubtext: { classPropertyName: "logoSubtext", publicName: "logoSubtext", isSignal: false, isRequired: false, transformFunction: null }, version: { classPropertyName: "version", publicName: "version", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { toggleExpanded: "toggleExpanded", itemClicked: "itemClicked" }, ngImport: i0, template: "<div class=\"drawer-host-wrapper\">\n <a href=\"/\" class=\"drawer-brand\" [class.is-collapsed]=\"!isExpanded\">\n <!-- Logo sits in its own sunken tile (reference `.sb-logo`, measured 16/09):\n the tile is what carries the hover border, so the mark keeps its own\n size and nothing shifts by a pixel when that border appears. -->\n <span class=\"drawer-brand-logo\">\n @if (logo) {\n <img [src]=\"logo\" alt=\"Home\" class=\"drawer-brand-mark\" />\n } @else {\n <span class=\"drawer-brand-mark\"></span>\n }\n </span>\n @if (isExpanded && (logoText || logoSubtext)) {\n <span class=\"drawer-brand-copy\">\n @if (logoText) {\n <span class=\"drawer-brand-text\">{{ logoText }}</span>\n }\n @if (logoSubtext) {\n <span class=\"drawer-brand-subtext\">{{ logoSubtext }}</span>\n }\n </span>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- V2: bottom section (Administration group, user block, \u2026) -->\n <div class=\"mt-auto\">\n @if (footerItems().length) {\n <nav class=\"drawer-footer-nav\">\n @for (item of footerItems(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n }\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n @if (item.heading) {\n @if (isExpanded) {\n <div class=\"drawer-section-label\">{{ item.label }}</div>\n } @else {\n <div class=\"drawer-section-rule\"></div>\n }\n } @else {\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n @if (item.route && !item.children) {\n <a\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 13 : 18\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 13 : 18\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\n type=\"button\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 13 : 18\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 13 : 18\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;display:flex;height:100%;flex-direction:column;background:rgb(var(--og-surface-sunken));border-right:1px solid rgb(var(--og-border-subtle))}.drawer-brand{display:flex;height:60px;flex-shrink:0;align-items:center;gap:10px;overflow:hidden;text-decoration-line:none;padding-left:16px;padding-right:8px;transition:padding .3s cubic-bezier(.4,0,.2,1);max-width:260px}.drawer-brand.is-collapsed{justify-content:center;padding-left:0;padding-right:0;max-width:70px}.drawer-brand-logo{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;padding:6px;border-radius:var(--og-radius-control);background:rgb(var(--og-surface-sunken));border:1px solid transparent;transition:padding .22s cubic-bezier(.4,0,.2,1),border-color .15s ease}.drawer-brand:hover .drawer-brand-logo{border-color:rgb(var(--og-border))}.drawer-brand.is-collapsed .drawer-brand-logo{padding:4px}.drawer-brand-mark{height:21px;width:auto;flex-shrink:0}.drawer-brand.is-collapsed .drawer-brand-mark{height:19px}.drawer-brand-copy{display:flex;min-width:0px;flex-direction:column;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25)}.drawer-brand-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--og-fs-lg);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary));-webkit-user-select:none;user-select:none;font-family:var(--og-font-display);letter-spacing:-.015em;line-height:1}.drawer-brand-subtext{margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;--tw-font-weight: var(--font-weight-normal, 400);font-weight:var(--font-weight-normal, 400);-webkit-user-select:none;user-select:none;color:rgb(var(--og-text-muted));letter-spacing:.02em;line-height:1.2}.drawer-container{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden;padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:background-color .2s ease,box-shadow .2s ease}.toggle-btn:before{content:\"\";position:absolute;inset:-8px;border-radius:9999px}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{background-color:rgb(var(--bg-primary-hover))}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-footer-nav{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:0px;padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:var(--spacing, .25rem)}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:var(--og-radius-control);background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-section-label{padding-inline:1rem;padding-top:calc(var(--spacing, .25rem) * 4);padding-bottom:var(--spacing, .25rem);font-size:10.5px;line-height:1.4;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgb(var(--og-text-faint));-webkit-user-select:none;user-select:none;letter-spacing:var(--og-tracking-label)}.drawer-section-rule{margin-inline:calc(var(--spacing, .25rem) * 3);margin-block:calc(var(--spacing, .25rem) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;display:flex;width:100%;cursor:pointer;align-items:center;--tw-border-style: none;border-style:none;background-color:transparent;text-decoration-line:none;margin-top:1px;min-height:30px;padding:6px 8px;font-size:var(--og-fs-sm);color:rgb(var(--og-text-body));border-radius:var(--og-radius-control);transition:background-color .13s ease,color .13s ease}.drawer-item:hover{color:rgb(var(--og-text));background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item:hover{background:color-mix(in srgb,rgb(var(--og-text)) 8%,transparent)}}.drawer-item.active{color:rgb(var(--og-text));font-weight:500;background:rgb(var(--og-text));box-shadow:inset 0 0 0 1px rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{background:color-mix(in srgb,rgb(var(--og-text)) 6%,transparent)}}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{box-shadow:inset 0 0 0 1px color-mix(in srgb,rgb(var(--og-text)) 7%,transparent)}}.drawer-item.active:hover{background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active:hover{background:color-mix(in srgb,rgb(var(--og-text)) 9%,transparent)}}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:9px;overflow:hidden}.drawer-item.is-collapsed .item-icon{width:18px;height:18px;margin-right:0}.item-icon--solid{fill:currentColor}:host ::ng-deep .item-icon--solid svg,:host ::ng-deep .item-icon--solid path,:host ::ng-deep .item-icon--solid polygon{fill:currentColor}.item-icon{flex-shrink:0;color:inherit;width:13px;height:13px;margin-right:5px}.item-label{flex:1;overflow:hidden;text-align:left;--tw-leading: 18px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;font-size:inherit}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:var(--og-font-mono)}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "ngmodule", type: FxLucideModule }, { kind: "component", type: i1$4.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], animations: [
4150
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DrawerComponent, isStandalone: true, selector: "fx-ui-drawer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, footerItems: { classPropertyName: "footerItems", publicName: "footerItems", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: false, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: false, isRequired: false, transformFunction: null }, logoText: { classPropertyName: "logoText", publicName: "logoText", isSignal: false, isRequired: false, transformFunction: null }, logoSubtext: { classPropertyName: "logoSubtext", publicName: "logoSubtext", isSignal: false, isRequired: false, transformFunction: null }, version: { classPropertyName: "version", publicName: "version", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { toggleExpanded: "toggleExpanded", itemClicked: "itemClicked" }, ngImport: i0, template: "<div class=\"drawer-host-wrapper\">\n <a href=\"/\" class=\"drawer-brand\" [class.is-collapsed]=\"!isExpanded\">\n <!-- Logo sits in its own sunken tile (reference `.sb-logo`, measured 16/09):\n the tile is what carries the hover border, so the mark keeps its own\n size and nothing shifts by a pixel when that border appears. -->\n <span class=\"drawer-brand-logo\">\n @if (logo) {\n <img [src]=\"logo\" alt=\"Home\" class=\"drawer-brand-mark\" />\n } @else {\n <span class=\"drawer-brand-mark\"></span>\n }\n </span>\n @if (isExpanded && (logoText || logoSubtext)) {\n <span class=\"drawer-brand-copy\">\n @if (logoText) {\n <span class=\"drawer-brand-text\">{{ logoText }}</span>\n }\n @if (logoSubtext) {\n <span class=\"drawer-brand-subtext\">{{ logoSubtext }}</span>\n }\n </span>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- V2: bottom section (Administration group, user block, \u2026) -->\n <div class=\"mt-auto\">\n @if (footerItems().length) {\n <nav class=\"drawer-footer-nav\">\n @for (item of footerItems(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n }\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n @if (item.heading) {\n @if (isExpanded) {\n <div class=\"drawer-section-label\">{{ item.label }}</div>\n } @else {\n <div class=\"drawer-section-rule\"></div>\n }\n } @else {\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n @if (item.route && !item.children) {\n <a\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 15 : 20\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 15 : 20\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\n type=\"button\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 15 : 20\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 15 : 20\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;display:flex;height:100%;flex-direction:column;background:rgb(var(--og-surface-sunken));border-right:1px solid rgb(var(--og-border-subtle))}.drawer-brand{display:flex;height:60px;flex-shrink:0;align-items:center;gap:10px;overflow:hidden;text-decoration-line:none;padding-left:16px;padding-right:8px;transition:padding .3s cubic-bezier(.4,0,.2,1);max-width:260px}.drawer-brand.is-collapsed{justify-content:center;padding-left:0;padding-right:0;max-width:70px}.drawer-brand-logo{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;padding:6px;border-radius:var(--og-radius-control);background:rgb(var(--og-surface-sunken));border:1px solid transparent;transition:padding .22s cubic-bezier(.4,0,.2,1),border-color .15s ease}.drawer-brand:hover .drawer-brand-logo{border-color:rgb(var(--og-border))}.drawer-brand.is-collapsed .drawer-brand-logo{padding:4px}.drawer-brand-mark{height:21px;width:auto;flex-shrink:0}.drawer-brand.is-collapsed .drawer-brand-mark{height:19px}.drawer-brand-copy{display:flex;min-width:0px;flex-direction:column;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25)}.drawer-brand-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--og-fs-lg);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary));-webkit-user-select:none;user-select:none;font-family:var(--og-font-display);letter-spacing:-.015em;line-height:1}.drawer-brand-subtext{margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;--tw-font-weight: var(--font-weight-normal, 400);font-weight:var(--font-weight-normal, 400);-webkit-user-select:none;user-select:none;color:rgb(var(--og-text-muted));letter-spacing:.02em;line-height:1.2}.drawer-container{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden;padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:background-color .2s ease,box-shadow .2s ease}.toggle-btn:before{content:\"\";position:absolute;inset:-8px;border-radius:9999px}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{background-color:rgb(var(--bg-primary-hover))}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-footer-nav{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:0px;padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:var(--spacing, .25rem)}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:var(--og-radius-control);background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-section-label{padding-inline:1rem;padding-top:calc(var(--spacing, .25rem) * 4);padding-bottom:var(--spacing, .25rem);font-size:var(--og-fs-xs);line-height:1.4;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgb(var(--og-text-faint));-webkit-user-select:none;user-select:none;letter-spacing:var(--og-tracking-label)}.drawer-section-rule{margin-inline:calc(var(--spacing, .25rem) * 3);margin-block:calc(var(--spacing, .25rem) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;display:flex;width:100%;cursor:pointer;align-items:center;--tw-border-style: none;border-style:none;background-color:transparent;text-decoration-line:none;margin-top:1px;min-height:34px;padding:7px 8px;font-size:14px;color:rgb(var(--og-text-body));border-radius:var(--og-radius-control);transition:background-color .13s ease,color .13s ease}.drawer-item:hover{color:rgb(var(--og-text));background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item:hover{background:color-mix(in srgb,rgb(var(--og-text)) 8%,transparent)}}.drawer-item.active{color:rgb(var(--og-text));font-weight:500;background:rgb(var(--og-text));box-shadow:inset 0 0 0 1px rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{background:color-mix(in srgb,rgb(var(--og-text)) 6%,transparent)}}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{box-shadow:inset 0 0 0 1px color-mix(in srgb,rgb(var(--og-text)) 7%,transparent)}}.drawer-item.active:hover{background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active:hover{background:color-mix(in srgb,rgb(var(--og-text)) 9%,transparent)}}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:9px;overflow:hidden}.drawer-item.is-collapsed .item-icon{width:20px;height:20px;margin-right:0}.item-icon--solid{fill:currentColor}:host ::ng-deep .item-icon--solid svg,:host ::ng-deep .item-icon--solid path,:host ::ng-deep .item-icon--solid polygon{fill:currentColor}.item-icon{flex-shrink:0;color:inherit;width:15px;height:15px;margin-right:6px}.item-label{flex:1;overflow:hidden;text-align:left;--tw-leading: 20px;line-height:20px;text-overflow:ellipsis;white-space:nowrap;font-size:inherit}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:12px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:var(--og-font-mono)}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "ngmodule", type: FxLucideModule }, { kind: "component", type: i1$4.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], animations: [
4151
4151
  trigger('drawerExpand', [
4152
4152
  state('collapsed', style({ width: '70px' })),
4153
4153
  state('expanded', style({ width: '260px' })),
@@ -4179,7 +4179,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
4179
4179
  HeroIconComponent,
4180
4180
  FxLucideModule,
4181
4181
  RouterLink,
4182
- ], template: "<div class=\"drawer-host-wrapper\">\n <a href=\"/\" class=\"drawer-brand\" [class.is-collapsed]=\"!isExpanded\">\n <!-- Logo sits in its own sunken tile (reference `.sb-logo`, measured 16/09):\n the tile is what carries the hover border, so the mark keeps its own\n size and nothing shifts by a pixel when that border appears. -->\n <span class=\"drawer-brand-logo\">\n @if (logo) {\n <img [src]=\"logo\" alt=\"Home\" class=\"drawer-brand-mark\" />\n } @else {\n <span class=\"drawer-brand-mark\"></span>\n }\n </span>\n @if (isExpanded && (logoText || logoSubtext)) {\n <span class=\"drawer-brand-copy\">\n @if (logoText) {\n <span class=\"drawer-brand-text\">{{ logoText }}</span>\n }\n @if (logoSubtext) {\n <span class=\"drawer-brand-subtext\">{{ logoSubtext }}</span>\n }\n </span>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- V2: bottom section (Administration group, user block, \u2026) -->\n <div class=\"mt-auto\">\n @if (footerItems().length) {\n <nav class=\"drawer-footer-nav\">\n @for (item of footerItems(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n }\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n @if (item.heading) {\n @if (isExpanded) {\n <div class=\"drawer-section-label\">{{ item.label }}</div>\n } @else {\n <div class=\"drawer-section-rule\"></div>\n }\n } @else {\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n @if (item.route && !item.children) {\n <a\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 13 : 18\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 13 : 18\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\n type=\"button\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 13 : 18\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 13 : 18\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;display:flex;height:100%;flex-direction:column;background:rgb(var(--og-surface-sunken));border-right:1px solid rgb(var(--og-border-subtle))}.drawer-brand{display:flex;height:60px;flex-shrink:0;align-items:center;gap:10px;overflow:hidden;text-decoration-line:none;padding-left:16px;padding-right:8px;transition:padding .3s cubic-bezier(.4,0,.2,1);max-width:260px}.drawer-brand.is-collapsed{justify-content:center;padding-left:0;padding-right:0;max-width:70px}.drawer-brand-logo{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;padding:6px;border-radius:var(--og-radius-control);background:rgb(var(--og-surface-sunken));border:1px solid transparent;transition:padding .22s cubic-bezier(.4,0,.2,1),border-color .15s ease}.drawer-brand:hover .drawer-brand-logo{border-color:rgb(var(--og-border))}.drawer-brand.is-collapsed .drawer-brand-logo{padding:4px}.drawer-brand-mark{height:21px;width:auto;flex-shrink:0}.drawer-brand.is-collapsed .drawer-brand-mark{height:19px}.drawer-brand-copy{display:flex;min-width:0px;flex-direction:column;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25)}.drawer-brand-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--og-fs-lg);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary));-webkit-user-select:none;user-select:none;font-family:var(--og-font-display);letter-spacing:-.015em;line-height:1}.drawer-brand-subtext{margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;--tw-font-weight: var(--font-weight-normal, 400);font-weight:var(--font-weight-normal, 400);-webkit-user-select:none;user-select:none;color:rgb(var(--og-text-muted));letter-spacing:.02em;line-height:1.2}.drawer-container{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden;padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:background-color .2s ease,box-shadow .2s ease}.toggle-btn:before{content:\"\";position:absolute;inset:-8px;border-radius:9999px}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{background-color:rgb(var(--bg-primary-hover))}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-footer-nav{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:0px;padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:var(--spacing, .25rem)}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:var(--og-radius-control);background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-section-label{padding-inline:1rem;padding-top:calc(var(--spacing, .25rem) * 4);padding-bottom:var(--spacing, .25rem);font-size:10.5px;line-height:1.4;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgb(var(--og-text-faint));-webkit-user-select:none;user-select:none;letter-spacing:var(--og-tracking-label)}.drawer-section-rule{margin-inline:calc(var(--spacing, .25rem) * 3);margin-block:calc(var(--spacing, .25rem) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;display:flex;width:100%;cursor:pointer;align-items:center;--tw-border-style: none;border-style:none;background-color:transparent;text-decoration-line:none;margin-top:1px;min-height:30px;padding:6px 8px;font-size:var(--og-fs-sm);color:rgb(var(--og-text-body));border-radius:var(--og-radius-control);transition:background-color .13s ease,color .13s ease}.drawer-item:hover{color:rgb(var(--og-text));background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item:hover{background:color-mix(in srgb,rgb(var(--og-text)) 8%,transparent)}}.drawer-item.active{color:rgb(var(--og-text));font-weight:500;background:rgb(var(--og-text));box-shadow:inset 0 0 0 1px rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{background:color-mix(in srgb,rgb(var(--og-text)) 6%,transparent)}}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{box-shadow:inset 0 0 0 1px color-mix(in srgb,rgb(var(--og-text)) 7%,transparent)}}.drawer-item.active:hover{background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active:hover{background:color-mix(in srgb,rgb(var(--og-text)) 9%,transparent)}}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:9px;overflow:hidden}.drawer-item.is-collapsed .item-icon{width:18px;height:18px;margin-right:0}.item-icon--solid{fill:currentColor}:host ::ng-deep .item-icon--solid svg,:host ::ng-deep .item-icon--solid path,:host ::ng-deep .item-icon--solid polygon{fill:currentColor}.item-icon{flex-shrink:0;color:inherit;width:13px;height:13px;margin-right:5px}.item-label{flex:1;overflow:hidden;text-align:left;--tw-leading: 18px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;font-size:inherit}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:11px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:var(--og-font-mono)}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
4182
+ ], template: "<div class=\"drawer-host-wrapper\">\n <a href=\"/\" class=\"drawer-brand\" [class.is-collapsed]=\"!isExpanded\">\n <!-- Logo sits in its own sunken tile (reference `.sb-logo`, measured 16/09):\n the tile is what carries the hover border, so the mark keeps its own\n size and nothing shifts by a pixel when that border appears. -->\n <span class=\"drawer-brand-logo\">\n @if (logo) {\n <img [src]=\"logo\" alt=\"Home\" class=\"drawer-brand-mark\" />\n } @else {\n <span class=\"drawer-brand-mark\"></span>\n }\n </span>\n @if (isExpanded && (logoText || logoSubtext)) {\n <span class=\"drawer-brand-copy\">\n @if (logoText) {\n <span class=\"drawer-brand-text\">{{ logoText }}</span>\n }\n @if (logoSubtext) {\n <span class=\"drawer-brand-subtext\">{{ logoSubtext }}</span>\n }\n </span>\n }\n </a>\n <div class=\"drawer-container\" [@drawerExpand]=\"getDrawerState()\">\n <!-- Navigation Items -->\n <nav class=\"drawer-nav\">\n @for (item of items(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n\n <!-- V2: bottom section (Administration group, user block, \u2026) -->\n <div class=\"mt-auto\">\n @if (footerItems().length) {\n <nav class=\"drawer-footer-nav\">\n @for (item of footerItems(); track item) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: item, level: 0 }\"\n ></ng-container>\n }\n </nav>\n }\n <ng-content select=\"[drawerFooter]\"></ng-content>\n </div>\n\n <!-- Version -->\n @if (version) {\n <div class=\"drawer-version\" [matTooltip]=\"!isExpanded ? version : ''\" matTooltipPosition=\"right\">\n @if (isExpanded) {\n <span>{{ version }}</span>\n }\n @if (!isExpanded) {\n <span class=\"drawer-version-dot\"></span>\n }\n </div>\n }\n </div>\n\n <!-- Floating Toggle Button on right border -->\n <button\n type=\"button\"\n class=\"toggle-btn\"\n [attr.aria-label]=\"isExpanded ? 'Collapse navigation' : 'Expand navigation'\"\n [attr.aria-expanded]=\"isExpanded\"\n (click)=\"toggleDrawer()\"\n [matTooltip]=\"isExpanded ? 'Collapse' : 'Expand'\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n matTooltipPosition=\"right\"\n >\n <fx-ui-hero-icon\n [icon]=\"isExpanded ? 'chevron-left' : 'chevron-right'\"\n [size]=\"16\"\n class=\"text-text-primary\"\n ></fx-ui-hero-icon>\n </button>\n</div>\n\n<!-- Recursive Template for Drawer Items -->\n<ng-template #drawerItem let-item let-level=\"level\">\n @if (item.heading) {\n @if (isExpanded) {\n <div class=\"drawer-section-label\">{{ item.label }}</div>\n } @else {\n <div class=\"drawer-section-rule\"></div>\n }\n } @else {\n <div class=\"drawer-item-wrapper\">\n <!-- Item Button/Link -->\n @if (item.route && !item.children) {\n <a\n [routerLink]=\"item.route\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-xs font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 15 : 20\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 15 : 20\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n </div>\n </a>\n }\n\n @if (!item.route || item.children) {\n <button\n type=\"button\"\n class=\"drawer-item\"\n [class.is-collapsed]=\"!isExpanded\"\n [class.active]=\"isActiveRoute(item.route)\"\n [class.has-children]=\"item.children && item.children.length > 0\"\n [style.paddingLeft.px]=\"isExpanded ? 8 + level * 16 : 16\"\n [matTooltip]=\"!isExpanded ? item.label : ''\"\n matTooltipPosition=\"right\"\n matTooltipClass=\"text-text-primary text-sm font-semibold\"\n (click)=\"onItemClick(item, $event)\"\n >\n <div class=\"item-content\">\n @if (item.iconData) {\n <lucide-icon\n [img]=\"item.iconData\"\n [size]=\"isExpanded ? 15 : 20\"\n class=\"item-icon\"\n [class.item-icon--solid]=\"item.iconSolid\"\n />\n } @else {\n <fx-ui-hero-icon [icon]=\"item.icon\" [size]=\"isExpanded ? 15 : 20\" class=\"item-icon\"></fx-ui-hero-icon>\n }\n @if (isExpanded) {\n <span class=\"item-label\">{{ item.label }}</span>\n }\n @if (isExpanded && item.children && item.children.length > 0) {\n <fx-ui-hero-icon\n [icon]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"chevron-icon\"\n [class.rotated]=\"isAccordionExpanded(item.id)\"\n ></fx-ui-hero-icon>\n }\n </div>\n </button>\n }\n\n <!-- Accordion Children -->\n @if (item.children && item.children.length > 0) {\n <div\n class=\"accordion-children\"\n [@accordionExpand]=\"getAccordionState(item.id)\"\n >\n @for (child of item.children; track child) {\n <ng-container\n *ngTemplateOutlet=\"drawerItem; context: { $implicit: child, level: level + 1 }\"\n ></ng-container>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";@layer properties;:host{display:block;height:100%}.drawer-host-wrapper{position:relative;display:flex;height:100%;flex-direction:column;background:rgb(var(--og-surface-sunken));border-right:1px solid rgb(var(--og-border-subtle))}.drawer-brand{display:flex;height:60px;flex-shrink:0;align-items:center;gap:10px;overflow:hidden;text-decoration-line:none;padding-left:16px;padding-right:8px;transition:padding .3s cubic-bezier(.4,0,.2,1);max-width:260px}.drawer-brand.is-collapsed{justify-content:center;padding-left:0;padding-right:0;max-width:70px}.drawer-brand-logo{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;padding:6px;border-radius:var(--og-radius-control);background:rgb(var(--og-surface-sunken));border:1px solid transparent;transition:padding .22s cubic-bezier(.4,0,.2,1),border-color .15s ease}.drawer-brand:hover .drawer-brand-logo{border-color:rgb(var(--og-border))}.drawer-brand.is-collapsed .drawer-brand-logo{padding:4px}.drawer-brand-mark{height:21px;width:auto;flex-shrink:0}.drawer-brand.is-collapsed .drawer-brand-mark{height:19px}.drawer-brand-copy{display:flex;min-width:0px;flex-direction:column;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25)}.drawer-brand-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--og-fs-lg);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgb(var(--text-primary));-webkit-user-select:none;user-select:none;font-family:var(--og-font-display);letter-spacing:-.015em;line-height:1}.drawer-brand-subtext{margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;--tw-font-weight: var(--font-weight-normal, 400);font-weight:var(--font-weight-normal, 400);-webkit-user-select:none;user-select:none;color:rgb(var(--og-text-muted));letter-spacing:.02em;line-height:1.2}.drawer-container{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden;padding-inline:calc(var(--spacing, .25rem) * 2);transition:width .3s cubic-bezier(.4,0,.2,1)}.toggle-btn{position:absolute;top:50%;z-index:50;display:flex;height:calc(var(--spacing, .25rem) * 6);width:calc(var(--spacing, .25rem) * 6);--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;justify-content:center;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgb(var(--border-default));background-color:rgb(var(--bg-primary));--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(var(--shadow-color) / .05));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);right:-12px;transition:background-color .2s ease,box-shadow .2s ease}.toggle-btn:before{content:\"\";position:absolute;inset:-8px;border-radius:9999px}.toggle-btn:hover{background-color:rgb(var(--bg-primary-hover));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(var(--shadow-color) / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(var(--shadow-color) / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.toggle-btn:active{background-color:rgb(var(--bg-primary-hover))}.toggle-btn:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-footer-nav{border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:0px;padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:var(--spacing, .25rem)}.drawer-nav{flex:1;overflow-x:hidden;overflow-y:auto;padding-block:calc(var(--spacing, .25rem) * 2)}.drawer-nav::-webkit-scrollbar{width:calc(var(--spacing, .25rem) * 1.5)}.drawer-nav::-webkit-scrollbar-track{background-color:transparent}.drawer-nav::-webkit-scrollbar-thumb{border-radius:var(--og-radius-control);background-color:rgb(var(--border-default))}.drawer-nav::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--text-placeholder))}.drawer-section-label{padding-inline:1rem;padding-top:calc(var(--spacing, .25rem) * 4);padding-bottom:var(--spacing, .25rem);font-size:var(--og-fs-xs);line-height:1.4;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgb(var(--og-text-faint));-webkit-user-select:none;user-select:none;letter-spacing:var(--og-tracking-label)}.drawer-section-rule{margin-inline:calc(var(--spacing, .25rem) * 3);margin-block:calc(var(--spacing, .25rem) * 3);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default))}.drawer-item-wrapper{position:relative}.drawer-item{position:relative;display:flex;width:100%;cursor:pointer;align-items:center;--tw-border-style: none;border-style:none;background-color:transparent;text-decoration-line:none;margin-top:1px;min-height:34px;padding:7px 8px;font-size:14px;color:rgb(var(--og-text-body));border-radius:var(--og-radius-control);transition:background-color .13s ease,color .13s ease}.drawer-item:hover{color:rgb(var(--og-text));background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item:hover{background:color-mix(in srgb,rgb(var(--og-text)) 8%,transparent)}}.drawer-item.active{color:rgb(var(--og-text));font-weight:500;background:rgb(var(--og-text));box-shadow:inset 0 0 0 1px rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{background:color-mix(in srgb,rgb(var(--og-text)) 6%,transparent)}}@supports (color: color-mix(in lab,red,red)){.drawer-item.active{box-shadow:inset 0 0 0 1px color-mix(in srgb,rgb(var(--og-text)) 7%,transparent)}}.drawer-item.active:hover{background:rgb(var(--og-text))}@supports (color: color-mix(in lab,red,red)){.drawer-item.active:hover{background:color-mix(in srgb,rgb(var(--og-text)) 9%,transparent)}}.drawer-item:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-offset:2px;outline-color:rgb(var(--primary))}.drawer-item{-webkit-tap-highlight-color:transparent;--tw-outline-style: none;outline-style:none}.item-content{display:flex;width:100%;align-items:center;gap:9px;overflow:hidden}.drawer-item.is-collapsed .item-icon{width:20px;height:20px;margin-right:0}.item-icon--solid{fill:currentColor}:host ::ng-deep .item-icon--solid svg,:host ::ng-deep .item-icon--solid path,:host ::ng-deep .item-icon--solid polygon{fill:currentColor}.item-icon{flex-shrink:0;color:inherit;width:15px;height:15px;margin-right:6px}.item-label{flex:1;overflow:hidden;text-align:left;--tw-leading: 20px;line-height:20px;text-overflow:ellipsis;white-space:nowrap;font-size:inherit}.chevron-icon{margin-left:auto;flex-shrink:0;color:rgb(var(--text-primary));transition:transform .3s cubic-bezier(.4,0,.2,1)}.chevron-icon.rotated{transform:rotate(180deg)}.accordion-children{overflow:hidden}.drawer-version{display:flex;align-items:center;justify-content:center;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgb(var(--border-default));padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 3);font-size:12px;color:rgb(var(--text-placeholder));-webkit-user-select:none;user-select:none;font-family:var(--og-font-mono)}.drawer-version-dot{display:block;height:calc(var(--spacing, .25rem) * 1.5);width:calc(var(--spacing, .25rem) * 1.5);border-radius:calc(infinity * 1px);background-color:rgb(var(--text-placeholder))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial;--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-outline-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
4183
4183
  }], ctorParameters: () => [{ type: i2$1.Router }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], footerItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerItems", required: false }] }], isExpanded: [{
4184
4184
  type: Input
4185
4185
  }], logo: [{
@@ -4367,7 +4367,7 @@ class StatCardsComponent {
4367
4367
  return card.subTone ? toneText(card.subTone) : 'text-text-secondary';
4368
4368
  }
4369
4369
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: StatCardsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4370
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: StatCardsComponent, isStandalone: true, selector: "fx-ui-stat-cards", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: false, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- variant=\"figure\" is ONE ruled panel, not N cards: the reference draws the\n KPI strip as a single bordered box divided by hairlines (`.og-statgrid\n --ruled`, measured 16/09). It was four separate `card-common` boxes with an\n 8px gap, which read as four objects where the design has one. The other\n variant keeps its own cards. -->\n<div\n class=\"fx-stat-grid grid\"\n [class.fx-stat-grid--ruled]=\"variant() === 'figure'\"\n [class.gap-normal]=\"variant() !== 'figure'\"\n [ngStyle]=\"{ 'grid-template-columns': gridColumns }\"\n>\n @for (card of cards(); track card.label; let last = $last) {\n @if (variant() === 'figure') {\n <div class=\"fx-stat-cell flex flex-col min-w-0\" [class.fx-stat-cell--last]=\"last\">\n <span class=\"fx-stat-cell__label truncate\">{{ card.label }}</span>\n <span\n class=\"fx-stat-cell__figure\"\n [ngClass]=\"numClass(card)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.sub) {\n <span class=\"fx-stat-cell__sub\" [ngClass]=\"subClass(card)\">{{ card.sub }}</span>\n }\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n } @else {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"flex items-baseline gap-small\">\n <span\n class=\"txt-heading-04\"\n [ngClass]=\"numClass(card)\"\n style=\"font-family: var(--og-font-figure)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.delta) {\n <span class=\"text-xs font-semibold\" [ngClass]=\"deltaClass(card)\">\n {{ card.delta.direction === 'up' ? '\u25B2' : '\u25BC' }} {{ card.delta.value }}\n </span>\n }\n </div>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size}@container (width < 720px){.fx-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}}@container (width < 360px){.fx-stat-grid{grid-template-columns:minmax(0,1fr)!important}}.fx-stat-grid--ruled{gap:0;border:1px solid rgb(var(--og-border));border-radius:var(--og-radius-control);background:rgb(var(--og-surface));box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d;overflow:hidden}.fx-stat-grid--ruled .fx-stat-cell{padding:10px 12px;border-right:1px solid rgb(var(--og-border))}.fx-stat-grid--ruled .fx-stat-cell--last{border-right:0}.fx-stat-cell__label{font-size:var(--og-fs-2xs);font-weight:400;color:rgb(var(--og-text-faint))}.fx-stat-cell__figure{font-family:var(--og-font-figure);font-size:32px;font-weight:400;line-height:1.1;color:rgb(var(--og-text));margin-top:6px}.fx-stat-cell__sub{font-size:var(--og-fs-xs);font-weight:400;color:rgb(var(--og-text-muted));margin-top:4px}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "component", type: SparkbarComponent, selector: "fx-ui-sparkbar", inputs: ["values", "tone", "height"] }, { kind: "directive", type: FxCountUpDirective, selector: "[fxCountUp]", inputs: ["fxCountUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4370
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: StatCardsComponent, isStandalone: true, selector: "fx-ui-stat-cards", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: false, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- variant=\"figure\" is ONE ruled panel, not N cards: the reference draws the\n KPI strip as a single bordered box divided by hairlines (`.og-statgrid\n --ruled`, measured 16/09). It was four separate `card-common` boxes with an\n 8px gap, which read as four objects where the design has one. The other\n variant keeps its own cards. -->\n<div\n class=\"fx-stat-grid grid\"\n [class.fx-stat-grid--ruled]=\"variant() === 'figure'\"\n [class.gap-normal]=\"variant() !== 'figure'\"\n [ngStyle]=\"{ 'grid-template-columns': gridColumns }\"\n>\n @for (card of cards(); track card.label; let last = $last) {\n @if (variant() === 'figure') {\n <div class=\"fx-stat-cell flex flex-col min-w-0\" [class.fx-stat-cell--last]=\"last\">\n <span class=\"fx-stat-cell__label truncate\">{{ card.label }}</span>\n <span\n class=\"fx-stat-cell__figure\"\n [ngClass]=\"numClass(card)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.sub) {\n <span class=\"fx-stat-cell__sub\" [ngClass]=\"subClass(card)\">{{ card.sub }}</span>\n }\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n } @else {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"flex items-baseline gap-small\">\n <span\n class=\"txt-heading-04\"\n [ngClass]=\"numClass(card)\"\n style=\"font-family: var(--og-font-figure)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.delta) {\n <span class=\"text-xs font-semibold\" [ngClass]=\"deltaClass(card)\">\n {{ card.delta.direction === 'up' ? '\u25B2' : '\u25BC' }} {{ card.delta.value }}\n </span>\n }\n </div>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size}@container (width < 720px){.fx-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}}@container (width < 360px){.fx-stat-grid{grid-template-columns:minmax(0,1fr)!important}}.fx-stat-grid--ruled{gap:0;border:1px solid rgb(var(--og-border));border-radius:var(--og-radius-control);background:rgb(var(--og-surface));box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d;overflow:hidden}.fx-stat-grid--ruled .fx-stat-cell{padding:10px 12px;border-right:1px solid rgb(var(--og-border))}.fx-stat-grid--ruled .fx-stat-cell--last{border-right:0}.fx-stat-cell__label{font-size:var(--og-fs-2xs);font-weight:400;color:rgb(var(--og-text-faint))}.fx-stat-cell__figure{font-family:var(--og-font-figure);font-size:32px;font-weight:400;line-height:1.1;color:rgb(var(--og-text));margin-top:6px}@container (width < 720px){.fx-stat-cell__figure{font-size:22px;margin-top:4px}}@container (width < 360px){.fx-stat-cell__figure{font-size:20px}}.fx-stat-cell__sub{font-size:var(--og-fs-xs);font-weight:400;color:rgb(var(--og-text-muted));margin-top:4px}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }, { kind: "component", type: SparkbarComponent, selector: "fx-ui-sparkbar", inputs: ["values", "tone", "height"] }, { kind: "directive", type: FxCountUpDirective, selector: "[fxCountUp]", inputs: ["fxCountUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4371
4371
  }
4372
4372
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: StatCardsComponent, decorators: [{
4373
4373
  type: Component,
@@ -4377,7 +4377,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
4377
4377
  HeroIconComponent,
4378
4378
  SparkbarComponent,
4379
4379
  FxCountUpDirective,
4380
- ], template: "<!-- variant=\"figure\" is ONE ruled panel, not N cards: the reference draws the\n KPI strip as a single bordered box divided by hairlines (`.og-statgrid\n --ruled`, measured 16/09). It was four separate `card-common` boxes with an\n 8px gap, which read as four objects where the design has one. The other\n variant keeps its own cards. -->\n<div\n class=\"fx-stat-grid grid\"\n [class.fx-stat-grid--ruled]=\"variant() === 'figure'\"\n [class.gap-normal]=\"variant() !== 'figure'\"\n [ngStyle]=\"{ 'grid-template-columns': gridColumns }\"\n>\n @for (card of cards(); track card.label; let last = $last) {\n @if (variant() === 'figure') {\n <div class=\"fx-stat-cell flex flex-col min-w-0\" [class.fx-stat-cell--last]=\"last\">\n <span class=\"fx-stat-cell__label truncate\">{{ card.label }}</span>\n <span\n class=\"fx-stat-cell__figure\"\n [ngClass]=\"numClass(card)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.sub) {\n <span class=\"fx-stat-cell__sub\" [ngClass]=\"subClass(card)\">{{ card.sub }}</span>\n }\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n } @else {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"flex items-baseline gap-small\">\n <span\n class=\"txt-heading-04\"\n [ngClass]=\"numClass(card)\"\n style=\"font-family: var(--og-font-figure)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.delta) {\n <span class=\"text-xs font-semibold\" [ngClass]=\"deltaClass(card)\">\n {{ card.delta.direction === 'up' ? '\u25B2' : '\u25BC' }} {{ card.delta.value }}\n </span>\n }\n </div>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size}@container (width < 720px){.fx-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}}@container (width < 360px){.fx-stat-grid{grid-template-columns:minmax(0,1fr)!important}}.fx-stat-grid--ruled{gap:0;border:1px solid rgb(var(--og-border));border-radius:var(--og-radius-control);background:rgb(var(--og-surface));box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d;overflow:hidden}.fx-stat-grid--ruled .fx-stat-cell{padding:10px 12px;border-right:1px solid rgb(var(--og-border))}.fx-stat-grid--ruled .fx-stat-cell--last{border-right:0}.fx-stat-cell__label{font-size:var(--og-fs-2xs);font-weight:400;color:rgb(var(--og-text-faint))}.fx-stat-cell__figure{font-family:var(--og-font-figure);font-size:32px;font-weight:400;line-height:1.1;color:rgb(var(--og-text));margin-top:6px}.fx-stat-cell__sub{font-size:var(--og-fs-xs);font-weight:400;color:rgb(var(--og-text-muted));margin-top:4px}\n"] }]
4380
+ ], template: "<!-- variant=\"figure\" is ONE ruled panel, not N cards: the reference draws the\n KPI strip as a single bordered box divided by hairlines (`.og-statgrid\n --ruled`, measured 16/09). It was four separate `card-common` boxes with an\n 8px gap, which read as four objects where the design has one. The other\n variant keeps its own cards. -->\n<div\n class=\"fx-stat-grid grid\"\n [class.fx-stat-grid--ruled]=\"variant() === 'figure'\"\n [class.gap-normal]=\"variant() !== 'figure'\"\n [ngStyle]=\"{ 'grid-template-columns': gridColumns }\"\n>\n @for (card of cards(); track card.label; let last = $last) {\n @if (variant() === 'figure') {\n <div class=\"fx-stat-cell flex flex-col min-w-0\" [class.fx-stat-cell--last]=\"last\">\n <span class=\"fx-stat-cell__label truncate\">{{ card.label }}</span>\n <span\n class=\"fx-stat-cell__figure\"\n [ngClass]=\"numClass(card)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.sub) {\n <span class=\"fx-stat-cell__sub\" [ngClass]=\"subClass(card)\">{{ card.sub }}</span>\n }\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n } @else {\n <div class=\"card-common flex items-center gap-normal\">\n @if (card.icon) {\n <div\n class=\"w-10 h-10 rounded-lg flex items-center justify-center shrink-0\"\n [ngClass]=\"boxClass(card)\"\n >\n <fx-ui-hero-icon [icon]=\"card.icon\" [size]=\"20\"></fx-ui-hero-icon>\n </div>\n }\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"flex items-baseline gap-small\">\n <span\n class=\"txt-heading-04\"\n [ngClass]=\"numClass(card)\"\n style=\"font-family: var(--og-font-figure)\"\n ><span [fxCountUp]=\"card.value\"></span></span\n >\n @if (card.delta) {\n <span class=\"text-xs font-semibold\" [ngClass]=\"deltaClass(card)\">\n {{ card.delta.direction === 'up' ? '\u25B2' : '\u25BC' }} {{ card.delta.value }}\n </span>\n }\n </div>\n <span class=\"txt-utility-caption text-text-secondary truncate\">{{ card.label }}</span>\n @if (card.spark?.length) {\n <fx-ui-sparkbar class=\"mt-xs\" [values]=\"card.spark!\" [height]=\"16\" [tone]=\"card.tone ?? null\" />\n }\n </div>\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size}@container (width < 720px){.fx-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}}@container (width < 360px){.fx-stat-grid{grid-template-columns:minmax(0,1fr)!important}}.fx-stat-grid--ruled{gap:0;border:1px solid rgb(var(--og-border));border-radius:var(--og-radius-control);background:rgb(var(--og-surface));box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d;overflow:hidden}.fx-stat-grid--ruled .fx-stat-cell{padding:10px 12px;border-right:1px solid rgb(var(--og-border))}.fx-stat-grid--ruled .fx-stat-cell--last{border-right:0}.fx-stat-cell__label{font-size:var(--og-fs-2xs);font-weight:400;color:rgb(var(--og-text-faint))}.fx-stat-cell__figure{font-family:var(--og-font-figure);font-size:32px;font-weight:400;line-height:1.1;color:rgb(var(--og-text));margin-top:6px}@container (width < 720px){.fx-stat-cell__figure{font-size:22px;margin-top:4px}}@container (width < 360px){.fx-stat-cell__figure{font-size:20px}}.fx-stat-cell__sub{font-size:var(--og-fs-xs);font-weight:400;color:rgb(var(--og-text-muted));margin-top:4px}\n"] }]
4381
4381
  }], propDecorators: { cards: [{ type: i0.Input, args: [{ isSignal: true, alias: "cards", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], cols: [{
4382
4382
  type: Input
4383
4383
  }] } });
@@ -4758,8 +4758,30 @@ class MasterDetailComponent {
4758
4758
  /** True when the host projected a [mdFacets] block — switches to 3 columns. */
4759
4759
  hasFacets = false;
4760
4760
  table;
4761
- /** Fixed list-pane width on lg+ viewports (stacked full-width below). */
4762
- listWidth = input('420px', ...(ngDevMode ? [{ debugName: "listWidth" }] : /* istanbul ignore next */ []));
4761
+ /**
4762
+ * Optional CAP on the list pane.
4763
+ *
4764
+ * The list is the flexible track now (the design's `204px 1fr 340px`), so it
4765
+ * takes whatever the rail and the detail leave. Set this only for a screen
4766
+ * whose rows genuinely stop reading better past some width; left unset the
4767
+ * property is not emitted at all and the pane simply fills.
4768
+ */
4769
+ listWidth = input(null, ...(ngDevMode ? [{ debugName: "listWidth" }] : /* istanbul ignore next */ []));
4770
+ /**
4771
+ * The detail pane's fixed track — the design's own 340px, and 450px on the
4772
+ * screens anh Tú widened (17/09).
4773
+ *
4774
+ * Pass `'auto'` (or null) to give the detail the SPARE width instead and cap
4775
+ * the list at `listWidth` — the pre-0.7.130 behaviour, which Binaries and
4776
+ * Remediation keep because their panes carry header blocks, metric grids and
4777
+ * step lists that a narrow track cannot hold.
4778
+ */
4779
+ detailWidth = input('340px', ...(ngDevMode ? [{ debugName: "detailWidth" }] : /* istanbul ignore next */ []));
4780
+ /** true = detail takes the spare width; false = it is a fixed track. */
4781
+ detailFluid() {
4782
+ const w = this.detailWidth();
4783
+ return !w || w === 'auto';
4784
+ }
4763
4785
  /**
4764
4786
  * Chiều cao CHUNG của cả ba cụm (facets / list / detail). Mặc định trừ phần
4765
4787
  * chrome phía trên (topbar + tab strip + context line) khỏi viewport để
@@ -4861,7 +4883,7 @@ class MasterDetailComponent {
4861
4883
  el?.scrollIntoView({ block: 'nearest' });
4862
4884
  }
4863
4885
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MasterDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: MasterDetailComponent, isStandalone: true, selector: "fx-ui-master-detail", inputs: { table: { classPropertyName: "table", publicName: "table", isSignal: false, isRequired: false, transformFunction: null }, listWidth: { classPropertyName: "listWidth", publicName: "listWidth", isSignal: true, isRequired: false, transformFunction: null }, paneHeight: { classPropertyName: "paneHeight", publicName: "paneHeight", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, skeletonCards: { classPropertyName: "skeletonCards", publicName: "skeletonCards", isSignal: true, isRequired: false, transformFunction: null }, paginationStyle: { classPropertyName: "paginationStyle", publicName: "paginationStyle", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, pageLabel: { classPropertyName: "pageLabel", publicName: "pageLabel", isSignal: true, isRequired: false, transformFunction: null }, ofLabel: { classPropertyName: "ofLabel", publicName: "ofLabel", isSignal: true, isRequired: false, transformFunction: null }, facetsOpen: { classPropertyName: "facetsOpen", publicName: "facetsOpen", isSignal: true, isRequired: false, transformFunction: null }, facetsLabel: { classPropertyName: "facetsLabel", publicName: "facetsLabel", isSignal: true, isRequired: false, transformFunction: null }, expandFacetsLabel: { classPropertyName: "expandFacetsLabel", publicName: "expandFacetsLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseFacetsLabel: { classPropertyName: "collapseFacetsLabel", publicName: "collapseFacetsLabel", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["row"], descendants: true, isSignal: true }, { propertyName: "detailTemplate", first: true, predicate: ["detail"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- ONE frame, three columns (designs 11/14/17): facets rail \u00B7 list \u00B7 detail,\n separated by hairlines, sharing one height; only each pane's body scrolls.\n Row direction / height come from the CONTAINER QUERY in the CSS (the row's\n own width), never from `lg:*` \u2014 see the note at the top of the .css. -->\n<div\n class=\"fx-md-row flex flex-col items-stretch\"\n [class.fx-md-row--rail-open]=\"railOpen()\"\n [style.--fx-md-list-width]=\"listWidth()\"\n [style.--fx-md-pane-h]=\"paneHeight()\"\n>\n <!-- Facets rail \u2014 collapsible (\u00BB / \u00AB), collapsed = 40px strip with the label\n set vertically. The [mdFacets] projection is unconditional (hasFacets is\n detected by querying it) and only hidden while collapsed. -->\n <aside\n class=\"fx-md-facets flex flex-col min-h-0 min-w-0\"\n [class.hidden]=\"!hasFacets\"\n [class.fx-md-facets--open]=\"railOpen()\"\n >\n <div class=\"fx-md-rail-head flex items-center gap-small px-normal py-semi border-b border-border-subtle shrink-0\" [class.hidden]=\"!railOpen()\">\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-6 h-6 rounded-control text-muted hover:bg-bg-hover shrink-0\"\n [attr.aria-label]=\"collapseFacetsLabel()\"\n (click)=\"railOpen.set(false)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-left\" [size]=\"14\" class=\"flex\" />\n </button>\n <span class=\"txt-eyebrow truncate\">{{ facetsLabel() }}</span>\n </div>\n <div class=\"flex-1 min-h-0 overflow-auto px-normal py-normal\" [class.hidden]=\"!railOpen()\">\n <ng-content select=\"[mdFacets]\"></ng-content>\n </div>\n <button\n type=\"button\"\n class=\"fx-md-rail-toggle flex items-center gap-normal text-muted hover:bg-bg-hover transition-colors\"\n [class.hidden]=\"railOpen()\"\n [attr.aria-label]=\"expandFacetsLabel()\"\n [attr.aria-expanded]=\"false\"\n (click)=\"railOpen.set(true)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-right\" [size]=\"14\" class=\"flex shrink-0\" />\n <span class=\"fx-md-rail-label txt-eyebrow whitespace-nowrap\">{{ facetsLabel() }}</span>\n </button>\n </aside>\n\n <!-- Master: list pane -->\n <section class=\"fx-md-list flex flex-col min-h-0 min-w-0\">\n <div class=\"fx-md-list-head px-large pt-large pb-small border-b border-border-subtle shrink-0\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n </div>\n <div\n class=\"flex flex-col overflow-auto flex-1 min-h-0\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <div class=\"px-large py-normal\">\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n </div>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <!-- Hairline rows; the selected one is tinted with an accent bar on\n the left (design 11/14 selected finding / component). -->\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left px-large py-semi border-l-2 border-b border-b-border-subtle transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-l-accent bg-accent-soft/60'\n : 'border-l-transparent hover:bg-surface-sunken'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <div class=\"px-large py-large\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"fx-md-paginator\"\n [class.fx-md-paginator-hidden]=\"paginationStyle() === 'prevnext'\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n @if (paginationStyle() === 'prevnext') {\n <div class=\"flex items-center justify-between gap-normal px-large py-normal border-t border-border-subtle shrink-0\">\n <span class=\"txt-utility-description\" style=\"font-family: var(--og-font-figure)\">\n {{ rangeText() }}\n </span>\n <div class=\"flex gap-small\">\n <button\n type=\"button\"\n class=\"btn-alternative !h-8 !px-semi text-sm\"\n [disabled]=\"!paginator().hasPreviousPage()\"\n (click)=\"paginator().previousPage()\"\n >\n {{ prevLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"btn-alternative !h-8 !px-semi text-sm\"\n [disabled]=\"!paginator().hasNextPage()\"\n (click)=\"paginator().nextPage()\"\n >\n {{ nextLabel() }}\n </button>\n </div>\n </div>\n }\n </section>\n\n <!-- Detail pane -->\n <section class=\"fx-md-detail w-full min-w-0 flex flex-col min-h-0\">\n <div class=\"flex-1 min-h-0 overflow-auto px-large py-large\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-center h-full min-h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n </section>\n</div>\n", styles: [":host{display:block;container-type:inline-size;container-name:fx-md}.fx-md-row{background:rgb(var(--og-surface));border:1px solid rgb(var(--border-default));border-radius:.5rem;overflow:hidden;box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d}.fx-md-facets,.fx-md-list{border-bottom:1px solid rgb(var(--og-border-subtle))}.fx-md-rail-toggle{width:100%;padding:10px 12px;flex-direction:row;justify-content:flex-start}.fx-md-list,.fx-md-facets{width:100%}@container fx-md (min-width: 720px){.fx-md-row{flex-direction:row;height:var(--fx-md-pane-h, calc(100vh - 300px) );min-height:420px}.fx-md-facets,.fx-md-list{border-bottom:0;border-right:1px solid rgb(var(--og-border-subtle))}.fx-md-facets{flex:0 0 40px;width:40px;min-width:40px;max-width:40px}.fx-md-facets--open{flex:0 1 230px;width:auto;min-width:200px;max-width:260px}.fx-md-rail-toggle{height:100%;padding:12px 0;flex-direction:column;justify-content:flex-start}.fx-md-rail-label{writing-mode:vertical-rl;transform:rotate(180deg)}.fx-md-list{width:auto;flex:0 1 var(--fx-md-list-width, 420px);min-width:260px;max-width:var(--fx-md-list-width, 420px)}.fx-md-detail{flex:1 1 360px;min-width:360px}}.fx-md-paginator-hidden{position:absolute!important;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}.fx-md-paginator{padding:0 12px;border-top:1px solid rgb(var(--og-border-subtle))}\n"], dependencies: [{ kind: "component", type: SkeletonListComponent, selector: "fx-ui-skeleton-list", inputs: ["rows"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EmptyStateComponent, selector: "fx-ui-empty-state", inputs: ["message", "icon", "height"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SkeletonDetailComponent, selector: "fx-ui-skeleton-detail", inputs: ["cards", "rows"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
4886
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: MasterDetailComponent, isStandalone: true, selector: "fx-ui-master-detail", inputs: { table: { classPropertyName: "table", publicName: "table", isSignal: false, isRequired: false, transformFunction: null }, listWidth: { classPropertyName: "listWidth", publicName: "listWidth", isSignal: true, isRequired: false, transformFunction: null }, detailWidth: { classPropertyName: "detailWidth", publicName: "detailWidth", isSignal: true, isRequired: false, transformFunction: null }, paneHeight: { classPropertyName: "paneHeight", publicName: "paneHeight", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, skeletonCards: { classPropertyName: "skeletonCards", publicName: "skeletonCards", isSignal: true, isRequired: false, transformFunction: null }, paginationStyle: { classPropertyName: "paginationStyle", publicName: "paginationStyle", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, pageLabel: { classPropertyName: "pageLabel", publicName: "pageLabel", isSignal: true, isRequired: false, transformFunction: null }, ofLabel: { classPropertyName: "ofLabel", publicName: "ofLabel", isSignal: true, isRequired: false, transformFunction: null }, facetsOpen: { classPropertyName: "facetsOpen", publicName: "facetsOpen", isSignal: true, isRequired: false, transformFunction: null }, facetsLabel: { classPropertyName: "facetsLabel", publicName: "facetsLabel", isSignal: true, isRequired: false, transformFunction: null }, expandFacetsLabel: { classPropertyName: "expandFacetsLabel", publicName: "expandFacetsLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseFacetsLabel: { classPropertyName: "collapseFacetsLabel", publicName: "collapseFacetsLabel", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["row"], descendants: true, isSignal: true }, { propertyName: "detailTemplate", first: true, predicate: ["detail"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- ONE frame, three columns (designs 11/14/17): facets rail \u00B7 list \u00B7 detail,\n separated by hairlines, sharing one height; only each pane's body scrolls.\n Row direction / height come from the CONTAINER QUERY in the CSS (the row's\n own width), never from `lg:*` \u2014 see the note at the top of the .css. -->\n<div\n class=\"fx-md-row flex flex-col items-stretch\"\n [class.fx-md-row--rail-open]=\"railOpen()\"\n [style.--fx-md-list-width]=\"listWidth()\"\n [class.fx-md-row--detail-fluid]=\"detailFluid()\"\n [style.--fx-md-detail-width]=\"detailFluid() ? null : detailWidth()\"\n [style.--fx-md-pane-h]=\"paneHeight()\"\n>\n <!-- Facets rail \u2014 collapsible (\u00BB / \u00AB), collapsed = 40px strip with the label\n set vertically. The [mdFacets] projection is unconditional (hasFacets is\n detected by querying it) and only hidden while collapsed. -->\n <aside\n class=\"fx-md-facets flex flex-col min-h-0 min-w-0\"\n [class.hidden]=\"!hasFacets\"\n [class.fx-md-facets--open]=\"railOpen()\"\n >\n <div class=\"fx-md-rail-head flex items-center gap-small px-normal py-semi border-b border-border-subtle shrink-0\" [class.hidden]=\"!railOpen()\">\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-6 h-6 rounded-control text-muted hover:bg-bg-hover shrink-0\"\n [attr.aria-label]=\"collapseFacetsLabel()\"\n (click)=\"railOpen.set(false)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-left\" [size]=\"14\" class=\"flex\" />\n </button>\n <span class=\"txt-eyebrow truncate\">{{ facetsLabel() }}</span>\n </div>\n <div class=\"flex-1 min-h-0 overflow-auto px-normal py-normal\" [class.hidden]=\"!railOpen()\">\n <ng-content select=\"[mdFacets]\"></ng-content>\n </div>\n <button\n type=\"button\"\n class=\"fx-md-rail-toggle flex items-center gap-normal text-muted hover:bg-bg-hover transition-colors\"\n [class.hidden]=\"railOpen()\"\n [attr.aria-label]=\"expandFacetsLabel()\"\n [attr.aria-expanded]=\"false\"\n (click)=\"railOpen.set(true)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-right\" [size]=\"14\" class=\"flex shrink-0\" />\n <span class=\"fx-md-rail-label txt-eyebrow whitespace-nowrap\">{{ facetsLabel() }}</span>\n </button>\n </aside>\n\n <!-- Master: list pane -->\n <section class=\"fx-md-list flex flex-col min-h-0 min-w-0\">\n <div class=\"fx-md-list-head px-large pt-large pb-small border-b border-border-subtle shrink-0\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n </div>\n <div\n class=\"flex flex-col overflow-auto flex-1 min-h-0\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <div class=\"px-large py-normal\">\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n </div>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <!-- Hairline rows; the selected one is tinted with an accent bar on\n the left (design 11/14 selected finding / component). -->\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left px-large py-semi border-l-2 border-b border-b-border-subtle transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-l-accent bg-accent-soft/60'\n : 'border-l-transparent hover:bg-surface-sunken'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <div class=\"px-large py-large\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"fx-md-paginator\"\n [class.fx-md-paginator-hidden]=\"paginationStyle() === 'prevnext'\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n @if (paginationStyle() === 'prevnext') {\n <div class=\"flex items-center justify-between gap-normal px-large py-normal border-t border-border-subtle shrink-0\">\n <span class=\"txt-utility-description\" style=\"font-family: var(--og-font-figure)\">\n {{ rangeText() }}\n </span>\n <div class=\"flex gap-small\">\n <button\n type=\"button\"\n class=\"btn-alternative\"\n [disabled]=\"!paginator().hasPreviousPage()\"\n (click)=\"paginator().previousPage()\"\n >\n {{ prevLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"btn-alternative\"\n [disabled]=\"!paginator().hasNextPage()\"\n (click)=\"paginator().nextPage()\"\n >\n {{ nextLabel() }}\n </button>\n </div>\n </div>\n }\n </section>\n\n <!-- Detail pane -->\n <section class=\"fx-md-detail w-full min-w-0 flex flex-col min-h-0\">\n <div class=\"flex-1 min-h-0 overflow-auto px-large py-large\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-center h-full min-h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n </section>\n</div>\n", styles: [":host{display:block;container-type:inline-size;container-name:fx-md}.fx-md-row{background:rgb(var(--og-surface));border:1px solid rgb(var(--border-default));border-radius:.5rem;overflow:hidden;box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d}.fx-md-facets,.fx-md-list{border-bottom:1px solid rgb(var(--og-border-subtle))}.fx-md-rail-toggle{width:100%;padding:10px 12px;flex-direction:row;justify-content:flex-start}.fx-md-list,.fx-md-facets{width:100%}@container fx-md (min-width: 720px){.fx-md-row{flex-direction:row;height:var(--fx-md-pane-h, calc(100vh - 300px) );min-height:420px}.fx-md-facets,.fx-md-list{border-bottom:0;border-right:1px solid rgb(var(--og-border-subtle))}.fx-md-facets{flex:0 0 40px;width:40px;min-width:40px;max-width:40px}.fx-md-facets--open{flex:0 1 204px;width:auto;min-width:180px;max-width:204px}.fx-md-rail-toggle{height:100%;padding:12px 0;flex-direction:column;justify-content:flex-start}.fx-md-rail-label{writing-mode:vertical-rl;transform:rotate(180deg)}.fx-md-list{width:auto;flex:1 1 0;min-width:260px;max-width:var(--fx-md-list-width, none)}.fx-md-detail{width:auto;flex:0 1 var(--fx-md-detail-width, 340px);min-width:300px;max-width:var(--fx-md-detail-width, 340px)}.fx-md-row--detail-fluid .fx-md-list{flex:0 1 var(--fx-md-list-width, 420px);max-width:var(--fx-md-list-width, 420px)}.fx-md-row--detail-fluid .fx-md-detail{flex:1 1 360px;min-width:360px;max-width:none}}.fx-md-paginator-hidden{position:absolute!important;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}.fx-md-paginator{padding:0 12px;border-top:1px solid rgb(var(--og-border-subtle))}\n"], dependencies: [{ kind: "component", type: SkeletonListComponent, selector: "fx-ui-skeleton-list", inputs: ["rows"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EmptyStateComponent, selector: "fx-ui-empty-state", inputs: ["message", "icon", "height"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SkeletonDetailComponent, selector: "fx-ui-skeleton-detail", inputs: ["cards", "rows"] }, { kind: "component", type: HeroIconComponent, selector: "fx-ui-hero-icon", inputs: ["stroke", "icon", "solid", "outline", "size", "color", "class"] }] });
4865
4887
  }
4866
4888
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: MasterDetailComponent, decorators: [{
4867
4889
  type: Component,
@@ -4873,10 +4895,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
4873
4895
  MatPaginator,
4874
4896
  SkeletonDetailComponent,
4875
4897
  HeroIconComponent,
4876
- ], template: "<!-- ONE frame, three columns (designs 11/14/17): facets rail \u00B7 list \u00B7 detail,\n separated by hairlines, sharing one height; only each pane's body scrolls.\n Row direction / height come from the CONTAINER QUERY in the CSS (the row's\n own width), never from `lg:*` \u2014 see the note at the top of the .css. -->\n<div\n class=\"fx-md-row flex flex-col items-stretch\"\n [class.fx-md-row--rail-open]=\"railOpen()\"\n [style.--fx-md-list-width]=\"listWidth()\"\n [style.--fx-md-pane-h]=\"paneHeight()\"\n>\n <!-- Facets rail \u2014 collapsible (\u00BB / \u00AB), collapsed = 40px strip with the label\n set vertically. The [mdFacets] projection is unconditional (hasFacets is\n detected by querying it) and only hidden while collapsed. -->\n <aside\n class=\"fx-md-facets flex flex-col min-h-0 min-w-0\"\n [class.hidden]=\"!hasFacets\"\n [class.fx-md-facets--open]=\"railOpen()\"\n >\n <div class=\"fx-md-rail-head flex items-center gap-small px-normal py-semi border-b border-border-subtle shrink-0\" [class.hidden]=\"!railOpen()\">\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-6 h-6 rounded-control text-muted hover:bg-bg-hover shrink-0\"\n [attr.aria-label]=\"collapseFacetsLabel()\"\n (click)=\"railOpen.set(false)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-left\" [size]=\"14\" class=\"flex\" />\n </button>\n <span class=\"txt-eyebrow truncate\">{{ facetsLabel() }}</span>\n </div>\n <div class=\"flex-1 min-h-0 overflow-auto px-normal py-normal\" [class.hidden]=\"!railOpen()\">\n <ng-content select=\"[mdFacets]\"></ng-content>\n </div>\n <button\n type=\"button\"\n class=\"fx-md-rail-toggle flex items-center gap-normal text-muted hover:bg-bg-hover transition-colors\"\n [class.hidden]=\"railOpen()\"\n [attr.aria-label]=\"expandFacetsLabel()\"\n [attr.aria-expanded]=\"false\"\n (click)=\"railOpen.set(true)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-right\" [size]=\"14\" class=\"flex shrink-0\" />\n <span class=\"fx-md-rail-label txt-eyebrow whitespace-nowrap\">{{ facetsLabel() }}</span>\n </button>\n </aside>\n\n <!-- Master: list pane -->\n <section class=\"fx-md-list flex flex-col min-h-0 min-w-0\">\n <div class=\"fx-md-list-head px-large pt-large pb-small border-b border-border-subtle shrink-0\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n </div>\n <div\n class=\"flex flex-col overflow-auto flex-1 min-h-0\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <div class=\"px-large py-normal\">\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n </div>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <!-- Hairline rows; the selected one is tinted with an accent bar on\n the left (design 11/14 selected finding / component). -->\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left px-large py-semi border-l-2 border-b border-b-border-subtle transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-l-accent bg-accent-soft/60'\n : 'border-l-transparent hover:bg-surface-sunken'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <div class=\"px-large py-large\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"fx-md-paginator\"\n [class.fx-md-paginator-hidden]=\"paginationStyle() === 'prevnext'\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n @if (paginationStyle() === 'prevnext') {\n <div class=\"flex items-center justify-between gap-normal px-large py-normal border-t border-border-subtle shrink-0\">\n <span class=\"txt-utility-description\" style=\"font-family: var(--og-font-figure)\">\n {{ rangeText() }}\n </span>\n <div class=\"flex gap-small\">\n <button\n type=\"button\"\n class=\"btn-alternative !h-8 !px-semi text-sm\"\n [disabled]=\"!paginator().hasPreviousPage()\"\n (click)=\"paginator().previousPage()\"\n >\n {{ prevLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"btn-alternative !h-8 !px-semi text-sm\"\n [disabled]=\"!paginator().hasNextPage()\"\n (click)=\"paginator().nextPage()\"\n >\n {{ nextLabel() }}\n </button>\n </div>\n </div>\n }\n </section>\n\n <!-- Detail pane -->\n <section class=\"fx-md-detail w-full min-w-0 flex flex-col min-h-0\">\n <div class=\"flex-1 min-h-0 overflow-auto px-large py-large\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-center h-full min-h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n </section>\n</div>\n", styles: [":host{display:block;container-type:inline-size;container-name:fx-md}.fx-md-row{background:rgb(var(--og-surface));border:1px solid rgb(var(--border-default));border-radius:.5rem;overflow:hidden;box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d}.fx-md-facets,.fx-md-list{border-bottom:1px solid rgb(var(--og-border-subtle))}.fx-md-rail-toggle{width:100%;padding:10px 12px;flex-direction:row;justify-content:flex-start}.fx-md-list,.fx-md-facets{width:100%}@container fx-md (min-width: 720px){.fx-md-row{flex-direction:row;height:var(--fx-md-pane-h, calc(100vh - 300px) );min-height:420px}.fx-md-facets,.fx-md-list{border-bottom:0;border-right:1px solid rgb(var(--og-border-subtle))}.fx-md-facets{flex:0 0 40px;width:40px;min-width:40px;max-width:40px}.fx-md-facets--open{flex:0 1 230px;width:auto;min-width:200px;max-width:260px}.fx-md-rail-toggle{height:100%;padding:12px 0;flex-direction:column;justify-content:flex-start}.fx-md-rail-label{writing-mode:vertical-rl;transform:rotate(180deg)}.fx-md-list{width:auto;flex:0 1 var(--fx-md-list-width, 420px);min-width:260px;max-width:var(--fx-md-list-width, 420px)}.fx-md-detail{flex:1 1 360px;min-width:360px}}.fx-md-paginator-hidden{position:absolute!important;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}.fx-md-paginator{padding:0 12px;border-top:1px solid rgb(var(--og-border-subtle))}\n"] }]
4898
+ ], template: "<!-- ONE frame, three columns (designs 11/14/17): facets rail \u00B7 list \u00B7 detail,\n separated by hairlines, sharing one height; only each pane's body scrolls.\n Row direction / height come from the CONTAINER QUERY in the CSS (the row's\n own width), never from `lg:*` \u2014 see the note at the top of the .css. -->\n<div\n class=\"fx-md-row flex flex-col items-stretch\"\n [class.fx-md-row--rail-open]=\"railOpen()\"\n [style.--fx-md-list-width]=\"listWidth()\"\n [class.fx-md-row--detail-fluid]=\"detailFluid()\"\n [style.--fx-md-detail-width]=\"detailFluid() ? null : detailWidth()\"\n [style.--fx-md-pane-h]=\"paneHeight()\"\n>\n <!-- Facets rail \u2014 collapsible (\u00BB / \u00AB), collapsed = 40px strip with the label\n set vertically. The [mdFacets] projection is unconditional (hasFacets is\n detected by querying it) and only hidden while collapsed. -->\n <aside\n class=\"fx-md-facets flex flex-col min-h-0 min-w-0\"\n [class.hidden]=\"!hasFacets\"\n [class.fx-md-facets--open]=\"railOpen()\"\n >\n <div class=\"fx-md-rail-head flex items-center gap-small px-normal py-semi border-b border-border-subtle shrink-0\" [class.hidden]=\"!railOpen()\">\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-6 h-6 rounded-control text-muted hover:bg-bg-hover shrink-0\"\n [attr.aria-label]=\"collapseFacetsLabel()\"\n (click)=\"railOpen.set(false)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-left\" [size]=\"14\" class=\"flex\" />\n </button>\n <span class=\"txt-eyebrow truncate\">{{ facetsLabel() }}</span>\n </div>\n <div class=\"flex-1 min-h-0 overflow-auto px-normal py-normal\" [class.hidden]=\"!railOpen()\">\n <ng-content select=\"[mdFacets]\"></ng-content>\n </div>\n <button\n type=\"button\"\n class=\"fx-md-rail-toggle flex items-center gap-normal text-muted hover:bg-bg-hover transition-colors\"\n [class.hidden]=\"railOpen()\"\n [attr.aria-label]=\"expandFacetsLabel()\"\n [attr.aria-expanded]=\"false\"\n (click)=\"railOpen.set(true)\"\n >\n <fx-ui-hero-icon icon=\"chevron-double-right\" [size]=\"14\" class=\"flex shrink-0\" />\n <span class=\"fx-md-rail-label txt-eyebrow whitespace-nowrap\">{{ facetsLabel() }}</span>\n </button>\n </aside>\n\n <!-- Master: list pane -->\n <section class=\"fx-md-list flex flex-col min-h-0 min-w-0\">\n <div class=\"fx-md-list-head px-large pt-large pb-small border-b border-border-subtle shrink-0\">\n <ng-content select=\"[mdHeader]\"></ng-content>\n <ng-content select=\"[mdFilters]\"></ng-content>\n </div>\n <div\n class=\"flex flex-col overflow-auto flex-1 min-h-0\"\n role=\"listbox\"\n [attr.aria-label]=\"listLabel() || null\"\n >\n @if (table.loading) {\n <div class=\"px-large py-normal\">\n <fx-ui-skeleton-list [rows]=\"table.pageSize\"></fx-ui-skeleton-list>\n </div>\n } @else {\n @for (row of table.dataSource.data; track table.idOf(row); let i = $index) {\n <!-- Hairline rows; the selected one is tinted with an accent bar on\n the left (design 11/14 selected finding / component). -->\n <button\n type=\"button\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(row)\"\n [tabindex]=\"isSelected(row) ? 0 : -1\"\n (click)=\"table.selectItem(row)\"\n (keydown)=\"onKeydown($event, i)\"\n class=\"text-left px-large py-semi border-l-2 border-b border-b-border-subtle transition-colors\"\n [ngClass]=\"\n isSelected(row)\n ? 'border-l-accent bg-accent-soft/60'\n : 'border-l-transparent hover:bg-surface-sunken'\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: row, selected: isSelected(row) }\"\n ></ng-container>\n </button>\n }\n @if (!table.dataSource.data.length) {\n <div class=\"px-large py-large\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n }\n </div>\n <!-- No (page) binding: ngAfterViewInit hands this paginator to the table,\n whose own BaseTable subscription (running after this child's hook)\n wires page events \u2014 a binding here would double-fetch every change. -->\n <mat-paginator\n class=\"fx-md-paginator\"\n [class.fx-md-paginator-hidden]=\"paginationStyle() === 'prevnext'\"\n [length]=\"table.total\"\n [pageSize]=\"table.pageSize\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n ></mat-paginator>\n @if (paginationStyle() === 'prevnext') {\n <div class=\"flex items-center justify-between gap-normal px-large py-normal border-t border-border-subtle shrink-0\">\n <span class=\"txt-utility-description\" style=\"font-family: var(--og-font-figure)\">\n {{ rangeText() }}\n </span>\n <div class=\"flex gap-small\">\n <button\n type=\"button\"\n class=\"btn-alternative\"\n [disabled]=\"!paginator().hasPreviousPage()\"\n (click)=\"paginator().previousPage()\"\n >\n {{ prevLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"btn-alternative\"\n [disabled]=\"!paginator().hasNextPage()\"\n (click)=\"paginator().nextPage()\"\n >\n {{ nextLabel() }}\n </button>\n </div>\n </div>\n }\n </section>\n\n <!-- Detail pane -->\n <section class=\"fx-md-detail w-full min-w-0 flex flex-col min-h-0\">\n <div class=\"flex-1 min-h-0 overflow-auto px-large py-large\">\n @if (table.selected) {\n @if (table.detailBusy) {\n <fx-ui-skeleton-detail [cards]=\"skeletonCards()\"></fx-ui-skeleton-detail>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"detailTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: table.detail, selected: table.selected }\"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-center h-full min-h-[300px]\">\n <fx-ui-empty-state [message]=\"emptyMessage()\"></fx-ui-empty-state>\n </div>\n }\n </div>\n </section>\n</div>\n", styles: [":host{display:block;container-type:inline-size;container-name:fx-md}.fx-md-row{background:rgb(var(--og-surface));border:1px solid rgb(var(--border-default));border-radius:.5rem;overflow:hidden;box-shadow:0 1px 2px #0000000a,0 3px 8px #0000000d}.fx-md-facets,.fx-md-list{border-bottom:1px solid rgb(var(--og-border-subtle))}.fx-md-rail-toggle{width:100%;padding:10px 12px;flex-direction:row;justify-content:flex-start}.fx-md-list,.fx-md-facets{width:100%}@container fx-md (min-width: 720px){.fx-md-row{flex-direction:row;height:var(--fx-md-pane-h, calc(100vh - 300px) );min-height:420px}.fx-md-facets,.fx-md-list{border-bottom:0;border-right:1px solid rgb(var(--og-border-subtle))}.fx-md-facets{flex:0 0 40px;width:40px;min-width:40px;max-width:40px}.fx-md-facets--open{flex:0 1 204px;width:auto;min-width:180px;max-width:204px}.fx-md-rail-toggle{height:100%;padding:12px 0;flex-direction:column;justify-content:flex-start}.fx-md-rail-label{writing-mode:vertical-rl;transform:rotate(180deg)}.fx-md-list{width:auto;flex:1 1 0;min-width:260px;max-width:var(--fx-md-list-width, none)}.fx-md-detail{width:auto;flex:0 1 var(--fx-md-detail-width, 340px);min-width:300px;max-width:var(--fx-md-detail-width, 340px)}.fx-md-row--detail-fluid .fx-md-list{flex:0 1 var(--fx-md-list-width, 420px);max-width:var(--fx-md-list-width, 420px)}.fx-md-row--detail-fluid .fx-md-detail{flex:1 1 360px;min-width:360px;max-width:none}}.fx-md-paginator-hidden{position:absolute!important;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}.fx-md-paginator{padding:0 12px;border-top:1px solid rgb(var(--og-border-subtle))}\n"] }]
4877
4899
  }], propDecorators: { table: [{
4878
4900
  type: Input
4879
- }], listWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "listWidth", required: false }] }], paneHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneHeight", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], listLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "listLabel", required: false }] }], skeletonCards: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonCards", required: false }] }], paginationStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationStyle", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], pageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLabel", required: false }] }], ofLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ofLabel", required: false }] }], facetsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "facetsOpen", required: false }] }], facetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "facetsLabel", required: false }] }], expandFacetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandFacetsLabel", required: false }] }], collapseFacetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseFacetsLabel", required: false }] }], rowTemplate: [{ type: i0.ContentChild, args: ['row', { isSignal: true }] }], detailTemplate: [{ type: i0.ContentChild, args: ['detail', { isSignal: true }] }], paginator: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatPaginator), { isSignal: true }] }] } });
4901
+ }], listWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "listWidth", required: false }] }], detailWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailWidth", required: false }] }], paneHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneHeight", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], listLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "listLabel", required: false }] }], skeletonCards: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonCards", required: false }] }], paginationStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationStyle", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], pageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLabel", required: false }] }], ofLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ofLabel", required: false }] }], facetsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "facetsOpen", required: false }] }], facetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "facetsLabel", required: false }] }], expandFacetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandFacetsLabel", required: false }] }], collapseFacetsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseFacetsLabel", required: false }] }], rowTemplate: [{ type: i0.ContentChild, args: ['row', { isSignal: true }] }], detailTemplate: [{ type: i0.ContentChild, args: ['detail', { isSignal: true }] }], paginator: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatPaginator), { isSignal: true }] }] } });
4880
4902
 
4881
4903
  /**
4882
4904
  * Row-action dropdown wrapper over mat-menu (behavior-layer rule, Playbook