@frame-kit/ui-ng-patterns 0.2.17 → 0.2.19

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.
@@ -698,11 +698,11 @@ class SidebarNavComponent {
698
698
  panel.style.setProperty('--fk-sidebar-nav-flyout-caret-top', `${top}px`);
699
699
  }
700
700
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
701
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: SidebarNavComponent, isStandalone: true, selector: "fk-sidebar-nav", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "itemTpl", first: true, predicate: SidebarNavItemDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "flyoutTpl", first: true, predicate: ["flyoutTpl"], descendants: true, isSignal: true }], ngImport: i0, template: "@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT \u2014 disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"\n linkActive(child)\n \"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF \u2014 direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links \u2014 not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block}.fk-sidebar-nav__group{display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-group-inner-gap, var(--fk-rhythm-2, .5rem))}.fk-sidebar-nav__group+.fk-sidebar-nav__group{margin-top:var(--fk-sidebar-nav-group-gap, var(--fk-rhythm-5, 1.25rem))}.fk-sidebar-nav__group-label{padding-inline:var(--fk-sidebar-nav-label-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-label-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-label-font-size, .625rem);font-weight:var(--fk-sidebar-nav-label-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-label-color, var(--fk-color-muted, #64748b))}.fk-sidebar-nav__divider{display:none}.fk-sidebar-nav__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-row-stack, var(--fk-rhythm-1, .25rem))}.fk-sidebar-nav__row{box-sizing:border-box;display:flex;align-items:center;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border:none;border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .625rem));background:var(--fk-sidebar-nav-row-bg, transparent);font-family:var(--fk-sidebar-nav-row-font-family, var(--fk-font-family-base));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__row:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__row:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__row--active,.fk-sidebar-nav__row--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--active .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch,.fk-sidebar-nav__row--branch:hover{background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__row--branch .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__icon{flex:none;display:inline-flex;color:var(--fk-sidebar-nav-icon-color, var(--fk-color-muted, #8a93a8));transition:color .13s ease}.fk-sidebar-nav__row:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-icon-color-hover, var(--fk-color-text, #36405a))}.fk-sidebar-nav__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}.fk-sidebar-nav__chevron{flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--fk-sidebar-nav-chevron-color, var(--fk-color-muted, #8a93a8));transition:transform .18s ease}.fk-sidebar-nav__chevron--open{transform:rotate(90deg)}.fk-sidebar-nav__children{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-children-gap, var(--fk-rhythm-2, .5rem));list-style:none;margin:var(--fk-sidebar-nav-children-offset, var(--fk-rhythm-2, .5rem)) 0 0;padding-left:var(--fk-sidebar-nav-children-indent, var(--fk-rhythm-6, 1.5rem))}.fk-sidebar-nav__children:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--fk-sidebar-nav-children-line-offset, var(--fk-rhythm-3, .75rem));width:var(--fk-sidebar-nav-children-line-width, var(--fk-border-width, 1px));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__child{box-sizing:border-box;display:flex;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;margin:0;padding:var(--fk-sidebar-nav-child-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-child-radius, var(--fk-radius-md, .625rem));font-size:var(--fk-sidebar-nav-child-font-size, .875rem);font-weight:var(--fk-sidebar-nav-child-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-child-color, var(--fk-color-muted, #5c6781));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__child:hover{background:var(--fk-sidebar-nav-child-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-child-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__child:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__child--active,.fk-sidebar-nav__child--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-sidebar-nav__subgroup{margin:var(--fk-sidebar-nav-subgroup-offset, var(--fk-rhythm-2, .5rem)) 0 0}.fk-sidebar-nav__subgroup-title{display:block;padding-inline:var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group-label{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group:not(:first-child) .fk-sidebar-nav__divider{display:block;height:1px;margin:0 var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__row{justify-content:center;padding-inline:var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__label,:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__chevron{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__children{display:none}.fk-sidebar-nav__flyout-panel{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-width:var(--fk-sidebar-nav-flyout-min-width, 13rem);max-width:var(--fk-sidebar-nav-flyout-max-width, 22rem);max-height:var(--fk-sidebar-nav-flyout-max-height, min(28rem, 100dvh - 2rem));padding:var(--fk-sidebar-nav-flyout-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-radius:var(--fk-sidebar-nav-flyout-radius, var(--fk-radius-md, .75rem));box-shadow:var(--fk-sidebar-nav-flyout-shadow, var(--fk-shadow-lg, 0 18px 44px -14px rgba(20, 34, 80, .3)))}.fk-sidebar-nav__flyout-panel:before{content:\"\";position:absolute;left:-.375rem;top:var(--fk-sidebar-nav-flyout-caret-top, 1.375rem);width:.6875rem;height:.6875rem;background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border-left:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));transform:rotate(45deg)}.fk-sidebar-nav__flyout-items{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-inline:var(--fk-focus-ring-width, 3px);margin-inline:calc(var(--fk-focus-ring-width, 3px) * -1)}.fk-sidebar-nav__flyout-head{display:flex;flex-shrink:0;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:.4375rem var(--fk-rhythm-3, .625rem) .5625rem;border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__flyout-icon{flex:none;display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:var(--fk-sidebar-nav-flyout-icon-radius, var(--fk-radius-sm, .5rem));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0));background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe))}.fk-sidebar-nav__flyout-title{min-width:0;overflow:hidden;font-family:var(--fk-sidebar-nav-flyout-title-font-family, var(--fk-font-family-display, var(--fk-font-family-base)));font-size:var(--fk-sidebar-nav-flyout-title-font-size, .84375rem);font-weight:var(--fk-sidebar-nav-flyout-title-font-weight, var(--fk-font-weight-semibold, 600));white-space:nowrap;text-overflow:ellipsis;color:var(--fk-sidebar-nav-flyout-title-color, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-subgroup{display:block;flex-shrink:0;padding:var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-1, .25rem);font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}.fk-sidebar-nav__flyout-item{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .12s ease,color .12s ease}.fk-sidebar-nav__flyout-item:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-item:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__flyout-item--active,.fk-sidebar-nav__flyout-item--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IconComponent, selector: "fk-icon", inputs: ["name", "size", "color", "className", "id", "ariaLabel", "ariaHidden"] }, { kind: "directive", type: TooltipDirective, selector: "[fkTooltip]", inputs: ["fkTooltip", "fkTooltipPosition", "fkTooltipOffset", "fkTooltipShowDelay", "fkTooltipHideDelay", "fkTooltipDisabled", "fkTooltipClassName"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
701
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: SidebarNavComponent, isStandalone: true, selector: "fk-sidebar-nav", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "itemTpl", first: true, predicate: SidebarNavItemDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "flyoutTpl", first: true, predicate: ["flyoutTpl"], descendants: true, isSignal: true }], ngImport: i0, template: "@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT \u2014 disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"\n linkActive(child)\n \"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF \u2014 direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links \u2014 not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block}.fk-sidebar-nav__group{display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-group-inner-gap, var(--fk-rhythm-2, .5rem))}.fk-sidebar-nav__group+.fk-sidebar-nav__group{margin-top:var(--fk-sidebar-nav-group-gap, var(--fk-rhythm-5, 1.25rem))}.fk-sidebar-nav__group-label{padding-inline:var(--fk-sidebar-nav-label-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-label-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-label-font-size, .625rem);font-weight:var(--fk-sidebar-nav-label-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-label-color, var(--fk-color-muted, #64748b))}.fk-sidebar-nav__divider{display:none}.fk-sidebar-nav__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-row-stack, var(--fk-rhythm-1, .25rem))}.fk-sidebar-nav__row{box-sizing:border-box;display:flex;align-items:center;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border:none;border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .625rem));background:var(--fk-sidebar-nav-row-bg, transparent);font-family:var(--fk-sidebar-nav-row-font-family, var(--fk-font-family-base));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__row:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__row:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__row--active,.fk-sidebar-nav__row--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch,.fk-sidebar-nav__row--branch:hover{background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__icon{flex:none;display:inline-flex;color:var(--fk-sidebar-nav-icon-color, var(--fk-color-muted, #8a93a8));transition:color .13s ease}.fk-sidebar-nav__row:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-icon-color-hover, var(--fk-color-text, #36405a))}.fk-sidebar-nav__row--active .fk-sidebar-nav__icon,.fk-sidebar-nav__row--active:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch .fk-sidebar-nav__icon,.fk-sidebar-nav__row--branch:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}.fk-sidebar-nav__chevron{flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--fk-sidebar-nav-chevron-color, var(--fk-color-muted, #8a93a8));transition:transform .18s ease}.fk-sidebar-nav__chevron--open{transform:rotate(90deg)}.fk-sidebar-nav__children{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-children-gap, var(--fk-rhythm-2, .5rem));list-style:none;margin:var(--fk-sidebar-nav-children-offset, var(--fk-rhythm-2, .5rem)) 0 0;padding-left:var(--fk-sidebar-nav-children-indent, var(--fk-rhythm-6, 1.5rem))}.fk-sidebar-nav__children:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--fk-sidebar-nav-children-line-offset, var(--fk-rhythm-3, .75rem));width:var(--fk-sidebar-nav-children-line-width, var(--fk-border-width, 1px));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__child{box-sizing:border-box;display:flex;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;margin:0;padding:var(--fk-sidebar-nav-child-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-child-radius, var(--fk-radius-md, .625rem));font-size:var(--fk-sidebar-nav-child-font-size, .875rem);font-weight:var(--fk-sidebar-nav-child-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-child-color, var(--fk-color-muted, #5c6781));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__child:hover{background:var(--fk-sidebar-nav-child-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-child-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__child:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__child--active,.fk-sidebar-nav__child--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-sidebar-nav__subgroup{margin:var(--fk-sidebar-nav-subgroup-offset, var(--fk-rhythm-2, .5rem)) 0 0}.fk-sidebar-nav__subgroup-title{display:block;padding-inline:var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group-label{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group:not(:first-child) .fk-sidebar-nav__divider{display:block;height:1px;margin:0 var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__row{justify-content:center;padding-inline:var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__label,:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__chevron{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__children{display:none}.fk-sidebar-nav__flyout-panel{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-width:var(--fk-sidebar-nav-flyout-min-width, 13rem);max-width:var(--fk-sidebar-nav-flyout-max-width, 22rem);max-height:var(--fk-sidebar-nav-flyout-max-height, min(28rem, 100dvh - 2rem));padding:var(--fk-sidebar-nav-flyout-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-radius:var(--fk-sidebar-nav-flyout-radius, var(--fk-radius-md, .75rem));box-shadow:var(--fk-sidebar-nav-flyout-shadow, var(--fk-shadow-lg, 0 18px 44px -14px rgba(20, 34, 80, .3)))}.fk-sidebar-nav__flyout-panel:before{content:\"\";position:absolute;left:-.375rem;top:var(--fk-sidebar-nav-flyout-caret-top, 1.375rem);width:.6875rem;height:.6875rem;background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border-left:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));transform:rotate(45deg)}.fk-sidebar-nav__flyout-items{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-inline:var(--fk-focus-ring-width, 3px);margin-inline:calc(var(--fk-focus-ring-width, 3px) * -1)}.fk-sidebar-nav__flyout-head{display:flex;flex-shrink:0;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:.4375rem var(--fk-rhythm-3, .625rem) .5625rem;border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__flyout-icon{flex:none;display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:var(--fk-sidebar-nav-flyout-icon-radius, var(--fk-radius-sm, .5rem));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0));background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe))}.fk-sidebar-nav__flyout-title{min-width:0;overflow:hidden;font-family:var(--fk-sidebar-nav-flyout-title-font-family, var(--fk-font-family-display, var(--fk-font-family-base)));font-size:var(--fk-sidebar-nav-flyout-title-font-size, .84375rem);font-weight:var(--fk-sidebar-nav-flyout-title-font-weight, var(--fk-font-weight-semibold, 600));white-space:nowrap;text-overflow:ellipsis;color:var(--fk-sidebar-nav-flyout-title-color, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-subgroup{display:block;flex-shrink:0;padding:var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-1, .25rem);font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}.fk-sidebar-nav__flyout-item{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .12s ease,color .12s ease}.fk-sidebar-nav__flyout-item:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-item:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__flyout-item--active,.fk-sidebar-nav__flyout-item--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IconComponent, selector: "fk-icon", inputs: ["name", "size", "color", "className", "id", "ariaLabel", "ariaHidden"] }, { kind: "directive", type: TooltipDirective, selector: "[fkTooltip]", inputs: ["fkTooltip", "fkTooltipPosition", "fkTooltipOffset", "fkTooltipShowDelay", "fkTooltipHideDelay", "fkTooltipDisabled", "fkTooltipClassName"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
702
702
  }
