@a.nemreen/dga-ui 0.3.1 → 0.3.2

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.
@@ -0,0 +1,2483 @@
1
+ import*as a from"@angular/core";import{inject as p,ElementRef as q,input as o,booleanAttribute as y,model as w,output as u,signal as l,Injector as R,DOCUMENT as _,DestroyRef as U,viewChild as k,computed as n,effect as L,untracked as T,afterNextRender as b,HostListener as m,ChangeDetectionStrategy as F,Component as V}from"@angular/core";import{APP_BASE_HREF as Y,PlatformLocation as Q}from"@angular/common";import{dgaSafeHref as N,dgaCx as r,DgaAvatar as S,DgaBadge as C,DgaField as D,DgaFormControl as I,DgaFormEnd as z,DgaIcon as M,DgaIconBadge as A,DgaModal as P,DgaTooltip as O}from"@a.nemreen/dga-ui";function B($,e="/"){if(typeof window>"u")return!1;const t=N($.trim(),e);if(!t)return!1;try{const i=new URL(t,window.location.origin);return i.protocol!=="http:"&&i.protocol!=="https:"||i.origin!==window.location.origin?!1:(window.location.assign(`${i.pathname}${i.search}${i.hash}`),!0)}catch{return!1}}const H="group relative inline-flex h-(--size-header-portal) shrink-0 cursor-pointer items-center gap-md rounded-sm px-xl font-sans text-body-md font-medium text-fg hover:bg-neutral-light focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus",K="pointer-events-none absolute start-xl end-xl bottom-0 h-[5px] rounded-full",W="inline-flex min-h-5xl w-full cursor-pointer flex-col justify-center gap-xxs rounded-sm px-xl py-sm text-start text-body-md font-normal text-fg transition-colors hover:bg-neutral-light focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus",G="inline-flex min-h-11xl w-full cursor-pointer flex-col justify-center gap-xs rounded-md border border-border bg-card px-2xl py-xl text-start transition-colors hover:border-primary hover:bg-primary-faint focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus",Z="relative flex min-h-7xl w-full cursor-pointer items-center gap-lg rounded-md px-xl py-md text-start text-body-md font-medium text-fg transition-colors hover:bg-neutral-light active:bg-neutral-light focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus",X="flex min-h-6xl w-full cursor-pointer flex-col justify-center gap-xxs rounded-md px-xl py-md text-start text-body-md text-fg transition-colors hover:bg-neutral-light active:bg-neutral-light focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus";class g{host=p(q);baseHref=p(Y,{optional:!0})??p(Q).getBaseHrefFromDOM()??"/";closeTimer=null;dropdownSyncFrame=null;lastDropdownStyleKey="";collapseId="dga-nav-collapse";dropLink=W;dropTile=G;mobileLink=X;brand=o("",...ngDevMode?[{debugName:"brand"}]:[]);brandSlogan=o("",...ngDevMode?[{debugName:"brandSlogan"}]:[]);brandLogo=o("",...ngDevMode?[{debugName:"brandLogo"}]:[]);brandLogoAlt=o("\u0634\u0639\u0627\u0631 \u0627\u0644\u062C\u0647\u0629",...ngDevMode?[{debugName:"brandLogoAlt"}]:[]);brandPlaceholder=o(!1,{...ngDevMode?{debugName:"brandPlaceholder"}:{},transform:y});brandHref=o("#",...ngDevMode?[{debugName:"brandHref"}]:[]);navLabel=o("\u0627\u0644\u062A\u0646\u0642\u0644 \u0627\u0644\u0631\u0626\u064A\u0633\u064A",...ngDevMode?[{debugName:"navLabel"}]:[]);menuToggleLabel=o("\u0641\u062A\u062D \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u062A\u0646\u0642\u0644",...ngDevMode?[{debugName:"menuToggleLabel"}]:[]);menuCloseLabel=o("\u0625\u063A\u0644\u0627\u0642 \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u062A\u0646\u0642\u0644",...ngDevMode?[{debugName:"menuCloseLabel"}]:[]);appearance=o("default",...ngDevMode?[{debugName:"appearance"}]:[]);mobileNav=o("sheet",...ngDevMode?[{debugName:"mobileNav"}]:[]);sticky=o(!0,{...ngDevMode?{debugName:"sticky"}:{},transform:y});items=o([],...ngDevMode?[{debugName:"items"}]:[]);actions=o([],...ngDevMode?[{debugName:"actions"}]:[]);search=o(null,...ngDevMode?[{debugName:"search"}]:[]);searchQuery=w("",...ngDevMode?[{debugName:"searchQuery"}]:[]);notifications=o(null,...ngDevMode?[{debugName:"notifications"}]:[]);login=o(null,...ngDevMode?[{debugName:"login"}]:[]);user=o(null,...ngDevMode?[{debugName:"user"}]:[]);authenticated=w(!1,...ngDevMode?[{debugName:"authenticated"}]:[]);actionClick=u();searchSubmit=u();searchSuggestionSelect=u();searchVoice=u();notificationAction=u();loginSubmit=u();logout=u();userLinkClick=u();navLinkClick=u();mobileOpen=l(!1,...ngDevMode?[{debugName:"mobileOpen"}]:[]);openDropdown=l(null,...ngDevMode?[{debugName:"openDropdown"}]:[]);searchOpen=l(!1,...ngDevMode?[{debugName:"searchOpen"}]:[]);notificationsOpen=l(!1,...ngDevMode?[{debugName:"notificationsOpen"}]:[]);loginOpen=l(!1,...ngDevMode?[{debugName:"loginOpen"}]:[]);userMenuOpen=l(!1,...ngDevMode?[{debugName:"userMenuOpen"}]:[]);voiceListening=l(!1,...ngDevMode?[{debugName:"voiceListening"}]:[]);expandedNotificationId=l(null,...ngDevMode?[{debugName:"expandedNotificationId"}]:[]);loginEmail=l("",...ngDevMode?[{debugName:"loginEmail"}]:[]);loginPassword=l("",...ngDevMode?[{debugName:"loginPassword"}]:[]);showLoginPassword=l(!1,...ngDevMode?[{debugName:"showLoginPassword"}]:[]);loginSubmitting=l(!1,...ngDevMode?[{debugName:"loginSubmitting"}]:[]);dropdownPanelStyle=l({},...ngDevMode?[{debugName:"dropdownPanelStyle"}]:[]);dismissedNotificationIds=l(new Set,...ngDevMode?[{debugName:"dismissedNotificationIds"}]:[]);readNotificationIds=l(new Set,...ngDevMode?[{debugName:"readNotificationIds"}]:[]);dropdownTrigger=null;dropdownActionId=null;injector=p(R);doc=p(_);destroyRef=p(U);searchInputRef=k("searchInput",...ngDevMode?[{debugName:"searchInputRef"}]:[]);utilLayerRef=k("utilLayer",...ngDevMode?[{debugName:"utilLayerRef"}]:[]);searchPanelId="dga-header-search-panel";notificationsPanelId="dga-header-notifications-panel";loginPanelId="dga-header-login-panel";userPanelId="dga-header-user-panel";isPortal=n(()=>this.appearance()==="portal",...ngDevMode?[{debugName:"isPortal"}]:[]);appHref(e){return N(e,this.baseHref)}searchConfig=n(()=>this.search(),...ngDevMode?[{debugName:"searchConfig"}]:[]);searchActionId=n(()=>this.search()?.actionId??"search",...ngDevMode?[{debugName:"searchActionId"}]:[]);notificationsConfig=n(()=>this.notifications(),...ngDevMode?[{debugName:"notificationsConfig"}]:[]);notificationsActionId=n(()=>this.notifications()?.actionId??"notifications",...ngDevMode?[{debugName:"notificationsActionId"}]:[]);loginConfig=n(()=>this.login(),...ngDevMode?[{debugName:"loginConfig"}]:[]);loginActionId=n(()=>this.login()?.actionId??"login",...ngDevMode?[{debugName:"loginActionId"}]:[]);userConfig=n(()=>this.user(),...ngDevMode?[{debugName:"userConfig"}]:[]);utilityOverlayOpen=n(()=>this.notificationsOpen()||this.loginOpen()||this.userMenuOpen(),...ngDevMode?[{debugName:"utilityOverlayOpen"}]:[]);visibleNotifications=n(()=>{const e=this.notifications()?.items??[],t=this.dismissedNotificationIds(),i=this.readNotificationIds();return e.filter(s=>!t.has(s.id)).map(s=>({...s,read:!!s.read||i.has(s.id)}))},...ngDevMode?[{debugName:"visibleNotifications"}]:[]);unreadNotificationCount=n(()=>this.visibleNotifications().filter(e=>!e.read).length,...ngDevMode?[{debugName:"unreadNotificationCount"}]:[]);constructor(){this.destroyRef.onDestroy(()=>this.removePortaledUtilLayer()),L(()=>{this.mobileNav(),T(()=>{this.mobileOpen()&&this.closeAll()})}),L(()=>{if(!this.utilityOverlayOpen())return;this.utilLayerRef()?.nativeElement&&this.portalUtilLayer(),b(()=>this.portalUtilLayer(),{injector:this.injector})})}portalUtilLayer(){const e=this.utilLayerRef()?.nativeElement;!e||e.parentElement===this.doc.body||this.doc.body.appendChild(e)}removePortaledUtilLayer(){const e=this.utilLayerRef()?.nativeElement;e?.parentElement===this.doc.body&&e.remove()}activeWideDropdown=n(()=>{if(!this.hoverMenus()&&this.isMobileViewport())return null;const e=this.openDropdown();if(e===null)return null;const t=this.items()[e];if(!t?.dropdown)return null;const i=this.resolveVariant(t);return i==="menu"?null:{index:e,item:t,variant:i}},...ngDevMode?[{debugName:"activeWideDropdown"}]:[]);hostClasses=n(()=>r("relative z-header block overflow-visible border-b border-border-subtle bg-nav font-sans text-fg",this.sticky()&&"sticky top-0 shadow-md"),...ngDevMode?[{debugName:"hostClasses"}]:[]);innerClasses=n(()=>r("relative flex w-full gap-lg px-(--wrapper-padding)",this.appearance()==="default"&&"min-h-6xl items-center py-md",this.appearance()==="portal"&&"h-(--size-header-portal) items-stretch"),...ngDevMode?[{debugName:"innerClasses"}]:[]);desktopNavClasses=n(()=>r("min-w-0 flex-1",this.appearance()==="default"&&"flex flex-wrap items-center gap-lg self-center",this.appearance()==="portal"&&"hidden md:flex md:items-stretch"),...ngDevMode?[{debugName:"desktopNavClasses"}]:[]);actionsClasses=n(()=>r("ms-auto flex shrink-0 items-stretch empty:hidden",this.isPortal()&&this.items().length>0&&"max-md:hidden"),...ngDevMode?[{debugName:"actionsClasses"}]:[]);mobilePanelClass(){const e=this.mobileOpen(),t=this.mobileNav();return r("flex flex-col overflow-hidden bg-nav md:hidden",t==="sheet"&&"fixed top-0 bottom-0 end-0 z-20 w-[min(16rem,70vw)] max-w-[16rem] rounded-s-xl border-s border-border shadow-2xl",t==="fullscreen"&&"fixed inset-0 z-40 rounded-none border-0 shadow-none",t==="push"&&"absolute inset-x-0 top-full z-20 max-h-[min(70dvh,28rem)] border-b border-border shadow-lg",e?"dga-mobile-nav-open":"dga-mobile-nav-closed",e&&t==="sheet"&&"dga-mobile-sheet-open",e&&t==="fullscreen"&&"dga-mobile-fs-open",e&&t==="push"&&"dga-mobile-push-open")}hoverMenus(){return typeof matchMedia!="function"?!1:matchMedia("(hover: hover) and (pointer: fine)").matches}isMobileViewport(){return typeof matchMedia!="function"?!1:matchMedia("(max-width: 767px)").matches}resolveVariant(e){const t=e.dropdown;return t?t.variant?t.variant:t.featured?"featured":t.columns?.length||t.layout==="columns"||t.layout==="rows"?"mega":"menu":"menu"}resolveLayout(e){const t=e.dropdown;return t?t.layout?t.layout:t.columns?.length?"columns":"list":"list"}colCount(e){return e.dropdown?.columns?.length??0}flatLinks(e){const t=e.dropdown;return t?t.links?.length?t.links:t.columns?.flatMap(i=>i.links)??[]:[]}columnsGridClass(e){return r("grid w-full gap-2xl py-lg",e>1&&"sm:grid-cols-2",e>2&&"lg:grid-cols-3",e>3&&"xl:grid-cols-4")}featuredGridClass(e,t){return r("grid w-full gap-3xl",e==="featured"&&t&&"lg:grid-cols-[minmax(0,1fr)_minmax(14rem,18rem)]")}navItemClass(e,t=!1){return r(H,"justify-center",e&&"text-fg-primary",t&&"bg-neutral-light")}mobileItemClass(e,t=!1){return r(Z,e&&"bg-primary-faint",t&&"bg-neutral-light")}indicatorClass(e){return r(K,e?"bg-primary group-hover:bg-primary":"bg-transparent group-hover:bg-fg-disabled")}actionClass(e){return r(H,"relative justify-center")}badgeClass(){return r("dga-action-badge absolute top-lg end-md flex h-lg min-w-lg","items-center justify-center rounded-full bg-error px-xxs","text-body-2xs font-medium text-on-color")}isIconOnly(e){return e.iconOnly!==!1}isSearchAction(e){return!!this.search()&&e.id===this.searchActionId()}isNotificationsAction(e){return!!this.notifications()&&e.id===this.notificationsActionId()}isLoginAction(e){return!!this.login()&&e.id===this.loginActionId()}actionTooltip(e){return this.isLoginAction(e)&&this.authenticated()&&this.user()?.name||e.label}actionAriaLabel(e){return this.actionTooltip(e)}actionExpanded(e){return this.isSearchAction(e)?this.searchOpen():this.isNotificationsAction(e)?this.notificationsOpen():this.isLoginAction(e)?this.authenticated()?this.userMenuOpen():this.loginOpen():null}actionControls(e){return this.isSearchAction(e)?this.searchPanelId:this.isNotificationsAction(e)?this.notificationsPanelId:this.isLoginAction(e)?this.authenticated()?this.userPanelId:this.loginPanelId:null}actionIndicatorActive(e){return this.isSearchAction(e)?this.searchOpen():this.isNotificationsAction(e)?this.notificationsOpen():this.isLoginAction(e)?this.authenticated()?this.userMenuOpen():this.loginOpen():!1}clearCloseTimer(){this.closeTimer!==null&&(clearTimeout(this.closeTimer),this.closeTimer=null)}scheduleClose(){this.clearCloseTimer(),this.closeTimer=setTimeout(()=>{this.openDropdown.set(null),this.closeTimer=null},120)}setBodyScrollLocked(e){typeof document>"u"||document.documentElement.classList.toggle("dga-nav-locked",e)}unlockBodyIfIdle(){this.mobileOpen()||this.utilityOverlayOpen()||this.setBodyScrollLocked(!1)}onItemEnter(e){if(!this.isMobileViewport()){if(!this.items()[e]?.dropdown){this.hoverMenus()&&this.scheduleClose();return}this.clearCloseTimer(),this.hoverMenus()&&this.openDropdown.set(e)}}onPanelEnter(){this.clearCloseTimer()}onHostLeave(e){if(!this.hoverMenus()||this.isMobileViewport())return;const t=e.relatedTarget;t&&this.host.nativeElement.contains(t)||this.scheduleClose()}toggleMobile(){this.mobileOpen.update(e=>!e),this.openDropdown.set(null),this.setBodyScrollLocked(this.mobileOpen())}toggleDropdown(e,t){t.stopPropagation(),!(this.hoverMenus()&&!this.isMobileViewport()&&this.openDropdown()===e)&&(this.clearCloseTimer(),this.closeSearch(),this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.openDropdown.update(i=>i===e?null:e))}closeAll(){this.clearCloseTimer(),this.openDropdown.set(null),this.mobileOpen.set(!1),this.closeSearch(!1),this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.setBodyScrollLocked(!1)}onAction(e,t){const i=this.triggerFromEvent(t);if(this.isSearchAction(e)){this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.toggleSearch(),this.actionClick.emit(e);return}if(this.isNotificationsAction(e)){this.closeSearch(),this.closeLogin(),this.closeUserMenu(),this.toggleNotifications(i),this.actionClick.emit(e);return}if(this.isLoginAction(e)){this.closeSearch(),this.closeNotifications(),this.authenticated()?(this.closeLogin(),this.toggleUserMenu(i)):(this.closeUserMenu(),this.toggleLogin(i)),this.actionClick.emit(e);return}this.closeSearch(),this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.actionClick.emit(e)}onMobileAction(e,t){const i=this.triggerFromEvent(t);if(this.isSearchAction(e)){this.mobileOpen.set(!1),this.setBodyScrollLocked(!1),this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.toggleSearch(),this.actionClick.emit(e);return}if(this.isNotificationsAction(e)){this.mobileOpen.set(!1),this.closeSearch(),this.closeLogin(),this.closeUserMenu(),this.toggleNotifications(i),this.isMobileViewport()&&this.setBodyScrollLocked(!0),this.actionClick.emit(e);return}if(this.isLoginAction(e)){this.mobileOpen.set(!1),this.closeSearch(),this.closeNotifications(),this.authenticated()?(this.closeLogin(),this.toggleUserMenu(i)):(this.closeUserMenu(),this.toggleLogin(i)),this.isMobileViewport()&&this.setBodyScrollLocked(!0),this.actionClick.emit(e);return}this.actionClick.emit(e),this.closeAll()}closeUtilityOverlays(){this.closeSearch(),this.closeNotifications(),this.closeLogin(),this.closeUserMenu()}closePortalChromeMenus(){typeof document>"u"||document.dispatchEvent(new CustomEvent("dga-close-portal-chrome-menus"))}onCloseHeaderOverlays(){this.closeUtilityOverlays()}toggleSearch(){if(this.searchOpen()){this.closeSearch();return}this.openDropdown.set(null),this.closeNotifications(),this.closeLogin(),this.closeUserMenu(),this.closePortalChromeMenus(),this.searchOpen.set(!0)}onSearchModalOpenChange(e){if(e){this.searchOpen.set(!0);return}this.closeSearch()}focusSearchInput(){b(()=>this.searchInputRef()?.nativeElement.focus(),{injector:this.injector})}closeSearch(e=!0){this.searchOpen.set(!1),e&&this.stopVoice()}toggleNotifications(e){if(this.notificationsOpen()){this.closeNotifications();return}this.openDropdown.set(null),this.closeSearch(),this.closeLogin(),this.closeUserMenu(),this.closePortalChromeMenus(),this.notificationsOpen.set(!0);const t=this.visibleNotifications()[0];this.expandedNotificationId.set(t?.id??null),this.scheduleDropdownSync(this.notificationsActionId(),e),this.isMobileViewport()&&this.setBodyScrollLocked(!0)}closeNotifications(){this.notificationsOpen.set(!1),this.expandedNotificationId.set(null),this.clearDropdownAnchor(),this.unlockBodyIfIdle()}toggleLogin(e){if(this.loginOpen()){this.closeLogin();return}this.openDropdown.set(null),this.closeSearch(),this.closeNotifications(),this.closeUserMenu(),this.closePortalChromeMenus(),this.loginOpen.set(!0),this.scheduleDropdownSync(this.loginActionId(),e),this.isMobileViewport()&&this.setBodyScrollLocked(!0)}closeLogin(){this.loginOpen.set(!1),this.loginSubmitting.set(!1),this.showLoginPassword.set(!1),this.clearDropdownAnchor(),this.unlockBodyIfIdle()}toggleUserMenu(e){if(this.userMenuOpen()){this.closeUserMenu();return}this.openDropdown.set(null),this.closeSearch(),this.closeNotifications(),this.closeLogin(),this.closePortalChromeMenus(),this.userMenuOpen.set(!0),this.scheduleDropdownSync(this.loginActionId(),e),this.isMobileViewport()&&this.setBodyScrollLocked(!0)}closeUserMenu(){this.userMenuOpen.set(!1),this.clearDropdownAnchor(),this.unlockBodyIfIdle()}onLoginSubmit(e){e.preventDefault();const t=this.loginEmail().trim(),i=this.loginPassword();!t||!i||(this.loginSubmitting.set(!0),this.loginSubmit.emit({email:t,password:i}),setTimeout(()=>{this.loginOpen()&&(this.authenticated.set(!0),this.loginEmail.set(""),this.loginPassword.set(""),this.loginSubmitting.set(!1),this.closeLogin())},600))}onUserLink(e){if(this.userLinkClick.emit(e),e.id==="logout"||e.danger){this.authenticated.set(!1),this.logout.emit(),this.closeUserMenu();return}this.closeUserMenu()}toggleNotificationExpand(e){this.expandedNotificationId.update(t=>t===e.id?null:e.id),this.notificationAction.emit({item:e,action:"select"})}onNotificationAction(e,t){t==="read"&&this.readNotificationIds.update(i=>new Set([...i,e.id])),t==="dismiss"&&(this.dismissedNotificationIds.update(i=>new Set([...i,e.id])),this.expandedNotificationId.update(i=>i===e.id?null:i)),t==="view"&&e.href&&B(e.href,this.baseHref),this.notificationAction.emit({item:e,action:t})}markAllNotificationsRead(){const e=this.visibleNotifications().map(t=>t.id);this.readNotificationIds.update(t=>new Set([...t,...e]))}clearSearchQuery(){this.searchQuery.set(""),queueMicrotask(()=>this.searchInputRef()?.nativeElement.focus())}applySearchSuggestion(e){const t=e.value??e.label;this.searchQuery.set(t),this.searchSuggestionSelect.emit(e),queueMicrotask(()=>this.searchInputRef()?.nativeElement.focus())}onSearchFormSubmit(e){e.preventDefault();const t=this.searchQuery().trim();this.searchSubmit.emit(t);const i=this.search();if(i?.resultsHref){const s=i.queryParam??"q",d=new URL(i.resultsHref,typeof window<"u"?window.location.origin:"http://localhost");t?d.searchParams.set(s,t):d.searchParams.delete(s),typeof window<"u"&&window.location.assign(`${d.pathname}${d.search}${d.hash}`)}this.closeSearch()}onSearchVoice(){if(this.searchVoice.emit(),typeof window>"u")return;const e=window,t=e.SpeechRecognition||e.webkitSpeechRecognition;if(!t)return;this.stopVoice();const i=new t;i.lang=typeof document<"u"&&document.documentElement.lang?document.documentElement.lang:"ar-SA",i.interimResults=!1,i.maxAlternatives=1,this.voiceListening.set(!0),i.onresult=s=>{const d=s.results[0]?.[0]?.transcript?.trim();d&&this.searchQuery.set(d),this.voiceListening.set(!1)},i.onerror=()=>this.voiceListening.set(!1),i.onend=()=>this.voiceListening.set(!1),this.speechRecognition=i,i.start()}speechRecognition=null;stopVoice(){this.speechRecognition?.stop(),this.speechRecognition=null,this.voiceListening.set(!1)}triggerFromEvent(e){const t=e?.currentTarget;return t instanceof HTMLElement?t:null}scheduleDropdownSync(e,t){this.dropdownActionId=e,this.dropdownTrigger=t??null,b(()=>this.requestDropdownSync(t),{injector:this.injector})}requestDropdownSync(e){if(typeof requestAnimationFrame!="function"){this.syncDropdownPanel(e);return}this.dropdownSyncFrame===null&&(this.dropdownSyncFrame=requestAnimationFrame(()=>{this.dropdownSyncFrame=null,this.syncDropdownPanel(e)}))}clearDropdownAnchor(){this.notificationsOpen()||this.loginOpen()||this.userMenuOpen()||(this.dropdownTrigger=null,this.dropdownActionId=null,this.lastDropdownStyleKey="",this.dropdownPanelStyle.set({}))}findActionTrigger(e){const t=this.host.nativeElement.querySelectorAll(`[data-dga-action="${CSS.escape(e)}"]`);for(const i of Array.from(t)){const s=i;if(s.getClientRects().length>0)return s}return t[0]??null}syncDropdownPanel(e){if(typeof window>"u")return;if(this.isMobileViewport()){const c={top:"auto",bottom:"max(0.75rem, env(safe-area-inset-bottom, 0px))",left:"0.75rem",right:"0.75rem",width:"auto",maxWidth:"none"},v=`sheet|${c.bottom}`;if(v===this.lastDropdownStyleKey)return;this.lastDropdownStyleKey=v,this.dropdownPanelStyle.set(c);return}const t=e??this.dropdownTrigger??(this.dropdownActionId?this.findActionTrigger(this.dropdownActionId):null);if(!t)return;this.dropdownTrigger=t;const i=t.getBoundingClientRect();if(i.width<1&&i.height<1)return;const s=getComputedStyle(this.host.nativeElement).direction,j=(typeof document<"u"?document.documentElement.getAttribute("dir"):null)==="rtl"||s==="rtl",E=8,h=Math.min(448,window.innerWidth-32),f={top:`${Math.round(i.bottom+E)}px`};if(j){let c=Math.round(i.left);c=Math.max(16,Math.min(c,window.innerWidth-h-16)),f.left=`${c}px`,f.right="auto"}else{let c=Math.round(window.innerWidth-i.right);c=Math.max(16,Math.min(c,window.innerWidth-h-16)),f.right=`${c}px`,f.left="auto"}const x=`${f.top}|${f.left??""}|${f.right??""}`;x!==this.lastDropdownStyleKey&&(this.lastDropdownStyleKey=x,this.dropdownPanelStyle.set(f))}onKey(e){e.key==="Escape"&&this.closeAll()}onScroll(){(this.notificationsOpen()||this.loginOpen()||this.userMenuOpen())&&this.requestDropdownSync()}onResize(){typeof window>"u"||(window.matchMedia("(max-width: 767px)").matches||(this.mobileOpen.set(!1),this.setBodyScrollLocked(!1)),(this.notificationsOpen()||this.loginOpen()||this.userMenuOpen())&&(this.lastDropdownStyleKey="",this.requestDropdownSync()))}onNavLinkClick(e,t){this.navLinkClick.emit(e),e.href||t.preventDefault()}onDocClick(e){this.searchOpen()||this.notificationsOpen()||this.loginOpen()||this.userMenuOpen()||this.hoverMenus()&&!this.isMobileViewport()||this.mobileOpen()||this.host.nativeElement.contains(e.target)||this.openDropdown.set(null)}static \u0275fac=a.\u0275\u0275ngDeclareFactory({minVersion:"12.0.0",version:"22.0.7",ngImport:a,type:g,deps:[],target:a.\u0275\u0275FactoryTarget.Component});static \u0275cmp=a.\u0275\u0275ngDeclareComponent({minVersion:"17.0.0",version:"22.0.7",type:g,isStandalone:!0,selector:"dga-header",inputs:{brand:{classPropertyName:"brand",publicName:"brand",isSignal:!0,isRequired:!1,transformFunction:null},brandSlogan:{classPropertyName:"brandSlogan",publicName:"brandSlogan",isSignal:!0,isRequired:!1,transformFunction:null},brandLogo:{classPropertyName:"brandLogo",publicName:"brandLogo",isSignal:!0,isRequired:!1,transformFunction:null},brandLogoAlt:{classPropertyName:"brandLogoAlt",publicName:"brandLogoAlt",isSignal:!0,isRequired:!1,transformFunction:null},brandPlaceholder:{classPropertyName:"brandPlaceholder",publicName:"brandPlaceholder",isSignal:!0,isRequired:!1,transformFunction:null},brandHref:{classPropertyName:"brandHref",publicName:"brandHref",isSignal:!0,isRequired:!1,transformFunction:null},navLabel:{classPropertyName:"navLabel",publicName:"navLabel",isSignal:!0,isRequired:!1,transformFunction:null},menuToggleLabel:{classPropertyName:"menuToggleLabel",publicName:"menuToggleLabel",isSignal:!0,isRequired:!1,transformFunction:null},menuCloseLabel:{classPropertyName:"menuCloseLabel",publicName:"menuCloseLabel",isSignal:!0,isRequired:!1,transformFunction:null},appearance:{classPropertyName:"appearance",publicName:"appearance",isSignal:!0,isRequired:!1,transformFunction:null},mobileNav:{classPropertyName:"mobileNav",publicName:"mobileNav",isSignal:!0,isRequired:!1,transformFunction:null},sticky:{classPropertyName:"sticky",publicName:"sticky",isSignal:!0,isRequired:!1,transformFunction:null},items:{classPropertyName:"items",publicName:"items",isSignal:!0,isRequired:!1,transformFunction:null},actions:{classPropertyName:"actions",publicName:"actions",isSignal:!0,isRequired:!1,transformFunction:null},search:{classPropertyName:"search",publicName:"search",isSignal:!0,isRequired:!1,transformFunction:null},searchQuery:{classPropertyName:"searchQuery",publicName:"searchQuery",isSignal:!0,isRequired:!1,transformFunction:null},notifications:{classPropertyName:"notifications",publicName:"notifications",isSignal:!0,isRequired:!1,transformFunction:null},login:{classPropertyName:"login",publicName:"login",isSignal:!0,isRequired:!1,transformFunction:null},user:{classPropertyName:"user",publicName:"user",isSignal:!0,isRequired:!1,transformFunction:null},authenticated:{classPropertyName:"authenticated",publicName:"authenticated",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{searchQuery:"searchQueryChange",authenticated:"authenticatedChange",actionClick:"actionClick",searchSubmit:"searchSubmit",searchSuggestionSelect:"searchSuggestionSelect",searchVoice:"searchVoice",notificationAction:"notificationAction",loginSubmit:"loginSubmit",logout:"logout",userLinkClick:"userLinkClick",navLinkClick:"navLinkClick"},host:{attributes:{role:"banner"},listeners:{mouseleave:"onHostLeave($event)","document:dga-close-header-overlays":"onCloseHeaderOverlays()","document:keydown":"onKey($event)","window:scroll":"onScroll()","window:resize":"onResize()","document:click":"onDocClick($event)"},properties:{class:"hostClasses()","attr.data-appearance":"appearance()","attr.data-mobile-nav":"mobileNav()","attr.data-mobile-open":"mobileOpen() || null"}},viewQueries:[{propertyName:"searchInputRef",first:!0,predicate:["searchInput"],descendants:!0,isSignal:!0},{propertyName:"utilLayerRef",first:!0,predicate:["utilLayer"],descendants:!0,isSignal:!0}],ngImport:a,template:`
2
+ <div [class]="innerClasses()">
3
+ <div class="relative flex min-w-0 shrink-0 items-center self-center">
4
+ <ng-content select="[dgaHeaderBrand]" />
5
+ @if (brand() || brandLogo()) {
6
+ <a
7
+ class="inline-flex h-(--size-header-logo) cursor-pointer items-center gap-lg font-sans
8
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
9
+ focus-visible:outline-focus"
10
+ [href]="appHref(brandHref())"
11
+ >
12
+ @if (brandLogo()) {
13
+ <img
14
+ class="h-(--size-header-logo) w-auto max-w-[min(100%,14rem)] shrink-0 object-contain"
15
+ [src]="brandLogo()"
16
+ [alt]="brandLogoAlt()"
17
+ height="58"
18
+ />
19
+ } @else if (appearance() === 'portal' && brandPlaceholder()) {
20
+ <span
21
+ class="inline-flex size-(--size-header-logo) shrink-0 items-center justify-center rounded-sm
22
+ bg-primary-faint text-fg-primary"
23
+ aria-hidden="true"
24
+ >
25
+ <dga-icon name="home" size="xl" tone="primary" />
26
+ </span>
27
+ }
28
+ @if (brand() && !brandLogo()) {
29
+ <span class="flex min-w-0 flex-col gap-xxs">
30
+ <span class="text-body-md font-bold text-display">{{ brand() }}</span>
31
+ @if (brandSlogan()) {
32
+ <span class="text-body-sm font-normal text-muted">{{ brandSlogan() }}</span>
33
+ }
34
+ </span>
35
+ }
36
+ </a>
37
+ }
38
+ </div>
39
+
40
+ @if (isPortal() && items().length) {
41
+ <button
42
+ type="button"
43
+ class="dga-burger relative z-30 ms-auto hidden h-full w-6xl shrink-0 cursor-pointer
44
+ items-center justify-center self-stretch rounded-md text-fg transition-colors
45
+ hover:bg-neutral-light max-md:inline-flex
46
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
47
+ focus-visible:outline-focus"
48
+ [class.dga-burger--open]="mobileOpen()"
49
+ [class.dga-burger--hidden]="mobileOpen() && mobileNav() !== 'push'"
50
+ [attr.aria-expanded]="mobileOpen()"
51
+ [attr.aria-controls]="collapseId"
52
+ [attr.aria-label]="mobileOpen() ? menuCloseLabel() : menuToggleLabel()"
53
+ (click)="toggleMobile()"
54
+ >
55
+ <span class="dga-burger__box" aria-hidden="true">
56
+ <span class="dga-burger__line"></span>
57
+ <span class="dga-burger__line"></span>
58
+ <span class="dga-burger__line"></span>
59
+ </span>
60
+ </button>
61
+ }
62
+
63
+ <!-- Desktop navigation -->
64
+ <nav
65
+ [class]="desktopNavClasses()"
66
+ [attr.aria-label]="navLabel()"
67
+ [attr.hidden]="null"
68
+ >
69
+ @if (items().length) {
70
+ <ul
71
+ class="m-0 flex list-none flex-row flex-nowrap items-stretch gap-none p-0"
72
+ [class.overflow-x-auto]="openDropdown() === null"
73
+ [class.overflow-visible]="openDropdown() !== null"
74
+ role="list"
75
+ >
76
+ @for (item of items(); track item.label; let i = $index) {
77
+ <li
78
+ class="relative"
79
+ [class.z-dropdown]="openDropdown() === i"
80
+ [attr.data-open]="openDropdown() === i || null"
81
+ [attr.data-variant]="item.dropdown ? resolveVariant(item) : null"
82
+ (mouseenter)="onItemEnter(i)"
83
+ (focusin)="onItemEnter(i)"
84
+ >
85
+ @if (item.dropdown) {
86
+ <button
87
+ type="button"
88
+ [class]="navItemClass(!!item.current, openDropdown() === i)"
89
+ [attr.aria-expanded]="openDropdown() === i"
90
+ [attr.aria-haspopup]="'true'"
91
+ (click)="toggleDropdown(i, $event)"
92
+ >
93
+ <span
94
+ aria-hidden="true"
95
+ [class]="indicatorClass(!!item.current || openDropdown() === i)"
96
+ ></span>
97
+ <span class="whitespace-nowrap">{{ item.label }}</span>
98
+ <dga-icon
99
+ name="chevronDown"
100
+ size="md"
101
+ [class]="
102
+ openDropdown() === i
103
+ ? 'rotate-180 transition-transform duration-200'
104
+ : 'transition-transform duration-200'
105
+ "
106
+ />
107
+ </button>
108
+
109
+ @if (openDropdown() === i && resolveVariant(item) === 'menu') {
110
+ <div
111
+ class="absolute start-0 top-full z-dropdown min-w-[16rem]
112
+ max-w-[min(100vw-2rem,20rem)]"
113
+ role="menu"
114
+ [attr.aria-label]="item.label"
115
+ >
116
+ <div class="h-xs" aria-hidden="true"></div>
117
+ <div
118
+ class="dga-panel-enter rounded-md border border-border bg-card p-sm
119
+ shadow-lg"
120
+ >
121
+ @if (item.dropdown.columns?.length) {
122
+ <div class="flex flex-col gap-lg p-md">
123
+ @for (col of item.dropdown.columns!; track col.title ?? $index) {
124
+ <div class="flex flex-col gap-xs">
125
+ @if (col.title) {
126
+ <p class="px-xl text-body-sm font-medium text-fg-primary">
127
+ {{ col.title }}
128
+ </p>
129
+ }
130
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
131
+ @for (link of col.links; track link.label) {
132
+ <li role="none">
133
+ <a
134
+ role="menuitem"
135
+ [class]="dropLink"
136
+ [href]="appHref(link.href || '#')"
137
+ (click)="onNavLinkClick(link, $event)"
138
+ >{{ link.label }}</a
139
+ >
140
+ </li>
141
+ }
142
+ </ul>
143
+ </div>
144
+ }
145
+ </div>
146
+ } @else {
147
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
148
+ @for (link of item.dropdown.links || []; track link.label) {
149
+ <li role="none">
150
+ <a
151
+ role="menuitem"
152
+ [class]="dropLink"
153
+ [href]="appHref(link.href || '#')"
154
+ (click)="onNavLinkClick(link, $event)"
155
+ >{{ link.label }}</a
156
+ >
157
+ </li>
158
+ }
159
+ </ul>
160
+ }
161
+ </div>
162
+ </div>
163
+ }
164
+ } @else {
165
+ <a
166
+ [class]="navItemClass(!!item.current)"
167
+ [attr.aria-current]="item.current ? 'page' : null"
168
+ [href]="appHref(item.href || '#')"
169
+ (click)="onNavLinkClick(item, $event)"
170
+ >
171
+ <span aria-hidden="true" [class]="indicatorClass(!!item.current)"></span>
172
+ <span class="whitespace-nowrap">{{ item.label }}</span>
173
+ </a>
174
+ }
175
+ </li>
176
+ }
177
+ </ul>
178
+ }
179
+ <div class="contents">
180
+ <ng-content />
181
+ </div>
182
+ </nav>
183
+
184
+ <div [class]="actionsClasses()">
185
+ @for (action of actions(); track action.id) {
186
+ <dga-tooltip
187
+ class="relative flex h-full"
188
+ [text]="actionTooltip(action)"
189
+ placement="bottom"
190
+ [showIcon]="false"
191
+ [disabled]="!isIconOnly(action) && !(isLoginAction(action) && authenticated())"
192
+ >
193
+ @if (action.href) {
194
+ <a
195
+ [class]="actionClass(action)"
196
+ [href]="appHref(action.href)"
197
+ [attr.aria-label]="actionAriaLabel(action)"
198
+ [attr.data-dga-action]="action.id"
199
+ >
200
+ <span aria-hidden="true" [class]="indicatorClass(false)"></span>
201
+ @if (action.icon) {
202
+ <dga-icon [name]="action.icon" size="xl" />
203
+ }
204
+ @if (!isIconOnly(action)) {
205
+ <span>{{ action.label }}</span>
206
+ }
207
+ @if (action.badge) {
208
+ <span [class]="badgeClass()">{{ action.badge }}</span>
209
+ }
210
+ </a>
211
+ } @else {
212
+ <button
213
+ type="button"
214
+ [class]="actionClass(action)"
215
+ [attr.aria-label]="actionAriaLabel(action)"
216
+ [attr.aria-expanded]="actionExpanded(action)"
217
+ [attr.aria-controls]="actionControls(action)"
218
+ [attr.data-dga-action]="action.id"
219
+ (click)="onAction(action, $event)"
220
+ >
221
+ <span
222
+ aria-hidden="true"
223
+ [class]="indicatorClass(actionIndicatorActive(action))"
224
+ ></span>
225
+ @if (isLoginAction(action) && authenticated() && userConfig(); as u) {
226
+ <dga-avatar [name]="u.name" [src]="u.avatarSrc" size="sm" />
227
+ <span class="hidden max-w-11xl truncate lg:inline">{{ u.name }}</span>
228
+ } @else {
229
+ @if (action.icon) {
230
+ <dga-icon [name]="action.icon" size="xl" />
231
+ }
232
+ @if (!isIconOnly(action)) {
233
+ <span>{{ action.label }}</span>
234
+ }
235
+ }
236
+ @if (action.badge) {
237
+ <span [class]="badgeClass()">{{ action.badge }}</span>
238
+ }
239
+ </button>
240
+ }
241
+ </dga-tooltip>
242
+ }
243
+ <ng-content select="[dgaHeaderEnd]" />
244
+ </div>
245
+ </div>
246
+
247
+ <!-- Desktop mega / featured -->
248
+ @if (activeWideDropdown(); as drop) {
249
+ <div
250
+ class="absolute start-0 end-0 top-full z-dropdown hidden w-full md:block"
251
+ role="region"
252
+ [attr.aria-label]="drop.item.label"
253
+ [attr.data-variant]="drop.variant"
254
+ (mouseenter)="onPanelEnter()"
255
+ >
256
+ <div
257
+ class="dga-panel-enter border-b border-border bg-card shadow-lg md:rounded-b-lg"
258
+ >
259
+ <div class="w-full px-(--wrapper-padding) py-2xl lg:py-3xl">
260
+ <div [class]="featuredGridClass(drop.variant, !!drop.item.dropdown!.featured)">
261
+ <div class="min-w-0">
262
+ @switch (resolveLayout(drop.item)) {
263
+ @case ('columns') {
264
+ <div [class]="columnsGridClass(colCount(drop.item))">
265
+ @for (
266
+ col of drop.item.dropdown!.columns!;
267
+ track col.title ?? $index
268
+ ) {
269
+ <div class="flex min-w-0 flex-col gap-md">
270
+ @if (col.title) {
271
+ <p
272
+ class="border-b border-border-subtle pb-sm text-body-lg
273
+ font-medium text-fg-primary"
274
+ >
275
+ {{ col.title }}
276
+ </p>
277
+ }
278
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
279
+ @for (link of col.links; track link.label) {
280
+ <li>
281
+ <a
282
+ [class]="dropLink"
283
+ [href]="appHref(link.href || '#')"
284
+ (click)="onNavLinkClick(link, $event)"
285
+ >
286
+ <span>{{ link.label }}</span>
287
+ @if (link.description) {
288
+ <span class="text-body-sm text-muted">{{
289
+ link.description
290
+ }}</span>
291
+ }
292
+ </a>
293
+ </li>
294
+ }
295
+ </ul>
296
+ </div>
297
+ }
298
+ </div>
299
+ }
300
+ @case ('rows') {
301
+ <ul
302
+ class="m-0 grid w-full list-none grid-cols-1 gap-md p-0
303
+ sm:grid-cols-2 lg:grid-cols-4"
304
+ role="list"
305
+ >
306
+ @for (link of drop.item.dropdown!.links || []; track link.label) {
307
+ <li class="min-w-0">
308
+ <a
309
+ [class]="dropTile"
310
+ [href]="appHref(link.href || '#')"
311
+ (click)="onNavLinkClick(link, $event)"
312
+ >
313
+ <span class="text-body-md font-medium text-fg">{{
314
+ link.label
315
+ }}</span>
316
+ @if (link.description) {
317
+ <span class="text-body-sm text-muted">{{
318
+ link.description
319
+ }}</span>
320
+ }
321
+ </a>
322
+ </li>
323
+ }
324
+ </ul>
325
+ }
326
+ @default {
327
+ <ul
328
+ class="m-0 grid w-full max-w-(--container-5xl) list-none grid-cols-1 gap-xs
329
+ p-0 sm:grid-cols-2 lg:grid-cols-3"
330
+ role="list"
331
+ >
332
+ @for (link of flatLinks(drop.item); track link.label) {
333
+ <li class="min-w-0">
334
+ <a
335
+ [class]="dropLink"
336
+ [href]="appHref(link.href || '#')"
337
+ (click)="onNavLinkClick(link, $event)"
338
+ >
339
+ <span>{{ link.label }}</span>
340
+ @if (link.description) {
341
+ <span class="text-body-sm text-muted">{{
342
+ link.description
343
+ }}</span>
344
+ }
345
+ </a>
346
+ </li>
347
+ }
348
+ </ul>
349
+ }
350
+ }
351
+ </div>
352
+
353
+ @if (drop.variant === 'featured' && drop.item.dropdown!.featured; as feat) {
354
+ <aside
355
+ class="flex min-w-0 flex-col gap-lg overflow-hidden rounded-md
356
+ border border-border bg-primary-faint p-2xl lg:self-start"
357
+ >
358
+ @if (feat.imageUrl) {
359
+ <img
360
+ class="aspect-[16/10] h-auto w-full rounded-sm object-cover"
361
+ [src]="feat.imageUrl"
362
+ alt=""
363
+ />
364
+ }
365
+ <div class="flex min-w-0 flex-col gap-md">
366
+ <p class="text-body-lg font-semibold text-display">{{ feat.title }}</p>
367
+ @if (feat.description) {
368
+ <p class="text-body-sm leading-relaxed text-paragraph">
369
+ {{ feat.description }}
370
+ </p>
371
+ }
372
+ @if (feat.cta) {
373
+ <a
374
+ class="mt-xs inline-flex h-5xl cursor-pointer items-center justify-center gap-sm
375
+ rounded-sm bg-primary px-xl text-body-md font-medium text-on-color
376
+ transition-opacity hover:opacity-90
377
+ focus-visible:outline focus-visible:outline-2
378
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
379
+ [href]="appHref(feat.href || '#')"
380
+ >
381
+ <span>{{ feat.cta }}</span>
382
+ <dga-icon name="chevronLeft" size="sm" />
383
+ </a>
384
+ }
385
+ </div>
386
+ </aside>
387
+ }
388
+ </div>
389
+ </div>
390
+ </div>
391
+ </div>
392
+ }
393
+
394
+ <!-- Header search popup (dga-modal) -->
395
+ @if (searchConfig(); as cfg) {
396
+ <dga-modal
397
+ class="dga-header-search-modal"
398
+ [id]="searchPanelId"
399
+ [open]="searchOpen()"
400
+ (openChange)="onSearchModalOpenChange($event)"
401
+ [title]="cfg.title || cfg.submitLabel || 'Search'"
402
+ [description]="cfg.description || ''"
403
+ [closeLabel]="cfg.closeLabel || 'Close'"
404
+ size="lg"
405
+ animation="scale"
406
+ [scrollable]="false"
407
+ (opened)="focusSearchInput()"
408
+ >
409
+ <form
410
+ class="flex flex-col gap-xl"
411
+ role="search"
412
+ [attr.aria-label]="cfg.submitLabel || 'Search'"
413
+ (submit)="onSearchFormSubmit($event)"
414
+ >
415
+ <div class="flex w-full flex-col gap-md sm:flex-row sm:items-stretch sm:gap-lg">
416
+ <div class="min-w-0 flex-1">
417
+ <dga-form-control size="lg" startIcon="search" [filled]="!!searchQuery()">
418
+ <input
419
+ #searchInput
420
+ type="search"
421
+ name="q"
422
+ class="dga-search-input placeholder:text-muted"
423
+ [placeholder]="cfg.placeholder || 'Search...'"
424
+ [attr.aria-label]="cfg.placeholder || 'Search...'"
425
+ [value]="searchQuery()"
426
+ (input)="searchQuery.set($any($event.target).value)"
427
+ />
428
+ @if (searchQuery()) {
429
+ <button
430
+ type="button"
431
+ dgaEnd
432
+ [attr.aria-label]="cfg.clearLabel || 'Clear search'"
433
+ (click)="clearSearchQuery()"
434
+ >
435
+ <dga-icon name="close" size="sm" />
436
+ </button>
437
+ }
438
+ @if (cfg.voice !== false) {
439
+ <button
440
+ type="button"
441
+ dgaEnd
442
+ class="dga-search-voice"
443
+ [class.dga-search-voice--active]="voiceListening()"
444
+ [attr.aria-label]="cfg.voiceLabel || 'Voice input'"
445
+ [attr.aria-pressed]="voiceListening()"
446
+ (click)="onSearchVoice()"
447
+ >
448
+ <dga-icon
449
+ name="mic"
450
+ size="sm"
451
+ [tone]="voiceListening() ? 'current' : 'muted'"
452
+ />
453
+ </button>
454
+ }
455
+ </dga-form-control>
456
+ </div>
457
+ <button
458
+ type="submit"
459
+ class="inline-flex min-h-6xl shrink-0 cursor-pointer items-center justify-center gap-sm
460
+ rounded-md bg-primary px-xl text-body-md font-medium text-on-color shadow-sm
461
+ transition-opacity hover:opacity-90
462
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
463
+ focus-visible:outline-focus sm:px-2xl"
464
+ >
465
+ <dga-icon name="search" size="md" />
466
+ <span>{{ cfg.submitLabel || 'Search' }}</span>
467
+ </button>
468
+ </div>
469
+
470
+ @if (cfg.suggestions?.length) {
471
+ <div class="flex flex-col gap-md">
472
+ <span class="text-body-sm font-semibold text-display">
473
+ {{ cfg.suggestionsLabel || 'Suggestions:' }}
474
+ </span>
475
+ <div class="flex flex-wrap gap-sm">
476
+ @for (item of cfg.suggestions!; track item.value ?? item.label; let i = $index) {
477
+ <button
478
+ type="button"
479
+ class="dga-search-chip inline-flex h-4xl cursor-pointer items-center gap-xs
480
+ rounded-full border border-border bg-neutral-light px-lg text-body-sm
481
+ text-paragraph transition-[background-color,transform,border-color]
482
+ duration-150 ease-out hover:-translate-y-px hover:border-primary
483
+ hover:bg-sunken
484
+ focus-visible:outline focus-visible:outline-2
485
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
486
+ [style.animation-delay]="i * 40 + 'ms'"
487
+ (click)="applySearchSuggestion(item)"
488
+ >
489
+ <dga-icon [name]="item.icon || 'plus'" size="xs" />
490
+ <span>{{ item.label }}</span>
491
+ </button>
492
+ }
493
+ </div>
494
+ </div>
495
+ }
496
+ </form>
497
+ </dga-modal>
498
+ }
499
+
500
+ <!--
501
+ Utility overlays (notifications / login / user): portaled to body at z-urgent
502
+ so sticky announcement + chatbot/a11y FABs stay underneath.
503
+ -->
504
+ @if (utilityOverlayOpen()) {
505
+ <div #utilLayer class="dga-header-util-layer">
506
+ <button
507
+ type="button"
508
+ class="dga-util-backdrop absolute inset-0 cursor-default bg-overlay/50"
509
+ tabindex="-1"
510
+ aria-label="Close"
511
+ (click)="closeUtilityOverlays()"
512
+ ></button>
513
+
514
+ <!-- Header notifications panel -->
515
+ @if (notificationsOpen() && notificationsConfig(); as ncfg) {
516
+ <div
517
+ [id]="notificationsPanelId"
518
+ class="dga-header-util-panel fixed w-[min(28rem,calc(100vw-2rem))] max-md:inset-x-3
519
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
520
+ role="region"
521
+ [attr.aria-label]="ncfg.title || ncfg.viewAllLabel || 'Notifications'"
522
+ [style]="dropdownPanelStyle()"
523
+ >
524
+ <div
525
+ class="dga-panel-enter dga-panel-enter--anchor-end flex max-h-[min(85svh,40rem)]
526
+ flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-xl
527
+ md:max-h-[none] md:rounded-md"
528
+ >
529
+ <div
530
+ class="flex shrink-0 flex-col gap-sm border-b border-border-subtle px-xl py-md
531
+ md:flex-row md:items-center md:justify-between md:gap-md"
532
+ >
533
+ <div class="flex min-w-0 items-center justify-between gap-sm md:justify-start">
534
+ <div class="flex min-w-0 items-center gap-sm">
535
+ <h2 class="m-0 truncate text-body-lg font-semibold text-display md:text-body-md">
536
+ {{ ncfg.title || 'Notifications' }}
537
+ </h2>
538
+ @if (unreadNotificationCount() > 0) {
539
+ <span
540
+ class="inline-flex min-w-4xl items-center justify-center rounded-full
541
+ bg-error px-sm py-xxs text-body-2xs font-semibold text-on-color"
542
+ >
543
+ {{ unreadNotificationCount() }}
544
+ </span>
545
+ }
546
+ </div>
547
+ <button
548
+ type="button"
549
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
550
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
551
+ focus-visible:outline focus-visible:outline-2
552
+ focus-visible:outline-offset-2 focus-visible:outline-focus md:hidden"
553
+ [attr.aria-label]="ncfg.closeLabel || 'Close'"
554
+ (click)="closeNotifications()"
555
+ >
556
+ <dga-icon name="close" size="md" />
557
+ </button>
558
+ </div>
559
+ <div class="flex shrink-0 items-center gap-xxs max-md:justify-stretch">
560
+ @if (unreadNotificationCount() > 0) {
561
+ <button
562
+ type="button"
563
+ class="inline-flex h-4xl flex-1 cursor-pointer items-center justify-center
564
+ rounded-sm px-md text-body-sm font-medium text-fg-primary
565
+ transition-colors hover:bg-primary-faint
566
+ focus-visible:outline focus-visible:outline-2
567
+ focus-visible:outline-offset-2 focus-visible:outline-focus
568
+ md:flex-none"
569
+ (click)="markAllNotificationsRead()"
570
+ >
571
+ {{ ncfg.markAllReadLabel || 'Mark all as read' }}
572
+ </button>
573
+ }
574
+ <button
575
+ type="button"
576
+ class="hidden size-5xl cursor-pointer items-center justify-center rounded-sm
577
+ text-muted transition-colors hover:bg-neutral-light hover:text-fg
578
+ focus-visible:outline focus-visible:outline-2
579
+ focus-visible:outline-offset-2 focus-visible:outline-focus md:inline-flex"
580
+ [attr.aria-label]="ncfg.closeLabel || 'Close'"
581
+ (click)="closeNotifications()"
582
+ >
583
+ <dga-icon name="close" size="md" />
584
+ </button>
585
+ </div>
586
+ </div>
587
+
588
+ <div class="min-h-0 flex-1 overflow-y-auto overscroll-contain md:max-h-[min(48svh,28rem)]">
589
+ @if (visibleNotifications().length === 0) {
590
+ <div class="flex flex-col items-center gap-md px-xl py-3xl text-center">
591
+ <span
592
+ class="inline-flex size-6xl items-center justify-center rounded-full
593
+ bg-neutral-light text-muted"
594
+ aria-hidden="true"
595
+ >
596
+ <dga-icon name="bell" size="xl" tone="muted" />
597
+ </span>
598
+ <p class="m-0 text-body-sm text-muted">
599
+ {{ ncfg.emptyLabel || 'No notifications' }}
600
+ </p>
601
+ </div>
602
+ } @else {
603
+ <ul class="m-0 flex list-none flex-col p-0" role="list">
604
+ @for (item of visibleNotifications(); track item.id) {
605
+ <li
606
+ class="border-b border-border-subtle last:border-b-0"
607
+ [class]="item.read ? 'bg-surface' : 'bg-card'"
608
+ >
609
+ <button
610
+ type="button"
611
+ class="flex w-full cursor-pointer items-start gap-lg px-xl py-lg text-start
612
+ transition-colors hover:bg-neutral-light
613
+ focus-visible:outline focus-visible:outline-2
614
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
615
+ [attr.aria-expanded]="expandedNotificationId() === item.id"
616
+ (click)="toggleNotificationExpand(item)"
617
+ >
618
+ <span class="relative mt-xxs shrink-0">
619
+ <dga-icon-badge size="sm">
620
+ <dga-icon [name]="item.icon || 'bell'" size="sm" />
621
+ </dga-icon-badge>
622
+ @if (!item.read) {
623
+ <span
624
+ class="absolute -end-xxs -top-xxs size-[0.5rem] rounded-full bg-primary
625
+ ring-2 ring-white"
626
+ aria-hidden="true"
627
+ ></span>
628
+ }
629
+ </span>
630
+ <span class="min-w-0 flex-1">
631
+ <span class="mb-xs flex flex-wrap items-center gap-sm">
632
+ @if (item.statusLabel) {
633
+ <dga-badge [variant]="item.tone || 'neutral'" size="sm">
634
+ {{ item.statusLabel }}
635
+ </dga-badge>
636
+ }
637
+ <span
638
+ class="min-w-0 truncate text-body-md text-display"
639
+ [class.font-semibold]="!item.read"
640
+ [class.font-medium]="item.read"
641
+ [class.text-muted]="item.read"
642
+ >
643
+ {{ item.title }}
644
+ </span>
645
+ </span>
646
+ <span
647
+ class="text-body-sm text-paragraph"
648
+ [class.line-clamp-2]="expandedNotificationId() !== item.id"
649
+ >
650
+ {{ item.message }}
651
+ </span>
652
+ </span>
653
+ <dga-icon
654
+ class="mt-xs shrink-0 text-muted transition-transform duration-200"
655
+ [class.rotate-180]="expandedNotificationId() === item.id"
656
+ name="chevronDown"
657
+ size="sm"
658
+ />
659
+ </button>
660
+
661
+ @if (expandedNotificationId() === item.id) {
662
+ <div
663
+ class="dga-notif-actions flex flex-wrap gap-sm border-t border-border-subtle
664
+ bg-surface px-xl py-md"
665
+ >
666
+ @if (!item.read) {
667
+ <button
668
+ type="button"
669
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
670
+ px-md text-body-sm text-fg transition-colors hover:bg-neutral-light
671
+ focus-visible:outline focus-visible:outline-2
672
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
673
+ (click)="onNotificationAction(item, 'read'); $event.stopPropagation()"
674
+ >
675
+ <dga-icon name="success" size="sm" />
676
+ <span>{{ ncfg.markReadLabel || 'Mark as read' }}</span>
677
+ </button>
678
+ }
679
+ <button
680
+ type="button"
681
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
682
+ px-md text-body-sm text-fg transition-colors hover:bg-neutral-light
683
+ focus-visible:outline focus-visible:outline-2
684
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
685
+ (click)="onNotificationAction(item, 'view'); $event.stopPropagation()"
686
+ >
687
+ <dga-icon name="eye" size="sm" />
688
+ <span>{{ ncfg.viewLabel || 'View' }}</span>
689
+ </button>
690
+ <button
691
+ type="button"
692
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
693
+ px-md text-body-sm text-fg-error transition-colors hover:bg-error-light
694
+ focus-visible:outline focus-visible:outline-2
695
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
696
+ (click)="onNotificationAction(item, 'dismiss'); $event.stopPropagation()"
697
+ >
698
+ <dga-icon name="close" size="sm" />
699
+ <span>{{ ncfg.dismissLabel || 'Dismiss' }}</span>
700
+ </button>
701
+ </div>
702
+ }
703
+ </li>
704
+ }
705
+ </ul>
706
+ }
707
+ </div>
708
+
709
+ @if (ncfg.viewAllHref || ncfg.viewAllLabel) {
710
+ <div
711
+ class="shrink-0 border-t border-border
712
+ pb-[max(0px,env(safe-area-inset-bottom))] md:pb-0"
713
+ >
714
+ <a
715
+ class="inline-flex w-full cursor-pointer items-center justify-center gap-sm
716
+ px-xl py-lg text-body-sm font-medium text-fg-primary
717
+ transition-colors hover:bg-neutral-light
718
+ focus-visible:outline focus-visible:outline-2
719
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
720
+ [href]="appHref(ncfg.viewAllHref || '#')"
721
+ (click)="closeNotifications()"
722
+ >
723
+ <span>{{ ncfg.viewAllLabel || 'View all notifications' }}</span>
724
+ <dga-icon name="chevronLeft" size="sm" />
725
+ </a>
726
+ </div>
727
+ }
728
+ </div>
729
+ </div>
730
+ }
731
+
732
+ <!-- Header login panel (guest) -->
733
+ @if (loginOpen() && loginConfig(); as lcfg) {
734
+ <div
735
+ [id]="loginPanelId"
736
+ class="dga-header-util-panel fixed w-[min(24rem,calc(100vw-2rem))] max-md:inset-x-3
737
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
738
+ role="dialog"
739
+ [attr.aria-label]="lcfg.title || 'Login'"
740
+ [style]="dropdownPanelStyle()"
741
+ >
742
+ <div
743
+ class="dga-panel-enter dga-panel-enter--anchor-end max-h-[min(90svh,44rem)]
744
+ overflow-y-auto overscroll-contain rounded-2xl border border-border bg-card
745
+ shadow-xl md:max-h-[none] md:overflow-visible md:rounded-md"
746
+ >
747
+ <div class="flex items-start justify-between gap-md px-2xl pt-2xl max-md:pt-xl">
748
+ <div class="flex min-w-0 flex-col gap-xs">
749
+ <h2 class="m-0 text-body-lg font-semibold text-display">
750
+ {{ lcfg.title || 'Login' }}
751
+ </h2>
752
+ <p class="m-0 text-body-sm text-paragraph">
753
+ {{ lcfg.description || 'Sign in to access your account' }}
754
+ </p>
755
+ </div>
756
+ <button
757
+ type="button"
758
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
759
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
760
+ focus-visible:outline focus-visible:outline-2
761
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
762
+ [attr.aria-label]="lcfg.closeLabel || lcfg.cancelLabel || 'Close'"
763
+ (click)="closeLogin()"
764
+ >
765
+ <dga-icon name="close" size="md" />
766
+ </button>
767
+ </div>
768
+
769
+ <form
770
+ class="flex flex-col gap-xl px-2xl pb-[max(1.5rem,env(safe-area-inset-bottom))]
771
+ pt-xl md:pb-2xl"
772
+ (submit)="onLoginSubmit($event)"
773
+ >
774
+ <dga-field
775
+ [label]="lcfg.emailLabel || 'Email'"
776
+ controlId="dga-header-login-email"
777
+ [hint]="lcfg.emailHint || ''"
778
+ required
779
+ >
780
+ <dga-form-control startIcon="mail" [filled]="!!loginEmail()">
781
+ <input
782
+ id="dga-header-login-email"
783
+ type="email"
784
+ name="email"
785
+ autocomplete="username"
786
+ required
787
+ class="placeholder:text-muted"
788
+ [placeholder]="lcfg.emailPlaceholder || 'name@example.gov.sa'"
789
+ [value]="loginEmail()"
790
+ (input)="loginEmail.set($any($event.target).value)"
791
+ />
792
+ </dga-form-control>
793
+ </dga-field>
794
+
795
+ <dga-field
796
+ [label]="lcfg.passwordLabel || 'Password'"
797
+ controlId="dga-header-login-password"
798
+ [hint]="lcfg.passwordHint || ''"
799
+ required
800
+ >
801
+ <dga-form-control [filled]="!!loginPassword()">
802
+ <input
803
+ id="dga-header-login-password"
804
+ [type]="showLoginPassword() ? 'text' : 'password'"
805
+ name="password"
806
+ autocomplete="current-password"
807
+ required
808
+ class="placeholder:text-muted"
809
+ [placeholder]="lcfg.passwordPlaceholder || 'Enter your password'"
810
+ [value]="loginPassword()"
811
+ (input)="loginPassword.set($any($event.target).value)"
812
+ />
813
+ <button
814
+ type="button"
815
+ dgaEnd
816
+ [attr.aria-label]="
817
+ showLoginPassword()
818
+ ? lcfg.hidePasswordLabel || 'Hide password'
819
+ : lcfg.showPasswordLabel || 'Show password'
820
+ "
821
+ (click)="showLoginPassword.set(!showLoginPassword())"
822
+ >
823
+ <dga-icon [name]="showLoginPassword() ? 'eyeOff' : 'eye'" size="sm" />
824
+ </button>
825
+ </dga-form-control>
826
+ </dga-field>
827
+
828
+ @if (lcfg.forgotPasswordHref || lcfg.forgotPasswordLabel) {
829
+ <a
830
+ class="self-start text-body-sm font-medium text-fg-primary transition-opacity
831
+ hover:opacity-80
832
+ focus-visible:outline focus-visible:outline-2
833
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
834
+ [href]="appHref(lcfg.forgotPasswordHref || '#')"
835
+ >
836
+ {{ lcfg.forgotPasswordLabel || 'Forgot password?' }}
837
+ </a>
838
+ }
839
+
840
+ <div class="flex flex-col gap-md pt-xs">
841
+ <button
842
+ type="submit"
843
+ class="inline-flex h-5xl w-full cursor-pointer items-center justify-center gap-sm
844
+ rounded-sm bg-primary px-xl text-body-md font-medium text-on-color shadow-sm
845
+ transition-opacity hover:opacity-90 disabled:cursor-wait disabled:opacity-60
846
+ focus-visible:outline focus-visible:outline-2
847
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
848
+ [disabled]="loginSubmitting()"
849
+ >
850
+ @if (loginSubmitting()) {
851
+ <span
852
+ class="dga-login-spinner size-md rounded-full border-2 border-on-color/30
853
+ border-t-on-color"
854
+ aria-hidden="true"
855
+ ></span>
856
+ }
857
+ <span>
858
+ {{
859
+ loginSubmitting()
860
+ ? '\u2026'
861
+ : lcfg.submitLabel || 'Login'
862
+ }}
863
+ </span>
864
+ </button>
865
+ <button
866
+ type="button"
867
+ class="inline-flex h-5xl w-full cursor-pointer items-center justify-center
868
+ rounded-sm px-xl text-body-md font-medium text-fg transition-colors
869
+ hover:bg-neutral-light
870
+ focus-visible:outline focus-visible:outline-2
871
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
872
+ (click)="closeLogin()"
873
+ >
874
+ {{ lcfg.cancelLabel || 'Cancel' }}
875
+ </button>
876
+ </div>
877
+ </form>
878
+ </div>
879
+ </div>
880
+ }
881
+
882
+ <!-- Header user menu (authenticated) -->
883
+ @if (userMenuOpen() && userConfig(); as ucfg) {
884
+ <div
885
+ [id]="userPanelId"
886
+ class="dga-header-util-panel fixed w-[min(22rem,calc(100vw-2rem))] max-md:inset-x-3
887
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
888
+ role="menu"
889
+ [attr.aria-label]="ucfg.name"
890
+ [style]="dropdownPanelStyle()"
891
+ >
892
+ <div
893
+ class="dga-panel-enter dga-panel-enter--anchor-end max-h-[min(85svh,36rem)]
894
+ overflow-y-auto overscroll-contain rounded-2xl border border-border bg-card
895
+ shadow-xl md:max-h-[none] md:overflow-visible md:rounded-md"
896
+ >
897
+ <div class="flex items-center gap-lg border-b border-border-subtle px-xl py-lg">
898
+ <dga-avatar [name]="ucfg.name" [src]="ucfg.avatarSrc" size="md" />
899
+ <div class="flex min-w-0 flex-1 flex-col gap-xxs">
900
+ <span class="truncate text-body-md font-semibold text-display">{{ ucfg.name }}</span>
901
+ @if (ucfg.role) {
902
+ <span class="truncate text-body-sm text-muted">{{ ucfg.role }}</span>
903
+ }
904
+ @if (ucfg.email) {
905
+ <span class="truncate text-body-sm text-paragraph">{{ ucfg.email }}</span>
906
+ }
907
+ </div>
908
+ <button
909
+ type="button"
910
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
911
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
912
+ focus-visible:outline focus-visible:outline-2
913
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
914
+ aria-label="Close"
915
+ (click)="closeUserMenu()"
916
+ >
917
+ <dga-icon name="close" size="md" />
918
+ </button>
919
+ </div>
920
+ <div class="flex flex-col gap-xxs p-sm">
921
+ @for (link of ucfg.links || []; track link.id) {
922
+ @if (link.id === 'logout') {
923
+ <div class="my-xs border-t border-border-subtle" role="separator"></div>
924
+ <button
925
+ type="button"
926
+ role="menuitem"
927
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
928
+ text-start text-body-md text-fg-error transition-colors hover:bg-error-light
929
+ focus-visible:outline focus-visible:outline-2
930
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
931
+ (click)="onUserLink(link)"
932
+ >
933
+ @if (link.icon) {
934
+ <dga-icon [name]="link.icon" size="md" />
935
+ }
936
+ <span>{{ link.label }}</span>
937
+ </button>
938
+ } @else if (link.href) {
939
+ <a
940
+ role="menuitem"
941
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
942
+ text-start text-body-md text-fg transition-colors hover:bg-neutral-light
943
+ focus-visible:outline focus-visible:outline-2
944
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
945
+ [href]="appHref(link.href)"
946
+ (click)="onUserLink(link)"
947
+ >
948
+ @if (link.icon) {
949
+ <dga-icon [name]="link.icon" size="md" />
950
+ }
951
+ <span>{{ link.label }}</span>
952
+ </a>
953
+ } @else {
954
+ <button
955
+ type="button"
956
+ role="menuitem"
957
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
958
+ text-start text-body-md text-fg transition-colors hover:bg-neutral-light
959
+ focus-visible:outline focus-visible:outline-2
960
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
961
+ (click)="onUserLink(link)"
962
+ >
963
+ @if (link.icon) {
964
+ <dga-icon [name]="link.icon" size="md" />
965
+ }
966
+ <span>{{ link.label }}</span>
967
+ </button>
968
+ }
969
+ }
970
+ </div>
971
+ </div>
972
+ </div>
973
+ }
974
+ </div>
975
+ }
976
+
977
+ <!-- Mobile navigation: sheet | fullscreen | push -->
978
+ @if (isPortal() && items().length) {
979
+ @if (mobileOpen() && mobileNav() !== 'push') {
980
+ <button
981
+ type="button"
982
+ class="fixed inset-0 cursor-default md:hidden"
983
+ [class]="
984
+ mobileNav() === 'fullscreen'
985
+ ? 'z-[35] bg-overlay/60 backdrop-blur-[3px]'
986
+ : 'z-10 bg-overlay/40 backdrop-blur-[1px]'
987
+ "
988
+ tabindex="-1"
989
+ [attr.aria-label]="menuCloseLabel()"
990
+ (click)="closeAll()"
991
+ ></button>
992
+ }
993
+
994
+ <div
995
+ [id]="collapseId"
996
+ [class]="mobilePanelClass()"
997
+ [attr.data-mobile-nav]="mobileNav()"
998
+ [attr.aria-hidden]="!mobileOpen()"
999
+ [attr.inert]="mobileOpen() ? null : ''"
1000
+ >
1001
+ @if (mobileNav() === 'fullscreen') {
1002
+ <div
1003
+ class="flex h-(--size-header-portal) shrink-0 items-center justify-between
1004
+ gap-lg border-b border-border px-xl"
1005
+ >
1006
+ <div class="flex min-w-0 items-center gap-lg">
1007
+ @if (brandLogo()) {
1008
+ <img
1009
+ class="h-5xl w-auto max-w-[10rem] shrink-0 object-contain"
1010
+ [src]="brandLogo()"
1011
+ [alt]="brandLogoAlt()"
1012
+ />
1013
+ } @else {
1014
+ <span class="truncate text-body-md font-semibold text-display">{{
1015
+ brand() || brandLogoAlt() || navLabel()
1016
+ }}</span>
1017
+ }
1018
+ </div>
1019
+ <button
1020
+ type="button"
1021
+ class="inline-flex size-6xl shrink-0 cursor-pointer items-center justify-center
1022
+ rounded-md text-fg transition-colors hover:bg-neutral-light
1023
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
1024
+ focus-visible:outline-focus"
1025
+ [attr.aria-label]="menuCloseLabel()"
1026
+ (click)="closeAll()"
1027
+ >
1028
+ <dga-icon name="close" size="xl" />
1029
+ </button>
1030
+ </div>
1031
+ }
1032
+
1033
+ @if (mobileNav() === 'sheet') {
1034
+ <div
1035
+ class="flex min-h-(--size-header-portal) shrink-0 items-center justify-end
1036
+ border-b border-border-subtle px-md
1037
+ pt-[env(safe-area-inset-top,0px)]"
1038
+ >
1039
+ <button
1040
+ type="button"
1041
+ class="inline-flex size-6xl shrink-0 cursor-pointer items-center justify-center
1042
+ rounded-md text-fg transition-colors hover:bg-neutral-light
1043
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
1044
+ focus-visible:outline-focus"
1045
+ [attr.aria-label]="menuCloseLabel()"
1046
+ (click)="closeAll()"
1047
+ >
1048
+ <dga-icon name="close" size="xl" />
1049
+ </button>
1050
+ </div>
1051
+ }
1052
+
1053
+ @if (mobileNav() === 'push') {
1054
+ <div class="border-b border-border-subtle px-xl py-md">
1055
+ <p class="m-0 text-body-sm font-medium text-muted">{{ navLabel() }}</p>
1056
+ </div>
1057
+ }
1058
+
1059
+ <div
1060
+ class="min-h-0 flex-1 overflow-y-auto overscroll-contain px-xl py-lg
1061
+ pb-[max(1rem,env(safe-area-inset-bottom))]"
1062
+ >
1063
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
1064
+ @for (item of items(); track item.label; let i = $index) {
1065
+ <li class="border-b border-border-subtle last:border-b-0">
1066
+ @if (item.dropdown) {
1067
+ <button
1068
+ type="button"
1069
+ [class]="mobileItemClass(!!item.current, openDropdown() === i)"
1070
+ [attr.aria-expanded]="openDropdown() === i"
1071
+ (click)="toggleDropdown(i, $event)"
1072
+ >
1073
+ <span class="min-w-0 flex-1" [class]="item.current ? 'text-fg-primary' : ''">{{
1074
+ item.label
1075
+ }}</span>
1076
+ <dga-icon
1077
+ name="chevronDown"
1078
+ size="md"
1079
+ class="shrink-0"
1080
+ [class]="
1081
+ openDropdown() === i
1082
+ ? 'rotate-180 text-fg-primary transition-transform duration-200'
1083
+ : 'text-muted transition-transform duration-200'
1084
+ "
1085
+ />
1086
+ </button>
1087
+
1088
+ @if (openDropdown() === i) {
1089
+ <div
1090
+ class="dga-panel-enter space-y-md border-s-2 border-primary/30 pb-lg ps-lg
1091
+ ms-sm"
1092
+ >
1093
+ @if (item.dropdown.featured; as feat) {
1094
+ <a
1095
+ class="flex flex-col gap-sm rounded-md border border-border
1096
+ bg-primary-faint p-xl text-start no-underline"
1097
+ [href]="appHref(feat.href || '#')"
1098
+ (click)="closeAll()"
1099
+ >
1100
+ <span class="text-body-md font-semibold text-display">{{
1101
+ feat.title
1102
+ }}</span>
1103
+ @if (feat.description) {
1104
+ <span class="text-body-sm text-paragraph">{{
1105
+ feat.description
1106
+ }}</span>
1107
+ }
1108
+ @if (feat.cta) {
1109
+ <span class="text-body-sm font-medium text-fg-primary">{{
1110
+ feat.cta
1111
+ }}</span>
1112
+ }
1113
+ </a>
1114
+ }
1115
+
1116
+ @if (item.dropdown.columns?.length) {
1117
+ @for (col of item.dropdown.columns!; track col.title ?? $index) {
1118
+ <div class="flex flex-col gap-xs">
1119
+ @if (col.title) {
1120
+ <p class="px-xl text-body-sm font-medium text-fg-primary">
1121
+ {{ col.title }}
1122
+ </p>
1123
+ }
1124
+ <ul class="m-0 flex list-none flex-col gap-none p-0">
1125
+ @for (link of col.links; track link.label) {
1126
+ <li>
1127
+ <a
1128
+ [class]="mobileLink"
1129
+ [href]="appHref(link.href || '#')"
1130
+ (click)="onNavLinkClick(link, $event); closeAll()"
1131
+ >
1132
+ <span>{{ link.label }}</span>
1133
+ @if (link.description) {
1134
+ <span class="text-body-sm text-muted">{{
1135
+ link.description
1136
+ }}</span>
1137
+ }
1138
+ </a>
1139
+ </li>
1140
+ }
1141
+ </ul>
1142
+ </div>
1143
+ }
1144
+ } @else {
1145
+ <ul class="m-0 flex list-none flex-col gap-none p-0">
1146
+ @for (link of flatLinks(item); track link.label) {
1147
+ <li>
1148
+ <a
1149
+ [class]="mobileLink"
1150
+ [href]="appHref(link.href || '#')"
1151
+ (click)="onNavLinkClick(link, $event); closeAll()"
1152
+ >
1153
+ <span>{{ link.label }}</span>
1154
+ @if (link.description) {
1155
+ <span class="text-body-sm text-muted">{{
1156
+ link.description
1157
+ }}</span>
1158
+ }
1159
+ </a>
1160
+ </li>
1161
+ }
1162
+ </ul>
1163
+ }
1164
+ </div>
1165
+ }
1166
+ } @else {
1167
+ <a
1168
+ [class]="mobileItemClass(!!item.current)"
1169
+ [attr.aria-current]="item.current ? 'page' : null"
1170
+ [href]="appHref(item.href || '#')"
1171
+ (click)="onNavLinkClick(item, $event); closeAll()"
1172
+ >
1173
+ @if (item.current) {
1174
+ <span
1175
+ class="absolute inset-y-md start-0 w-1 rounded-e-sm bg-primary"
1176
+ aria-hidden="true"
1177
+ ></span>
1178
+ }
1179
+ <span class="min-w-0 flex-1" [class]="item.current ? 'text-fg-primary' : ''">{{
1180
+ item.label
1181
+ }}</span>
1182
+ </a>
1183
+ }
1184
+ </li>
1185
+ }
1186
+ </ul>
1187
+ </div>
1188
+
1189
+ @if (actions().length) {
1190
+ <div
1191
+ class="flex shrink-0 items-center justify-around gap-sm border-t border-border
1192
+ bg-nav px-xl py-md pb-[max(0.75rem,env(safe-area-inset-bottom))]"
1193
+ >
1194
+ @for (action of actions(); track action.id) {
1195
+ @if (action.href) {
1196
+ <a
1197
+ class="relative inline-flex min-h-6xl min-w-6xl cursor-pointer flex-col
1198
+ items-center justify-center gap-xxs rounded-md px-md text-fg
1199
+ hover:bg-neutral-light
1200
+ focus-visible:outline focus-visible:outline-2
1201
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1202
+ [href]="appHref(action.href)"
1203
+ [attr.aria-label]="action.label"
1204
+ [attr.data-dga-action]="action.id"
1205
+ (click)="closeAll()"
1206
+ >
1207
+ @if (action.icon) {
1208
+ <dga-icon [name]="action.icon" size="xl" />
1209
+ }
1210
+ <span class="max-w-11xl truncate text-body-2xs">{{ action.label }}</span>
1211
+ @if (action.badge) {
1212
+ <span [class]="badgeClass()">{{ action.badge }}</span>
1213
+ }
1214
+ </a>
1215
+ } @else {
1216
+ <button
1217
+ type="button"
1218
+ class="relative inline-flex min-h-6xl min-w-6xl cursor-pointer flex-col
1219
+ items-center justify-center gap-xxs rounded-md px-md text-fg
1220
+ hover:bg-neutral-light
1221
+ focus-visible:outline focus-visible:outline-2
1222
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1223
+ [attr.aria-label]="action.label"
1224
+ [attr.data-dga-action]="action.id"
1225
+ (click)="onMobileAction(action, $event)"
1226
+ >
1227
+ @if (action.icon) {
1228
+ <dga-icon [name]="action.icon" size="xl" />
1229
+ }
1230
+ <span class="max-w-11xl truncate text-body-2xs">{{ action.label }}</span>
1231
+ @if (action.badge) {
1232
+ <span [class]="badgeClass()">{{ action.badge }}</span>
1233
+ }
1234
+ </button>
1235
+ }
1236
+ }
1237
+ </div>
1238
+ }
1239
+ </div>
1240
+ }
1241
+ `,isInline:!0,styles:[`@keyframes dga-fade-in{0%{opacity:0}to{opacity:1}}@keyframes dga-panel-in{0%{opacity:0;transform:translateY(-.625rem) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes dga-chip-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-notif-row-in{0%{opacity:0;transform:translateY(.35rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-expand-fade{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-spin{to{transform:rotate(360deg)}}@keyframes dga-badge-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.12)}}@keyframes dga-push-in{0%{opacity:0;transform:translateY(-.75rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-sheet-in-ltr{0%{opacity:.85;transform:translate3d(-100%,0,0)}to{opacity:1;transform:translateZ(0)}}@keyframes dga-sheet-in-rtl{0%{opacity:.85;transform:translate3d(100%,0,0)}to{opacity:1;transform:translateZ(0)}}@keyframes dga-fs-in{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-sheet-in{0%{opacity:0;transform:translateY(1.25rem)}to{opacity:1;transform:translateY(0)}}:host .dga-util-backdrop,.dga-header-util-layer .dga-util-backdrop{animation:dga-fade-in .22s ease both}.dga-header-util-layer{position:fixed;inset:0;z-index:var(--z-index-urgent, 400);pointer-events:none}.dga-header-util-layer>.dga-util-backdrop,.dga-header-util-layer>.dga-header-util-panel{pointer-events:auto}:host .dga-panel-enter,.dga-header-util-layer .dga-panel-enter{animation:dga-panel-in .28s cubic-bezier(.16,1,.3,1) both;transform-origin:top center;will-change:transform,opacity}:host .dga-panel-enter--anchor-end,.dga-header-util-layer .dga-panel-enter--anchor-end{transform-origin:top right}:host-context([dir="rtl"]) .dga-panel-enter--anchor-end,:host([dir="rtl"]) .dga-panel-enter--anchor-end,:host-context([dir="rtl"]) .dga-header-util-layer .dga-panel-enter--anchor-end,[dir=rtl] .dga-header-util-layer .dga-panel-enter--anchor-end{transform-origin:top left}@media(max-width:767px){:host .dga-panel-enter--anchor-end,.dga-header-util-layer .dga-panel-enter--anchor-end{animation-name:dga-sheet-in;transform-origin:bottom center}}:host .dga-search-chip{animation:dga-chip-in .28s cubic-bezier(.16,1,.3,1) both}:host .dga-search-input{-webkit-appearance:none;appearance:none}:host .dga-search-input::-webkit-search-decoration,:host .dga-search-input::-webkit-search-cancel-button,:host .dga-search-input::-webkit-search-results-button,:host .dga-search-input::-webkit-search-results-decoration{-webkit-appearance:none;appearance:none;display:none}:host .dga-search-voice.dga-search-voice--active{color:var(--dga-text-primary, #1b8354)!important;background:var(--dga-bg-primary-faint, #f3faf6)!important}:host .dga-notif-item,.dga-header-util-layer .dga-notif-item{animation:dga-notif-row-in .26s cubic-bezier(.16,1,.3,1) both}:host .dga-notif-actions,.dga-header-util-layer .dga-notif-actions{animation:dga-expand-fade .2s ease both}:host .dga-login-spinner,.dga-header-util-layer .dga-login-spinner{animation:dga-spin .7s linear infinite}:host .dga-action-badge{animation:dga-badge-pulse 1.8s ease-in-out infinite;transform-origin:center}@media(prefers-reduced-motion:reduce){:host .dga-util-backdrop,:host .dga-panel-enter,:host .dga-search-chip,:host .dga-notif-item,:host .dga-notif-actions,.dga-header-util-layer .dga-util-backdrop,.dga-header-util-layer .dga-panel-enter{animation-duration:.01ms!important;animation-delay:0ms!important}}:host .dga-burger__box{position:relative;display:block;width:1.375rem;height:1rem}:host .dga-burger__line{position:absolute;inset-inline:0;height:2px;border-radius:1px;background:currentColor;transition:transform .22s cubic-bezier(.4,0,.2,1),opacity .16s ease,top .22s cubic-bezier(.4,0,.2,1)}:host .dga-burger__line:nth-child(1){top:0}:host .dga-burger__line:nth-child(2){top:calc(50% - 1px)}:host .dga-burger__line:nth-child(3){top:calc(100% - 2px)}:host .dga-burger--open{background:var(--color-neutral-light, #f3f4f6)}:host .dga-burger--hidden{visibility:hidden;pointer-events:none}:host .dga-burger--open .dga-burger__line:nth-child(1){top:calc(50% - 1px);transform:rotate(45deg)}:host .dga-burger--open .dga-burger__line:nth-child(2){opacity:0;transform:scaleX(.4)}:host .dga-burger--open .dga-burger__line:nth-child(3){top:calc(50% - 1px);transform:rotate(-45deg)}:host .dga-mobile-nav-closed{display:none}:host .dga-mobile-nav-open{display:flex}:host .dga-mobile-push-open{animation:dga-push-in .24s cubic-bezier(.4,0,.2,1) forwards}:host .dga-mobile-sheet-open{animation:dga-sheet-in-rtl .28s cubic-bezier(.4,0,.2,1) forwards}:host-context([dir="rtl"]) .dga-mobile-sheet-open{animation:dga-sheet-in-ltr .28s cubic-bezier(.4,0,.2,1) forwards}:host .dga-mobile-fs-open{animation:dga-fs-in .24s cubic-bezier(.4,0,.2,1) forwards}@media(prefers-reduced-motion:reduce){:host .dga-action-badge,:host .dga-mobile-push-open,:host .dga-mobile-sheet-open,:host .dga-mobile-fs-open,:host-context([dir="rtl"]) .dga-mobile-sheet-open,:host .dga-burger__line{animation:none;transition:none}}
1242
+ `],dependencies:[{kind:"component",type:S,selector:"dga-avatar",inputs:["src","name","size","alt"]},{kind:"component",type:C,selector:"dga-badge",inputs:["variant","size"]},{kind:"component",type:D,selector:"dga-field",inputs:["label","labelHint","hint","error","status","statusMessage","controlId","required"]},{kind:"component",type:I,selector:"dga-form-control",inputs:["size","status","disabled","filled","startIcon","endIcon"]},{kind:"directive",type:z,selector:"[dgaEnd]"},{kind:"component",type:M,selector:"dga-icon",inputs:["name","glyph","size","tone","label"]},{kind:"component",type:A,selector:"dga-icon-badge",inputs:["size","appearance"]},{kind:"component",type:P,selector:"dga-modal",inputs:["open","title","description","size","animation","closeLabel","closeOnBackdrop","closeOnEscape","showClose","scrollable","centered"],outputs:["openChange","closed","opened"]},{kind:"component",type:O,selector:"dga-tooltip",inputs:["text","title","placement","variant","showIcon","disabled","showDelay","hideDelay","dismissMs"]}],changeDetection:a.ChangeDetectionStrategy.OnPush})}a.\u0275\u0275ngDeclareClassMetadata({minVersion:"12.0.0",version:"22.0.7",ngImport:a,type:g,decorators:[{type:V,args:[{selector:"dga-header",standalone:!0,changeDetection:F.OnPush,imports:[S,C,D,I,z,M,A,P,O],template:`
1243
+ <div [class]="innerClasses()">
1244
+ <div class="relative flex min-w-0 shrink-0 items-center self-center">
1245
+ <ng-content select="[dgaHeaderBrand]" />
1246
+ @if (brand() || brandLogo()) {
1247
+ <a
1248
+ class="inline-flex h-(--size-header-logo) cursor-pointer items-center gap-lg font-sans
1249
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
1250
+ focus-visible:outline-focus"
1251
+ [href]="appHref(brandHref())"
1252
+ >
1253
+ @if (brandLogo()) {
1254
+ <img
1255
+ class="h-(--size-header-logo) w-auto max-w-[min(100%,14rem)] shrink-0 object-contain"
1256
+ [src]="brandLogo()"
1257
+ [alt]="brandLogoAlt()"
1258
+ height="58"
1259
+ />
1260
+ } @else if (appearance() === 'portal' && brandPlaceholder()) {
1261
+ <span
1262
+ class="inline-flex size-(--size-header-logo) shrink-0 items-center justify-center rounded-sm
1263
+ bg-primary-faint text-fg-primary"
1264
+ aria-hidden="true"
1265
+ >
1266
+ <dga-icon name="home" size="xl" tone="primary" />
1267
+ </span>
1268
+ }
1269
+ @if (brand() && !brandLogo()) {
1270
+ <span class="flex min-w-0 flex-col gap-xxs">
1271
+ <span class="text-body-md font-bold text-display">{{ brand() }}</span>
1272
+ @if (brandSlogan()) {
1273
+ <span class="text-body-sm font-normal text-muted">{{ brandSlogan() }}</span>
1274
+ }
1275
+ </span>
1276
+ }
1277
+ </a>
1278
+ }
1279
+ </div>
1280
+
1281
+ @if (isPortal() && items().length) {
1282
+ <button
1283
+ type="button"
1284
+ class="dga-burger relative z-30 ms-auto hidden h-full w-6xl shrink-0 cursor-pointer
1285
+ items-center justify-center self-stretch rounded-md text-fg transition-colors
1286
+ hover:bg-neutral-light max-md:inline-flex
1287
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
1288
+ focus-visible:outline-focus"
1289
+ [class.dga-burger--open]="mobileOpen()"
1290
+ [class.dga-burger--hidden]="mobileOpen() && mobileNav() !== 'push'"
1291
+ [attr.aria-expanded]="mobileOpen()"
1292
+ [attr.aria-controls]="collapseId"
1293
+ [attr.aria-label]="mobileOpen() ? menuCloseLabel() : menuToggleLabel()"
1294
+ (click)="toggleMobile()"
1295
+ >
1296
+ <span class="dga-burger__box" aria-hidden="true">
1297
+ <span class="dga-burger__line"></span>
1298
+ <span class="dga-burger__line"></span>
1299
+ <span class="dga-burger__line"></span>
1300
+ </span>
1301
+ </button>
1302
+ }
1303
+
1304
+ <!-- Desktop navigation -->
1305
+ <nav
1306
+ [class]="desktopNavClasses()"
1307
+ [attr.aria-label]="navLabel()"
1308
+ [attr.hidden]="null"
1309
+ >
1310
+ @if (items().length) {
1311
+ <ul
1312
+ class="m-0 flex list-none flex-row flex-nowrap items-stretch gap-none p-0"
1313
+ [class.overflow-x-auto]="openDropdown() === null"
1314
+ [class.overflow-visible]="openDropdown() !== null"
1315
+ role="list"
1316
+ >
1317
+ @for (item of items(); track item.label; let i = $index) {
1318
+ <li
1319
+ class="relative"
1320
+ [class.z-dropdown]="openDropdown() === i"
1321
+ [attr.data-open]="openDropdown() === i || null"
1322
+ [attr.data-variant]="item.dropdown ? resolveVariant(item) : null"
1323
+ (mouseenter)="onItemEnter(i)"
1324
+ (focusin)="onItemEnter(i)"
1325
+ >
1326
+ @if (item.dropdown) {
1327
+ <button
1328
+ type="button"
1329
+ [class]="navItemClass(!!item.current, openDropdown() === i)"
1330
+ [attr.aria-expanded]="openDropdown() === i"
1331
+ [attr.aria-haspopup]="'true'"
1332
+ (click)="toggleDropdown(i, $event)"
1333
+ >
1334
+ <span
1335
+ aria-hidden="true"
1336
+ [class]="indicatorClass(!!item.current || openDropdown() === i)"
1337
+ ></span>
1338
+ <span class="whitespace-nowrap">{{ item.label }}</span>
1339
+ <dga-icon
1340
+ name="chevronDown"
1341
+ size="md"
1342
+ [class]="
1343
+ openDropdown() === i
1344
+ ? 'rotate-180 transition-transform duration-200'
1345
+ : 'transition-transform duration-200'
1346
+ "
1347
+ />
1348
+ </button>
1349
+
1350
+ @if (openDropdown() === i && resolveVariant(item) === 'menu') {
1351
+ <div
1352
+ class="absolute start-0 top-full z-dropdown min-w-[16rem]
1353
+ max-w-[min(100vw-2rem,20rem)]"
1354
+ role="menu"
1355
+ [attr.aria-label]="item.label"
1356
+ >
1357
+ <div class="h-xs" aria-hidden="true"></div>
1358
+ <div
1359
+ class="dga-panel-enter rounded-md border border-border bg-card p-sm
1360
+ shadow-lg"
1361
+ >
1362
+ @if (item.dropdown.columns?.length) {
1363
+ <div class="flex flex-col gap-lg p-md">
1364
+ @for (col of item.dropdown.columns!; track col.title ?? $index) {
1365
+ <div class="flex flex-col gap-xs">
1366
+ @if (col.title) {
1367
+ <p class="px-xl text-body-sm font-medium text-fg-primary">
1368
+ {{ col.title }}
1369
+ </p>
1370
+ }
1371
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
1372
+ @for (link of col.links; track link.label) {
1373
+ <li role="none">
1374
+ <a
1375
+ role="menuitem"
1376
+ [class]="dropLink"
1377
+ [href]="appHref(link.href || '#')"
1378
+ (click)="onNavLinkClick(link, $event)"
1379
+ >{{ link.label }}</a
1380
+ >
1381
+ </li>
1382
+ }
1383
+ </ul>
1384
+ </div>
1385
+ }
1386
+ </div>
1387
+ } @else {
1388
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
1389
+ @for (link of item.dropdown.links || []; track link.label) {
1390
+ <li role="none">
1391
+ <a
1392
+ role="menuitem"
1393
+ [class]="dropLink"
1394
+ [href]="appHref(link.href || '#')"
1395
+ (click)="onNavLinkClick(link, $event)"
1396
+ >{{ link.label }}</a
1397
+ >
1398
+ </li>
1399
+ }
1400
+ </ul>
1401
+ }
1402
+ </div>
1403
+ </div>
1404
+ }
1405
+ } @else {
1406
+ <a
1407
+ [class]="navItemClass(!!item.current)"
1408
+ [attr.aria-current]="item.current ? 'page' : null"
1409
+ [href]="appHref(item.href || '#')"
1410
+ (click)="onNavLinkClick(item, $event)"
1411
+ >
1412
+ <span aria-hidden="true" [class]="indicatorClass(!!item.current)"></span>
1413
+ <span class="whitespace-nowrap">{{ item.label }}</span>
1414
+ </a>
1415
+ }
1416
+ </li>
1417
+ }
1418
+ </ul>
1419
+ }
1420
+ <div class="contents">
1421
+ <ng-content />
1422
+ </div>
1423
+ </nav>
1424
+
1425
+ <div [class]="actionsClasses()">
1426
+ @for (action of actions(); track action.id) {
1427
+ <dga-tooltip
1428
+ class="relative flex h-full"
1429
+ [text]="actionTooltip(action)"
1430
+ placement="bottom"
1431
+ [showIcon]="false"
1432
+ [disabled]="!isIconOnly(action) && !(isLoginAction(action) && authenticated())"
1433
+ >
1434
+ @if (action.href) {
1435
+ <a
1436
+ [class]="actionClass(action)"
1437
+ [href]="appHref(action.href)"
1438
+ [attr.aria-label]="actionAriaLabel(action)"
1439
+ [attr.data-dga-action]="action.id"
1440
+ >
1441
+ <span aria-hidden="true" [class]="indicatorClass(false)"></span>
1442
+ @if (action.icon) {
1443
+ <dga-icon [name]="action.icon" size="xl" />
1444
+ }
1445
+ @if (!isIconOnly(action)) {
1446
+ <span>{{ action.label }}</span>
1447
+ }
1448
+ @if (action.badge) {
1449
+ <span [class]="badgeClass()">{{ action.badge }}</span>
1450
+ }
1451
+ </a>
1452
+ } @else {
1453
+ <button
1454
+ type="button"
1455
+ [class]="actionClass(action)"
1456
+ [attr.aria-label]="actionAriaLabel(action)"
1457
+ [attr.aria-expanded]="actionExpanded(action)"
1458
+ [attr.aria-controls]="actionControls(action)"
1459
+ [attr.data-dga-action]="action.id"
1460
+ (click)="onAction(action, $event)"
1461
+ >
1462
+ <span
1463
+ aria-hidden="true"
1464
+ [class]="indicatorClass(actionIndicatorActive(action))"
1465
+ ></span>
1466
+ @if (isLoginAction(action) && authenticated() && userConfig(); as u) {
1467
+ <dga-avatar [name]="u.name" [src]="u.avatarSrc" size="sm" />
1468
+ <span class="hidden max-w-11xl truncate lg:inline">{{ u.name }}</span>
1469
+ } @else {
1470
+ @if (action.icon) {
1471
+ <dga-icon [name]="action.icon" size="xl" />
1472
+ }
1473
+ @if (!isIconOnly(action)) {
1474
+ <span>{{ action.label }}</span>
1475
+ }
1476
+ }
1477
+ @if (action.badge) {
1478
+ <span [class]="badgeClass()">{{ action.badge }}</span>
1479
+ }
1480
+ </button>
1481
+ }
1482
+ </dga-tooltip>
1483
+ }
1484
+ <ng-content select="[dgaHeaderEnd]" />
1485
+ </div>
1486
+ </div>
1487
+
1488
+ <!-- Desktop mega / featured -->
1489
+ @if (activeWideDropdown(); as drop) {
1490
+ <div
1491
+ class="absolute start-0 end-0 top-full z-dropdown hidden w-full md:block"
1492
+ role="region"
1493
+ [attr.aria-label]="drop.item.label"
1494
+ [attr.data-variant]="drop.variant"
1495
+ (mouseenter)="onPanelEnter()"
1496
+ >
1497
+ <div
1498
+ class="dga-panel-enter border-b border-border bg-card shadow-lg md:rounded-b-lg"
1499
+ >
1500
+ <div class="w-full px-(--wrapper-padding) py-2xl lg:py-3xl">
1501
+ <div [class]="featuredGridClass(drop.variant, !!drop.item.dropdown!.featured)">
1502
+ <div class="min-w-0">
1503
+ @switch (resolveLayout(drop.item)) {
1504
+ @case ('columns') {
1505
+ <div [class]="columnsGridClass(colCount(drop.item))">
1506
+ @for (
1507
+ col of drop.item.dropdown!.columns!;
1508
+ track col.title ?? $index
1509
+ ) {
1510
+ <div class="flex min-w-0 flex-col gap-md">
1511
+ @if (col.title) {
1512
+ <p
1513
+ class="border-b border-border-subtle pb-sm text-body-lg
1514
+ font-medium text-fg-primary"
1515
+ >
1516
+ {{ col.title }}
1517
+ </p>
1518
+ }
1519
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
1520
+ @for (link of col.links; track link.label) {
1521
+ <li>
1522
+ <a
1523
+ [class]="dropLink"
1524
+ [href]="appHref(link.href || '#')"
1525
+ (click)="onNavLinkClick(link, $event)"
1526
+ >
1527
+ <span>{{ link.label }}</span>
1528
+ @if (link.description) {
1529
+ <span class="text-body-sm text-muted">{{
1530
+ link.description
1531
+ }}</span>
1532
+ }
1533
+ </a>
1534
+ </li>
1535
+ }
1536
+ </ul>
1537
+ </div>
1538
+ }
1539
+ </div>
1540
+ }
1541
+ @case ('rows') {
1542
+ <ul
1543
+ class="m-0 grid w-full list-none grid-cols-1 gap-md p-0
1544
+ sm:grid-cols-2 lg:grid-cols-4"
1545
+ role="list"
1546
+ >
1547
+ @for (link of drop.item.dropdown!.links || []; track link.label) {
1548
+ <li class="min-w-0">
1549
+ <a
1550
+ [class]="dropTile"
1551
+ [href]="appHref(link.href || '#')"
1552
+ (click)="onNavLinkClick(link, $event)"
1553
+ >
1554
+ <span class="text-body-md font-medium text-fg">{{
1555
+ link.label
1556
+ }}</span>
1557
+ @if (link.description) {
1558
+ <span class="text-body-sm text-muted">{{
1559
+ link.description
1560
+ }}</span>
1561
+ }
1562
+ </a>
1563
+ </li>
1564
+ }
1565
+ </ul>
1566
+ }
1567
+ @default {
1568
+ <ul
1569
+ class="m-0 grid w-full max-w-(--container-5xl) list-none grid-cols-1 gap-xs
1570
+ p-0 sm:grid-cols-2 lg:grid-cols-3"
1571
+ role="list"
1572
+ >
1573
+ @for (link of flatLinks(drop.item); track link.label) {
1574
+ <li class="min-w-0">
1575
+ <a
1576
+ [class]="dropLink"
1577
+ [href]="appHref(link.href || '#')"
1578
+ (click)="onNavLinkClick(link, $event)"
1579
+ >
1580
+ <span>{{ link.label }}</span>
1581
+ @if (link.description) {
1582
+ <span class="text-body-sm text-muted">{{
1583
+ link.description
1584
+ }}</span>
1585
+ }
1586
+ </a>
1587
+ </li>
1588
+ }
1589
+ </ul>
1590
+ }
1591
+ }
1592
+ </div>
1593
+
1594
+ @if (drop.variant === 'featured' && drop.item.dropdown!.featured; as feat) {
1595
+ <aside
1596
+ class="flex min-w-0 flex-col gap-lg overflow-hidden rounded-md
1597
+ border border-border bg-primary-faint p-2xl lg:self-start"
1598
+ >
1599
+ @if (feat.imageUrl) {
1600
+ <img
1601
+ class="aspect-[16/10] h-auto w-full rounded-sm object-cover"
1602
+ [src]="feat.imageUrl"
1603
+ alt=""
1604
+ />
1605
+ }
1606
+ <div class="flex min-w-0 flex-col gap-md">
1607
+ <p class="text-body-lg font-semibold text-display">{{ feat.title }}</p>
1608
+ @if (feat.description) {
1609
+ <p class="text-body-sm leading-relaxed text-paragraph">
1610
+ {{ feat.description }}
1611
+ </p>
1612
+ }
1613
+ @if (feat.cta) {
1614
+ <a
1615
+ class="mt-xs inline-flex h-5xl cursor-pointer items-center justify-center gap-sm
1616
+ rounded-sm bg-primary px-xl text-body-md font-medium text-on-color
1617
+ transition-opacity hover:opacity-90
1618
+ focus-visible:outline focus-visible:outline-2
1619
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1620
+ [href]="appHref(feat.href || '#')"
1621
+ >
1622
+ <span>{{ feat.cta }}</span>
1623
+ <dga-icon name="chevronLeft" size="sm" />
1624
+ </a>
1625
+ }
1626
+ </div>
1627
+ </aside>
1628
+ }
1629
+ </div>
1630
+ </div>
1631
+ </div>
1632
+ </div>
1633
+ }
1634
+
1635
+ <!-- Header search popup (dga-modal) -->
1636
+ @if (searchConfig(); as cfg) {
1637
+ <dga-modal
1638
+ class="dga-header-search-modal"
1639
+ [id]="searchPanelId"
1640
+ [open]="searchOpen()"
1641
+ (openChange)="onSearchModalOpenChange($event)"
1642
+ [title]="cfg.title || cfg.submitLabel || 'Search'"
1643
+ [description]="cfg.description || ''"
1644
+ [closeLabel]="cfg.closeLabel || 'Close'"
1645
+ size="lg"
1646
+ animation="scale"
1647
+ [scrollable]="false"
1648
+ (opened)="focusSearchInput()"
1649
+ >
1650
+ <form
1651
+ class="flex flex-col gap-xl"
1652
+ role="search"
1653
+ [attr.aria-label]="cfg.submitLabel || 'Search'"
1654
+ (submit)="onSearchFormSubmit($event)"
1655
+ >
1656
+ <div class="flex w-full flex-col gap-md sm:flex-row sm:items-stretch sm:gap-lg">
1657
+ <div class="min-w-0 flex-1">
1658
+ <dga-form-control size="lg" startIcon="search" [filled]="!!searchQuery()">
1659
+ <input
1660
+ #searchInput
1661
+ type="search"
1662
+ name="q"
1663
+ class="dga-search-input placeholder:text-muted"
1664
+ [placeholder]="cfg.placeholder || 'Search...'"
1665
+ [attr.aria-label]="cfg.placeholder || 'Search...'"
1666
+ [value]="searchQuery()"
1667
+ (input)="searchQuery.set($any($event.target).value)"
1668
+ />
1669
+ @if (searchQuery()) {
1670
+ <button
1671
+ type="button"
1672
+ dgaEnd
1673
+ [attr.aria-label]="cfg.clearLabel || 'Clear search'"
1674
+ (click)="clearSearchQuery()"
1675
+ >
1676
+ <dga-icon name="close" size="sm" />
1677
+ </button>
1678
+ }
1679
+ @if (cfg.voice !== false) {
1680
+ <button
1681
+ type="button"
1682
+ dgaEnd
1683
+ class="dga-search-voice"
1684
+ [class.dga-search-voice--active]="voiceListening()"
1685
+ [attr.aria-label]="cfg.voiceLabel || 'Voice input'"
1686
+ [attr.aria-pressed]="voiceListening()"
1687
+ (click)="onSearchVoice()"
1688
+ >
1689
+ <dga-icon
1690
+ name="mic"
1691
+ size="sm"
1692
+ [tone]="voiceListening() ? 'current' : 'muted'"
1693
+ />
1694
+ </button>
1695
+ }
1696
+ </dga-form-control>
1697
+ </div>
1698
+ <button
1699
+ type="submit"
1700
+ class="inline-flex min-h-6xl shrink-0 cursor-pointer items-center justify-center gap-sm
1701
+ rounded-md bg-primary px-xl text-body-md font-medium text-on-color shadow-sm
1702
+ transition-opacity hover:opacity-90
1703
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
1704
+ focus-visible:outline-focus sm:px-2xl"
1705
+ >
1706
+ <dga-icon name="search" size="md" />
1707
+ <span>{{ cfg.submitLabel || 'Search' }}</span>
1708
+ </button>
1709
+ </div>
1710
+
1711
+ @if (cfg.suggestions?.length) {
1712
+ <div class="flex flex-col gap-md">
1713
+ <span class="text-body-sm font-semibold text-display">
1714
+ {{ cfg.suggestionsLabel || 'Suggestions:' }}
1715
+ </span>
1716
+ <div class="flex flex-wrap gap-sm">
1717
+ @for (item of cfg.suggestions!; track item.value ?? item.label; let i = $index) {
1718
+ <button
1719
+ type="button"
1720
+ class="dga-search-chip inline-flex h-4xl cursor-pointer items-center gap-xs
1721
+ rounded-full border border-border bg-neutral-light px-lg text-body-sm
1722
+ text-paragraph transition-[background-color,transform,border-color]
1723
+ duration-150 ease-out hover:-translate-y-px hover:border-primary
1724
+ hover:bg-sunken
1725
+ focus-visible:outline focus-visible:outline-2
1726
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1727
+ [style.animation-delay]="i * 40 + 'ms'"
1728
+ (click)="applySearchSuggestion(item)"
1729
+ >
1730
+ <dga-icon [name]="item.icon || 'plus'" size="xs" />
1731
+ <span>{{ item.label }}</span>
1732
+ </button>
1733
+ }
1734
+ </div>
1735
+ </div>
1736
+ }
1737
+ </form>
1738
+ </dga-modal>
1739
+ }
1740
+
1741
+ <!--
1742
+ Utility overlays (notifications / login / user): portaled to body at z-urgent
1743
+ so sticky announcement + chatbot/a11y FABs stay underneath.
1744
+ -->
1745
+ @if (utilityOverlayOpen()) {
1746
+ <div #utilLayer class="dga-header-util-layer">
1747
+ <button
1748
+ type="button"
1749
+ class="dga-util-backdrop absolute inset-0 cursor-default bg-overlay/50"
1750
+ tabindex="-1"
1751
+ aria-label="Close"
1752
+ (click)="closeUtilityOverlays()"
1753
+ ></button>
1754
+
1755
+ <!-- Header notifications panel -->
1756
+ @if (notificationsOpen() && notificationsConfig(); as ncfg) {
1757
+ <div
1758
+ [id]="notificationsPanelId"
1759
+ class="dga-header-util-panel fixed w-[min(28rem,calc(100vw-2rem))] max-md:inset-x-3
1760
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
1761
+ role="region"
1762
+ [attr.aria-label]="ncfg.title || ncfg.viewAllLabel || 'Notifications'"
1763
+ [style]="dropdownPanelStyle()"
1764
+ >
1765
+ <div
1766
+ class="dga-panel-enter dga-panel-enter--anchor-end flex max-h-[min(85svh,40rem)]
1767
+ flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-xl
1768
+ md:max-h-[none] md:rounded-md"
1769
+ >
1770
+ <div
1771
+ class="flex shrink-0 flex-col gap-sm border-b border-border-subtle px-xl py-md
1772
+ md:flex-row md:items-center md:justify-between md:gap-md"
1773
+ >
1774
+ <div class="flex min-w-0 items-center justify-between gap-sm md:justify-start">
1775
+ <div class="flex min-w-0 items-center gap-sm">
1776
+ <h2 class="m-0 truncate text-body-lg font-semibold text-display md:text-body-md">
1777
+ {{ ncfg.title || 'Notifications' }}
1778
+ </h2>
1779
+ @if (unreadNotificationCount() > 0) {
1780
+ <span
1781
+ class="inline-flex min-w-4xl items-center justify-center rounded-full
1782
+ bg-error px-sm py-xxs text-body-2xs font-semibold text-on-color"
1783
+ >
1784
+ {{ unreadNotificationCount() }}
1785
+ </span>
1786
+ }
1787
+ </div>
1788
+ <button
1789
+ type="button"
1790
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
1791
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
1792
+ focus-visible:outline focus-visible:outline-2
1793
+ focus-visible:outline-offset-2 focus-visible:outline-focus md:hidden"
1794
+ [attr.aria-label]="ncfg.closeLabel || 'Close'"
1795
+ (click)="closeNotifications()"
1796
+ >
1797
+ <dga-icon name="close" size="md" />
1798
+ </button>
1799
+ </div>
1800
+ <div class="flex shrink-0 items-center gap-xxs max-md:justify-stretch">
1801
+ @if (unreadNotificationCount() > 0) {
1802
+ <button
1803
+ type="button"
1804
+ class="inline-flex h-4xl flex-1 cursor-pointer items-center justify-center
1805
+ rounded-sm px-md text-body-sm font-medium text-fg-primary
1806
+ transition-colors hover:bg-primary-faint
1807
+ focus-visible:outline focus-visible:outline-2
1808
+ focus-visible:outline-offset-2 focus-visible:outline-focus
1809
+ md:flex-none"
1810
+ (click)="markAllNotificationsRead()"
1811
+ >
1812
+ {{ ncfg.markAllReadLabel || 'Mark all as read' }}
1813
+ </button>
1814
+ }
1815
+ <button
1816
+ type="button"
1817
+ class="hidden size-5xl cursor-pointer items-center justify-center rounded-sm
1818
+ text-muted transition-colors hover:bg-neutral-light hover:text-fg
1819
+ focus-visible:outline focus-visible:outline-2
1820
+ focus-visible:outline-offset-2 focus-visible:outline-focus md:inline-flex"
1821
+ [attr.aria-label]="ncfg.closeLabel || 'Close'"
1822
+ (click)="closeNotifications()"
1823
+ >
1824
+ <dga-icon name="close" size="md" />
1825
+ </button>
1826
+ </div>
1827
+ </div>
1828
+
1829
+ <div class="min-h-0 flex-1 overflow-y-auto overscroll-contain md:max-h-[min(48svh,28rem)]">
1830
+ @if (visibleNotifications().length === 0) {
1831
+ <div class="flex flex-col items-center gap-md px-xl py-3xl text-center">
1832
+ <span
1833
+ class="inline-flex size-6xl items-center justify-center rounded-full
1834
+ bg-neutral-light text-muted"
1835
+ aria-hidden="true"
1836
+ >
1837
+ <dga-icon name="bell" size="xl" tone="muted" />
1838
+ </span>
1839
+ <p class="m-0 text-body-sm text-muted">
1840
+ {{ ncfg.emptyLabel || 'No notifications' }}
1841
+ </p>
1842
+ </div>
1843
+ } @else {
1844
+ <ul class="m-0 flex list-none flex-col p-0" role="list">
1845
+ @for (item of visibleNotifications(); track item.id) {
1846
+ <li
1847
+ class="border-b border-border-subtle last:border-b-0"
1848
+ [class]="item.read ? 'bg-surface' : 'bg-card'"
1849
+ >
1850
+ <button
1851
+ type="button"
1852
+ class="flex w-full cursor-pointer items-start gap-lg px-xl py-lg text-start
1853
+ transition-colors hover:bg-neutral-light
1854
+ focus-visible:outline focus-visible:outline-2
1855
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
1856
+ [attr.aria-expanded]="expandedNotificationId() === item.id"
1857
+ (click)="toggleNotificationExpand(item)"
1858
+ >
1859
+ <span class="relative mt-xxs shrink-0">
1860
+ <dga-icon-badge size="sm">
1861
+ <dga-icon [name]="item.icon || 'bell'" size="sm" />
1862
+ </dga-icon-badge>
1863
+ @if (!item.read) {
1864
+ <span
1865
+ class="absolute -end-xxs -top-xxs size-[0.5rem] rounded-full bg-primary
1866
+ ring-2 ring-white"
1867
+ aria-hidden="true"
1868
+ ></span>
1869
+ }
1870
+ </span>
1871
+ <span class="min-w-0 flex-1">
1872
+ <span class="mb-xs flex flex-wrap items-center gap-sm">
1873
+ @if (item.statusLabel) {
1874
+ <dga-badge [variant]="item.tone || 'neutral'" size="sm">
1875
+ {{ item.statusLabel }}
1876
+ </dga-badge>
1877
+ }
1878
+ <span
1879
+ class="min-w-0 truncate text-body-md text-display"
1880
+ [class.font-semibold]="!item.read"
1881
+ [class.font-medium]="item.read"
1882
+ [class.text-muted]="item.read"
1883
+ >
1884
+ {{ item.title }}
1885
+ </span>
1886
+ </span>
1887
+ <span
1888
+ class="text-body-sm text-paragraph"
1889
+ [class.line-clamp-2]="expandedNotificationId() !== item.id"
1890
+ >
1891
+ {{ item.message }}
1892
+ </span>
1893
+ </span>
1894
+ <dga-icon
1895
+ class="mt-xs shrink-0 text-muted transition-transform duration-200"
1896
+ [class.rotate-180]="expandedNotificationId() === item.id"
1897
+ name="chevronDown"
1898
+ size="sm"
1899
+ />
1900
+ </button>
1901
+
1902
+ @if (expandedNotificationId() === item.id) {
1903
+ <div
1904
+ class="dga-notif-actions flex flex-wrap gap-sm border-t border-border-subtle
1905
+ bg-surface px-xl py-md"
1906
+ >
1907
+ @if (!item.read) {
1908
+ <button
1909
+ type="button"
1910
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
1911
+ px-md text-body-sm text-fg transition-colors hover:bg-neutral-light
1912
+ focus-visible:outline focus-visible:outline-2
1913
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1914
+ (click)="onNotificationAction(item, 'read'); $event.stopPropagation()"
1915
+ >
1916
+ <dga-icon name="success" size="sm" />
1917
+ <span>{{ ncfg.markReadLabel || 'Mark as read' }}</span>
1918
+ </button>
1919
+ }
1920
+ <button
1921
+ type="button"
1922
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
1923
+ px-md text-body-sm text-fg transition-colors hover:bg-neutral-light
1924
+ focus-visible:outline focus-visible:outline-2
1925
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1926
+ (click)="onNotificationAction(item, 'view'); $event.stopPropagation()"
1927
+ >
1928
+ <dga-icon name="eye" size="sm" />
1929
+ <span>{{ ncfg.viewLabel || 'View' }}</span>
1930
+ </button>
1931
+ <button
1932
+ type="button"
1933
+ class="inline-flex h-4xl cursor-pointer items-center gap-xs rounded-sm
1934
+ px-md text-body-sm text-fg-error transition-colors hover:bg-error-light
1935
+ focus-visible:outline focus-visible:outline-2
1936
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
1937
+ (click)="onNotificationAction(item, 'dismiss'); $event.stopPropagation()"
1938
+ >
1939
+ <dga-icon name="close" size="sm" />
1940
+ <span>{{ ncfg.dismissLabel || 'Dismiss' }}</span>
1941
+ </button>
1942
+ </div>
1943
+ }
1944
+ </li>
1945
+ }
1946
+ </ul>
1947
+ }
1948
+ </div>
1949
+
1950
+ @if (ncfg.viewAllHref || ncfg.viewAllLabel) {
1951
+ <div
1952
+ class="shrink-0 border-t border-border
1953
+ pb-[max(0px,env(safe-area-inset-bottom))] md:pb-0"
1954
+ >
1955
+ <a
1956
+ class="inline-flex w-full cursor-pointer items-center justify-center gap-sm
1957
+ px-xl py-lg text-body-sm font-medium text-fg-primary
1958
+ transition-colors hover:bg-neutral-light
1959
+ focus-visible:outline focus-visible:outline-2
1960
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
1961
+ [href]="appHref(ncfg.viewAllHref || '#')"
1962
+ (click)="closeNotifications()"
1963
+ >
1964
+ <span>{{ ncfg.viewAllLabel || 'View all notifications' }}</span>
1965
+ <dga-icon name="chevronLeft" size="sm" />
1966
+ </a>
1967
+ </div>
1968
+ }
1969
+ </div>
1970
+ </div>
1971
+ }
1972
+
1973
+ <!-- Header login panel (guest) -->
1974
+ @if (loginOpen() && loginConfig(); as lcfg) {
1975
+ <div
1976
+ [id]="loginPanelId"
1977
+ class="dga-header-util-panel fixed w-[min(24rem,calc(100vw-2rem))] max-md:inset-x-3
1978
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
1979
+ role="dialog"
1980
+ [attr.aria-label]="lcfg.title || 'Login'"
1981
+ [style]="dropdownPanelStyle()"
1982
+ >
1983
+ <div
1984
+ class="dga-panel-enter dga-panel-enter--anchor-end max-h-[min(90svh,44rem)]
1985
+ overflow-y-auto overscroll-contain rounded-2xl border border-border bg-card
1986
+ shadow-xl md:max-h-[none] md:overflow-visible md:rounded-md"
1987
+ >
1988
+ <div class="flex items-start justify-between gap-md px-2xl pt-2xl max-md:pt-xl">
1989
+ <div class="flex min-w-0 flex-col gap-xs">
1990
+ <h2 class="m-0 text-body-lg font-semibold text-display">
1991
+ {{ lcfg.title || 'Login' }}
1992
+ </h2>
1993
+ <p class="m-0 text-body-sm text-paragraph">
1994
+ {{ lcfg.description || 'Sign in to access your account' }}
1995
+ </p>
1996
+ </div>
1997
+ <button
1998
+ type="button"
1999
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
2000
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
2001
+ focus-visible:outline focus-visible:outline-2
2002
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2003
+ [attr.aria-label]="lcfg.closeLabel || lcfg.cancelLabel || 'Close'"
2004
+ (click)="closeLogin()"
2005
+ >
2006
+ <dga-icon name="close" size="md" />
2007
+ </button>
2008
+ </div>
2009
+
2010
+ <form
2011
+ class="flex flex-col gap-xl px-2xl pb-[max(1.5rem,env(safe-area-inset-bottom))]
2012
+ pt-xl md:pb-2xl"
2013
+ (submit)="onLoginSubmit($event)"
2014
+ >
2015
+ <dga-field
2016
+ [label]="lcfg.emailLabel || 'Email'"
2017
+ controlId="dga-header-login-email"
2018
+ [hint]="lcfg.emailHint || ''"
2019
+ required
2020
+ >
2021
+ <dga-form-control startIcon="mail" [filled]="!!loginEmail()">
2022
+ <input
2023
+ id="dga-header-login-email"
2024
+ type="email"
2025
+ name="email"
2026
+ autocomplete="username"
2027
+ required
2028
+ class="placeholder:text-muted"
2029
+ [placeholder]="lcfg.emailPlaceholder || 'name@example.gov.sa'"
2030
+ [value]="loginEmail()"
2031
+ (input)="loginEmail.set($any($event.target).value)"
2032
+ />
2033
+ </dga-form-control>
2034
+ </dga-field>
2035
+
2036
+ <dga-field
2037
+ [label]="lcfg.passwordLabel || 'Password'"
2038
+ controlId="dga-header-login-password"
2039
+ [hint]="lcfg.passwordHint || ''"
2040
+ required
2041
+ >
2042
+ <dga-form-control [filled]="!!loginPassword()">
2043
+ <input
2044
+ id="dga-header-login-password"
2045
+ [type]="showLoginPassword() ? 'text' : 'password'"
2046
+ name="password"
2047
+ autocomplete="current-password"
2048
+ required
2049
+ class="placeholder:text-muted"
2050
+ [placeholder]="lcfg.passwordPlaceholder || 'Enter your password'"
2051
+ [value]="loginPassword()"
2052
+ (input)="loginPassword.set($any($event.target).value)"
2053
+ />
2054
+ <button
2055
+ type="button"
2056
+ dgaEnd
2057
+ [attr.aria-label]="
2058
+ showLoginPassword()
2059
+ ? lcfg.hidePasswordLabel || 'Hide password'
2060
+ : lcfg.showPasswordLabel || 'Show password'
2061
+ "
2062
+ (click)="showLoginPassword.set(!showLoginPassword())"
2063
+ >
2064
+ <dga-icon [name]="showLoginPassword() ? 'eyeOff' : 'eye'" size="sm" />
2065
+ </button>
2066
+ </dga-form-control>
2067
+ </dga-field>
2068
+
2069
+ @if (lcfg.forgotPasswordHref || lcfg.forgotPasswordLabel) {
2070
+ <a
2071
+ class="self-start text-body-sm font-medium text-fg-primary transition-opacity
2072
+ hover:opacity-80
2073
+ focus-visible:outline focus-visible:outline-2
2074
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2075
+ [href]="appHref(lcfg.forgotPasswordHref || '#')"
2076
+ >
2077
+ {{ lcfg.forgotPasswordLabel || 'Forgot password?' }}
2078
+ </a>
2079
+ }
2080
+
2081
+ <div class="flex flex-col gap-md pt-xs">
2082
+ <button
2083
+ type="submit"
2084
+ class="inline-flex h-5xl w-full cursor-pointer items-center justify-center gap-sm
2085
+ rounded-sm bg-primary px-xl text-body-md font-medium text-on-color shadow-sm
2086
+ transition-opacity hover:opacity-90 disabled:cursor-wait disabled:opacity-60
2087
+ focus-visible:outline focus-visible:outline-2
2088
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2089
+ [disabled]="loginSubmitting()"
2090
+ >
2091
+ @if (loginSubmitting()) {
2092
+ <span
2093
+ class="dga-login-spinner size-md rounded-full border-2 border-on-color/30
2094
+ border-t-on-color"
2095
+ aria-hidden="true"
2096
+ ></span>
2097
+ }
2098
+ <span>
2099
+ {{
2100
+ loginSubmitting()
2101
+ ? '\u2026'
2102
+ : lcfg.submitLabel || 'Login'
2103
+ }}
2104
+ </span>
2105
+ </button>
2106
+ <button
2107
+ type="button"
2108
+ class="inline-flex h-5xl w-full cursor-pointer items-center justify-center
2109
+ rounded-sm px-xl text-body-md font-medium text-fg transition-colors
2110
+ hover:bg-neutral-light
2111
+ focus-visible:outline focus-visible:outline-2
2112
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2113
+ (click)="closeLogin()"
2114
+ >
2115
+ {{ lcfg.cancelLabel || 'Cancel' }}
2116
+ </button>
2117
+ </div>
2118
+ </form>
2119
+ </div>
2120
+ </div>
2121
+ }
2122
+
2123
+ <!-- Header user menu (authenticated) -->
2124
+ @if (userMenuOpen() && userConfig(); as ucfg) {
2125
+ <div
2126
+ [id]="userPanelId"
2127
+ class="dga-header-util-panel fixed w-[min(22rem,calc(100vw-2rem))] max-md:inset-x-3
2128
+ max-md:bottom-3 max-md:top-auto max-md:w-auto"
2129
+ role="menu"
2130
+ [attr.aria-label]="ucfg.name"
2131
+ [style]="dropdownPanelStyle()"
2132
+ >
2133
+ <div
2134
+ class="dga-panel-enter dga-panel-enter--anchor-end max-h-[min(85svh,36rem)]
2135
+ overflow-y-auto overscroll-contain rounded-2xl border border-border bg-card
2136
+ shadow-xl md:max-h-[none] md:overflow-visible md:rounded-md"
2137
+ >
2138
+ <div class="flex items-center gap-lg border-b border-border-subtle px-xl py-lg">
2139
+ <dga-avatar [name]="ucfg.name" [src]="ucfg.avatarSrc" size="md" />
2140
+ <div class="flex min-w-0 flex-1 flex-col gap-xxs">
2141
+ <span class="truncate text-body-md font-semibold text-display">{{ ucfg.name }}</span>
2142
+ @if (ucfg.role) {
2143
+ <span class="truncate text-body-sm text-muted">{{ ucfg.role }}</span>
2144
+ }
2145
+ @if (ucfg.email) {
2146
+ <span class="truncate text-body-sm text-paragraph">{{ ucfg.email }}</span>
2147
+ }
2148
+ </div>
2149
+ <button
2150
+ type="button"
2151
+ class="inline-flex size-5xl shrink-0 cursor-pointer items-center justify-center
2152
+ rounded-sm text-muted transition-colors hover:bg-neutral-light hover:text-fg
2153
+ focus-visible:outline focus-visible:outline-2
2154
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2155
+ aria-label="Close"
2156
+ (click)="closeUserMenu()"
2157
+ >
2158
+ <dga-icon name="close" size="md" />
2159
+ </button>
2160
+ </div>
2161
+ <div class="flex flex-col gap-xxs p-sm">
2162
+ @for (link of ucfg.links || []; track link.id) {
2163
+ @if (link.id === 'logout') {
2164
+ <div class="my-xs border-t border-border-subtle" role="separator"></div>
2165
+ <button
2166
+ type="button"
2167
+ role="menuitem"
2168
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
2169
+ text-start text-body-md text-fg-error transition-colors hover:bg-error-light
2170
+ focus-visible:outline focus-visible:outline-2
2171
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
2172
+ (click)="onUserLink(link)"
2173
+ >
2174
+ @if (link.icon) {
2175
+ <dga-icon [name]="link.icon" size="md" />
2176
+ }
2177
+ <span>{{ link.label }}</span>
2178
+ </button>
2179
+ } @else if (link.href) {
2180
+ <a
2181
+ role="menuitem"
2182
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
2183
+ text-start text-body-md text-fg transition-colors hover:bg-neutral-light
2184
+ focus-visible:outline focus-visible:outline-2
2185
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
2186
+ [href]="appHref(link.href)"
2187
+ (click)="onUserLink(link)"
2188
+ >
2189
+ @if (link.icon) {
2190
+ <dga-icon [name]="link.icon" size="md" />
2191
+ }
2192
+ <span>{{ link.label }}</span>
2193
+ </a>
2194
+ } @else {
2195
+ <button
2196
+ type="button"
2197
+ role="menuitem"
2198
+ class="flex w-full cursor-pointer items-center gap-md rounded-sm px-lg py-sm
2199
+ text-start text-body-md text-fg transition-colors hover:bg-neutral-light
2200
+ focus-visible:outline focus-visible:outline-2
2201
+ focus-visible:outline-offset-[-2px] focus-visible:outline-focus"
2202
+ (click)="onUserLink(link)"
2203
+ >
2204
+ @if (link.icon) {
2205
+ <dga-icon [name]="link.icon" size="md" />
2206
+ }
2207
+ <span>{{ link.label }}</span>
2208
+ </button>
2209
+ }
2210
+ }
2211
+ </div>
2212
+ </div>
2213
+ </div>
2214
+ }
2215
+ </div>
2216
+ }
2217
+
2218
+ <!-- Mobile navigation: sheet | fullscreen | push -->
2219
+ @if (isPortal() && items().length) {
2220
+ @if (mobileOpen() && mobileNav() !== 'push') {
2221
+ <button
2222
+ type="button"
2223
+ class="fixed inset-0 cursor-default md:hidden"
2224
+ [class]="
2225
+ mobileNav() === 'fullscreen'
2226
+ ? 'z-[35] bg-overlay/60 backdrop-blur-[3px]'
2227
+ : 'z-10 bg-overlay/40 backdrop-blur-[1px]'
2228
+ "
2229
+ tabindex="-1"
2230
+ [attr.aria-label]="menuCloseLabel()"
2231
+ (click)="closeAll()"
2232
+ ></button>
2233
+ }
2234
+
2235
+ <div
2236
+ [id]="collapseId"
2237
+ [class]="mobilePanelClass()"
2238
+ [attr.data-mobile-nav]="mobileNav()"
2239
+ [attr.aria-hidden]="!mobileOpen()"
2240
+ [attr.inert]="mobileOpen() ? null : ''"
2241
+ >
2242
+ @if (mobileNav() === 'fullscreen') {
2243
+ <div
2244
+ class="flex h-(--size-header-portal) shrink-0 items-center justify-between
2245
+ gap-lg border-b border-border px-xl"
2246
+ >
2247
+ <div class="flex min-w-0 items-center gap-lg">
2248
+ @if (brandLogo()) {
2249
+ <img
2250
+ class="h-5xl w-auto max-w-[10rem] shrink-0 object-contain"
2251
+ [src]="brandLogo()"
2252
+ [alt]="brandLogoAlt()"
2253
+ />
2254
+ } @else {
2255
+ <span class="truncate text-body-md font-semibold text-display">{{
2256
+ brand() || brandLogoAlt() || navLabel()
2257
+ }}</span>
2258
+ }
2259
+ </div>
2260
+ <button
2261
+ type="button"
2262
+ class="inline-flex size-6xl shrink-0 cursor-pointer items-center justify-center
2263
+ rounded-md text-fg transition-colors hover:bg-neutral-light
2264
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
2265
+ focus-visible:outline-focus"
2266
+ [attr.aria-label]="menuCloseLabel()"
2267
+ (click)="closeAll()"
2268
+ >
2269
+ <dga-icon name="close" size="xl" />
2270
+ </button>
2271
+ </div>
2272
+ }
2273
+
2274
+ @if (mobileNav() === 'sheet') {
2275
+ <div
2276
+ class="flex min-h-(--size-header-portal) shrink-0 items-center justify-end
2277
+ border-b border-border-subtle px-md
2278
+ pt-[env(safe-area-inset-top,0px)]"
2279
+ >
2280
+ <button
2281
+ type="button"
2282
+ class="inline-flex size-6xl shrink-0 cursor-pointer items-center justify-center
2283
+ rounded-md text-fg transition-colors hover:bg-neutral-light
2284
+ focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
2285
+ focus-visible:outline-focus"
2286
+ [attr.aria-label]="menuCloseLabel()"
2287
+ (click)="closeAll()"
2288
+ >
2289
+ <dga-icon name="close" size="xl" />
2290
+ </button>
2291
+ </div>
2292
+ }
2293
+
2294
+ @if (mobileNav() === 'push') {
2295
+ <div class="border-b border-border-subtle px-xl py-md">
2296
+ <p class="m-0 text-body-sm font-medium text-muted">{{ navLabel() }}</p>
2297
+ </div>
2298
+ }
2299
+
2300
+ <div
2301
+ class="min-h-0 flex-1 overflow-y-auto overscroll-contain px-xl py-lg
2302
+ pb-[max(1rem,env(safe-area-inset-bottom))]"
2303
+ >
2304
+ <ul class="m-0 flex list-none flex-col gap-none p-0" role="list">
2305
+ @for (item of items(); track item.label; let i = $index) {
2306
+ <li class="border-b border-border-subtle last:border-b-0">
2307
+ @if (item.dropdown) {
2308
+ <button
2309
+ type="button"
2310
+ [class]="mobileItemClass(!!item.current, openDropdown() === i)"
2311
+ [attr.aria-expanded]="openDropdown() === i"
2312
+ (click)="toggleDropdown(i, $event)"
2313
+ >
2314
+ <span class="min-w-0 flex-1" [class]="item.current ? 'text-fg-primary' : ''">{{
2315
+ item.label
2316
+ }}</span>
2317
+ <dga-icon
2318
+ name="chevronDown"
2319
+ size="md"
2320
+ class="shrink-0"
2321
+ [class]="
2322
+ openDropdown() === i
2323
+ ? 'rotate-180 text-fg-primary transition-transform duration-200'
2324
+ : 'text-muted transition-transform duration-200'
2325
+ "
2326
+ />
2327
+ </button>
2328
+
2329
+ @if (openDropdown() === i) {
2330
+ <div
2331
+ class="dga-panel-enter space-y-md border-s-2 border-primary/30 pb-lg ps-lg
2332
+ ms-sm"
2333
+ >
2334
+ @if (item.dropdown.featured; as feat) {
2335
+ <a
2336
+ class="flex flex-col gap-sm rounded-md border border-border
2337
+ bg-primary-faint p-xl text-start no-underline"
2338
+ [href]="appHref(feat.href || '#')"
2339
+ (click)="closeAll()"
2340
+ >
2341
+ <span class="text-body-md font-semibold text-display">{{
2342
+ feat.title
2343
+ }}</span>
2344
+ @if (feat.description) {
2345
+ <span class="text-body-sm text-paragraph">{{
2346
+ feat.description
2347
+ }}</span>
2348
+ }
2349
+ @if (feat.cta) {
2350
+ <span class="text-body-sm font-medium text-fg-primary">{{
2351
+ feat.cta
2352
+ }}</span>
2353
+ }
2354
+ </a>
2355
+ }
2356
+
2357
+ @if (item.dropdown.columns?.length) {
2358
+ @for (col of item.dropdown.columns!; track col.title ?? $index) {
2359
+ <div class="flex flex-col gap-xs">
2360
+ @if (col.title) {
2361
+ <p class="px-xl text-body-sm font-medium text-fg-primary">
2362
+ {{ col.title }}
2363
+ </p>
2364
+ }
2365
+ <ul class="m-0 flex list-none flex-col gap-none p-0">
2366
+ @for (link of col.links; track link.label) {
2367
+ <li>
2368
+ <a
2369
+ [class]="mobileLink"
2370
+ [href]="appHref(link.href || '#')"
2371
+ (click)="onNavLinkClick(link, $event); closeAll()"
2372
+ >
2373
+ <span>{{ link.label }}</span>
2374
+ @if (link.description) {
2375
+ <span class="text-body-sm text-muted">{{
2376
+ link.description
2377
+ }}</span>
2378
+ }
2379
+ </a>
2380
+ </li>
2381
+ }
2382
+ </ul>
2383
+ </div>
2384
+ }
2385
+ } @else {
2386
+ <ul class="m-0 flex list-none flex-col gap-none p-0">
2387
+ @for (link of flatLinks(item); track link.label) {
2388
+ <li>
2389
+ <a
2390
+ [class]="mobileLink"
2391
+ [href]="appHref(link.href || '#')"
2392
+ (click)="onNavLinkClick(link, $event); closeAll()"
2393
+ >
2394
+ <span>{{ link.label }}</span>
2395
+ @if (link.description) {
2396
+ <span class="text-body-sm text-muted">{{
2397
+ link.description
2398
+ }}</span>
2399
+ }
2400
+ </a>
2401
+ </li>
2402
+ }
2403
+ </ul>
2404
+ }
2405
+ </div>
2406
+ }
2407
+ } @else {
2408
+ <a
2409
+ [class]="mobileItemClass(!!item.current)"
2410
+ [attr.aria-current]="item.current ? 'page' : null"
2411
+ [href]="appHref(item.href || '#')"
2412
+ (click)="onNavLinkClick(item, $event); closeAll()"
2413
+ >
2414
+ @if (item.current) {
2415
+ <span
2416
+ class="absolute inset-y-md start-0 w-1 rounded-e-sm bg-primary"
2417
+ aria-hidden="true"
2418
+ ></span>
2419
+ }
2420
+ <span class="min-w-0 flex-1" [class]="item.current ? 'text-fg-primary' : ''">{{
2421
+ item.label
2422
+ }}</span>
2423
+ </a>
2424
+ }
2425
+ </li>
2426
+ }
2427
+ </ul>
2428
+ </div>
2429
+
2430
+ @if (actions().length) {
2431
+ <div
2432
+ class="flex shrink-0 items-center justify-around gap-sm border-t border-border
2433
+ bg-nav px-xl py-md pb-[max(0.75rem,env(safe-area-inset-bottom))]"
2434
+ >
2435
+ @for (action of actions(); track action.id) {
2436
+ @if (action.href) {
2437
+ <a
2438
+ class="relative inline-flex min-h-6xl min-w-6xl cursor-pointer flex-col
2439
+ items-center justify-center gap-xxs rounded-md px-md text-fg
2440
+ hover:bg-neutral-light
2441
+ focus-visible:outline focus-visible:outline-2
2442
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2443
+ [href]="appHref(action.href)"
2444
+ [attr.aria-label]="action.label"
2445
+ [attr.data-dga-action]="action.id"
2446
+ (click)="closeAll()"
2447
+ >
2448
+ @if (action.icon) {
2449
+ <dga-icon [name]="action.icon" size="xl" />
2450
+ }
2451
+ <span class="max-w-11xl truncate text-body-2xs">{{ action.label }}</span>
2452
+ @if (action.badge) {
2453
+ <span [class]="badgeClass()">{{ action.badge }}</span>
2454
+ }
2455
+ </a>
2456
+ } @else {
2457
+ <button
2458
+ type="button"
2459
+ class="relative inline-flex min-h-6xl min-w-6xl cursor-pointer flex-col
2460
+ items-center justify-center gap-xxs rounded-md px-md text-fg
2461
+ hover:bg-neutral-light
2462
+ focus-visible:outline focus-visible:outline-2
2463
+ focus-visible:outline-offset-2 focus-visible:outline-focus"
2464
+ [attr.aria-label]="action.label"
2465
+ [attr.data-dga-action]="action.id"
2466
+ (click)="onMobileAction(action, $event)"
2467
+ >
2468
+ @if (action.icon) {
2469
+ <dga-icon [name]="action.icon" size="xl" />
2470
+ }
2471
+ <span class="max-w-11xl truncate text-body-2xs">{{ action.label }}</span>
2472
+ @if (action.badge) {
2473
+ <span [class]="badgeClass()">{{ action.badge }}</span>
2474
+ }
2475
+ </button>
2476
+ }
2477
+ }
2478
+ </div>
2479
+ }
2480
+ </div>
2481
+ }
2482
+ `,host:{role:"banner","[class]":"hostClasses()","[attr.data-appearance]":"appearance()","[attr.data-mobile-nav]":"mobileNav()","[attr.data-mobile-open]":"mobileOpen() || null","(mouseleave)":"onHostLeave($event)"},styles:[`@keyframes dga-fade-in{0%{opacity:0}to{opacity:1}}@keyframes dga-panel-in{0%{opacity:0;transform:translateY(-.625rem) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes dga-chip-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-notif-row-in{0%{opacity:0;transform:translateY(.35rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-expand-fade{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-spin{to{transform:rotate(360deg)}}@keyframes dga-badge-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.12)}}@keyframes dga-push-in{0%{opacity:0;transform:translateY(-.75rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-sheet-in-ltr{0%{opacity:.85;transform:translate3d(-100%,0,0)}to{opacity:1;transform:translateZ(0)}}@keyframes dga-sheet-in-rtl{0%{opacity:.85;transform:translate3d(100%,0,0)}to{opacity:1;transform:translateZ(0)}}@keyframes dga-fs-in{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes dga-sheet-in{0%{opacity:0;transform:translateY(1.25rem)}to{opacity:1;transform:translateY(0)}}:host .dga-util-backdrop,.dga-header-util-layer .dga-util-backdrop{animation:dga-fade-in .22s ease both}.dga-header-util-layer{position:fixed;inset:0;z-index:var(--z-index-urgent, 400);pointer-events:none}.dga-header-util-layer>.dga-util-backdrop,.dga-header-util-layer>.dga-header-util-panel{pointer-events:auto}:host .dga-panel-enter,.dga-header-util-layer .dga-panel-enter{animation:dga-panel-in .28s cubic-bezier(.16,1,.3,1) both;transform-origin:top center;will-change:transform,opacity}:host .dga-panel-enter--anchor-end,.dga-header-util-layer .dga-panel-enter--anchor-end{transform-origin:top right}:host-context([dir="rtl"]) .dga-panel-enter--anchor-end,:host([dir="rtl"]) .dga-panel-enter--anchor-end,:host-context([dir="rtl"]) .dga-header-util-layer .dga-panel-enter--anchor-end,[dir=rtl] .dga-header-util-layer .dga-panel-enter--anchor-end{transform-origin:top left}@media(max-width:767px){:host .dga-panel-enter--anchor-end,.dga-header-util-layer .dga-panel-enter--anchor-end{animation-name:dga-sheet-in;transform-origin:bottom center}}:host .dga-search-chip{animation:dga-chip-in .28s cubic-bezier(.16,1,.3,1) both}:host .dga-search-input{-webkit-appearance:none;appearance:none}:host .dga-search-input::-webkit-search-decoration,:host .dga-search-input::-webkit-search-cancel-button,:host .dga-search-input::-webkit-search-results-button,:host .dga-search-input::-webkit-search-results-decoration{-webkit-appearance:none;appearance:none;display:none}:host .dga-search-voice.dga-search-voice--active{color:var(--dga-text-primary, #1b8354)!important;background:var(--dga-bg-primary-faint, #f3faf6)!important}:host .dga-notif-item,.dga-header-util-layer .dga-notif-item{animation:dga-notif-row-in .26s cubic-bezier(.16,1,.3,1) both}:host .dga-notif-actions,.dga-header-util-layer .dga-notif-actions{animation:dga-expand-fade .2s ease both}:host .dga-login-spinner,.dga-header-util-layer .dga-login-spinner{animation:dga-spin .7s linear infinite}:host .dga-action-badge{animation:dga-badge-pulse 1.8s ease-in-out infinite;transform-origin:center}@media(prefers-reduced-motion:reduce){:host .dga-util-backdrop,:host .dga-panel-enter,:host .dga-search-chip,:host .dga-notif-item,:host .dga-notif-actions,.dga-header-util-layer .dga-util-backdrop,.dga-header-util-layer .dga-panel-enter{animation-duration:.01ms!important;animation-delay:0ms!important}}:host .dga-burger__box{position:relative;display:block;width:1.375rem;height:1rem}:host .dga-burger__line{position:absolute;inset-inline:0;height:2px;border-radius:1px;background:currentColor;transition:transform .22s cubic-bezier(.4,0,.2,1),opacity .16s ease,top .22s cubic-bezier(.4,0,.2,1)}:host .dga-burger__line:nth-child(1){top:0}:host .dga-burger__line:nth-child(2){top:calc(50% - 1px)}:host .dga-burger__line:nth-child(3){top:calc(100% - 2px)}:host .dga-burger--open{background:var(--color-neutral-light, #f3f4f6)}:host .dga-burger--hidden{visibility:hidden;pointer-events:none}:host .dga-burger--open .dga-burger__line:nth-child(1){top:calc(50% - 1px);transform:rotate(45deg)}:host .dga-burger--open .dga-burger__line:nth-child(2){opacity:0;transform:scaleX(.4)}:host .dga-burger--open .dga-burger__line:nth-child(3){top:calc(50% - 1px);transform:rotate(-45deg)}:host .dga-mobile-nav-closed{display:none}:host .dga-mobile-nav-open{display:flex}:host .dga-mobile-push-open{animation:dga-push-in .24s cubic-bezier(.4,0,.2,1) forwards}:host .dga-mobile-sheet-open{animation:dga-sheet-in-rtl .28s cubic-bezier(.4,0,.2,1) forwards}:host-context([dir="rtl"]) .dga-mobile-sheet-open{animation:dga-sheet-in-ltr .28s cubic-bezier(.4,0,.2,1) forwards}:host .dga-mobile-fs-open{animation:dga-fs-in .24s cubic-bezier(.4,0,.2,1) forwards}@media(prefers-reduced-motion:reduce){:host .dga-action-badge,:host .dga-mobile-push-open,:host .dga-mobile-sheet-open,:host .dga-mobile-fs-open,:host-context([dir="rtl"]) .dga-mobile-sheet-open,:host .dga-burger__line{animation:none;transition:none}}
2483
+ `]}]}],ctorParameters:()=>[],propDecorators:{brand:[{type:a.Input,args:[{isSignal:!0,alias:"brand",required:!1}]}],brandSlogan:[{type:a.Input,args:[{isSignal:!0,alias:"brandSlogan",required:!1}]}],brandLogo:[{type:a.Input,args:[{isSignal:!0,alias:"brandLogo",required:!1}]}],brandLogoAlt:[{type:a.Input,args:[{isSignal:!0,alias:"brandLogoAlt",required:!1}]}],brandPlaceholder:[{type:a.Input,args:[{isSignal:!0,alias:"brandPlaceholder",required:!1}]}],brandHref:[{type:a.Input,args:[{isSignal:!0,alias:"brandHref",required:!1}]}],navLabel:[{type:a.Input,args:[{isSignal:!0,alias:"navLabel",required:!1}]}],menuToggleLabel:[{type:a.Input,args:[{isSignal:!0,alias:"menuToggleLabel",required:!1}]}],menuCloseLabel:[{type:a.Input,args:[{isSignal:!0,alias:"menuCloseLabel",required:!1}]}],appearance:[{type:a.Input,args:[{isSignal:!0,alias:"appearance",required:!1}]}],mobileNav:[{type:a.Input,args:[{isSignal:!0,alias:"mobileNav",required:!1}]}],sticky:[{type:a.Input,args:[{isSignal:!0,alias:"sticky",required:!1}]}],items:[{type:a.Input,args:[{isSignal:!0,alias:"items",required:!1}]}],actions:[{type:a.Input,args:[{isSignal:!0,alias:"actions",required:!1}]}],search:[{type:a.Input,args:[{isSignal:!0,alias:"search",required:!1}]}],searchQuery:[{type:a.Input,args:[{isSignal:!0,alias:"searchQuery",required:!1}]},{type:a.Output,args:["searchQueryChange"]}],notifications:[{type:a.Input,args:[{isSignal:!0,alias:"notifications",required:!1}]}],login:[{type:a.Input,args:[{isSignal:!0,alias:"login",required:!1}]}],user:[{type:a.Input,args:[{isSignal:!0,alias:"user",required:!1}]}],authenticated:[{type:a.Input,args:[{isSignal:!0,alias:"authenticated",required:!1}]},{type:a.Output,args:["authenticatedChange"]}],actionClick:[{type:a.Output,args:["actionClick"]}],searchSubmit:[{type:a.Output,args:["searchSubmit"]}],searchSuggestionSelect:[{type:a.Output,args:["searchSuggestionSelect"]}],searchVoice:[{type:a.Output,args:["searchVoice"]}],notificationAction:[{type:a.Output,args:["notificationAction"]}],loginSubmit:[{type:a.Output,args:["loginSubmit"]}],logout:[{type:a.Output,args:["logout"]}],userLinkClick:[{type:a.Output,args:["userLinkClick"]}],navLinkClick:[{type:a.Output,args:["navLinkClick"]}],searchInputRef:[{type:a.ViewChild,args:["searchInput",{isSignal:!0}]}],utilLayerRef:[{type:a.ViewChild,args:["utilLayer",{isSignal:!0}]}],onCloseHeaderOverlays:[{type:m,args:["document:dga-close-header-overlays"]}],onKey:[{type:m,args:["document:keydown",["$event"]]}],onScroll:[{type:m,args:["window:scroll"]}],onResize:[{type:m,args:["window:resize"]}],onDocClick:[{type:m,args:["document:click",["$event"]]}]}});export{g as DgaHeader};