703
703
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarNavComponent, decorators: [{
704
704
  type: Component,
705
- args: [{ selector: 'fk-sidebar-nav', standalone: true, imports: [RouterLink, IconComponent, TooltipDirective, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT \u2014 disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"\n linkActive(child)\n \"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF \u2014 direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links \u2014 not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block}.fk-sidebar-nav__group{display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-group-inner-gap, var(--fk-rhythm-2, .5rem))}.fk-sidebar-nav__group+.fk-sidebar-nav__group{margin-top:var(--fk-sidebar-nav-group-gap, var(--fk-rhythm-5, 1.25rem))}.fk-sidebar-nav__group-label{padding-inline:var(--fk-sidebar-nav-label-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-label-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-label-font-size, .625rem);font-weight:var(--fk-sidebar-nav-label-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-label-color, var(--fk-color-muted, #64748b))}.fk-sidebar-nav__divider{display:none}.fk-sidebar-nav__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-row-stack, var(--fk-rhythm-1, .25rem))}.fk-sidebar-nav__row{box-sizing:border-box;display:flex;align-items:center;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border:none;border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .625rem));background:var(--fk-sidebar-nav-row-bg, transparent);font-family:var(--fk-sidebar-nav-row-font-family, var(--fk-font-family-base));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__row:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__row:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__row--active,.fk-sidebar-nav__row--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--active .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch,.fk-sidebar-nav__row--branch:hover{background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__row--branch .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__icon{flex:none;display:inline-flex;color:var(--fk-sidebar-nav-icon-color, var(--fk-color-muted, #8a93a8));transition:color .13s ease}.fk-sidebar-nav__row:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-icon-color-hover, var(--fk-color-text, #36405a))}.fk-sidebar-nav__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}.fk-sidebar-nav__chevron{flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--fk-sidebar-nav-chevron-color, var(--fk-color-muted, #8a93a8));transition:transform .18s ease}.fk-sidebar-nav__chevron--open{transform:rotate(90deg)}.fk-sidebar-nav__children{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-children-gap, var(--fk-rhythm-2, .5rem));list-style:none;margin:var(--fk-sidebar-nav-children-offset, var(--fk-rhythm-2, .5rem)) 0 0;padding-left:var(--fk-sidebar-nav-children-indent, var(--fk-rhythm-6, 1.5rem))}.fk-sidebar-nav__children:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--fk-sidebar-nav-children-line-offset, var(--fk-rhythm-3, .75rem));width:var(--fk-sidebar-nav-children-line-width, var(--fk-border-width, 1px));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__child{box-sizing:border-box;display:flex;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;margin:0;padding:var(--fk-sidebar-nav-child-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-child-radius, var(--fk-radius-md, .625rem));font-size:var(--fk-sidebar-nav-child-font-size, .875rem);font-weight:var(--fk-sidebar-nav-child-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-child-color, var(--fk-color-muted, #5c6781));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__child:hover{background:var(--fk-sidebar-nav-child-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-child-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__child:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__child--active,.fk-sidebar-nav__child--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-sidebar-nav__subgroup{margin:var(--fk-sidebar-nav-subgroup-offset, var(--fk-rhythm-2, .5rem)) 0 0}.fk-sidebar-nav__subgroup-title{display:block;padding-inline:var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group-label{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group:not(:first-child) .fk-sidebar-nav__divider{display:block;height:1px;margin:0 var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__row{justify-content:center;padding-inline:var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__label,:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__chevron{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__children{display:none}.fk-sidebar-nav__flyout-panel{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-width:var(--fk-sidebar-nav-flyout-min-width, 13rem);max-width:var(--fk-sidebar-nav-flyout-max-width, 22rem);max-height:var(--fk-sidebar-nav-flyout-max-height, min(28rem, 100dvh - 2rem));padding:var(--fk-sidebar-nav-flyout-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-radius:var(--fk-sidebar-nav-flyout-radius, var(--fk-radius-md, .75rem));box-shadow:var(--fk-sidebar-nav-flyout-shadow, var(--fk-shadow-lg, 0 18px 44px -14px rgba(20, 34, 80, .3)))}.fk-sidebar-nav__flyout-panel:before{content:\"\";position:absolute;left:-.375rem;top:var(--fk-sidebar-nav-flyout-caret-top, 1.375rem);width:.6875rem;height:.6875rem;background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border-left:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));transform:rotate(45deg)}.fk-sidebar-nav__flyout-items{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-inline:var(--fk-focus-ring-width, 3px);margin-inline:calc(var(--fk-focus-ring-width, 3px) * -1)}.fk-sidebar-nav__flyout-head{display:flex;flex-shrink:0;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:.4375rem var(--fk-rhythm-3, .625rem) .5625rem;border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__flyout-icon{flex:none;display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:var(--fk-sidebar-nav-flyout-icon-radius, var(--fk-radius-sm, .5rem));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0));background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe))}.fk-sidebar-nav__flyout-title{min-width:0;overflow:hidden;font-family:var(--fk-sidebar-nav-flyout-title-font-family, var(--fk-font-family-display, var(--fk-font-family-base)));font-size:var(--fk-sidebar-nav-flyout-title-font-size, .84375rem);font-weight:var(--fk-sidebar-nav-flyout-title-font-weight, var(--fk-font-weight-semibold, 600));white-space:nowrap;text-overflow:ellipsis;color:var(--fk-sidebar-nav-flyout-title-color, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-subgroup{display:block;flex-shrink:0;padding:var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-1, .25rem);font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}.fk-sidebar-nav__flyout-item{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .12s ease,color .12s ease}.fk-sidebar-nav__flyout-item:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-item:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__flyout-item--active,.fk-sidebar-nav__flyout-item--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}\n"] }]
705
+ args: [{ selector: 'fk-sidebar-nav', standalone: true, imports: [RouterLink, IconComponent, TooltipDirective, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT \u2014 disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"\n linkActive(child)\n \"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF \u2014 direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links \u2014 not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block}.fk-sidebar-nav__group{display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-group-inner-gap, var(--fk-rhythm-2, .5rem))}.fk-sidebar-nav__group+.fk-sidebar-nav__group{margin-top:var(--fk-sidebar-nav-group-gap, var(--fk-rhythm-5, 1.25rem))}.fk-sidebar-nav__group-label{padding-inline:var(--fk-sidebar-nav-label-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-label-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-label-font-size, .625rem);font-weight:var(--fk-sidebar-nav-label-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-label-color, var(--fk-color-muted, #64748b))}.fk-sidebar-nav__divider{display:none}.fk-sidebar-nav__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-row-stack, var(--fk-rhythm-1, .25rem))}.fk-sidebar-nav__row{box-sizing:border-box;display:flex;align-items:center;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border:none;border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .625rem));background:var(--fk-sidebar-nav-row-bg, transparent);font-family:var(--fk-sidebar-nav-row-font-family, var(--fk-font-family-base));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__row:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__row:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__row--active,.fk-sidebar-nav__row--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch,.fk-sidebar-nav__row--branch:hover{background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__icon{flex:none;display:inline-flex;color:var(--fk-sidebar-nav-icon-color, var(--fk-color-muted, #8a93a8));transition:color .13s ease}.fk-sidebar-nav__row:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-icon-color-hover, var(--fk-color-text, #36405a))}.fk-sidebar-nav__row--active .fk-sidebar-nav__icon,.fk-sidebar-nav__row--active:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-row-color-active, #ffffff)}.fk-sidebar-nav__row--branch .fk-sidebar-nav__icon,.fk-sidebar-nav__row--branch:hover .fk-sidebar-nav__icon{color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0))}.fk-sidebar-nav__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}.fk-sidebar-nav__chevron{flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--fk-sidebar-nav-chevron-color, var(--fk-color-muted, #8a93a8));transition:transform .18s ease}.fk-sidebar-nav__chevron--open{transform:rotate(90deg)}.fk-sidebar-nav__children{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-children-gap, var(--fk-rhythm-2, .5rem));list-style:none;margin:var(--fk-sidebar-nav-children-offset, var(--fk-rhythm-2, .5rem)) 0 0;padding-left:var(--fk-sidebar-nav-children-indent, var(--fk-rhythm-6, 1.5rem))}.fk-sidebar-nav__children:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--fk-sidebar-nav-children-line-offset, var(--fk-rhythm-3, .75rem));width:var(--fk-sidebar-nav-children-line-width, var(--fk-border-width, 1px));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__child{box-sizing:border-box;display:flex;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));width:100%;margin:0;padding:var(--fk-sidebar-nav-child-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-child-radius, var(--fk-radius-md, .625rem));font-size:var(--fk-sidebar-nav-child-font-size, .875rem);font-weight:var(--fk-sidebar-nav-child-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-child-color, var(--fk-color-muted, #5c6781));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .13s ease,color .13s ease}.fk-sidebar-nav__child:hover{background:var(--fk-sidebar-nav-child-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-child-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__child:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__child--active,.fk-sidebar-nav__child--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-sidebar-nav__subgroup{margin:var(--fk-sidebar-nav-subgroup-offset, var(--fk-rhythm-2, .5rem)) 0 0}.fk-sidebar-nav__subgroup-title{display:block;padding-inline:var(--fk-sidebar-nav-child-padding-inline, var(--fk-rhythm-3, .75rem));font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group-label{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__group:not(:first-child) .fk-sidebar-nav__divider{display:block;height:1px;margin:0 var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-children-line-color, var(--fk-color-border, #e5e8ef))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__row{justify-content:center;padding-inline:var(--fk-sidebar-nav-rail-padding, var(--fk-rhythm-2, .5rem))}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__label,:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__chevron{display:none}:host(.fk-sidebar-nav--collapsed) .fk-sidebar-nav__children{display:none}.fk-sidebar-nav__flyout-panel{position:relative;display:flex;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-width:var(--fk-sidebar-nav-flyout-min-width, 13rem);max-width:var(--fk-sidebar-nav-flyout-max-width, 22rem);max-height:var(--fk-sidebar-nav-flyout-max-height, min(28rem, 100dvh - 2rem));padding:var(--fk-sidebar-nav-flyout-padding, var(--fk-rhythm-2, .5rem));background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-radius:var(--fk-sidebar-nav-flyout-radius, var(--fk-radius-md, .75rem));box-shadow:var(--fk-sidebar-nav-flyout-shadow, var(--fk-shadow-lg, 0 18px 44px -14px rgba(20, 34, 80, .3)))}.fk-sidebar-nav__flyout-panel:before{content:\"\";position:absolute;left:-.375rem;top:var(--fk-sidebar-nav-flyout-caret-top, 1.375rem);width:.6875rem;height:.6875rem;background:var(--fk-sidebar-nav-flyout-bg, var(--fk-color-surface, #ffffff));border-left:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef));transform:rotate(45deg)}.fk-sidebar-nav__flyout-items{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fk-sidebar-nav-flyout-gap, var(--fk-rhythm-1, .25rem));min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-inline:var(--fk-focus-ring-width, 3px);margin-inline:calc(var(--fk-focus-ring-width, 3px) * -1)}.fk-sidebar-nav__flyout-head{display:flex;flex-shrink:0;align-items:center;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:.4375rem var(--fk-rhythm-3, .625rem) .5625rem;border-bottom:var(--fk-border-width, 1px) solid var(--fk-sidebar-nav-flyout-border, var(--fk-color-border, #e5e8ef))}.fk-sidebar-nav__flyout-icon{flex:none;display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:var(--fk-sidebar-nav-flyout-icon-radius, var(--fk-radius-sm, .5rem));color:var(--fk-sidebar-nav-branch-color, var(--fk-color-primary, #2348e0));background:var(--fk-sidebar-nav-branch-bg, var(--fk-color-primary-light, #eef2fe))}.fk-sidebar-nav__flyout-title{min-width:0;overflow:hidden;font-family:var(--fk-sidebar-nav-flyout-title-font-family, var(--fk-font-family-display, var(--fk-font-family-base)));font-size:var(--fk-sidebar-nav-flyout-title-font-size, .84375rem);font-weight:var(--fk-sidebar-nav-flyout-title-font-weight, var(--fk-font-weight-semibold, 600));white-space:nowrap;text-overflow:ellipsis;color:var(--fk-sidebar-nav-flyout-title-color, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-subgroup{display:block;flex-shrink:0;padding:var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem) var(--fk-rhythm-1, .25rem);font-family:var(--fk-sidebar-nav-subgroup-font-family, var(--fk-font-family-mono));font-size:var(--fk-sidebar-nav-subgroup-font-size, .625rem);font-weight:var(--fk-sidebar-nav-subgroup-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--fk-sidebar-nav-subgroup-color, var(--fk-color-muted, #8a93a8))}.fk-sidebar-nav__flyout-item{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;gap:var(--fk-sidebar-nav-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-sidebar-nav-row-padding-block, var(--fk-rhythm-2, .5rem)) var(--fk-sidebar-nav-row-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-sidebar-nav-row-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-sidebar-nav-row-font-size, .875rem);font-weight:var(--fk-sidebar-nav-row-font-weight, var(--fk-font-weight-medium, 500));color:var(--fk-sidebar-nav-row-color, var(--fk-color-muted, #36405a));text-decoration:none;white-space:nowrap;cursor:pointer;transition:background-color .12s ease,color .12s ease}.fk-sidebar-nav__flyout-item:hover{background:var(--fk-sidebar-nav-row-bg-hover, var(--fk-color-surface-muted, #f5f6fa));color:var(--fk-sidebar-nav-row-color-hover, var(--fk-color-text, #0e1526))}.fk-sidebar-nav__flyout-item:focus-visible{outline:none;box-shadow:var(--fk-sidebar-nav-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(35, 72, 224, .28)))}.fk-sidebar-nav__flyout-item--active,.fk-sidebar-nav__flyout-item--active:hover{background:var(--fk-sidebar-nav-row-bg-active, var(--fk-color-primary, #2348e0));color:var(--fk-sidebar-nav-row-color-active, #ffffff);font-weight:var(--fk-sidebar-nav-child-font-weight-active, var(--fk-font-weight-semibold, 600))}\n"] }]
706
706
  }], ctorParameters: () => [], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], flyoutTpl: [{ type: i0.ViewChild, args: ['flyoutTpl', { isSignal: true }] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SidebarNavItemDirective), { isSignal: true }] }], hostClass: [{
707
707
  type: HostBinding,
708
708
  args: ['class']
@@ -2191,6 +2191,114 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2191
2191
  args: ['attr.id']
2192
2192
  }] } });
2193
2193
 
2194
+ /**
2195
+ * The chrome of a signed-in dashboard, built on `fk-app-shell`: a full-height
2196
+ * aside with a brand header and collapse toggle, a sticky frosted topbar with
2197
+ * a mobile hamburger, a capped page area with an optional loading veil, and a
2198
+ * footer. Every dashboard that uses it gets the identical structure — the
2199
+ * same hamburger, the same collapse, the same scroll behaviour — and differs
2200
+ * only in what it projects.
2201
+ *
2202
+ * <fk-dashboard-layout [pageLoading]="navigating()">
2203
+ * <fk-nav-brand layoutBrand brandText="Acme" />
2204
+ * <fk-dashboard-nav layoutAside [groups]="groups()" [collapsed]="collapsed()" />
2205
+ * <nav layoutTopbarStart>Acme / Overview</nav>
2206
+ * <fk-user-menu layoutTopbarEnd … />
2207
+ * <router-outlet />
2208
+ * <span layoutFooter>© Acme</span>
2209
+ * </fk-dashboard-layout>
2210
+ *
2211
+ * A dashboard that needs a trailing panel — a documentation reader, a detail
2212
+ * inspector — projects it into `[layoutEnd]` and chooses its `endMode`. One
2213
+ * that needs a panel beside the page, such as a secondary navigation, projects
2214
+ * it into `[layoutContentPanel]`, which sits in the content row ahead of the
2215
+ * scroll container so the page scrolls under it rather than with it.
2216
+ *
2217
+ * The aside's toggle and the topbar's hamburger drive the underlying shell;
2218
+ * `collapsed` reports the rail state so projected controls can follow it.
2219
+ * The toggle glyphs are projection slots with a built-in fallback, so no icon
2220
+ * registry is required.
2221
+ */
2222
+ class DashboardLayoutComponent {
2223
+ // ===== INPUTS =====
2224
+ /** Passed to `fk-app-shell`. `icon` collapses to a rail; `side` hides entirely. */
2225
+ mode = input('icon', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
2226
+ sidenavWidth = input('260px', ...(ngDevMode ? [{ debugName: "sidenavWidth" }] : /* istanbul ignore next */ []));
2227
+ collapsedWidth = input('64px', ...(ngDevMode ? [{ debugName: "collapsedWidth" }] : /* istanbul ignore next */ []));
2228
+ /** Layout mode for the trailing panel, when `[layoutEnd]` is projected. */
2229
+ endMode = input('over', ...(ngDevMode ? [{ debugName: "endMode" }] : /* istanbul ignore next */ []));
2230
+ endWidth = input('400px', ...(ngDevMode ? [{ debugName: "endWidth" }] : /* istanbul ignore next */ []));
2231
+ endCollapsedWidth = input('64px', ...(ngDevMode ? [{ debugName: "endCollapsedWidth" }] : /* istanbul ignore next */ []));
2232
+ /** Veil the page area with the projected `[layoutPageLoader]` content. */
2233
+ pageLoading = input(false, ...(ngDevMode ? [{ debugName: "pageLoading" }] : /* istanbul ignore next */ []));
2234
+ /** Accessible name for the aside's collapse toggle. */
2235
+ toggleAriaLabel = input('Toggle navigation', ...(ngDevMode ? [{ debugName: "toggleAriaLabel" }] : /* istanbul ignore next */ []));
2236
+ /** Accessible name for the topbar's mobile hamburger. */
2237
+ menuAriaLabel = input('Open navigation', ...(ngDevMode ? [{ debugName: "menuAriaLabel" }] : /* istanbul ignore next */ []));
2238
+ // ===== BASE PROPS =====
2239
+ className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
2240
+ id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
2241
+ // ===== COMPUTED =====
2242
+ shell = viewChild(AppShellComponent, ...(ngDevMode ? [{ debugName: "shell" }] : /* istanbul ignore next */ []));
2243
+ /** Whether the aside is in its icon rail. Projected controls follow this. */
2244
+ collapsed = computed(() => this.shell()?.isCollapsed() ?? false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
2245
+ /** Whether the trailing panel is showing. Projected controls follow this. */
2246
+ endOpen = computed(() => this.shell()?.endOpen() ?? false, ...(ngDevMode ? [{ debugName: "endOpen" }] : /* istanbul ignore next */ []));
2247
+ classes = computed(() => [
2248
+ 'fk-dashboard-layout',
2249
+ this.collapsed() ? 'fk-dashboard-layout--collapsed' : '',
2250
+ this.pageLoading() ? 'fk-dashboard-layout--page-loading' : '',
2251
+ this.className(),
2252
+ ]
2253
+ .filter(Boolean)
2254
+ .join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
2255
+ get hostClass() {
2256
+ return this.classes();
2257
+ }
2258
+ get hostId() {
2259
+ return this.id();
2260
+ }
2261
+ /** The aside header's toggle: collapse or expand the rail. */
2262
+ toggleSidenav() {
2263
+ this.shell()?.toggleSidenav();
2264
+ }
2265
+ /** The topbar hamburger: open the off-canvas aside on narrow viewports. */
2266
+ openSidenav() {
2267
+ this.shell()?.openSidenav();
2268
+ }
2269
+ /**
2270
+ * Collapse the rail from outside the header's own toggle — what a dashboard
2271
+ * calls when it opens the trailing panel and wants the room.
2272
+ */
2273
+ closeSidenav() {
2274
+ this.shell()?.closeSidenav();
2275
+ }
2276
+ /** Show the projected `[layoutEnd]` panel. */
2277
+ openEnd() {
2278
+ this.shell()?.openEnd();
2279
+ }
2280
+ /** Hide it. */
2281
+ closeEnd() {
2282
+ this.shell()?.closeEnd();
2283
+ }
2284
+ /** Hide it if it is showing, show it if it is not. */
2285
+ toggleEnd() {
2286
+ this.shell()?.toggleEnd();
2287
+ }
2288
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2289
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DashboardLayoutComponent, isStandalone: true, selector: "fk-dashboard-layout", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, sidenavWidth: { classPropertyName: "sidenavWidth", publicName: "sidenavWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, endMode: { classPropertyName: "endMode", publicName: "endMode", isSignal: true, isRequired: false, transformFunction: null }, endWidth: { classPropertyName: "endWidth", publicName: "endWidth", isSignal: true, isRequired: false, transformFunction: null }, endCollapsedWidth: { classPropertyName: "endCollapsedWidth", publicName: "endCollapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, pageLoading: { classPropertyName: "pageLoading", publicName: "pageLoading", isSignal: true, isRequired: false, transformFunction: null }, toggleAriaLabel: { classPropertyName: "toggleAriaLabel", publicName: "toggleAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, menuAriaLabel: { classPropertyName: "menuAriaLabel", publicName: "menuAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, viewQueries: [{ propertyName: "shell", first: true, predicate: AppShellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n Banners sit above the shell, in flow, inside the fixed-height host: the\n shell absorbs whatever height they leave, so a banner appearing never adds a\n document scrollbar.\n-->\n<ng-content select=\"[layoutBanner]\" />\n\n<fk-app-shell\n [mode]=\"mode()\"\n [sidenavWidth]=\"sidenavWidth()\"\n [collapsedWidth]=\"collapsedWidth()\"\n [endMode]=\"endMode()\"\n [endWidth]=\"endWidth()\"\n [endCollapsedWidth]=\"endCollapsedWidth()\"\n>\n <div appShellSidenav class=\"fk-dashboard-layout__aside\">\n <div class=\"fk-dashboard-layout__aside-header\">\n <div class=\"fk-dashboard-layout__brand\">\n <ng-content select=\"[layoutBrand]\" />\n </div>\n\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__toggle\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"toggleSidenav()\"\n >\n <ng-content select=\"[layoutToggleIcon]\" />\n </button>\n </div>\n\n <div class=\"fk-dashboard-layout__aside-body\">\n <ng-content select=\"[layoutAside]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__aside-footer\">\n <ng-content select=\"[layoutAsideFooter]\" />\n </div>\n </div>\n\n <div appShellContent class=\"fk-dashboard-layout__content\">\n <!--\n A panel beside the page \u2014 a secondary navigation, a filter rail \u2014 sits in\n the content row ahead of the scroll container, so the topbar and the page\n scroll under it rather than it scrolling with them.\n -->\n <ng-content select=\"[layoutContentPanel]\" />\n\n <!--\n The scroll container. The topbar sticks at its top and the page scrolls\n under it, which is what lets the frosted bar show content through.\n -->\n <div class=\"fk-dashboard-layout__body\">\n <header class=\"fk-dashboard-layout__topbar\">\n <div class=\"fk-dashboard-layout__topbar-inner\">\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__menu\"\n [attr.aria-label]=\"menuAriaLabel()\"\n (click)=\"openSidenav()\"\n >\n <ng-content select=\"[layoutMenuIcon]\" />\n </button>\n\n <div class=\"fk-dashboard-layout__topbar-start\">\n <ng-content select=\"[layoutTopbarStart]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__topbar-end\">\n <ng-content select=\"[layoutTopbarEnd]\" />\n </div>\n </div>\n </header>\n\n <div class=\"fk-dashboard-layout__page\">\n <ng-content />\n\n @if (pageLoading()) {\n <div class=\"fk-dashboard-layout__page-loader\" aria-live=\"polite\">\n <ng-content select=\"[layoutPageLoader]\" />\n </div>\n }\n </div>\n </div>\n </div>\n\n <!--\n A plain div, not a second `aside`: `fk-app-shell` already makes its end\n region an aside, and nesting one inside it would declare two landmarks for\n one panel.\n -->\n <div appShellEnd class=\"fk-dashboard-layout__end\">\n <ng-content select=\"[layoutEnd]\" />\n </div>\n\n <footer appShellFooter class=\"fk-dashboard-layout__footer\">\n <ng-content select=\"[layoutFooter]\" />\n </footer>\n</fk-app-shell>\n", styles: [":host{display:flex;flex-direction:column;height:var(--fk-dashboard-layout-height, 100vh);overflow:hidden;--_max-width: var(--fk-dashboard-layout-max-width, 1400px);--_topbar-height: var(--fk-dashboard-layout-topbar-height, 4rem)}fk-app-shell{flex:1;min-height:0}.fk-dashboard-layout__aside{display:flex;flex-direction:column;height:100%;background:var(--fk-dashboard-layout-aside-bg, var(--fk-color-surface, #ffffff));border-right:1px solid var(--fk-dashboard-layout-aside-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__aside-header{display:flex;align-items:center;gap:var(--fk-rhythm-2, .5rem);flex-shrink:0;padding:var(--fk-dashboard-layout-aside-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-5, 1.25rem))}.fk-dashboard-layout__brand{flex:1 1 auto;min-width:0;display:flex;align-items:center}.fk-dashboard-layout__aside-body{flex:1;min-height:0;overflow-y:auto}.fk-dashboard-layout__aside-footer{flex-shrink:0}.fk-dashboard-layout__aside-footer:empty{display:none}.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{display:grid;place-items:center;flex:none;padding:0;border:1px solid transparent;border-radius:var(--fk-radius-sm, .25rem);background:none;color:var(--fk-dashboard-layout-toggle-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:border-color .15s,background-color .15s,color .15s}.fk-dashboard-layout__toggle:hover,.fk-dashboard-layout__menu:hover{border-color:var(--fk-dashboard-layout-toggle-hover-border-color, var(--fk-color-border, #d9e2ee));background:var(--fk-dashboard-layout-toggle-hover-bg, var(--fk-color-surface, #ffffff));color:var(--fk-dashboard-layout-toggle-hover-color, var(--fk-color-text, #1f2d3d))}.fk-dashboard-layout__toggle:focus-visible,.fk-dashboard-layout__menu:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dashboard-layout__toggle:not(:has(*)):before,.fk-dashboard-layout__menu:not(:has(*)):before{content:\"\";width:1rem;height:.75rem;background:linear-gradient(currentColor 0 2px,transparent 2px 5px,currentColor 5px 7px,transparent 7px 10px,currentColor 10px 12px)}.fk-dashboard-layout__toggle{width:var(--fk-dashboard-layout-toggle-size, 2rem);height:var(--fk-dashboard-layout-toggle-size, 2rem)}.fk-dashboard-layout__menu{width:var(--fk-dashboard-layout-menu-size, 2.25rem);height:var(--fk-dashboard-layout-menu-size, 2.25rem)}.fk-dashboard-layout__content{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__content:has(>:not(.fk-dashboard-layout__body)){flex-direction:row;width:100%}.fk-dashboard-layout__body{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fk-dashboard-layout__topbar{position:sticky;top:0;z-index:20;height:var(--_topbar-height);background:var(--fk-dashboard-layout-topbar-bg, rgba(251, 251, 253, .82));backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));-webkit-backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));border-bottom:1px solid var(--fk-dashboard-layout-topbar-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__topbar-inner{display:flex;align-items:center;gap:var(--fk-rhythm-4, 1rem);height:100%;max-width:var(--_max-width);margin-inline:auto;padding-inline:var(--fk-dashboard-layout-topbar-padding-inline, var(--fk-rhythm-8, 2rem))}.fk-dashboard-layout__topbar-start{display:flex;align-items:center;min-width:0}.fk-dashboard-layout__topbar-end{display:flex;align-items:center;gap:var(--fk-rhythm-3, .75rem);margin-left:auto}.fk-dashboard-layout__menu{display:none}.fk-dashboard-layout__end{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__end:empty{display:none}.fk-dashboard-layout__page{container-type:inline-size;position:relative;max-width:var(--_max-width);margin-inline:auto;padding:var(--fk-dashboard-layout-page-padding, var(--fk-rhythm-4, 1rem));min-height:calc(100% - var(--_topbar-height))}.fk-dashboard-layout__page-loader{position:absolute;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;min-height:12rem;background:var(--fk-dashboard-layout-page-loader-bg, color-mix(in srgb, var(--fk-color-bg, #fbfbfd) 72%, transparent));backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fk-dashboard-layout__footer{position:relative;z-index:100;display:flex;align-items:center;justify-content:center;flex-shrink:0;height:var(--fk-dashboard-layout-footer-height, 2.5rem);background:var(--fk-dashboard-layout-footer-bg, var(--fk-color-surface, #ffffff));border-top:1px solid var(--fk-dashboard-layout-footer-border-color, var(--fk-color-border, #d9e2ee));font-family:var(--fk-dashboard-layout-footer-font-family, var(--fk-font-family-base, sans-serif));font-size:var(--fk-dashboard-layout-footer-font-size, var(--fk-typography-small-font-size, .75rem));color:var(--fk-dashboard-layout-footer-color, var(--fk-color-muted, #8a98a8))}.fk-dashboard-layout__footer:empty{display:none}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__aside-header{justify-content:center;padding-inline:0}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__brand{display:none}@media(min-width:48em){.fk-dashboard-layout__page{padding:var(--fk-dashboard-layout-page-padding-wide, var(--fk-rhythm-6, 1.5rem) var(--fk-rhythm-8, 2rem))}}@media(max-width:760px){.fk-dashboard-layout__menu{display:grid}.fk-dashboard-layout__topbar-inner{padding-inline:var(--fk-rhythm-4, 1rem)}}@media(prefers-reduced-motion:reduce){.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{transition:none}}\n"], dependencies: [{ kind: "component", type: AppShellComponent, selector: "fk-app-shell", inputs: ["mode", "sidenavWidth", "collapsedWidth", "breakpoint", "sticky", "collapseOnMobile", "endMode", "endWidth", "endCollapsedWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2290
+ }
2291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardLayoutComponent, decorators: [{
2292
+ type: Component,
2293
+ args: [{ selector: 'fk-dashboard-layout', standalone: true, imports: [AppShellComponent], encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n Banners sit above the shell, in flow, inside the fixed-height host: the\n shell absorbs whatever height they leave, so a banner appearing never adds a\n document scrollbar.\n-->\n<ng-content select=\"[layoutBanner]\" />\n\n<fk-app-shell\n [mode]=\"mode()\"\n [sidenavWidth]=\"sidenavWidth()\"\n [collapsedWidth]=\"collapsedWidth()\"\n [endMode]=\"endMode()\"\n [endWidth]=\"endWidth()\"\n [endCollapsedWidth]=\"endCollapsedWidth()\"\n>\n <div appShellSidenav class=\"fk-dashboard-layout__aside\">\n <div class=\"fk-dashboard-layout__aside-header\">\n <div class=\"fk-dashboard-layout__brand\">\n <ng-content select=\"[layoutBrand]\" />\n </div>\n\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__toggle\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"toggleSidenav()\"\n >\n <ng-content select=\"[layoutToggleIcon]\" />\n </button>\n </div>\n\n <div class=\"fk-dashboard-layout__aside-body\">\n <ng-content select=\"[layoutAside]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__aside-footer\">\n <ng-content select=\"[layoutAsideFooter]\" />\n </div>\n </div>\n\n <div appShellContent class=\"fk-dashboard-layout__content\">\n <!--\n A panel beside the page \u2014 a secondary navigation, a filter rail \u2014 sits in\n the content row ahead of the scroll container, so the topbar and the page\n scroll under it rather than it scrolling with them.\n -->\n <ng-content select=\"[layoutContentPanel]\" />\n\n <!--\n The scroll container. The topbar sticks at its top and the page scrolls\n under it, which is what lets the frosted bar show content through.\n -->\n <div class=\"fk-dashboard-layout__body\">\n <header class=\"fk-dashboard-layout__topbar\">\n <div class=\"fk-dashboard-layout__topbar-inner\">\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__menu\"\n [attr.aria-label]=\"menuAriaLabel()\"\n (click)=\"openSidenav()\"\n >\n <ng-content select=\"[layoutMenuIcon]\" />\n </button>\n\n <div class=\"fk-dashboard-layout__topbar-start\">\n <ng-content select=\"[layoutTopbarStart]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__topbar-end\">\n <ng-content select=\"[layoutTopbarEnd]\" />\n </div>\n </div>\n </header>\n\n <div class=\"fk-dashboard-layout__page\">\n <ng-content />\n\n @if (pageLoading()) {\n <div class=\"fk-dashboard-layout__page-loader\" aria-live=\"polite\">\n <ng-content select=\"[layoutPageLoader]\" />\n </div>\n }\n </div>\n </div>\n </div>\n\n <!--\n A plain div, not a second `aside`: `fk-app-shell` already makes its end\n region an aside, and nesting one inside it would declare two landmarks for\n one panel.\n -->\n <div appShellEnd class=\"fk-dashboard-layout__end\">\n <ng-content select=\"[layoutEnd]\" />\n </div>\n\n <footer appShellFooter class=\"fk-dashboard-layout__footer\">\n <ng-content select=\"[layoutFooter]\" />\n </footer>\n</fk-app-shell>\n", styles: [":host{display:flex;flex-direction:column;height:var(--fk-dashboard-layout-height, 100vh);overflow:hidden;--_max-width: var(--fk-dashboard-layout-max-width, 1400px);--_topbar-height: var(--fk-dashboard-layout-topbar-height, 4rem)}fk-app-shell{flex:1;min-height:0}.fk-dashboard-layout__aside{display:flex;flex-direction:column;height:100%;background:var(--fk-dashboard-layout-aside-bg, var(--fk-color-surface, #ffffff));border-right:1px solid var(--fk-dashboard-layout-aside-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__aside-header{display:flex;align-items:center;gap:var(--fk-rhythm-2, .5rem);flex-shrink:0;padding:var(--fk-dashboard-layout-aside-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-5, 1.25rem))}.fk-dashboard-layout__brand{flex:1 1 auto;min-width:0;display:flex;align-items:center}.fk-dashboard-layout__aside-body{flex:1;min-height:0;overflow-y:auto}.fk-dashboard-layout__aside-footer{flex-shrink:0}.fk-dashboard-layout__aside-footer:empty{display:none}.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{display:grid;place-items:center;flex:none;padding:0;border:1px solid transparent;border-radius:var(--fk-radius-sm, .25rem);background:none;color:var(--fk-dashboard-layout-toggle-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:border-color .15s,background-color .15s,color .15s}.fk-dashboard-layout__toggle:hover,.fk-dashboard-layout__menu:hover{border-color:var(--fk-dashboard-layout-toggle-hover-border-color, var(--fk-color-border, #d9e2ee));background:var(--fk-dashboard-layout-toggle-hover-bg, var(--fk-color-surface, #ffffff));color:var(--fk-dashboard-layout-toggle-hover-color, var(--fk-color-text, #1f2d3d))}.fk-dashboard-layout__toggle:focus-visible,.fk-dashboard-layout__menu:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dashboard-layout__toggle:not(:has(*)):before,.fk-dashboard-layout__menu:not(:has(*)):before{content:\"\";width:1rem;height:.75rem;background:linear-gradient(currentColor 0 2px,transparent 2px 5px,currentColor 5px 7px,transparent 7px 10px,currentColor 10px 12px)}.fk-dashboard-layout__toggle{width:var(--fk-dashboard-layout-toggle-size, 2rem);height:var(--fk-dashboard-layout-toggle-size, 2rem)}.fk-dashboard-layout__menu{width:var(--fk-dashboard-layout-menu-size, 2.25rem);height:var(--fk-dashboard-layout-menu-size, 2.25rem)}.fk-dashboard-layout__content{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__content:has(>:not(.fk-dashboard-layout__body)){flex-direction:row;width:100%}.fk-dashboard-layout__body{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fk-dashboard-layout__topbar{position:sticky;top:0;z-index:20;height:var(--_topbar-height);background:var(--fk-dashboard-layout-topbar-bg, rgba(251, 251, 253, .82));backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));-webkit-backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));border-bottom:1px solid var(--fk-dashboard-layout-topbar-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__topbar-inner{display:flex;align-items:center;gap:var(--fk-rhythm-4, 1rem);height:100%;max-width:var(--_max-width);margin-inline:auto;padding-inline:var(--fk-dashboard-layout-topbar-padding-inline, var(--fk-rhythm-8, 2rem))}.fk-dashboard-layout__topbar-start{display:flex;align-items:center;min-width:0}.fk-dashboard-layout__topbar-end{display:flex;align-items:center;gap:var(--fk-rhythm-3, .75rem);margin-left:auto}.fk-dashboard-layout__menu{display:none}.fk-dashboard-layout__end{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__end:empty{display:none}.fk-dashboard-layout__page{container-type:inline-size;position:relative;max-width:var(--_max-width);margin-inline:auto;padding:var(--fk-dashboard-layout-page-padding, var(--fk-rhythm-4, 1rem));min-height:calc(100% - var(--_topbar-height))}.fk-dashboard-layout__page-loader{position:absolute;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;min-height:12rem;background:var(--fk-dashboard-layout-page-loader-bg, color-mix(in srgb, var(--fk-color-bg, #fbfbfd) 72%, transparent));backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fk-dashboard-layout__footer{position:relative;z-index:100;display:flex;align-items:center;justify-content:center;flex-shrink:0;height:var(--fk-dashboard-layout-footer-height, 2.5rem);background:var(--fk-dashboard-layout-footer-bg, var(--fk-color-surface, #ffffff));border-top:1px solid var(--fk-dashboard-layout-footer-border-color, var(--fk-color-border, #d9e2ee));font-family:var(--fk-dashboard-layout-footer-font-family, var(--fk-font-family-base, sans-serif));font-size:var(--fk-dashboard-layout-footer-font-size, var(--fk-typography-small-font-size, .75rem));color:var(--fk-dashboard-layout-footer-color, var(--fk-color-muted, #8a98a8))}.fk-dashboard-layout__footer:empty{display:none}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__aside-header{justify-content:center;padding-inline:0}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__brand{display:none}@media(min-width:48em){.fk-dashboard-layout__page{padding:var(--fk-dashboard-layout-page-padding-wide, var(--fk-rhythm-6, 1.5rem) var(--fk-rhythm-8, 2rem))}}@media(max-width:760px){.fk-dashboard-layout__menu{display:grid}.fk-dashboard-layout__topbar-inner{padding-inline:var(--fk-rhythm-4, 1rem)}}@media(prefers-reduced-motion:reduce){.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{transition:none}}\n"] }]
2294
+ }], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], sidenavWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidenavWidth", required: false }] }], collapsedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedWidth", required: false }] }], endMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "endMode", required: false }] }], endWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "endWidth", required: false }] }], endCollapsedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "endCollapsedWidth", required: false }] }], pageLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLoading", required: false }] }], toggleAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleAriaLabel", required: false }] }], menuAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuAriaLabel", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], shell: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AppShellComponent), { isSignal: true }] }], hostClass: [{
2295
+ type: HostBinding,
2296
+ args: ['class']
2297
+ }], hostId: [{
2298
+ type: HostBinding,
2299
+ args: ['attr.id']
2300
+ }] } });
2301
+
2194
2302
  /**
2195
2303
  * A dashboard's sidebar navigation: the caller's groups, with items the
2196
2304
  * caller may not open already removed, rendered as one `fk-sidebar-nav` per
@@ -2236,10 +2344,20 @@ class DashboardNavComponent {
2236
2344
  id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
2237
2345
  ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
2238
2346
  // ===== INJECTED =====
2347
+ // The layout first, and it matters which: `fk-app-shell` sits inside
2348
+ // `fk-dashboard-layout`'s own template, so a nav projected into the
2349
+ // layout is declared outside the shell and can never inject it. The
2350
+ // layout is the ancestor it is actually written inside.
2351
+ layout = inject(DashboardLayoutComponent, {
2352
+ optional: true,
2353
+ });
2239
2354
  shell = inject(AppShellComponent, { optional: true });
2240
2355
  // ===== COMPUTED =====
2241
- /** The rail state in force: this input, else the ancestor shell's. */
2242
- isCollapsed = computed(() => this.collapsed() ?? this.shell?.isCollapsed() ?? false, ...(ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []));
2356
+ /** The rail state in force: this input, else whichever ancestor owns it. */
2357
+ isCollapsed = computed(() => this.collapsed() ??
2358
+ this.layout?.collapsed() ??
2359
+ this.shell?.isCollapsed() ??
2360
+ false, ...(ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []));
2243
2361
  /**
2244
2362
  * Visible groups sliced into render segments, each carrying a single-group
2245
2363
  * `SidebarNavModel`.
@@ -2343,114 +2461,6 @@ function toModelItem(item) {
2343
2461
  };
2344
2462
  }
2345
2463
 
2346
- /**
2347
- * The chrome of a signed-in dashboard, built on `fk-app-shell`: a full-height
2348
- * aside with a brand header and collapse toggle, a sticky frosted topbar with
2349
- * a mobile hamburger, a capped page area with an optional loading veil, and a
2350
- * footer. Every dashboard that uses it gets the identical structure — the
2351
- * same hamburger, the same collapse, the same scroll behaviour — and differs
2352
- * only in what it projects.
2353
- *
2354
- * <fk-dashboard-layout [pageLoading]="navigating()">
2355
- * <fk-nav-brand layoutBrand brandText="Acme" />
2356
- * <fk-dashboard-nav layoutAside [groups]="groups()" [collapsed]="collapsed()" />
2357
- * <nav layoutTopbarStart>Acme / Overview</nav>
2358
- * <fk-user-menu layoutTopbarEnd … />
2359
- * <router-outlet />
2360
- * <span layoutFooter>© Acme</span>
2361
- * </fk-dashboard-layout>
2362
- *
2363
- * A dashboard that needs a trailing panel — a documentation reader, a detail
2364
- * inspector — projects it into `[layoutEnd]` and chooses its `endMode`. One
2365
- * that needs a panel beside the page, such as a secondary navigation, projects
2366
- * it into `[layoutContentPanel]`, which sits in the content row ahead of the
2367
- * scroll container so the page scrolls under it rather than with it.
2368
- *
2369
- * The aside's toggle and the topbar's hamburger drive the underlying shell;
2370
- * `collapsed` reports the rail state so projected controls can follow it.
2371
- * The toggle glyphs are projection slots with a built-in fallback, so no icon
2372
- * registry is required.
2373
- */
2374
- class DashboardLayoutComponent {
2375
- // ===== INPUTS =====
2376
- /** Passed to `fk-app-shell`. `icon` collapses to a rail; `side` hides entirely. */
2377
- mode = input('icon', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
2378
- sidenavWidth = input('260px', ...(ngDevMode ? [{ debugName: "sidenavWidth" }] : /* istanbul ignore next */ []));
2379
- collapsedWidth = input('64px', ...(ngDevMode ? [{ debugName: "collapsedWidth" }] : /* istanbul ignore next */ []));
2380
- /** Layout mode for the trailing panel, when `[layoutEnd]` is projected. */
2381
- endMode = input('over', ...(ngDevMode ? [{ debugName: "endMode" }] : /* istanbul ignore next */ []));
2382
- endWidth = input('400px', ...(ngDevMode ? [{ debugName: "endWidth" }] : /* istanbul ignore next */ []));
2383
- endCollapsedWidth = input('64px', ...(ngDevMode ? [{ debugName: "endCollapsedWidth" }] : /* istanbul ignore next */ []));
2384
- /** Veil the page area with the projected `[layoutPageLoader]` content. */
2385
- pageLoading = input(false, ...(ngDevMode ? [{ debugName: "pageLoading" }] : /* istanbul ignore next */ []));
2386
- /** Accessible name for the aside's collapse toggle. */
2387
- toggleAriaLabel = input('Toggle navigation', ...(ngDevMode ? [{ debugName: "toggleAriaLabel" }] : /* istanbul ignore next */ []));
2388
- /** Accessible name for the topbar's mobile hamburger. */
2389
- menuAriaLabel = input('Open navigation', ...(ngDevMode ? [{ debugName: "menuAriaLabel" }] : /* istanbul ignore next */ []));
2390
- // ===== BASE PROPS =====
2391
- className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
2392
- id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
2393
- // ===== COMPUTED =====
2394
- shell = viewChild(AppShellComponent, ...(ngDevMode ? [{ debugName: "shell" }] : /* istanbul ignore next */ []));
2395
- /** Whether the aside is in its icon rail. Projected controls follow this. */
2396
- collapsed = computed(() => this.shell()?.isCollapsed() ?? false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
2397
- /** Whether the trailing panel is showing. Projected controls follow this. */
2398
- endOpen = computed(() => this.shell()?.endOpen() ?? false, ...(ngDevMode ? [{ debugName: "endOpen" }] : /* istanbul ignore next */ []));
2399
- classes = computed(() => [
2400
- 'fk-dashboard-layout',
2401
- this.collapsed() ? 'fk-dashboard-layout--collapsed' : '',
2402
- this.pageLoading() ? 'fk-dashboard-layout--page-loading' : '',
2403
- this.className(),
2404
- ]
2405
- .filter(Boolean)
2406
- .join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
2407
- get hostClass() {
2408
- return this.classes();
2409
- }
2410
- get hostId() {
2411
- return this.id();
2412
- }
2413
- /** The aside header's toggle: collapse or expand the rail. */
2414
- toggleSidenav() {
2415
- this.shell()?.toggleSidenav();
2416
- }
2417
- /** The topbar hamburger: open the off-canvas aside on narrow viewports. */
2418
- openSidenav() {
2419
- this.shell()?.openSidenav();
2420
- }
2421
- /**
2422
- * Collapse the rail from outside the header's own toggle — what a dashboard
2423
- * calls when it opens the trailing panel and wants the room.
2424
- */
2425
- closeSidenav() {
2426
- this.shell()?.closeSidenav();
2427
- }
2428
- /** Show the projected `[layoutEnd]` panel. */
2429
- openEnd() {
2430
- this.shell()?.openEnd();
2431
- }
2432
- /** Hide it. */
2433
- closeEnd() {
2434
- this.shell()?.closeEnd();
2435
- }
2436
- /** Hide it if it is showing, show it if it is not. */
2437
- toggleEnd() {
2438
- this.shell()?.toggleEnd();
2439
- }
2440
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2441
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DashboardLayoutComponent, isStandalone: true, selector: "fk-dashboard-layout", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, sidenavWidth: { classPropertyName: "sidenavWidth", publicName: "sidenavWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, endMode: { classPropertyName: "endMode", publicName: "endMode", isSignal: true, isRequired: false, transformFunction: null }, endWidth: { classPropertyName: "endWidth", publicName: "endWidth", isSignal: true, isRequired: false, transformFunction: null }, endCollapsedWidth: { classPropertyName: "endCollapsedWidth", publicName: "endCollapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, pageLoading: { classPropertyName: "pageLoading", publicName: "pageLoading", isSignal: true, isRequired: false, transformFunction: null }, toggleAriaLabel: { classPropertyName: "toggleAriaLabel", publicName: "toggleAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, menuAriaLabel: { classPropertyName: "menuAriaLabel", publicName: "menuAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, viewQueries: [{ propertyName: "shell", first: true, predicate: AppShellComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n Banners sit above the shell, in flow, inside the fixed-height host: the\n shell absorbs whatever height they leave, so a banner appearing never adds a\n document scrollbar.\n-->\n<ng-content select=\"[layoutBanner]\" />\n\n<fk-app-shell\n [mode]=\"mode()\"\n [sidenavWidth]=\"sidenavWidth()\"\n [collapsedWidth]=\"collapsedWidth()\"\n [endMode]=\"endMode()\"\n [endWidth]=\"endWidth()\"\n [endCollapsedWidth]=\"endCollapsedWidth()\"\n>\n <div appShellSidenav class=\"fk-dashboard-layout__aside\">\n <div class=\"fk-dashboard-layout__aside-header\">\n <div class=\"fk-dashboard-layout__brand\">\n <ng-content select=\"[layoutBrand]\" />\n </div>\n\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__toggle\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"toggleSidenav()\"\n >\n <ng-content select=\"[layoutToggleIcon]\" />\n </button>\n </div>\n\n <div class=\"fk-dashboard-layout__aside-body\">\n <ng-content select=\"[layoutAside]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__aside-footer\">\n <ng-content select=\"[layoutAsideFooter]\" />\n </div>\n </div>\n\n <div appShellContent class=\"fk-dashboard-layout__content\">\n <!--\n A panel beside the page \u2014 a secondary navigation, a filter rail \u2014 sits in\n the content row ahead of the scroll container, so the topbar and the page\n scroll under it rather than it scrolling with them.\n -->\n <ng-content select=\"[layoutContentPanel]\" />\n\n <!--\n The scroll container. The topbar sticks at its top and the page scrolls\n under it, which is what lets the frosted bar show content through.\n -->\n <div class=\"fk-dashboard-layout__body\">\n <header class=\"fk-dashboard-layout__topbar\">\n <div class=\"fk-dashboard-layout__topbar-inner\">\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__menu\"\n [attr.aria-label]=\"menuAriaLabel()\"\n (click)=\"openSidenav()\"\n >\n <ng-content select=\"[layoutMenuIcon]\" />\n </button>\n\n <div class=\"fk-dashboard-layout__topbar-start\">\n <ng-content select=\"[layoutTopbarStart]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__topbar-end\">\n <ng-content select=\"[layoutTopbarEnd]\" />\n </div>\n </div>\n </header>\n\n <div class=\"fk-dashboard-layout__page\">\n <ng-content />\n\n @if (pageLoading()) {\n <div class=\"fk-dashboard-layout__page-loader\" aria-live=\"polite\">\n <ng-content select=\"[layoutPageLoader]\" />\n </div>\n }\n </div>\n </div>\n </div>\n\n <!--\n A plain div, not a second `aside`: `fk-app-shell` already makes its end\n region an aside, and nesting one inside it would declare two landmarks for\n one panel.\n -->\n <div appShellEnd class=\"fk-dashboard-layout__end\">\n <ng-content select=\"[layoutEnd]\" />\n </div>\n\n <footer appShellFooter class=\"fk-dashboard-layout__footer\">\n <ng-content select=\"[layoutFooter]\" />\n </footer>\n</fk-app-shell>\n", styles: [":host{display:flex;flex-direction:column;height:var(--fk-dashboard-layout-height, 100vh);overflow:hidden;--_max-width: var(--fk-dashboard-layout-max-width, 1400px);--_topbar-height: var(--fk-dashboard-layout-topbar-height, 4rem)}fk-app-shell{flex:1;min-height:0}.fk-dashboard-layout__aside{display:flex;flex-direction:column;height:100%;background:var(--fk-dashboard-layout-aside-bg, var(--fk-color-surface, #ffffff));border-right:1px solid var(--fk-dashboard-layout-aside-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__aside-header{display:flex;align-items:center;gap:var(--fk-rhythm-2, .5rem);flex-shrink:0;padding:var(--fk-dashboard-layout-aside-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-5, 1.25rem))}.fk-dashboard-layout__brand{flex:1 1 auto;min-width:0;display:flex;align-items:center}.fk-dashboard-layout__aside-body{flex:1;min-height:0;overflow-y:auto}.fk-dashboard-layout__aside-footer{flex-shrink:0}.fk-dashboard-layout__aside-footer:empty{display:none}.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{display:grid;place-items:center;flex:none;padding:0;border:1px solid transparent;border-radius:var(--fk-radius-sm, .25rem);background:none;color:var(--fk-dashboard-layout-toggle-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:border-color .15s,background-color .15s,color .15s}.fk-dashboard-layout__toggle:hover,.fk-dashboard-layout__menu:hover{border-color:var(--fk-dashboard-layout-toggle-hover-border-color, var(--fk-color-border, #d9e2ee));background:var(--fk-dashboard-layout-toggle-hover-bg, var(--fk-color-surface, #ffffff));color:var(--fk-dashboard-layout-toggle-hover-color, var(--fk-color-text, #1f2d3d))}.fk-dashboard-layout__toggle:focus-visible,.fk-dashboard-layout__menu:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dashboard-layout__toggle:not(:has(*)):before,.fk-dashboard-layout__menu:not(:has(*)):before{content:\"\";width:1rem;height:.75rem;background:linear-gradient(currentColor 0 2px,transparent 2px 5px,currentColor 5px 7px,transparent 7px 10px,currentColor 10px 12px)}.fk-dashboard-layout__toggle{width:var(--fk-dashboard-layout-toggle-size, 2rem);height:var(--fk-dashboard-layout-toggle-size, 2rem)}.fk-dashboard-layout__menu{width:var(--fk-dashboard-layout-menu-size, 2.25rem);height:var(--fk-dashboard-layout-menu-size, 2.25rem)}.fk-dashboard-layout__content{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__content:has(>:not(.fk-dashboard-layout__body)){flex-direction:row;width:100%}.fk-dashboard-layout__body{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fk-dashboard-layout__topbar{position:sticky;top:0;z-index:20;height:var(--_topbar-height);background:var(--fk-dashboard-layout-topbar-bg, rgba(251, 251, 253, .82));backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));-webkit-backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));border-bottom:1px solid var(--fk-dashboard-layout-topbar-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__topbar-inner{display:flex;align-items:center;gap:var(--fk-rhythm-4, 1rem);height:100%;max-width:var(--_max-width);margin-inline:auto;padding-inline:var(--fk-dashboard-layout-topbar-padding-inline, var(--fk-rhythm-8, 2rem))}.fk-dashboard-layout__topbar-start{display:flex;align-items:center;min-width:0}.fk-dashboard-layout__topbar-end{display:flex;align-items:center;gap:var(--fk-rhythm-3, .75rem);margin-left:auto}.fk-dashboard-layout__menu{display:none}.fk-dashboard-layout__end{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__end:empty{display:none}.fk-dashboard-layout__page{container-type:inline-size;position:relative;max-width:var(--_max-width);margin-inline:auto;padding:var(--fk-dashboard-layout-page-padding, var(--fk-rhythm-4, 1rem));min-height:calc(100% - var(--_topbar-height))}.fk-dashboard-layout__page-loader{position:absolute;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;min-height:12rem;background:var(--fk-dashboard-layout-page-loader-bg, color-mix(in srgb, var(--fk-color-bg, #fbfbfd) 72%, transparent));backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fk-dashboard-layout__footer{position:relative;z-index:100;display:flex;align-items:center;justify-content:center;flex-shrink:0;height:var(--fk-dashboard-layout-footer-height, 2.5rem);background:var(--fk-dashboard-layout-footer-bg, var(--fk-color-surface, #ffffff));border-top:1px solid var(--fk-dashboard-layout-footer-border-color, var(--fk-color-border, #d9e2ee));font-family:var(--fk-dashboard-layout-footer-font-family, var(--fk-font-family-base, sans-serif));font-size:var(--fk-dashboard-layout-footer-font-size, var(--fk-typography-small-font-size, .75rem));color:var(--fk-dashboard-layout-footer-color, var(--fk-color-muted, #8a98a8))}.fk-dashboard-layout__footer:empty{display:none}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__aside-header{justify-content:center;padding-inline:0}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__brand{display:none}@media(min-width:48em){.fk-dashboard-layout__page{padding:var(--fk-dashboard-layout-page-padding-wide, var(--fk-rhythm-6, 1.5rem) var(--fk-rhythm-8, 2rem))}}@media(max-width:760px){.fk-dashboard-layout__menu{display:grid}.fk-dashboard-layout__topbar-inner{padding-inline:var(--fk-rhythm-4, 1rem)}}@media(prefers-reduced-motion:reduce){.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{transition:none}}\n"], dependencies: [{ kind: "component", type: AppShellComponent, selector: "fk-app-shell", inputs: ["mode", "sidenavWidth", "collapsedWidth", "breakpoint", "sticky", "collapseOnMobile", "endMode", "endWidth", "endCollapsedWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2442
- }
2443
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DashboardLayoutComponent, decorators: [{
2444
- type: Component,
2445
- args: [{ selector: 'fk-dashboard-layout', standalone: true, imports: [AppShellComponent], encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n Banners sit above the shell, in flow, inside the fixed-height host: the\n shell absorbs whatever height they leave, so a banner appearing never adds a\n document scrollbar.\n-->\n<ng-content select=\"[layoutBanner]\" />\n\n<fk-app-shell\n [mode]=\"mode()\"\n [sidenavWidth]=\"sidenavWidth()\"\n [collapsedWidth]=\"collapsedWidth()\"\n [endMode]=\"endMode()\"\n [endWidth]=\"endWidth()\"\n [endCollapsedWidth]=\"endCollapsedWidth()\"\n>\n <div appShellSidenav class=\"fk-dashboard-layout__aside\">\n <div class=\"fk-dashboard-layout__aside-header\">\n <div class=\"fk-dashboard-layout__brand\">\n <ng-content select=\"[layoutBrand]\" />\n </div>\n\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__toggle\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"toggleSidenav()\"\n >\n <ng-content select=\"[layoutToggleIcon]\" />\n </button>\n </div>\n\n <div class=\"fk-dashboard-layout__aside-body\">\n <ng-content select=\"[layoutAside]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__aside-footer\">\n <ng-content select=\"[layoutAsideFooter]\" />\n </div>\n </div>\n\n <div appShellContent class=\"fk-dashboard-layout__content\">\n <!--\n A panel beside the page \u2014 a secondary navigation, a filter rail \u2014 sits in\n the content row ahead of the scroll container, so the topbar and the page\n scroll under it rather than it scrolling with them.\n -->\n <ng-content select=\"[layoutContentPanel]\" />\n\n <!--\n The scroll container. The topbar sticks at its top and the page scrolls\n under it, which is what lets the frosted bar show content through.\n -->\n <div class=\"fk-dashboard-layout__body\">\n <header class=\"fk-dashboard-layout__topbar\">\n <div class=\"fk-dashboard-layout__topbar-inner\">\n <button\n type=\"button\"\n class=\"fk-dashboard-layout__menu\"\n [attr.aria-label]=\"menuAriaLabel()\"\n (click)=\"openSidenav()\"\n >\n <ng-content select=\"[layoutMenuIcon]\" />\n </button>\n\n <div class=\"fk-dashboard-layout__topbar-start\">\n <ng-content select=\"[layoutTopbarStart]\" />\n </div>\n\n <div class=\"fk-dashboard-layout__topbar-end\">\n <ng-content select=\"[layoutTopbarEnd]\" />\n </div>\n </div>\n </header>\n\n <div class=\"fk-dashboard-layout__page\">\n <ng-content />\n\n @if (pageLoading()) {\n <div class=\"fk-dashboard-layout__page-loader\" aria-live=\"polite\">\n <ng-content select=\"[layoutPageLoader]\" />\n </div>\n }\n </div>\n </div>\n </div>\n\n <!--\n A plain div, not a second `aside`: `fk-app-shell` already makes its end\n region an aside, and nesting one inside it would declare two landmarks for\n one panel.\n -->\n <div appShellEnd class=\"fk-dashboard-layout__end\">\n <ng-content select=\"[layoutEnd]\" />\n </div>\n\n <footer appShellFooter class=\"fk-dashboard-layout__footer\">\n <ng-content select=\"[layoutFooter]\" />\n </footer>\n</fk-app-shell>\n", styles: [":host{display:flex;flex-direction:column;height:var(--fk-dashboard-layout-height, 100vh);overflow:hidden;--_max-width: var(--fk-dashboard-layout-max-width, 1400px);--_topbar-height: var(--fk-dashboard-layout-topbar-height, 4rem)}fk-app-shell{flex:1;min-height:0}.fk-dashboard-layout__aside{display:flex;flex-direction:column;height:100%;background:var(--fk-dashboard-layout-aside-bg, var(--fk-color-surface, #ffffff));border-right:1px solid var(--fk-dashboard-layout-aside-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__aside-header{display:flex;align-items:center;gap:var(--fk-rhythm-2, .5rem);flex-shrink:0;padding:var(--fk-dashboard-layout-aside-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-5, 1.25rem))}.fk-dashboard-layout__brand{flex:1 1 auto;min-width:0;display:flex;align-items:center}.fk-dashboard-layout__aside-body{flex:1;min-height:0;overflow-y:auto}.fk-dashboard-layout__aside-footer{flex-shrink:0}.fk-dashboard-layout__aside-footer:empty{display:none}.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{display:grid;place-items:center;flex:none;padding:0;border:1px solid transparent;border-radius:var(--fk-radius-sm, .25rem);background:none;color:var(--fk-dashboard-layout-toggle-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:border-color .15s,background-color .15s,color .15s}.fk-dashboard-layout__toggle:hover,.fk-dashboard-layout__menu:hover{border-color:var(--fk-dashboard-layout-toggle-hover-border-color, var(--fk-color-border, #d9e2ee));background:var(--fk-dashboard-layout-toggle-hover-bg, var(--fk-color-surface, #ffffff));color:var(--fk-dashboard-layout-toggle-hover-color, var(--fk-color-text, #1f2d3d))}.fk-dashboard-layout__toggle:focus-visible,.fk-dashboard-layout__menu:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dashboard-layout__toggle:not(:has(*)):before,.fk-dashboard-layout__menu:not(:has(*)):before{content:\"\";width:1rem;height:.75rem;background:linear-gradient(currentColor 0 2px,transparent 2px 5px,currentColor 5px 7px,transparent 7px 10px,currentColor 10px 12px)}.fk-dashboard-layout__toggle{width:var(--fk-dashboard-layout-toggle-size, 2rem);height:var(--fk-dashboard-layout-toggle-size, 2rem)}.fk-dashboard-layout__menu{width:var(--fk-dashboard-layout-menu-size, 2.25rem);height:var(--fk-dashboard-layout-menu-size, 2.25rem)}.fk-dashboard-layout__content{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__content:has(>:not(.fk-dashboard-layout__body)){flex-direction:row;width:100%}.fk-dashboard-layout__body{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fk-dashboard-layout__topbar{position:sticky;top:0;z-index:20;height:var(--_topbar-height);background:var(--fk-dashboard-layout-topbar-bg, rgba(251, 251, 253, .82));backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));-webkit-backdrop-filter:blur(var(--fk-dashboard-layout-topbar-blur, 14px));border-bottom:1px solid var(--fk-dashboard-layout-topbar-border-color, var(--fk-color-border, #d9e2ee))}.fk-dashboard-layout__topbar-inner{display:flex;align-items:center;gap:var(--fk-rhythm-4, 1rem);height:100%;max-width:var(--_max-width);margin-inline:auto;padding-inline:var(--fk-dashboard-layout-topbar-padding-inline, var(--fk-rhythm-8, 2rem))}.fk-dashboard-layout__topbar-start{display:flex;align-items:center;min-width:0}.fk-dashboard-layout__topbar-end{display:flex;align-items:center;gap:var(--fk-rhythm-3, .75rem);margin-left:auto}.fk-dashboard-layout__menu{display:none}.fk-dashboard-layout__end{display:flex;flex-direction:column;height:100%;min-height:0}.fk-dashboard-layout__end:empty{display:none}.fk-dashboard-layout__page{container-type:inline-size;position:relative;max-width:var(--_max-width);margin-inline:auto;padding:var(--fk-dashboard-layout-page-padding, var(--fk-rhythm-4, 1rem));min-height:calc(100% - var(--_topbar-height))}.fk-dashboard-layout__page-loader{position:absolute;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;min-height:12rem;background:var(--fk-dashboard-layout-page-loader-bg, color-mix(in srgb, var(--fk-color-bg, #fbfbfd) 72%, transparent));backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fk-dashboard-layout__footer{position:relative;z-index:100;display:flex;align-items:center;justify-content:center;flex-shrink:0;height:var(--fk-dashboard-layout-footer-height, 2.5rem);background:var(--fk-dashboard-layout-footer-bg, var(--fk-color-surface, #ffffff));border-top:1px solid var(--fk-dashboard-layout-footer-border-color, var(--fk-color-border, #d9e2ee));font-family:var(--fk-dashboard-layout-footer-font-family, var(--fk-font-family-base, sans-serif));font-size:var(--fk-dashboard-layout-footer-font-size, var(--fk-typography-small-font-size, .75rem));color:var(--fk-dashboard-layout-footer-color, var(--fk-color-muted, #8a98a8))}.fk-dashboard-layout__footer:empty{display:none}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__aside-header{justify-content:center;padding-inline:0}:host(.fk-dashboard-layout--collapsed) .fk-dashboard-layout__brand{display:none}@media(min-width:48em){.fk-dashboard-layout__page{padding:var(--fk-dashboard-layout-page-padding-wide, var(--fk-rhythm-6, 1.5rem) var(--fk-rhythm-8, 2rem))}}@media(max-width:760px){.fk-dashboard-layout__menu{display:grid}.fk-dashboard-layout__topbar-inner{padding-inline:var(--fk-rhythm-4, 1rem)}}@media(prefers-reduced-motion:reduce){.fk-dashboard-layout__toggle,.fk-dashboard-layout__menu{transition:none}}\n"] }]
2446
- }], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], sidenavWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidenavWidth", required: false }] }], collapsedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedWidth", required: false }] }], endMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "endMode", required: false }] }], endWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "endWidth", required: false }] }], endCollapsedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "endCollapsedWidth", required: false }] }], pageLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLoading", required: false }] }], toggleAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleAriaLabel", required: false }] }], menuAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuAriaLabel", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], shell: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AppShellComponent), { isSignal: true }] }], hostClass: [{
2447
- type: HostBinding,
2448
- args: ['class']
2449
- }], hostId: [{
2450
- type: HostBinding,
2451
- args: ['attr.id']
2452
- }] } });
2453
-
2454
2464
  /**
2455
2465
  * A whole dashboard shell in one element: the collapsing aside and its
2456
2466
  * toggle, the brand block at its head, the icon-rail navigation, and the