PageSourceSearch

https://carriehaymondgroup.com/contact

html carriehaymondgroup.com collected 2026-10-06 19:44:51 UTC 377,670 bytes, 7,318 lines download raw bytes

1<!DOCTYPE html>
2<html class="no-js" lang=en>
3<head>
4    <meta charset="utf-8">
5    <meta http-equiv="x-ua-compatible" content="ie=edge">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <meta name="twitter:card" content="summary_large_image">
8    <meta property="og:type" content="website">
9        <title>Contact Us | Get Expert Advice | Carrie Haymond Group</title>
10        <meta property="og:title" content="Contact Us | Get Expert Advice | Carrie Haymond Group">
11        <meta name="twitter:title" content="Contact Us | Get Expert Advice | Carrie Haymond Group">
12        <meta name="description" content="Looking for expert advice in real estate? Contact the Carrie Haymond Group today for personalized solutions to all your property needs. Satisfaction guaranteed!">
13        <meta property="og:description" content="Looking for expert advice in real estate? Contact the Carrie Haymond Group today for personalized solutions to all your property needs. Satisfaction guaranteed!">
14        <meta name="twitter:description" content="Looking for expert advice in real estate? Contact the Carrie Haymond Group today for personalized solutions to all your property needs. Satisfaction guaranteed!">
15        <meta property="og:image" content="https://media-production.lp-cdn.com/cdn-cgi/image/format&#x3D;auto,quality&#x3D;85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c">
16        <meta name="twitter:image" content="https://media-production.lp-cdn.com/cdn-cgi/image/format&#x3D;auto,quality&#x3D;85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c">
17        <meta property="og:url" content="https://carriehaymondgroup.com/contact">
18        <link rel="canonical" href="https://carriehaymondgroup.com/contact">
19    
19<script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script>
19
20    <link rel="preconnect" href="https://fonts.googleapis.com">
21    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
22    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open%20Sans:300,400,500,600,700,800,300i,400i,500i,600i,700i,800i">
23    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
24    <noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css"></noscript>
25    <link rel="icon" type="image/x-icon" href="/favicon.ico">
26    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
27    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
28    <link rel="icon" type="image/png" sizes="48x48" href="/favicon-48x48.png">
29    <style id="global-css">:root{--global-primary-font-family:Montserrat,sans-serif;--global-primary-font-family-short:Montserrat;--global-secondary-font-family:'Open Sans',sans-serif;--global-secondary-font-family-short:Open Sans;--global-body-padding:0px;--global-background-color:#fff;--global-body-font-size:16px;--global-h1-font-size:64px;--global-h2-font-size:52px;--global-h3-font-size:42px;--global-h4-font-size:24px;--global-h5-font-size:12px;--global-h6-font-size:32px;--global-section-padding:96px;}@media (max-width: 768px){:root{--global-section-padding:64px;}}body{padding:0px;background-color:#fff;font-family:'Open Sans',sans-serif;font-size:16px;}@media (min-width: 768px){body{padding:0px 0px 0px 0px;}}h1,h2,h3,h4,h5,h6,button{font-family:Montserrat,sans-serif;}h1{font-size:64px;}h2{font-size:52px;}h3{font-size:42px;}h4{font-size:24px;}h5{font-size:12px;}h6{font-size:32px;}</style>
30        <link rel="stylesheet" type="text/css" href="https://styles.luxurypresence.com/visionary/index.css" />
31    <style id="website-css">:root{--lp-color-primary-accent:#36454F;--primary:#36454F;--secondary:#708090;--accent:#C5A565;--blocking:#000;--text-input:#f3f3f3;--black:#000;--white:#FFF;--light-gray:#CCC;--dark-gray:#999;--lp-color-error:#F00;}:root{--global-h4-font-size:32px;--global-h5-font-size:24px;--global-h6-font-size:20px;}.lp-h1,.lp-h2,.lp-h3{font-variation-settings:'opsz' 44,'GRAD' 0,'slnt' 0,'XTRA' 510,'XOPQ' 96,'YOPQ' 40,'YTLC' 540,'YTUC' 712,'YTAS' 750,'YTDE' -220,'YTFI' 738;}.watermark{font-variation-settings:'GRAD' 0,'slnt' 0,'XTRA' 511,'XOPQ' 96,'YOPQ' 50,'YTLC' 537,'YTUC' 712,'YTAS' 750,'YTDE' -221,'YTFI' 738,'opsz' 44;}@media only screen and (max-width:768px){.contact-form-modal__close:after{height:25px;width:20px;--iconColor:#000;}}@media only screen and (min-width:769px){.contact-form-modal__close:after{height:30px;width:40px;}}@media only screen and (min-width:769px){body.page-sellers .hoverable-section{padding-bottom:0;padding-top:0;}}@media only screen and (max-width:768px){body.page-sellers .hoverable-section{padding-bottom:80px;padding-top:80px;}}@media only screen and (min-width:769px){body.page-buyers .hoverable-section{padding-bottom:0;padding-top:0;}}@media only screen and (max-width:768px){body.page-buyers .hoverable-section{padding-bottom:80px;padding-top:80px;}}.header-container{height:80px!important;}@media only screen and (max-width: 768px){.header-container{height:60px!important;}}.header-logo{height:100%;max-width:350px!important;}@media only screen and (max-width: 768px){.header-logo{height:100%;max-width:280px!important;}}.header:is(.scroll){background:var(--primary)!important;color:var(--white)!important;}.header:is(.scroll) .header-logo__img--light{display:block!important;}.header:is(.scroll) .header-logo__img--dark{display:none!important;}.header:is(.scroll) .header-navigation__link:before,.header:is(.scroll) .header-navigation__link:after{background-color:var(--white);}.header:is(.scroll) .header-hamburger-btn{border-color:var(--white);background:transparent;}.header:is(.scroll) .header-hamburger-btn:empty:before,.header:is(.scroll) .header-hamburger-btn:empty:after{background:var(--white);}.header:is(.scroll) .header-hamburger-btn:hover:not(:disabled){border-color:var(--white);background:var(--white);}.header:is(.scroll) .header-hamburger-btn:hover:not(:disabled):empty:before,.header:is(.scroll) .header-hamburger-btn:hover:not(:disabled):empty:after{background:var(--primary);}.header:is(.scroll) .header-navigation__sub-nav{padding:0px;background:var(--black);min-width:150px;}.header:is(.scroll) .header-navigation__sub-nav-link{padding:12px 16px;color:var(--white);}.header:is(.scroll) .header-navigation__sub-nav-link:hover{background-color:var(--white);color:var(--primary);}.header:not(.scroll){background:transparent!important;}.header:not(.scroll) .header-logo__img--light{display:block!important;}.header:not(.scroll) .header-logo__img--dark{display:none!important;}.header:not(.scroll) .header-hamburger-btn{border-color:var(--white);background:transparent;}.header:not(.scroll) .header-hamburger-btn:empty:before,.header:not(.scroll) .header-hamburger-btn:empty:after{background:var(--white);}.header:not(.scroll) .header-hamburger-btn:hover:not(:disabled){border-color:var(--white);background:var(--white);}.header:not(.scroll) .header-hamburger-btn:hover:not(:disabled):empty:before,.header:not(.scroll) .header-hamburger-btn:hover:not(:disabled):empty:after{background:var(--accent);}.header:not(.scroll) .header-navigation__link:before,.header:not(.scroll) .header-navigation__link:after{background-color:var(--white);}.header:not(.scroll) .header-navigation__sub-nav{padding:0px;background:var(--white);min-width:150px;}.header:not(.scroll) .header-navigation__sub-nav-link{padding:12px 16px;color:var(--black);}.header:not(.scroll) .header-navigation__sub-nav-link:hover{background-color:var(--primary);color:var(--white);}.contact-form-modal-consultation-link{color:#fff!important;position:relative!important;font-size:14px;}.contact-form-modal-consultation-link:before,.contact-form-modal-consultation-link:after{-webkit-transition:0.4s;transition:0.4s;-webkit-text-decoration:none!important;text-decoration:none!important;line-height:1;content:"";height:1px;position:absolute!important;bottom:-2px;left:0;}.contact-form-modal-consultation-link:before{width:100%!important;background-color:rgba(250,250,250,0.8)!important;}.contact-form-modal-consultation-link:after{width:0%!important;background-color:var(--primary)!important;}.contact-form-modal-consultation-link:hover:after{width:100%!important;}@media (min-width: 769px){.sidemenu{width:auto;}}.sidemenu-wrapper{min-height:-webkit-fit-content;min-height:-moz-fit-content;min-height:fit-content;max-height:100%;}@media (min-width: 1025px){.sidemenu-nav-holder:has(> .sidemenu-navigation:nth-child(1):last-child){-ms-grid-columns:auto;grid-template-columns:auto;}.sidemenu-nav-holder:has(> .sidemenu-navigation:nth-child(2):last-child){-ms-grid-columns:auto auto;grid-template-columns:auto auto;}.sidemenu-nav-holder:has(> .sidemenu-navigation:nth-child(3):last-child){-ms-grid-columns:auto auto auto;grid-template-columns:auto auto auto;}.sidemenu-nav-holder:has(> .sidemenu-navigation:nth-child(4):last-child){-ms-grid-columns:auto auto auto auto;grid-template-columns:auto auto auto auto;}}@media (max-width: 768px){.sidemenu-wrapper{width:100%;}}@media (min-width: 769px){.sidemenu-footer:before{width:100%;}}@media (max-width: 768px){.sidemenu-socials-block:before{width:100%;}}@media (max-width: 768px){#global-sidemenu{padding-top:128px;padding-bottom:48px;}}@media (min-width: 1025px){.sidemenu-footer{padding-top:70px;}}@media (max-width: 768px){.sidemenu-footer{padding-top:70px;padding-bottom:0px;}}.sidemenu__col-description{white-space:pre-line;}@media (max-width: 768px){.sidemenu-close{top:16px;right:16px;}}.sidemenu-close{border-color:var(--primary);background:var(--primary);}
31.sidemenu-close:after{background:var(--white);}.sidemenu-close:hover:not(:disabled){border-color:var(--primary);background:transparent;}.sidemenu-close:hover:not(:disabled):after{background:var(--primary);}.sidemenu-navigation__link:hover{color:var(--primary);}.sidemenu__col-phone,.sidemenu__col-email,.sidemenu-navigation-sub-nav__link{-webkit-transition:0.25s;transition:0.25s;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content;text-decoration-color:var(--light-gray)!important;}.sidemenu__col-phone:hover,.sidemenu__col-phone:focus,.sidemenu__col-email:hover,.sidemenu__col-email:focus,.sidemenu-navigation-sub-nav__link:hover,.sidemenu-navigation-sub-nav__link:focus{text-decoration-color:var(--primary)!important;}.sidemenu__col-phone:active,.sidemenu__col-email:active,.sidemenu-navigation-sub-nav__link:active{--lp-color-primary-accent-dark:var(--primary);}.sidemenu-footer:before,.sidemenu-socials-block:before{background:var(--primary);opacity:1;}@media only screen and (max-width: 768px){.sidemenu-navigation{gap:16px;}.sidemenu-footer{padding-top:0;}}#global-sidemenu .sidemenu-navigation__link{display:block;white-space:normal;overflow:visible;}.sidemenu__col-content:first-of-type{width:64%;}.contact-form-modal__bg-image{content:url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');}.contact-form-modal-details__title{max-width:100%;}
31.contact-form-modal-agent{opacity:1;}.contact-form-modal-agent__link{-webkit-transition:0.25s;transition:0.25s;--lp-color-secondary-gray-600:var(--light-gray);}.contact-form-modal-agent__link:hover,.contact-form-modal-agent__link:focus{color:var(--white);--lp-color-primary-accent:var(--primary);}.contact-form-modal-agent__link:active{--lp-color-primary-accent-dark:var(--primary);}.custom-form__form-row .lp-input,.modal-content .custom-select-toggle.is-placeholder{color:#000!important;}.modal-content .custom-select .custom-select-item{color:#000;background:#fff;}.modal-content .custom-select .custom-select-item:hover{color:#fff;background:var(--primary)!important;}.contact-form-modal__close-container{top:0px;right:0px;}.email-sign-up-modal .email-sign-up-modal__form .email-sign-up-modal__close{opacity:1!important;}.contact-form-modal__close{top:16px!important;right:48px!important;padding:0px;}.contact-form-modal__close:after{background:var(--white);}.contact-form-modal-agent__contact{max-width:100%;}@media only screen and (max-width: 768px){.contact-form-modal-form__title{text-align:center;}}.contact-form-modal-form__group .lp-input{background-color:var(--text-input);}.mobile-contact-wrapper .lp-container{padding:0px!important;}.mobile-contact-wrapper .contact-form{padding:0px;}.mobile-contact-wrapper .contact-form__container{padding:48px;}.mobile-contact-wrapper{z-index:101!important;}.mobile-contact-wrapper .close-btn{top:16px!important;right:16px!important;}.mobile-contact-wrapper .contact-form__container{border-radius:8px;}.mobile-contact-wrapper .pop-up{max-width:700px!important;}.mobile-contact-wrapper .pop-up{box-shadow:0px 8px 16px rgba(0, 0, 0, 0.15);}.mobile-contact-wrapper .contact-form__container{border-color:rgba(0, 0, 0, 0);}@media only screen and (max-width: 768px){div.mobile-contact-wrapper .pop-up .close-btn{padding:0!important;margin-top:0!important;}.mobile-contact-wrapper .contact-form__container{padding:20px;}}.floating-contact-button-pop-up{background:#fff!important;}.custom-intro__content-box{background-color:transparent;}.custom-intro__pre-title{color:var(--white);}.custom-intro__title{color:var(--white);}.custom-intro__description{color:var(--white);}.custom-intro__scroll-btn,.neighborhood-intro__scroll-btn,.blog-post-intro__scroll-btn,.agent-intro__scroll-btn{border-color:var(--white);background:var(--white);}.custom-intro__scroll-btn:after,.neighborhood-intro__scroll-btn:after,.blog-post-intro__scroll-btn:after,.agent-intro__scroll-btn:after{background:var(--primary);}.custom-intro__scroll-btn:hover,.neighborhood-intro__scroll-btn:hover,.blog-post-intro__scroll-btn:hover,.agent-intro__scroll-btn:hover{border-color:var(--white);background:transparent;}.custom-intro__scroll-btn:hover:after,.neighborhood-intro__scroll-btn:hover:after,.blog-post-intro__scroll-btn:hover:after,.agent-intro__scroll-btn:hover:after{background:var(--white);}.lp-title-group{max-width:1400px;}.lp-lightbox__close{border-color:var(--white)!important;background:var(--white)!important;color:var(--primary)!important;-webkit-transition:all 0.3s ease;transition:all 0.3s ease;}.lp-lightbox__close:hover{color:var(--white)!important;background:transparent!important;}.lp-lightbox__close:hover:after,.lp-lightbox__close:hover:before{background-color:var(--white);}.lp-lightbox.show .lp-lightbox-arrow{border-color:var(--white);background:var(--white)!important;}.lp-lightbox.show .lp-lightbox-arrow:before{border-color:var(--primary)!important;}.lp-lightbox.show .lp-lightbox-arrow:hover{background-color:transparent!important;}.lp-lightbox.show .lp-lightbox-arrow:hover:before{border-color:var(--white)!important;}li[class^="paginationjs"]{--lp-color-primary-2:#fff;}footer#global-footer a:not(.lp-socials__link){color:var(--dark);-webkit-transition:0.4s;transition:0.4s;--lp-color-secondary-gray-600:var(--light-gray);}footer#global-footer a:not(.lp-socials__link):hover,footer#global-footer a:not(.lp-socials__link):focus{color:var(--dark);--lp-color-primary-accent:var(--primary);}.footer-navigation__item+.footer-navigation__item{border-left:1px solid #fff;}.footer-navigation__item{text-transform:uppercase;}.footer-info{border-right:1px solid #fff;}.footer-contact-row{border-bottom:1px solid #fff;}@media (max-width: 768px){.footer-bottom-row{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:16px;}}@media (max-width: 768px){.footer-copyright{width:100%;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;
31-webkit-justify-content:space-between;justify-content:space-between;gap:16px;}.footer-copyright__powered,.footer-copyright__privacy{-webkit-flex-basis:calc((100% / 2) - 16px + (16px / 2));-ms-flex-preferred-size:calc((100% / 2) - 16px + (16px / 2));flex-basis:calc((100% / 2) - 16px + (16px / 2));}}@media (max-width: 768px){.footer-copyright__powered,.footer-copyright__privacy{-webkit-flex-basis:calc((100% / 2) - 16px + (16px / 2));-ms-flex-preferred-size:calc((100% / 2) - 16px + (16px / 2));flex-basis:calc((100% / 2) - 16px + (16px / 2));}}.footer-logos-row .footer-logo{max-height:100px;}@media (max-width: 768px){.footer-logos-row .footer-logo{max-width:180px;}}.footer__col-content{max-width:300px;}@media only screen and (max-width: 768px){.footer__section-content{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:30px;}.footer-navigation{gap:10px;}}.footer__col-description{max-width:unset!important;}.footer-navigation__link:hover{cursor:pointer;}@media (max-width:768px){.lp-socials{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}}@media (max-width:768px){.footer-navigation__item+.footer-navigation__item,.footer-info,.footer-copyright__privacy{border:none!important;}}.lp-btn{white-space:inherit!important;}@media (max-width: 400px){h2{font-size:28px!important;}h1{font-size:32px!important;}}</style>
32    <style id="wow-hide-elements">.wow{visibility:hidden!important}</style>
33        <style id="page-css">
34            #section-2d2580ef-5c09-4535-96fc-598bf76a02df{color:#c0c0c0;--fontColor:#c0c0c0;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:75%;--fontColor_A:1;--fontColor_darkenDir:-1;--bgColor:#ffffff;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;background-color:#ffffff;--gradient-color:var(--overlay-color, rgba(0, 0, 0, 0.00));background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');background-repeat:no-repeat;-webkit-background-position:center;background-position:center;-webkit-background-size:cover;background-size:cover;}@media (min-width: 960px) and (orientation: landscape){#section-2d2580ef-5c09-4535-96fc-598bf76a02df{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');}}@media (min-width: 1280px) and (orientation: landscape){#section-2d2580ef-5c09-4535-96fc-598bf76a02df{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');}}@media (min-width: 1920px) and (orientation: landscape){#section-2d2580ef-5c09-4535-96fc-598bf76a02df{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');}}@media (min-width: 2560px) and (orientation: landscape){#section-2d2580ef-5c09-4535-96fc-598bf76a02df{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c');}}#section-38f572f9-08ff-41a8-be87-094800542ec9{color:#1A1A1A;--fontColor:#1A1A1A;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:10%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:#ffffff;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;background-color:#ffffff;}#section-38f572f9-08ff-41a8-be87-094800542ec9 .contact-form__container{background:var(--primary);color:var(--text-input);}#section-8a4a6b14-8bd9-4c11-bcb3-41a529fb04d0{color:#000;--fontColor:#000;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:0%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:#fff;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;--section-padding-top:calc(0 / 4 * var(--global-section-padding));background-color:#fff;}#section-8a4a6b14-8bd9-4c11-bcb3-41a529fb04d0 h3{text-align:center;}#section-8a4a6b14-8bd9-4c11-bcb3-41a529fb04d0>div:last-child{padding-top:calc(0 / 4 * var(--global-section-padding))!important;}
34#section-bdc20bac-df92-415d-b33f-0bbba2991620{color:#1a1a1a;--fontColor:#1a1a1a;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:10%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:#ffffff;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;background-color:#ffffff;}body>div.sidemenu{background-color:rgba(255, 255, 255, 1);color:rgba(54, 69, 79, 1);--fontColor:rgba(54, 69, 79, 1);--fontColor_H:204;--fontColor_S:19%;--fontColor_L:26%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:rgba(255, 255, 255, 1);--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;}footer{background-color:rgba(255, 255, 255, 1);color:rgba(26, 26, 26, 1);--fontColor:rgba(26, 26, 26, 1);--fontColor_H:0;--fontColor_S:0%;--fontColor_L:10%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:rgba(255, 255, 255, 1);--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;}
35        </style>
36    <style id="custom-style-css">.social_icons-style-1 a{border-color:#36454F!important;background-color:#36454F!important;color:rgba(255, 255, 255, 1)!important;}.social_icons-style-1 a:hover{border-color:#C5A565!important;background-color:#C5A565!important;color:#FFFFFF!important;}.social_icons-style-1 a i{color:inherit!important;}
36.social_icons-style-1 a svg,.social_icons-style-1 a svg path{fill:currentColor!important;}.button-style-1{color:rgba(255, 255, 255, 1)!important;background-color:#36454F!important;border-color:#36454F!important;}.button-style-1:hover{color:#36454F!important;background-color:rgba(0, 0, 0, 0)!important;border-color:#36454F!important;}.hyperlink-style-1{color:rgba(26, 26, 26, 1)!important;}.hyperlink-style-1:hover{color:#C5A565!important;}.pagination-style-1 li a{color:rgba(255, 255, 255, 1)!important;background-color:#36454F!important;border-color:#36454F!important;}.pagination-style-1 li a:hover{color:#36454F!important;background-color:rgba(0, 0, 0, 0)!important;border-color:#36454F!important;}.pagination-style-1 li.active a{color:#36454F!important;background-color:rgba(0, 0, 0, 0)!important;border-color:#36454F!important;}.button-style-2{color:#36454F!important;background-color:#FFFFFF!important;border-color:#FFFFFF!important;}.button-style-2:hover{color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:#FFFFFF!important;}.social_icons-style-2 a{border-color:rgba(255, 255, 255, 1)!important;background-color:#FFFFFF!important;color:#36454F!important;}.social_icons-style-2 a:hover{border-color:#FFFFFF!important;background-color:rgba(255, 255, 255, 1)!important;color:#C5A565!important;}.social_icons-style-2 a i{color:inherit!important;}
36.social_icons-style-2 a svg,.social_icons-style-2 a svg path{fill:currentColor!important;}.pagination-style-2 li a{color:#36454F!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(0, 0, 0, 0)!important;}.pagination-style-2 li a:hover{color:#FFFFFF!important;background-color:#36454F!important;border-color:#36454F!important;}.pagination-style-2 li.active a{color:#FFFFFF!important;background-color:#36454F!important;border-color:#36454F!important;}.hyperlink-style-2{color:rgba(255, 255, 255, 1)!important;}.hyperlink-style-2:hover{color:#C5A565!important;}.button-style-3{color:#36454F!important;background-color:#FFFFFF!important;border-color:#36454F!important;}.button-style-3:hover{color:#FFFFFF!important;background-color:#36454F!important;border-color:#36454F!important;}.hyperlink-style-3{color:#36454F!important;}.hyperlink-style-3:hover{color:#C5A565!important;}</style>
37
38
39        
39<script>
40            (function utmParse() {
41                const url = new URL(window.location.href);
42                if (url.search) {
43                    const utm = url.search.split(/\?|&/g).reduce((acc, current) => {
44                        const matched = current.match(/utm_(content|campaign|medium|source|term|id)|gclid/g);
45                        if (matched) {
46                        acc[matched[0]] = current.replace(`${matched[0]}=`, '');
47                        }
48                        return acc;
49                    }, {});
50                    if (Object.keys(utm).length) {
51                        window.localStorage.setItem('utm_vars', JSON.stringify(utm));
52                    } else {
53                        // Remove old utm vars
54                        window.localStorage.removeItem('utm_vars');
55                    }
56                }
57                // Set referrer in local storage
58                // This is meant to be stored once to avoid self-referrals and to have the first referrer only.
59                if (!window.localStorage.getItem('referrer')) {
60                    // Capture the Referrer URL
61                    const referrer = document.referrer;
62                    if (referrer) {
63                        // Only store the referrer if it comes from outside the current domain (to avoid self-referrals)
64                        const currentDomain = window.location.hostname;
65                        const referrerDomain = new URL(referrer).hostname;
66
67                        if (referrerDomain !== currentDomain) {
68                            // Store it in localStorage
69                            localStorage.setItem('referrer', referrer);
70                        }
71                    }
72                }
73            })();
74        </script>
74
75        <!-- Bing Webmaster Tools Verification -->
76<script>
77// Check if on the homepage before the body loads
78if (window.location.pathname === '/' || window.location.pathname === '/index.html') {
79document.write('<meta name="msvalidate.01" content="18166674FE9A03570D2BCFB935D429DC" />');
80}
81</script>
81
82    <!-- GOOGLE TRANSLATE STYLES are moved to external CSS -->
83</head>
84<body>
85    <div id="google_translate_element" style="display: none"></div>
86
87        <nav id="global-navbar" data-el-id="3242b8f0-253e-46f7-b814-162ccf958ec2">
88            
89<header class="header js-header" style="--textColor: rgba(255, 255, 255, 1); --backgroundColor: rgba(26, 26, 26, 1);">
90  <div class="header-container ">
91    
92    <a href="/" class="header-logo">
93      <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=2560/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 2560w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=3456/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 3456w" sizes="350px" alt="Company logo" class="header-logo__img header-logo__img--dark">
94      <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=2560/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 2560w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=3456/https://media-production.lp-cdn.com/media/b3c9faf9-995c-4ed7-83e3-cc759c40dc93 3456w" sizes="350px" alt="Company logo" class="header-logo__img header-logo__img--light">
95    </a>
96
97    <ul class="header-navigation">
98      <li class="header-navigation__item ">
99        
100        <a class="header-navigation__link "  href="/neighborhoods"  style="--delay: 0s">Neighborhoods</a>
101      </li>
102      <li class="header-navigation__item ">
103        
104        <a class="header-navigation__link "  href="/team"  style="--delay: 0.1s">About</a>
105      </li>
106      <li class="header-navigation__item ">
107        
108        <a class="header-navigation__link "  href="/home-search/listings"  style="--delay: 0.2s">Home Search</a>
109      </li>
110      <li class="header-navigation__item ">
111        
112        <a class="header-navigation__link "  href="/home-valuation"  style="--delay: 0.30000000000000004s">Home Valuation</a>
113      </li>
114      <li class="header-navigation__item ">
115        
116        <a class="header-navigation__link "  href="/properties"  style="--delay: 0.4s">Portfolio</a>
117      </li>
118      <li class="header-navigation__item ">
119        
120        <a class="header-navigation__link "  data-type="CONTACT_US" tabindex="0" style="--delay: 0.5s">Contact Us</a>
121      </li>
122    </ul>
123
124
125    <div class="header-buttons-wrapper">
126
127
128
129      <button type="button" class="header-hamburger-btn lp-btn hamburger-component hamburger js-sidemenu-opener"
130        title="Toggle Sidemenu"></button>
131    </div>
132  </div>
133
134</header>
135
136        </nav>
137        <div id="global-sidemenu" class="sidemenu" data-el-id="033c3235-a8bd-45bf-a4a8-96977e33190d">
138            
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154<button class="sidemenu-close toggle close lp-btn lp-icon link-icon--plus"></button>
155
156
157<div class="sidemenu-wrapper sidemenu-wrapper--small" style="--navItemNumberColor: rgba(197, 165, 101, 1);">
158    <div class="sidemenu-nav-holder ">
159        <ul class="sidemenu-navigation sidemenu-navigation--index">
160                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
161                            <a  
162                                href="/" 
163                                class="sidemenu-navigation__link">Home</a>
164                
165                    </li>
166                  
167                    <li class="sidemenu-navigation__item js-idemenu-navigation-item sidemenu-navigation__item--sub-nav">
168                            <span class="sidemenu-navigation__link sidemenu-navigation__link--sub-nav sidemenu-navigation__link--sub-nav-active js-sub-nav-opener lp-icon">
169                                About
170                            </span>
171                
172                        <ul class="sidemenu-navigation-sub-nav lp-a">
173                            <li class="sidemenu-navigation-sub-nav__item"><a  href="/team" class="sidemenu-navigation-sub-nav__link">Meet the Team</a></li>
174                            <li class="sidemenu-navigation-sub-nav__item"><a  href="/testimonials" class="sidemenu-navigation-sub-nav__link">Testimonials</a></li>
175                        </ul>
176                    </li>
177                  
178                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
179                            <a  
180                                href="/home-search" 
181                                class="sidemenu-navigation__link">Home Search</a>
182                
183                    </li>
184                  
185        </ul>
186
187        <ul class="sidemenu-navigation sidemenu-navigation--index">
188                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
189                            <a  
190                                href="/home-valuation" 
191                                class="sidemenu-navigation__link">Home Valuation</a>
192                
193                    </li>
194                  
195                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
196                            <a  
197                                href="/properties" 
198                                class="sidemenu-navigation__link">Portfolio</a>
199                
200                    </li>
201                  
202                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
203                            <a  
204                                href="/neighborhoods" 
205                                class="sidemenu-navigation__link">Neighborhoods</a>
206                
207                    </li>
208                  
209        </ul>
210
211        <ul class="sidemenu-navigation sidemenu-navigation--index">
212                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
213                            <a  
214                                href="/blog" 
215                                class="sidemenu-navigation__link">Blog</a>
216                
217                    </li>
218                  
219                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
220                            <a  
221                                href="/vlog" 
222                                class="sidemenu-navigation__link">Vlog</a>
223                
224                    </li>
225                  
226                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
227                            <a  
228                               target="_blank" href="https://www.inspiredlifescapes.com/" 
229                                class="sidemenu-navigation__link">Inspired Lifescapes</a>
230                
231                    </li>
232                  
233        </ul>
234
235        <ul class="sidemenu-navigation sidemenu-navigation--index">
236                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
237                            <a  
238                                href="/contact" 
239                                class="sidemenu-navigation__link">Contact Us</a>
240                
241                    </li>
242                  
243                    <li class="sidemenu-navigation__item js-idemenu-navigation-item ">
244                            <a  
245                                href="/home-search/auth/sign_in" 
246                                class="sidemenu-navigation__link">My Search Portal</a>
247                
248                    </li>
249                  
250        </ul>
251    </div>
252
253    <div class="sidemenu-footer">
254        <div class="sidemenu__info-group sidemenu__col">
255                    <div class="sidemenu__section-content">
256                                <div class="sidemenu__col-content">
257                                <p class="sidemenu__col-title">Contact</p><div class="sidemenu__col-description lp-a">
258                                        <p class="sidemenu__col-agent-name">Carrie Haymond Group</p>
259                                        <a href="tel:(206) 512-0850" class="sidemenu__col-phone">(206) 512-0850</a>
260                                        <a href="/cdn-cgi/l/email-protection#781b190a0a111d1019011517161c381b1a1a191116561b1715" class="sidemenu__col-email"><span class="__cf_email__" data-cfemail="77141605051e121f160e1a18191337141515161e195914181a">[email&#160;protected]</span></a>
261                                    </div>
262                                </div>
263                                <div class="sidemenu__col-content">
264                                <p class="sidemenu__col-title">Office</p>                <div class="sidemenu__col-description lp-a sidemenu__col-description--pre-line"><p>150 Bellevue Way SE<br>Bellevue WA 98004 &nbsp; &nbsp;</p></div>
265                                        
266                                </div>
267                    </div>
268                    
269        </div>
270
271            <div class="sidemenu-socials-block">
272                <p class="sidemenu__col-title">Follow Us</p>
273                    <ul class="lp-socials social_icons-style-1">
274                    
275                            <li>
276                              <a
277                                href="https://www.facebook.com/CarrieSeattleInspiredLifescapes"
278                                class="lp-socials__link"
279                                data-wow-delay="0s"
280                                target="_blank"
281                                aria-label="FACEBOOK"
282                              >
283                                  <span class="lp-i lp-i--facebook" aria-hidden="true"></span>
284                              </a>
285                            </li>
286                            <li>
287                              <a
288                                href="https://www.instagram.com/carriethebroker/"
289                                class="lp-socials__link"
290                                data-wow-delay="0.1s"
291                                target="_blank"
292                                aria-label="INSTAGRAM"
293                              >
294                                  <span class="lp-i lp-i--instagram" aria-hidden="true"></span>
295                              </a>
296                            </li>
297                            <li>
298                              <a
299                                href="https://www.linkedin.com/in/carriehaymond/"
300                                class="lp-socials__link"
301                                data-wow-delay="0.2s"
302                                target="_blank"
303                                aria-label="LINKEDIN"
304                              >
305                                  <span class="lp-i lp-i--linkedin" aria-hidden="true"></span>
306                              </a>
307                            </li>
308                            <li>
309                              <a
310                                href="https://www.youtube.com/@carriehaymond8746"
311                                class="lp-socials__link"
312                                data-wow-delay="0.3s"
313                                target="_blank"
314                                aria-label="YOUTUBE"
315                              >
316                                  <span class="lp-i lp-i--youtube" aria-hidden="true"></span>
317                              </a>
318                            </li>
319                            <li>
320                              <a
321                                href="https://x.com/carrieseattle"
322                                class="lp-socials__link"
323                                data-wow-delay="0.4s"
324                                target="_blank"
325                                aria-label="TWITTER"
326                              >
327                                  <span class="lp-i lp-i--twitter" aria-hidden="true"></span>
328                              </a>
329                            </li>
330                            <li>
331                              <a
332                                href="https://www.pinterest.com/carrieseattle1/"
333                                class="lp-socials__link"
334                                data-wow-delay="0.5s"
335                                target="_blank"
336                                aria-label="PINTEREST"
337                              >
338                                  <span class="lp-i lp-i--pinterest" aria-hidden="true"></span>
339                              </a>
340                            </li>
341                            <li>
342                              <a
343                                href="https://www.zillow.com/profile/CarrieHaymond"
344                                class="lp-socials__link"
345                                data-wow-delay="0.6s"
346                                target="_blank"
347                                aria-label="ZILLOW"
348                              >
349                                  <span class="lp-i lp-i--zillow" aria-hidden="true"></span>
350                              </a>
351                            </li>
352                      </ul>            </div>
353    </div>
354</div>
355        </div>
356        <div  id="global-mobile-contact" class="mobile-contact-wrapper" data-el-id="4c08210d-8fa1-4e4b-ad13-3209994c2ceb">
357            <div class="floating-contact-button">
358  <div class="floating-contact-button__btn-holder js-btn-holder"
359    style="--backgroundColor: rgba(238, 237, 233, 1); --textColor: rgba(26, 26, 26, 1);  --pillTextColor: rgba(255, 255, 255, 1); --pillBackgroundColor: rgba(54, 69, 79, 1);">
360    <button type="button" class="floating-contact-button__btn-connect js-btn-connect lp-icon lp-ico-arrow-top">Let&#x27;s Connect</button>
361  </div>
362
363  <div class="floating-contact-button-pop-up js-pop-up" style="--backgroundColor: rgba(238, 237, 233, 1); --textColor: rgba(26, 26, 26, 1);">
364      <form class="floating-contact-button-pop-up__form js-form" data-type="contact-form">
365          <h3 class="floating-contact-button-pop-up__title">Leave a Message</h3>
366
367        <div class="floating-contact-button-pop-up__input-group lp-input-group">
368          <input id="__FullName" type="text" name="name"
369            class="lp-input js-input-name lp-input--light"
370            required placeholder="Full Name">
371        </div>
372        
373        <div class="floating-contact-button-pop-up__input-group lp-input-group">
374          <input id="__Email" type="email" name="email"
375            class="lp-input js-email-input "
376            required placeholder="Email">
377        </div>
378        
379        <div class="floating-contact-button-pop-up__input-group lp-input-group">
380          <input class="lp-input " type="tel" placeholder="Phone" id="__Phone"
381            name="phone" required>
382        </div>
383        
384        <select name="interest" id="-field-interest"
385          class="floating-contact-button-pop-up__input-group lp-input js-select " required>
386          <option value="" selected disabled data-label="Interest">Interested in...</option>
387          <option value="Selling &amp; Buying">Selling &amp; Buying</option>
388          <option value="Selling">Selling</option>
389          <option value="Buying">Buying</option>
390          <option value="Renting">Renting</option>
391          <option value="Other">Other</option>
392          <label for="-field-interest" class="lp-label sr-only">Interest</label>
393        </select>
394        
395        <div class="floating-contact-button-pop-up__input-group lp-input-group">
396          <textarea name="message" rows="4" id="__Message" class="lp-input "
397            placeholder="Message" required></textarea>
398        </div>
399        
400        <div class="lp-disclaimer">  <label style='display: none;' for='-termsAccepted'>Opt In/Disclaimer Consent:</label>
401  <label class='lp-tcr-content'>
402    <span class='lp-tcr-checkbox'>
403      <input
404        type='checkbox'
405        id='-termsAccepted'
406        name='termsAccepted'
407        oninvalid="this.setCustomValidity('Please accept the terms and conditions')"
408        oninput="this.setCustomValidity('')"
409        required
410      /></span>
411    <span class='lp-tcr-message'>
412      
413        I agree to be contacted by
414        Carrie Haymond
415        via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance.
416        You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary.
417        <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>.
418    </span>
419  </label>
420
421</div>
422        
423        <button type="submit" class="floating-contact-button-pop-up__btn-submit lp-btn lp-btn--mob-full-width button-style-1">Submit</button>
424
425        <div class="lp-h-pot">
426          <input id="__newsSignMiddleName" name="middleName" value="" autocomplete="off"
427            tabindex="-1">
428        </div>
429        <input style="display: none;" type="text" name="source" value="CONTACT_INQUIRY" />
430        <input type="hidden" name="button_text" value="Let&#x27;s Connect">
431      </form>
432
433      <div class="floating-contact-button-pop-up__success js-success">
434          <h3 class="floating-contact-button-pop-up__title">Thank you for your message. We will be in touch with you shortly.</h3>
435
436                <a
437                    href="/properties"
438                    
439                    class="lp-btn floating-contact-button-pop-up__success-btn button-style-1"
440                    
441                    
442                    
443                    
444                    
445                    >
446                            Explore Our Properties
447                    </a>
448      </div>
449    <button type="button" class="floating-contact-button-pop-up__close js-close-btn lp-icon"></button>
450  </div>
451</div>
452
453        </div>
454        <section  class="image-section is-font-color-light is-background-color-light" id="section-2d2580ef-5c09-4535-96fc-598bf76a02df" data-el-id="d1637c2a-e69e-42d9-8d39-7fe5c68c7ee9">
455    <div class="custom-intro js-scroll-section custom-intro__horizon-center"
456    style="
457        --titleColor: rgba(177, 132, 99, 1);
458        --boxBackColor: rgba(26, 26, 26, 1);
459        --backOverlayColor: rgba(255, 255, 255, 1);
460    "
461    >
462    <div class="custom-intro__container">
463        <div class="custom-intro__content-wrapper">
464                <div class="custom-intro__content-box">
465                        <h1 class="custom-intro__title ">Contact Us</h1>
466                    <div class="custom-intro__scroll-btn jsScrollBtn"></div>
467                </div>
468        </div>
469    </div>
470</div>
471
472</section>
473<section id="section-38f572f9-08ff-41a8-be87-094800542ec9"  class="solid-section is-font-color-dark is-background-color-light" data-el-id="ebc5d50e-a4a6-419c-8f09-726c01970aad">
474  <div class="contact-form lp-vertical-paddings">
475  <div class="contact-form__container">
476  <div class="contact-form__title-group lp-title-group">
477    <h2 class="contact-form__title">Get in Touch</h2>
478    
479  </div>
480  <form action="" class="contact-form__form js-form" data-type="contact-form">
481    <div class="lp-h-pot">
482      <label for="section-38f572f9-08ff-41a8-be87-094800542ec9-if-middleName">Middle Name</label>
483      <input id="section-38f572f9-08ff-41a8-be87-094800542ec9-if-middleName" name="middleName" value="" autocomplete="off" tabindex="-1">
484    </div>
485    <div class="contact-form__group">
486      <div class="contact-form__group-container lp-input-group">
487        <input required id="section-38f572f9-08ff-41a8-be87-094800542ec9-name" name="name" type="text" class="contact-form__input lp-input js-input-name"
488          placeholder="Enter Your Full Name">
489        <label for="section-38f572f9-08ff-41a8-be87-094800542ec9-name" class="contact-form__label lp-label">Name</label>
490      </div>
491      <div class="contact-form__group-container lp-input-group">
492        <input required id="section-38f572f9-08ff-41a8-be87-094800542ec9-phone" name="phone" type="tel" class="contact-form__input lp-input"
493          placeholder="Your Phone">
494        <label for="section-38f572f9-08ff-41a8-be87-094800542ec9-phone" class="contact-form__label lp-label">Phone</label>
495      </div>
496      <div class="contact-form__group-container lp-input-group">
497        <div class="contact-form__input-container">
498          <input required id="section-38f572f9-08ff-41a8-be87-094800542ec9-email" name="email" type="email" class="contact-form__input lp-input js-email-input"
499            placeholder="@">
500          <div class="contact-form__error error">Enter a valid email</div>
501        </div>
502
503        <label for="section-38f572f9-08ff-41a8-be87-094800542ec9-email" class="contact-form__label lp-label">Email</label>
504      </div>
505    </div>
506
507    <div class="contact-form__input-group lp-input-group">
508      <textarea id="section-38f572f9-08ff-41a8-be87-094800542ec9-message" name="message" class="contact-form__input lp-input"
509        placeholder="Type Your Message"></textarea>
510      <label for="section-38f572f9-08ff-41a8-be87-094800542ec9-message" class="contact-form__label lp-label">Your Message</label>
511    </div>
512    <div class="contact-form__disclaimer lp-disclaimer">  <label style='display: none;' for='section-38f572f9-08ff-41a8-be87-094800542ec9-termsAccepted'>Opt In/Disclaimer Consent:</label>
513  <label class='lp-tcr-content'>
514    <span class='lp-tcr-checkbox'>
515      <input
516        type='checkbox'
517        id='section-38f572f9-08ff-41a8-be87-094800542ec9-termsAccepted'
518        name='termsAccepted'
519        oninvalid="this.setCustomValidity('Please accept the terms and conditions')"
520        oninput="this.setCustomValidity('')"
521        required
522      /></span>
523    <span class='lp-tcr-message'>
524      
525        I agree to be contacted by
526        Carrie Haymond
527        via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance.
528        You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary.
529        <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>.
530    </span>
531  </label>
532
533</div>
534    <button type="submit" class="contact-form-submit lp-btn lp-icon button-style-2">
535      <div class="contact-form-submit__default">
536        <span class="contact-form-submit__content lp-btn__content">Send Message</span>
537      </div>
538      <div class="contact-form-submit__loading">
539        <span class="contact-form-submit__content lp-btn__content">Sending</span>
540      </div>
541      <div class="contact-form-submit__success">
542        <div class="contact-form-submit__content lp-btn__content">Message Sent!</div>
543      </div>
544    </button>
545  </form>
546  
547  </div>
548</div>
549
550</section>
551<section id="section-8a4a6b14-8bd9-4c11-bcb3-41a529fb04d0"  class="solid-section is-font-color-dark is-background-color-light" data-el-id="9e19adb8-cf89-4fae-8080-d1a77c6a3b57">
552  <div class="gallery-style-menu lp-vertical-paddings">
553
554  <div class="gallery-style-menu-grid  gallery-style-menu-grid--3">
555      <a class="gallery-style-menu-grid__item lp_animation-img-zoom"
556 href="/home-search/listings"            >
557
558        <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/04f9d44a-92ee-4fea-b9b2-9662f681b5f9 2000w" alt="Home Search" sizes="(max-width: 768px) 100vw, 50vw" class="gallery-style-menu-grid__image portrait" loading="lazy">
559        <h3 class="gallery-style-menu-grid__title">Home Search</h3>
560      </a>
561      <a class="gallery-style-menu-grid__item lp_animation-img-zoom"
562 href="/home-valuation"            >
563
564        <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/2e9e1444-9f8a-4b42-82a2-311831954c7f 2000w" alt="Home Valuation" sizes="(max-width: 768px) 100vw, 50vw" class="gallery-style-menu-grid__image portrait" loading="lazy">
565        <h3 class="gallery-style-menu-grid__title">Home Valuation</h3>
566      </a>
567      <a class="gallery-style-menu-grid__item lp_animation-img-zoom"
568 href="/team"            >
569
570        <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/4cf8e5d7-33c6-4cf5-abb3-b07272e1095a 2000w" alt="Meet The Team" sizes="(max-width: 768px) 100vw, 50vw" class="gallery-style-menu-grid__image portrait" loading="lazy">
571        <h3 class="gallery-style-menu-grid__title">Meet The Team</h3>
572      </a>
573  </div>
574</div>
575</section>
576<section id="section-bdc20bac-df92-415d-b33f-0bbba2991620"  class="solid-section is-font-color-dark is-background-color-light" data-el-id="85dc9e17-a4c7-449c-8890-869fdc11b485">
577  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/[email protected]/dist/css/splide-core.min.css"/>
vendor: 109 bytes, lines 577-578
577
578<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
578<script src="https://cdn.jsdelivr.net/npm/@splidejs/[email protected]/dist/js/splide.min.js"></script>
vendor: 1 bytes, line 578
578
579<script type="text/x-handlebars-template" class="jsIGTemplate">
580    {{#each items}}
581        <a href="{{permalink}}" target="_blank" class="instagram-feed__item lp_animation-img-zoom splide__slide insta-item insta-type-{{mediaType}}">
582          <img class="instagram-feed__image" src="{{#ifEquals mediaType 'VIDEO'}}{{thumbnailUrl}}{{else}}{{mediaUrl}}{{/ifEquals}}" alt="Instagram post by @{{username}}">
583        </a>
584    {{/each}}
585</script>
585
586
587<div class="instagram-feed lp-vertical-paddings">
588    <div class="instagram-feed__container" style="--titleColor: #B18463; --boxColor: rgba(238, 237, 233, 1);">
589        <div class="instagram-feed__title-group lp-title-group">
590            <div class="instagram-feed__icon lp-icon"></div>
591            <p class="instagram-feed__pretitle">Follow Us On Instagram</p>
592            <h2 class="instagram-feed__title instagram-feed__title--with-pretitle"><a href="#" target="_blank" class="instagram-feed__link jsIGLink jsIGName"></a></h2>
593        </div>
594
595        <div class="instagram-feed__collection splide js-slider">
596          <div class="splide__track">
597              <ul class="splide__list jsIGContainer">
598              </ul>
599          </div>
600        </div>
601    </div>
602</div>
603
604
605
606
607</section>
608
609        <div id="modals" class="modals"></div>
610        <footer id="global-footer" class="is-font-color-dark is-background-color-light" data-el-id="b8c9ffd0-3b1f-4577-96fc-828efdac86e7">
611            
612
613<div class="footer"> 
614        <div class="footer-logos-row">
615            <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1920/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=2560/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 2560w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=3456/https://media-production.lp-cdn.com/media/563f4413-7569-4756-ab7a-523457967f6a 3456w" class="footer-logo" sizes="350px" alt="">
616            
617        </div>
618    <div class="footer-contact-row">
619        <div class="footer-info ">
620                    <div class="footer__col">
621                        <h5 class="footer__section-title">Carrie Haymond Group</h5>
622                        <div class="footer__section-content">
623                                <div class="footer__col-content">
624                                    <p class="footer__col-title">Contact</p>                <div class="footer__col-description lp-a lp-pre-line"><div><a href="tel:2065120850">(206) 512-0850</a><br><a href="/cdn-cgi/l/email-protection#ec8f8d9e9e8589848d9581838288ac8f8e8e8d8582c28f8381"><span class="__cf_email__" data-cfemail="6c0f0d1e1e0509040d15010302082c0f0e0e0d0502420f0301">[email&#160;protected]</span></a></div></div>
625                                </div>
626                            
627                                <div class="footer__col-content">
628                                    <p class="footer__col-title">Office</p>                <div class="footer__col-description lp-a lp-pre-line"><p>150 Bellevue Way SE <br>Bellevue WA 98004 &nbsp; &nbsp;</p></div>
629                                </div>
630                        </div>
631                    </div>
632                
633                
634                
635        </div>
636
637            <ul class="lp-socials social_icons-style-1 footer-socials">
638            
639                    <li>
640                      <a
641                        href="https://www.facebook.com/CarrieSeattleInspiredLifescapes"
642                        class="lp-socials__link socials__link"
643                        data-wow-delay="0s"
644                        target="_blank"
645                        aria-label="FACEBOOK"
646                      >
647                          <span class="lp-i lp-i--facebook" aria-hidden="true"></span>
648                      </a>
649                    </li>
650                    <li>
651                      <a
652                        href="https://www.instagram.com/carriethebroker/"
653                        class="lp-socials__link socials__link"
654                        data-wow-delay="0.1s"
655                        target="_blank"
656                        aria-label="INSTAGRAM"
657                      >
658                          <span class="lp-i lp-i--instagram" aria-hidden="true"></span>
659                      </a>
660                    </li>
661                    <li>
662                      <a
663                        href="https://www.linkedin.com/in/carriehaymond/"
664                        class="lp-socials__link socials__link"
665                        data-wow-delay="0.2s"
666                        target="_blank"
667                        aria-label="LINKEDIN"
668                      >
669                          <span class="lp-i lp-i--linkedin" aria-hidden="true"></span>
670                      </a>
671                    </li>
672                    <li>
673                      <a
674                        href="https://www.youtube.com/@carriehaymond8746"
675                        class="lp-socials__link socials__link"
676                        data-wow-delay="0.3s"
677                        target="_blank"
678                        aria-label="YOUTUBE"
679                      >
680                          <span class="lp-i lp-i--youtube" aria-hidden="true"></span>
681                      </a>
682                    </li>
683                    <li>
684                      <a
685                        href="https://x.com/carrieseattle"
686                        class="lp-socials__link socials__link"
687                        data-wow-delay="0.4s"
688                        target="_blank"
689                        aria-label="TWITTER"
690                      >
691                          <span class="lp-i lp-i--twitter" aria-hidden="true"></span>
692                      </a>
693                    </li>
694                    <li>
695                      <a
696                        href="https://www.pinterest.com/carrieseattle1/"
697                        class="lp-socials__link socials__link"
698                        data-wow-delay="0.5s"
699                        target="_blank"
700                        aria-label="PINTEREST"
701                      >
702                          <span class="lp-i lp-i--pinterest" aria-hidden="true"></span>
703                      </a>
704                    </li>
705                    <li>
706                      <a
707                        href="https://www.zillow.com/profile/CarrieHaymond"
708                        class="lp-socials__link socials__link"
709                        data-wow-delay="0.6s"
710                        target="_blank"
711                        aria-label="ZILLOW"
712                      >
713                          <span class="lp-i lp-i--zillow" aria-hidden="true"></span>
714                      </a>
715                    </li>
716              </ul>    </div>
717    
718
719        <div class="footer-navigation-row">
720            <p class="footer-navigation-title">navigation</p>
721            
722            <ul class="footer-navigation lp-a">
723                    <li class="footer-navigation__item">
724                            <a  href="/properties" class="footer-navigation__link ">Portfolio</a>
725
726                    </li>
727                    <li class="footer-navigation__item">
728                            <a  href="/neighborhoods" class="footer-navigation__link ">Neighborhoods</a>
729
730                    </li>
731                    <li class="footer-navigation__item">
732                            <a  href="/home-valuation" class="footer-navigation__link ">Home Valuation</a>
733
734                    </li>
735                    <li class="footer-navigation__item">
736                            <a  href="/home-search/listings" class="footer-navigation__link ">Search Homes</a>
737
738                    </li>
739                    <li class="footer-navigation__item">
740
741                            <a data-type="CONTACT_US" type="button" role="button" class="footer-navigation__link " >Contact Us</a>
742                    </li>
743            </ul>
744        </div>
745
746        <div class="footer-navigation-row">
747            <p class="footer-navigation-title">useful items</p>
748            
749            <ul class="footer-navigation lp-a">
750                    <li class="footer-navigation__item">
751                            <a  href="/testimonials" class="footer-navigation__link ">Testimonials</a>
752
753                    </li>
754                    <li class="footer-navigation__item">
755                            <a  href="/dmca-notice" class="footer-navigation__link ">DMCA Notice</a>
756
757                    </li>
758            </ul>
759        </div>
760
761   
762        <div class="footer-disclaimer-row">
763            <div class="footer-disclaimer"><p>
763The property information herein is derived from various sources that may include, but not be limited to, county records and the Multiple Listing Service, and it may include approximations. Although the information is believed to be accurate, it is not warranted and you should not rely upon it without personal verification. Affiliated real estate agents are independent contractor sales associates, not employees. &copy;<span class="auto-year-update">#</span> Coldwell Banker. All Rights Reserved. Coldwell Banker and the Coldwell Banker logo are trademarks of Coldwell Banker Real Estate LLC. The Coldwell Banker&reg; System is comprised of company owned offices which are owned by a subsidiary of Anywhere Advisors LLC and franchised offices which are independently owned and operated. The Coldwell Banker System fully supports the principles of the Fair Housing Act and the Equal Opportunity Act. <img src="https://res.cloudinary.com/luxuryp/images/f_auto,q_auto/g5qzbyky8ifp5w0ex0ik/realtor-eho-logo-07232021-update-dark" alt="" width="25px"></p></div>
764            
765            
766        </div>
767    
768
769    <div class="footer-bottom-row">
770            <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/jnymuan6tigs629jigsz" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/jnymuan6tigs629jigsz 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/jnymuan6tigs629jigsz 390w" class="footer-logo" sizes="350px" alt="">
771
772        <div class="footer-copyright lp-a">
773            <div class="footer-copyright__powered">
774                Powered by <a href="https://www.luxurypresence.com/" class="" target="_blank">Luxury Presence</a>
775            </div>
776            
777            <div class="footer-copyright__privacy">
778                <span>Copyright © <span class="auto-year-update">2026</span></span>
779                
780           
781                <a href="/terms-and-conditions" class="footer-copyright__privacy-policy">Privacy Policy</a>
782            </div>
783        </div>
784    </div>
785
786</div>
787
788        </footer>
789
790        <div id="modal-global-contact-us" class="modal "
791            data-el-id=""
792            style="background-color: ;"
793            >
794            <div class="modal-content">
795                
796        
797        <div class="contact-form-modal lp-vertical-paddings" style="--leftPanelBgColor: rgba(54, 69, 79, 1); --textColor:rgba(255, 255, 255, 1); --formBgColor: rgba(255, 255, 255, 1); --formTextColor: rgba(26, 26, 26, 1)">
798            <div class="contact-form-modal__bg">
799                <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c" srcset="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c 960w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/86a15bdb-75b5-40cb-88f6-2a894b67e21c 1200w" sizes="(min-width: 1981px) 12.2222vw, (min-width: 1025px) 424px, 100vw" class="contact-form-modal__bg-image" alt="">
800            </div>
801            <div class="contact-form-modal__close-container">
802                <button class="contact-form-modal__close toggle close lp-btn lp-icon link-icon--plus"></button>
803            </div>
804            <div class="contact-form-modal__container">
805                  <div class="contact-form-modal-details only-desktop">
806                        <h2 class="contact-form-modal-details__title only-desktop js-contact-title">Get in Touch</h2>
807                        <div class="contact-form-modal-agent">
808                            <div class="contact-form-modal-agent__contact">    
809                                <p class="contact-form-modal-agent__name">Carrie Haymond Group</p>
810                                <p class="contact-form-modal-agent__phone lp-a">
811                                  <a class="contact-form-modal-agent__link" href="tel:(206) 512-0850">(206) 512-0850</a>
812                                </p>
813                                <p class="contact-form-modal-agent__email lp-a">
814                                  <a class="contact-form-modal-agent__link" href="/cdn-cgi/l/email-protection#bddedccfcfd4d8d5dcc4d0d2d3d9fddedfdfdcd4d393ded2d0"><span class="__cf_email__" data-cfemail="2e4d4f5c5c474b464f574341404a6e4d4c4c4f4740004d4143">[email&#160;protected]</span></a>
815                                </p>
816                            </div>
817                            <div class="contact-form-modal-agent__contact">
818                                <p class="contact-form-modal-agent__addres lp-pre-line">150 Bellevue Way SE
819                Bellevue WA 98004</p>
820                            </div>
821                        </div>
822                
823                        
824                        
825                
826                        <div class="contact-form-modal-details__socials">
827                            <ul class="lp-socials social_icons-style-2 contact-form-modal-details__socials-l
827ist lp-socials">
828                            
829                                    <li>
830                                      <a
831                                        href="https://www.facebook.com/CarrieSeattleInspiredLifescapes"
832                                        class="lp-socials__link contact-form-modal-details__socials-link"
833                                        data-wow-delay="0s"
834                                        target="_blank"
835                                        aria-label="FACEBOOK"
836                                      >
837                                          <span class="lp-i lp-i--facebook" aria-hidden="true"></span>
838                                      </a>
839                                    </li>
840                                    <li>
841                                      <a
842                                        href="https://www.instagram.com/carriethebroker/"
843                                        class="lp-socials__link contact-form-modal-details__socials-link"
844                                        data-wow-delay="0.1s"
845                                        target="_blank"
846                                        aria-label="INSTAGRAM"
847                                      >
848                                          <span class="lp-i lp-i--instagram" aria-hidden="true"></span>
849                                      </a>
850                                    </li>
851                                    <li>
852                                      <a
853                                        href="https://www.linkedin.com/in/carriehaymond/"
854                                        class="lp-socials__link contact-form-modal-details__socials-link"
855                                        data-wow-delay="0.2s"
856                                        target="_blank"
857                                        aria-label="LINKEDIN"
858                                      >
859                                          <span class="lp-i lp-i--linkedin" aria-hidden="true"></span>
860                                      </a>
861                                    </li>
862                                    <li>
863                                      <a
864                                        href="https://www.youtube.com/@carriehaymond8746"
865                                        class="lp-socials__link contact-form-modal-details__socials-link"
866                                        data-wow-delay="0.3s"
867                                        target="_blank"
868                                        aria-label="YOUTUBE"
869                                      >
870                                          <span class="lp-i lp-i--youtube" aria-hidden="true"></span>
871                                      </a>
872                                    </li>
873                                    <li>
874                                      <a
875                                        href="https://x.com/carrieseattle"
876                                        class="lp-socials__link contact-form-modal-details__socials-link"
877                                        data-wow-delay="0.4s"
878                                        target="_blank"
879                                        aria-label="TWITTER"
880                                      >
881                                          <span class="lp-i lp-i--twitter" aria-hidden="true"></span>
882                                      </a>
883                                    </li>
884                                    <li>
885                                      <a
886                                        href="https://www.pinterest.com/carrieseattle1/"
887                                        class="lp-socials__link contact-form-modal-details__socials-link"
888                                        data-wow-delay="0.5s"
889                                        target="_blank"
890                                        aria-label="PINTEREST"
891                                      >
892                                          <span class="lp-i lp-i--pinterest" aria-hidden="true"></span>
893                                      </a>
894                                    </li>
895                                    <li>
896                                      <a
897                                        href="https://www.zillow.com/profile/CarrieHaymond"
898                                        class="lp-socials__link contact-form-modal-details__socials-l
898ink"
899                                        data-wow-delay="0.6s"
900                                        target="_blank"
901                                        aria-label="ZILLOW"
902                                      >
903                                          <span class="lp-i lp-i--zillow" aria-hidden="true"></span>
904                                      </a>
905                                    </li>
906                              </ul>        </div>
907                  </div>
908                    <div class="contact-form-modal-form">
909                        <h2 class="contact-form-modal-form__title only-mobile js-contact-title">Get in Touch</h2>
910                        <form action="" class="contact-form-modal-form__form js-form" data-type="contact-form">
911                            <div class="lp-h-pot">
912                                  <label for="-if-middleName">Middle Name</label>
913                                  <input id="-if-middleName" name="middleName" value="" autocomplete="off" tabindex="-1">
914                            </div> 
915                            <div class="contact-form-modal-form__group">
916                                <div class="contact-form-modal-form__group-container lp-input-group">
917                                    <input required id="-name" name="name" type="text" class="lp-input js-input-name" placeholder="Enter your full name">
918                                    <label for="-name" class="lp-label contact-form-modal-form__label">Name</label>
919                                </div>   
920                                <div class="contact-form-modal-form__group-container lp-input-group">
921                                    <input required id="-phone" name="phone" type="tel" class="lp-input" placeholder="Your phone">
922                                    <label for="-phone" class="lp-label contact-form-modal-form__label">Phone</label>
923                                </div>
924                            </div>
925                            <div class="contact-form-modal-form__group lp-input-group">
926                                <div class="contact-form-modal-form__input-container">
927                                    <input required id="-email" name="email" type="email" class="lp-input js-email-input" placeholder="@">
928                                    <div class="contact-form-modal-form__error error">Enter a valid email</div>
929                                </div>
930                                
931                                <label for="-email" class="contact-form-modal-form__label lp-label">Email</label>
932                            </div>
933                            <div class="contact-form-modal-form__group lp-input-group">
934                                <textarea id="-message" name="message" class="contact-form-modal-form__textarea lp-input" placeholder="Type your message"></textarea>
935                                <label for="-message" class="contact-form-modal-form__label lp-label">Your Message</label>
936                            </div>
937                
938                            <div class="contact-form-modal-form__disclaimer lp-disclaimer">  <label style='display: none;' for='-termsAccepted'>Opt In/Disclaimer Consent:</label>
939                  <label class='lp-tcr-content'>
940                    <span class='lp-tcr-checkbox'>
941                      <input
942                        type='checkbox'
943                        id='-termsAccepted'
944                        name='termsAccepted'
945                        oninvalid="this.setCustomValidity('Please accept the terms and conditions')"
946                        oninput="this.setCustomValidity('')"
947                        required
948                      /></span>
949                    <span class='lp-tcr-message'>
950                      
951                        I agree to be contacted by
952                        Carrie Haymond Group
953                        via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance.
954                        You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary.
955                        <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>.
956                    </span>
957                  </label>
958                
959                </div>
960                
961                            <button type="submit" class="contact-form-modal-submit lp-btn lp-icon button-style-1">
962                                <div class="contact-form-modal-submit__default">
963                                  <span class="contact-form-modal-submit__content lp-btn__content">Send Message</span>
964                                </div>
965                                <div class="contact-form-modal-submit__loading">
966                                  <span class="contact-form-modal-submit__content lp-btn__content">Sending</span>
967                                </div>
968                                <div class="contact-form-modal-submit__success">
969                                  <span class="contact-form-modal-submit__content lp-btn__content">Message Sent!</span>
970                                </div>
971                            </button>
972                        </form>
973                    </div>
974                    
975                  <div class="contact-form-modal-details only-mobile">
976                        <h2 class="contact-form-modal-details__title only-desktop js-contact-title">Get in Touch</h2>
977                        <div class="contact-form-modal-agent">
978                            <div class="contact-form-modal-agent__contact">    
979                                <p class="contact-form-modal-agent__name">Carrie Haymond Group</p>
980                                <p class="contact-form-modal-agent__phone lp-a">
981                                  <a class="contact-form-modal-agent__link" href="tel:(206) 512-0850">(206) 512-0850</a>
982                                </p>
983                                <p class="contact-form-modal-agent__email lp-a">
984                                  <a class="contact-form-modal-agent__link" href="/cdn-cgi/l/email-protection#5c3f3d2e2e3539343d25313332381c3f3e3e3d3532723f3331"><span class="__cf_email__" data-cfemail="5a393b2828333f323b233735343e1a3938383b333474393537">[email&#160;protected]</span></a>
985                                </p>
986                            </div>
987                            <div class="contact-form-modal-agent__contact">
988                                <p class="contact-form-modal-agent__addres lp-pre-line">150 Bellevue Way SE
989                Bellevue WA 98004</p>
990                            </div>
991                        </div>
992                
993                        
994                        
995                
996                        <div class="contact-form-modal-details__socials">
997                            <ul class="lp-socials social_icons-style-2 contact-form-modal-details__socials-list lp-socials">
998                            
999                                    <li>
1000                                      <a
1001                                        href="https://www.facebook.com/CarrieSeattleInspiredLifescapes"
1002                                        class="lp-socials__link contact-form-modal-details__socials-link"
1003                                        data-wow-delay="0s"
1004                                        target="_blank"
1005                                        aria-label="FACEBOOK"
1006                                      >
1007                                          <span class="lp-i lp-i--facebook" aria-hidden="true"></span>
1008                                      </a>
1009                                    </li>
1010                                    <li>
1011                                      <a
1012                                        href="https://www.instagram.com/carriethebroker/"
1013                                        class="lp-socials__link contact-form-modal-details__socials-link"
1014                                        data-wow-delay="0.1s"
1015                                        target="_blank"
1016                                        aria-label="INSTAGRAM"
1017                                      >
1018                                          <span class="lp-i lp-i--instagram" aria-hidden="true"></span>
1019                                      </a>
1020                                    </li>
1021                                    <li>
1022                                      <a
1023                                        href="https://www.linkedin.com/in/carriehaymond/"
1024                                        class="lp-socials__link contact-form-modal-details__socials-l
1024ink"
1025                                        data-wow-delay="0.2s"
1026                                        target="_blank"
1027                                        aria-label="LINKEDIN"
1028                                      >
1029                                          <span class="lp-i lp-i--linkedin" aria-hidden="true"></span>
1030                                      </a>
1031                                    </li>
1032                                    <li>
1033                                      <a
1034                                        href="https://www.youtube.com/@carriehaymond8746"
1035                                        class="lp-socials__link contact-form-modal-details__socials-link"
1036                                        data-wow-delay="0.3s"
1037                                        target="_blank"
1038                                        aria-label="YOUTUBE"
1039                                      >
1040                                          <span class="lp-i lp-i--youtube" aria-hidden="true"></span>
1041                                      </a>
1042                                    </li>
1043                                    <li>
1044                                      <a
1045                                        href="https://x.com/carrieseattle"
1046                                        class="lp-socials__link contact-form-modal-details__socials-link"
1047                                        data-wow-delay="0.4s"
1048                                        target="_blank"
1049                                        aria-label="TWITTER"
1050                                      >
1051                                          <span class="lp-i lp-i--twitter" aria-hidden="true"></span>
1052                                      </a>
1053                                    </li>
1054                                    <li>
1055                                      <a
1056                                        href="https://www.pinterest.com/carrieseattle1/"
1057                                        class="lp-socials__link contact-form-modal-details__socials-link"
1058                                        data-wow-delay="0.5s"
1059                                        target="_blank"
1060                                        aria-label="PINTEREST"
1061                                      >
1062                                          <span class="lp-i lp-i--pinterest" aria-hidden="true"></span>
1063                                      </a>
1064                                    </li>
1065                                    <li>
1066                                      <a
1067                                        href="https://www.zillow.com/profile/CarrieHaymond"
1068                                        class="lp-socials__link contact-form-modal-details__socials-link"
1069                                        data-wow-delay="0.6s"
1070                                        target="_blank"
1071                                        aria-label="ZILLOW"
1072                                      >
1073                                          <span class="lp-i lp-i--zillow" aria-hidden="true"></span>
1074                                      </a>
1075                                    </li>
1076                              </ul>        </div>
1077                  </div>
1078            </div>
1079        </div>
1080        
1081            </div>
1082            <button class="close lp-close" type="button" aria-label="close modal">
1083                <span class="lp-close-icon" aria-hidden="true"></span>
1084            </button>
1085        </div>
1086        <div id="qualifying-questions-modal" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="qualifying-questions-modal-title" aria-hidden="true" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1050; display: none; align-items: center; justify-content: center;">
1087          <style>
1088            #qualifying-questions-modal .custom-select-toggle {
1089              border: 1px solid #848484;
1090              border-radius: 8px;
1091              padding: 12px 16px;
1092            }
1093        
1094            #qualifying-questions-modal .custom-select-toggle.is-placeholder {
1095              color: #848484;
1096            }
1097        
1098            #qualifying-questions-modal #qualifying-questions-modal-phoneNumber::placeholder {
1099              color: #848484;
1100              opacity: 1;
1101            }
1102        
1103            #qualifying-questions-modal .disclaimer-more {
1104              display: none;
1105            }
1106        
1107            #qualifying-questions-modal #qualifying-questions-modal-disclaimer-text:not(.collapsed) .disclaimer-more {
1108              display: inline;
1109            }
1110        
1111            #qualifying-questions-modal #qualifying-questions-modal-disclaimer-text:not(.collapsed) .disclaimer-ellipsis {
1112              display: none;
1113            }
1114          </style>
vendor: 119 bytes, lines 1114-1115
1114
1115          <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
1115<script>
1116            function toggleDisclaimerQualifyingQuestionsModal() {
1117              const disclaimerText = document.getElementById('qualifying-questions-modal-disclaimer-text');
1118              const toggleButton = document.getElementById('qualifying-questions-modal-toggle-disclaimer');
1119        
1120              if (disclaimerText.classList.contains('collapsed')) {
1121                disclaimerText.classList.remove('collapsed');
1122                toggleButton.textContent = 'Read less';
1123                toggleButton.setAttribute('aria-expanded', 'true');
1124              } else {
1125                disclaimerText.classList.add('collapsed');
1126                toggleButton.textContent = 'Read more';
1127                toggleButton.setAttribute('aria-expanded', 'false');
1128              }
1129            }
1130          </script>
1130
1131          <div style="max-width: 400px; width: 95%; margin: 0 auto;">
1132            <div style="background: #fff; border: none; border-radius: 16px; color: black; box-shadow: none; position: relative;">
1133              <button type="button" data-dismiss="modal" aria-label="Close" style="position: absolute; right: 20px; top: 10px; font-size: 28px; font-weight: 300; color: black; opacity: 1; background: none; border: none; padding: 0; width: auto; height: auto; cursor: pointer; z-index: 10;">
1134                <span aria-hidden="true">&times;</span>
1135              </button>
1136              <div style="padding: 40px 30px 32px;">
1137                <div style="text-align: left; margin-bottom: 32px;">
1138                  <h2 id="qualifying-questions-modal-title" style="margin: 0; color: #333; font-size: 18px; line-height: 1.4; text-transform: uppercase; letter-spacing: 0.5px; font-weight: normal;">
1139                    Thanks, please provide more information to help serve you
1140                  </h2>
1141                </div>
1142                <form id="qualifying-questions-modal-form" data-type="contact-form">
1143                  <input type="hidden" name="source" value="PROFILE_UPDATE" />
1144                  <input type="hidden" name="email" value="" id="qualifying-questions-modal-email" />
1145                  <input type="hidden" name="triggerSource" id="qualifying-questions-modal-triggerSource" value="" />
1146                  <label for="qualifying-questions-modal-email" style="display:none;">
1147                    Email
1148                  </label>
1149                  <label for="qualifying-questions-modal-triggerSource" style="display:none;">
1150                    Trigger Source
1151                  </label>
1152        
1153                  <div style="margin-bottom: 20px;">
1154                    <label for="qualifying-questions-modal-phoneNumber" style="display:none;">
1155                      Phone Number
1156                    </label>
1157                    <input
1158                      type="tel"
1159                      id="qualifying-questions-modal-phoneNumber"
1160                      name="phoneNumber"
1161                      style="padding: 12px 16px; font-size: 16px; border: 1px solid #848484; border-radius: 8px; background: transparent; color: black; width: 100%; box-sizing: border-box; outline: none;"
1162                      pattern="^\+?1?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}$"
1163                      required
1164                      placeholder="Phone"
1165                      aria-label="Phone Number"
1166                      inputmode="tel"
1167                      autocomplete="tel"
1168                      onfocus="this.style.borderColor='black';"
1169                      onblur="this.style.borderColor='#848484';"
1170                    />
1171                  </div>
1172        
1173                  <div style="margin-bottom: 20px;">
1174                    <label for="qualifying-questions-modal-interest" style="display:none;">
1175                      Interest
1176                    </label>
1177                    <select
1178                      id="qualifying-questions-modal-interest"
1179                      name="interest"
1180                      required
1181                      data-label="Interest"
1182                      aria-label="Interest"
1183                      style="padding: 12px 16px; font-size: 16px; border: 1px solid #848484; border-radius: 8px; background: #fff; color: #848484; width: 100%; box-sizing: border-box; outline: none; appearance: none; -webkit-appearance: none; -moz-appearance: none; background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 16 16%22%3E%3Cpath fill=%22%23666%22 d=%22M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z%22/%3E%3C/svg%3E'); background-repeat: no-repeat; background-position: right 16px center; background-size: 16px;"
1184                      onfocus="this.style.borderColor='black'; this.style.color='black';"
1185                      onblur="this.style.borderColor='#848484'; if(this.value === '') this.style.color='#848484'; else this.style.color='black';"
1186                    >
1187                      <option value="" style="background: #fff; color: #848484;" disabled selected>Interested in...</option>
1188                      <option value="Selling & Buying" style="background: #fff; color: black;">Selling & Buying</option>
1189                      <option value="Selling" style="background: #fff; color: black;">Selling</option>
1190                      <option value="Buying" style="background: #fff; color: black;">Buying</option>
1191                      <option value="Renting" style="background: #fff; color: black;">Renting</option>
1192                      <option value="Other" style="background: #fff; color: black;">Other</option>
1193                    </select>
1194                  </div>
1195        
1196                  <div style="margin-bottom: 32px; font-size: 12px; line-height: 1.2;">
1197                    <label style='display: none;' for='qualifying-questions-modal-qualifying-questions-termsAccepted'>Opt In/Disclaimer Consent:</label>
1198                    <label class='lp-tcr-content'>
1199                      <span class='lp-tcr-checkbox'>
1200                        <input
1201                          type='checkbox'
1202                          id='qualifying-questions-modal-qualifying-questions-termsAccepted'
1203                          name='termsAccepted'
1204                          aria-describedby='qualifying-questions-modal-disclaimer-text'
1205                          oninvalid="this.setCustomValidity('Please accept the terms and conditions')"
1206                          oninput="this.setCustomValidity('')"
1207                          required
1208                        /></span>
1209                      <span class='lp-tcr-message'>
1210                        <div id="qualifying-questions-modal-disclaimer-text" class="collapsed" style="color: #848484;">
1211                          
1212                            I agree to be contacted by
1213                            <strong>Carrie Haymond</strong>
1214                            via call, email, and text <span class="disclaimer-more">for real estate services. 
1215                            To opt out, you can reply 'stop' at any time or reply 'help' for assistance. 
1216                            You can also click the unsubscribe link in the emails. 
1217                            Message and data rates may apply. Message frequency may vary.</span>
1218                            <span class="disclaimer-ellipsis">...</span>
1219                            <a href='/terms-and-conditions' target='_blank' rel='noopener noreferrer' style='text-decoration: underline;'>Privacy Policy</a>.
1220                        </div>
1221                        <button
1222                          id="qualifying-questions-modal-toggle-disclaimer"
1223                          type="button"
1224                          style="background: none; border: none; color: #848484; font-size: inherit; font-weight: bold; padding: 0; margin-top: 4px; cursor: pointer;"
1225                          aria-expanded="false"
1226                          onclick="toggleDisclaimerQualifyingQuestionsModal()"
1227                        >
1228                          Read more
1229                        </button>
1230                      </span>
1231                    </label>
1232                  </div>
1233        
1234                  <div>
1235                    <button
1236                      type="submit"
1237                      style="padding: 12px 24px; font-size: 16px; font-weight: normal; border-radius: 8px; border: 1px solid black; background: black; color: white; width: 100%; cursor: pointer; transition: all 0.2s ease; text-transform: uppercase; letter-spacing: 0.5px;"
1238                      onmouseover="this.style.background='transparent'; this.style.color='black';"
1239                      onmouseout="this.style.background='black'; this.style.color='white';"
1240                    >
1241                      Submit
1242                    </button>
1243                  </div>
1244                </form>
1245              </div>
1246            </div>
1247          </div>
1248        </div>
1249
1250    
1250<script>
1251        (function() {
1252        var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));
1253
1254        if ("IntersectionObserver" in window && lazyVideos.length > 0) {
1255            var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
1256            entries.forEach(function(video) {
1257                if (video.isIntersecting) {
1258                for (var source in video.target.children) {
1259                    var videoSource = video.target.children[source];
1260                    if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
1261                    videoSource.src = videoSource.dataset.src;
1262                    }
1263                }
1264
1265                video.target.load();
1266                video.target.classList.remove("lazy");
1267                lazyVideoObserver.unobserve(video.target);
1268                }
1269            });
1270            });
1271
1272            lazyVideos.forEach(function(lazyVideo) {
1273                lazyVideoObserver.observe(lazyVideo);
1274            });
1275        }
1276        })();
1277    </script>
1277
1278
1279        <!-- Global site tag (gtag.js) - Google Analytics -->
1280        
1280<script defer src="https://www.googletagmanager.com/gtag/js"></script>
1280
1281
1282            <!-- Google Tag Manager -->
1283            
1283<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
1284                new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
1285                j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.defer=true;j.async=false;j.src=
1286                'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
1287            })(window,document,'script','dataLayer','GTM-T9SFQGHZ');</script>
1287
1288            <!-- End Google Tag Manager -->
1289
1290
1291        <!-- LP Tracker (divolte.js) - LP Divolte -->
1292            
1292<script>window.divolteLp=window.divolteLp||function(){(divolteLp.q=divolteLp.q||[]).push(arguments)}</script>
1292
1293        <!-- LP Tracker (eventBus) - LP EventBus -->
1294            
1294<script>window.eventBusLp=window.eventBusLp||function(){(eventBusLp.q=eventBusLp.q||[]).push(arguments)}</script>
1294
1295
1296    
1296<script>
1297        window.dataLayer = window.dataLayer || [];
1298        document.sendGoogleTagManagerEvent = function() {
1299            /* Honor GPC-enabled browsers and prevent GTM event if GPC is enabled. More details: https://global-privacy-control.glitch.me/ */
1300            if (window.navigator.globalPrivacyControl) {
1301                return;
1302            }
1303
1304            dataLayer.push(arguments);
1305        }
1306
1307        document.sendGoogleTagManagerEvent('js', new Date());
1308            document.sendGoogleTagManagerEvent('config', 'G-N4XPEJXVWV', { page: location.pathname, location: location.href });
1309        document.sendGoogleAnalyticsEvent = function(googleEvent) {
1310            document.sendGoogleTagManagerEvent('event', googleEvent.eventAction || googleEvent.hitType, {
1311                event_category: googleEvent.eventCategory,
1312                event_label: googleEvent.eventLabel,
1313                value: googleEvent.eventValue,
1314                page: googleEvent.page,
1315                location: googleEvent.location
1316            })
1317        };
1318
1319        document.addEventListener("DOMContentLoaded", function() {
1320            (function() {
1321                //If the page has an element with ID of auto-year-update the element will be populated with the current year.
1322                var date = new Date();
1323                var elements = document.getElementsByClassName('auto-year-update');
1324                var i;
1325                for (i = 0; i < elements.length; i++) {
1326                    elements[i].innerText = date.getFullYear();
1327                }
1328            })();
1329            if (window.divolteLp) {
1330                window.divolteLp('sendLpPageView', {});
1331            }
1332            if (window.eventBusLp) {
1333                window.eventBusLp('sendLpPageView', {});
1334            }
1335        });
1336    </script>
1336
1337
1338
1339    
1339<script>
1340    // Function to dynamically load a script
1341    function loadScript(url, callback) {
1342        var script = document.createElement('script');
1343        script.type = 'text/javascript';
1344        script.src = url;
1345        script.defer = true;
1346        script.async = true;
1347        script.onload = callback;
1348        document.head.appendChild(script);
1349    }
1350
1351    // Function to dynamically load CSS file
1352    function loadCSS(url) {
1353        var link = document.createElement("link");
1354        link.rel = "stylesheet";
1355        link.href = url;
1356        document.head.appendChild(link);
1357    }
1358
1359    // Global methods / variables that can be accessed by element js
1360    window.luxuryPresence = {
1361        libs: {
1362            loadJs: loadScript,
1363            loadCss: loadCSS,
1364            jsLibsMap: {
1365                paroller: {
1366                    jsSrc: 'https://d1e1jt2fj4r8r.cloudfront.net/javascript/jquery.paroller.min.js',
1367                    isLoaded: false,
1368                },
1369                ionRangeSlider: {
1370                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js',
1371                    cssSrc: 'https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css',
1372                    isLoaded: false,
1373                    requires: ['jquery'],
1374                },
1375                splide: {
1376                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/splidejs/4.1.4/js/splide.min.js',
1377                    cssSrc: 'https://cdnjs.cloudflare.com/ajax/libs/splidejs/4.1.4/css/splide-core.min.css',
1378                    isLoaded: false,
1379                },
1380                wow: {
1381                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js',
1382                    isLoaded: false,
1383                },
1384                jquery: {
1385                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js',
1386                    isLoaded: false,
1387                },
1388                slick: {
1389                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js',
1390                    isLoaded: false,
1391                    requires: ['jquery'],
1392                },
1393                libphonenumber: {
1394                    jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/libphonenumber-js/1.11.8/libphonenumber-js.min.js',
1395                    isLoaded: false,
1396                },
1397            },
1398        },
1399    };
1400    </script>
1400
1401    
1401<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer" onload="window.luxuryPresence.libs.jsLibsMap.jquery.isLoaded = true"></script>
1401
1402    
1402<script defer src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js"></script>
1402
1403    
1403<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/handlebars-intl.min.js"></script>
1403
1404    
1404<script defer src="https://cdnjs.cloudflare.com/ajax/libs/superagent/4.1.0/superagent.min.js"></script>
1404
1405    
1405<script defer src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js" onload="window.luxuryPresence.libs.jsLibsMap.slick.isLoaded = true"></script>
1405
1406    
1406<script defer src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js" onload="window.luxuryPresence.libs.jsLibsMap.wow.isLoaded = true"></script>
1406
1407    
1407<script defer src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js" onload="window.luxuryPresence.libs.jsLibsMap.ionRangeSlider.isLoaded = true"></script>
1407
1408
1409    <!-- GOOGLE TRANSLATE SCRIPT -->
1410    
1410<script>
1411        function googleTranslateElementInit() {
1412            // list of languages can be overridden by setting window.customLanguages in the head JS. example `window.customLanguages = 'en,de,fr,ro,sk,pl'`
1413            // Language codes can be taken from here https://cloud.google.com/translate/docs/languages
1414            const DEFAULT_LANGUAGES = 'en,es,zh-CN,zh-TW,tl,vi,ar,ko,ru,de,fr,hi,pt';
1415            document.querySelectorAll('[data-type="TRANSLATE"]').forEach(function(translate){
1416                translate.innerText = '';
1417                new google.translate.TranslateElement({
1418                    pageLanguage: 'en',
1419                    layout: google.translate.TranslateElement.InlineLayout.SIMPLE,
1420                    includedLanguages: window.customLanguages || DEFAULT_LANGUAGES,
1421                }, translate);
1422            });
1423        }
1424    </script>
1424
1425    
1425<script defer src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
1425
1426            
1426<script defer src="https://accounts.google.com/gsi/intermediate"></script>
1426
1427
1428    <!-- GOOGLE TRANSLATE SCRIPT END-->
1429    
1429<script>
1430
1431        // UI helpers
1432        (function () {
1433
1434            function getSideMenu () {
1435                return document.querySelector('body > div.sidemenu');
1436            }
1437
1438            function sideMenuHide (instant) {
1439                var sideMenu = getSideMenu();
1440                if (!sideMenu || !sideMenu.classList.contains('visible')) {
1441                  return;
1442                }
1443                sideMenu.classList.remove('visible');
1444                sideMenu.dispatchEvent(new CustomEvent('lpui-hide', { detail: { instant: !!instant } }));
1445                window.dispatchEvent(new CustomEvent('lpui-sidemenu-hide', { detail: {instant: !!instant} }));
1446            }
1447
1448            function sideMenuShow () {
1449                var sideMenu = getSideMenu();
1450                if (!sideMenu || sideMenu.classList.contains('visible')) {
1451                  return;
1452                }
1453                sideMenu.classList.add('visible');
1454                sideMenu.dispatchEvent(new Event('lpui-show'));
1455                window.dispatchEvent(new Event('lpui-sidemenu-show'));
1456            }
1457
1458            function sideMenuToggle () {
1459                var sideMenu = getSideMenu();
1460                if (!sideMenu) {
1461                  return;
1462                }
1463                var isSideMenuVisible = sideMenu.classList.contains('visible');
1464                if (isSideMenuVisible) {
1465                    sideMenuHide();
1466                } else {
1467                    sideMenuShow();
1468                }
1469            }
1470
1471            var scrollLockRequests = {};
1472            window.__debug_scrollLockRequests = scrollLockRequests;
1473            var hideScrollStyles = ''+
1474                    'body {'+
1475                    'overflow: hidden;' +
1476                    '}';
1477            var hideScrollId = 'hide-body-scroll-style';
1478
1479            function scrollLock () {
1480                var style = document.createElement('style');
1481                style.id = hideScrollId;
1482                style.textContent = hideScrollStyles;
1483                document.head.appendChild(style);
1484                window.dispatchEvent(new Event('lpui-scroll-locked'));
1485            }
1486
1487            function scrollUnlock () {
1488                document.getElementById(hideScrollId)?.remove();
1489                window.dispatchEvent(new Event('lpui-scroll-unlocked'));
1490            }
1491
1492            function requestScrollLock (lockId) {
1493                var wasLocked = Object.keys(scrollLockRequests).length > 0;
1494                scrollLockRequests[lockId || '__anonymous_lock'] = true;
1495                if (!wasLocked) {
1496                    scrollLock();
1497                }
1498            }
1499
1500            function releaseScrollLock (lockId) {
1501                if (lockId) {
1502                    delete scrollLockRequests[lockId];
1503                    if (!Object.keys(scrollLockRequests).length) {
1504                        scrollUnlock();
1505                    }
1506                } else {
1507                    scrollLockRequests = {};
1508                    window.__debug_scrollLockRequests = scrollLockRequests;
1509                    scrollUnlock();
1510                }
1511            }
1512
1513            function showModal (modalId, options) {
1514                var modal = document.getElementById(modalId);
1515                if (!modal) {
1516                    return;
1517                }
1518
1519                if (!modal.classList.contains('visible')) {
1520                    modal.classList.add('visible');
1521                    if (options && options.scrollLock) {
1522                        window.lpUI.requestScrollLock(modalId);
1523                    }
1524                    modal.dispatchEvent(new Event('lpui-show'));
1525                    window.dispatchEvent(new CustomEvent('lpui-modal-show', { detail: { id: modalId } }));
1526                }
1527
1528                const visibleModals = document.querySelectorAll('.modal.visible');
1529
1530                if (visibleModals.length > 1) {
1531
1532                    const maxZIndex = Array.from(visibleModals).reduce((maxZIndex, modal) => {
1533                        const zIndex = window.getComputedStyle(modal).zIndex;
1534                        const parsedZIndex = zIndex !== 'auto' ? parseInt(zIndex) : 0;
1535                        return Math.max(maxZIndex, parsedZIndex);
1536                    }, 0);
1537
1538                    modal.style.zIndex = maxZIndex + 1;
1539                }
1540
1541            }
1542
1543            function _hideModal (modalEl) {
1544                if (!modalEl) {
1545                    return;
1546                }
1547                if (!modalEl.classList.contains('visible')) {
1548                    return;
1549                }
1550                modalEl.classList.remove('visible');
1551                modalEl.style.zIndex = '';
1552                modalEl.dispatchEvent(new Event('lpui-hide'));
1553                var modalId = modalEl.getAttribute('id');
1554                if (modalId) {
1555                    window.lpUI.releaseScrollLock(modalId);
1556                    window.dispatchEvent(new CustomEvent('lpui-modal-hide', { detail: { id: modalId } }));
1557                }
1558            }
1559
1560            function hideModal (modalId) {
1561                _hideModal(document.getElementById(modalId));
1562            }
1563
1564            function hideClosestModal (el) {
1565              const modal = el?.closest('.modal');
1566              if (!modal) {
1567                return;
1568              }
1569              if (modal.classList) {
1570                _hideModal(modal);
1571                return;
1572              }
1573              if (modal.length && modal[0].classList) {
1574                _hideModal(modal[0]);
1575              }
1576            }
1577
1578            window.lpUI = {
1579                sideMenuHide: sideMenuHide,
1580                sideMenuShow: sideMenuShow,
1581                sideMenuToggle: sideMenuToggle,
1582                requestScrollLock: requestScrollLock,
1583                releaseScrollLock: releaseScrollLock,
1584                showModal: showModal,
1585                hideModal: hideModal,
1586                hideClosestModal: hideClosestModal
1587            }
1588        })();
1589
1590        var stringifyPrimitive = function(v) {
1591            switch (typeof v) {
1592                case 'string':
1593                    return v;
1594
1595                case 'boolean':
1596                    return v ? 'true' : 'false';
1597
1598                case 'number':
1599                    return isFinite(v) ? v : '';
1600
1601                default:
1602                    return '';
1603            }
1604        };
1605
1606        function objectToQuerystring(obj, sep, eq, name) {
1607            // https://github.com/Gozala/querystring/blob/master/encode.js
1608            sep = sep || '&';
1609            eq = eq || '=';
1610            if (obj === null) {
1611                obj = undefined;
1612            }
1613
1614            if (typeof obj === 'object') {
1615                return Object.keys(obj).map(function(k) {
1616                    var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
1617                    if (Array.isArray(obj[k])) {
1618                        return obj[k].map(function(v) {
1619                            return ks + encodeURIComponent(stringifyPrimitive(v));
1620                        }).join(sep);
1621                    } else {
1622                        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
1623                    }
1624                }).filter(Boolean).join(sep);
1625
1626            }
1627
1628            if (!name) return '';
1629            return encodeURIComponent(stringifyPrimitive(name)) + eq +
1630                    encodeURIComponent(stringifyPrimitive(obj));
1631        }
1632
1633        function getPath(url, options) {
1634            var parser = document.createElement('a');
1635            parser.href = url || '';
1636            var path = parser.pathname || '';
1637            if (path[0] !== '/') {
1638              // IE does not return path starting with a slash
1639              path = '/' + path;
1640            }
1641
1642            if (options && options.queryString) {
1643                path += parser.search;
1644            }
1645
1646            return path;
1647        }
1648
1649        function getMLSAutocomplete(keyword) {
1650            var searchURL = window.location.protocol + '//' + window.location.hostname + '/home-search/auto_complete';
1651            var query = {
1652                kind: 'listings',
1653                query: keyword
1654            };
1655
1656            return superagent
1657                .get(searchURL)
1658                .query(query)
1659                .then(function(res) {
1660                    var data = res.body || [];
1661                    /*
1662                        Of the format:
1663                          [{
1664                            "_index": "listing_auto_completes_production_20190723232720775",
1665                            "_type": "listing_auto_complete",
1666                            "_id": "235875624",
1667                            "_score": 0,
1668                            "status_modified_at": 1553250708,
1669                            "city": "Jupiter",
1670                            "price": 1335743,
1671                            "display_address": "10088 Calabrese Trail Unit: 9 Jupiter FL 33478",
1672                            "sold_price": null,
1673                            "id": 235875624,
1674                            "state": "FL",
1675                            "photo_urls": [
1676                              "http://cdn.photos.sparkplatform.com/fl/20190322153144208228000000-o.jpg"
1677                            ],
1678                            "status": "Pending"
1679                          }, ...]
1680                      */
1681
1682                    return data;
1683                });
1684        }
1685
1686        function getMLSAutocompleteWithFilters(keyword, filters = {}) {
1687            var searchURL = window.location.protocol + '//' + window.location.hostname + '/home-search/auto_complete';
1688
1689            return superagent
1690                .get(searchURL)
1691                .query({ kind: 'listings', query: keyword, ...filters })
1692                .then(function(res) {
1693                    /*
1694                        Of the format:
1695                          [{
1696                            "_index": "listing_auto_completes_production_20190723232720775",
1697                            "_type": "listing_auto_complete",
1698                            "_id": "235875624",
1699                            "_score": 0,
1700                            "status_modified_at": 1553250708,
1701                            "city": "Jupiter",
1702                            "price": 1335743,
1703                            "display_address": "10088 Calabrese Trail Unit: 9 Jupiter FL 33478",
1704                            "sold_price": null,
1705                            "id": 235875624,
1706                            "state": "FL",
1707                            "photo_urls": [
1708                              "http://cdn.photos.sparkplatform.com/fl/20190322153144208228000000-o.jpg"
1709                            ],
1710                            "status": "Pending"
1711                          }, ...]
1712                    */
1713                    return res.body || [];
1714                });
1715        }
1716
1717        function makeMlsLink(data) {
1718            // Code Dupe from utils/googlePlace
1719            // mapping of google data type to mls data type
1720            var mapping = {
1721                neighborhood: 'neighborhood',
1722                locality: 'place',
1723                administrative_area_level_2: 'county',
1724                administrative_area_level_1: 'state',
1725                postal_code: 'postalcode',
1726            };
1727
1728            function _filterTypes(types) {
1729                return types.filter(function(type) { return type !== 'political' });
1730            }
1731
1732            if (!data || !Object.keys(data).length) {
1733                return '/home-search/listings';
1734            }
1735
1736            var newData = {};
1737            _filterTypes(data.types).forEach(function(type) {
1738                if (mapping[type]) {
1739                    newData.search_type = mapping[type];
1740                }
1741            });
1742            newData.omnibox = data.formatted_address;
1743            data.address_components.forEach(function(component) {
1744                _filterTypes(component.types).forEach(function(type) {
1745                    if (mapping[type]) {
1746                        newData[mapping[type]] = component.long_name;
1747                    }
1748                });
1749            });
1750            var bounds = data.geometry.bounds;
1751            var convertedData = Object.assign(bounds, newData);
1752
1753            return '/home-search/listings?' + objectToQuerystring(convertedData);
1754        }
1755
1756        function debounce(func, wait) {
1757            let timeout;
1758            return function(...args) {
1759                const context = this;
1760                clearTimeout(timeout);
1761                timeout = setTimeout(() => func.apply(context, args), wait)
1762            }
1763        }
1764
1765        // Global methods / variables that can be accessed by element js
1766        window.luxuryPresence = {
1767            ...window.luxuryPresence,
1768            defaults: {
1769                companyId: 'bba607a7-df71-48c9-84ae-e87d443d6b5b',
1770                apiGatewayUrl: '/api-gw',
1771                routerUrl: '/api-nv',
1772                gql: {"agents":"\n  query Agents (\n    $agentId: ID\n    $agentIds: [ID!]\n    $companyId: String\n    $network: Boolean\n    $networkId: String\n    $officeId: [ID!]\n    $excludeOfficeId: [ID!]\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n    $search: String\n    $tags: [String]\n    $tagsMode: TagsModeEnum\n    $teamId: [ID!]\n    $developmentId: [ID!]\n    $prioritizeIds: Boolean\n  ) {\n    agents (\n      agentId: $agentId\n      agentIds: $agentIds\n      companyId: $companyId\n      network: $network\n      networkId: $networkId\n      officeId: $officeId\n      excludeOfficeId: $excludeOfficeId\n      offset: $offset\n      limit: $limit\n      sort: $sort\n      sortDir: $sortDir\n      search: $search\n      tags: $tags\n      tagsMode: $tagsMode\n      teamId: $teamId\n      developmentId: $developmentId\n      prioritizeIds: $prioritizeIds\n    ) {\n      id\n      firstName\n      lastName\n      avatar {\n        smallUrl\n        mediumUrl\n        largeUrl\n        height\n        width\n      }\n      position\n      bioLong\n      bioShort\n      seoTitle\n      seoDescription\n      slug\n      phoneNumber\n      phoneNumber2\n      license\n      email\n      leadAgent\n      greaterArea\n      tags\n    }\n    agentsCount(\n      agentIds: $agentIds\n      companyId: $companyId\n      network: $network\n      networkId: $networkId\n      officeId: $officeId\n      excludeOfficeId: $excludeOfficeId\n      search: $search\n      tags: $tags\n      tagsMode: $tagsMode\n      teamId: $teamId\n      developmentId: $developmentId\n      prioritizeIds: $prioritizeIds\n    ) {\n      count\n    }\n  }\n","properties":"\n  query Properties(\n    $agentIds: [ID!]\n    $teamIds: [ID!]\n    $neighborhoodIds: [ID!]\n    $officeIds: [ID!]\n    $propertyId: ID\n    $companyId: String\n    $networkId: String\n    $network: Boolean\n    $statusId: String\n    $propertyIds: [ID!]\n    $prioritizeIds: Boolean\n    $statusIds: [String!]\n    $excludeStatusId: [String!]\n    $neighborhoodId: String\n    $addressState: [String!]\n    $addressCity: [String!]\n    $relatedNeighborhoodPropertyId: String\n    $developmentId: String\n    $featuredListing: Boolean\n    $leaseProperty: Boolean\n    $search: String\n    $searchTermMode: SearchTermModeEnum\n    $globalProperty: Boolean\n    $archived: Boolean\n    $salesPriceGTE: Float\n    $salesPriceLTE: Float\n    $leasePriceGTE: Float\n    $leasePriceLTE: Float\n    $livingSpaceSizeGTE: Float\n    $livingSpaceSizeLTE: Float\n    $bathCountGTE: Float\n    $bathCountLTE: Float\n    $bedroomCountGTE: Float\n    $bedroomCountLTE: Float\n    $architectureStyle: String\n    $lifestyle: String\n    $propertyTypeId: String\n    $propertyTypeIds: [String!]\n    $spaceTypeIds: [ID!]\n    $tag: String\n    $backfillMLSResults: Boolean\n    $displayMLSListings: String\n    $hostname: String\n    $websiteId: ID\n    $backfillProviders: [String!]\n    $backfillMLSListingIds: [String!]\n    $backfillMLSAgentIds: [String!]\n    $backfillMLSOfficeIds: [String!]\n    $backfillBoundary: JSON\n    $openHouse: Boolean\n    $withGeo: Boolean\n    $advancedFilters: JSON\n    $seasonalPriceId: ID\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n  ) {\n    properties(\n      \n      agentIds: $agentIds\n      teamIds: $teamIds\n      propertyId: $propertyId\n      propertyIds: $propertyIds\n      prioritizeIds: $prioritizeIds\n      companyId: $companyId\n      network: $network\n      networkId: $networkId\n      statusId: $statusId\n      statusIds: $statusIds\n      excludeStatusId: $excludeStatusId\n      neighborhoodId: $neighborhoodId\n      neighborhoodIds: $neighborhoodIds\n      officeIds: $officeIds\n      addressState: $addressState\n      addressCity: $addressCity\n      developmentId: $developmentId\n      featuredListing: $featuredListing\n      leaseProperty: $leaseProperty\n      search: $search\n      searchTermMode: $searchTermMode\n      salesPriceGTE: $salesPriceGTE\n      salesPriceLTE: $salesPriceLTE\n      leasePriceGTE: $leasePriceGTE\n      leasePriceLTE: $leasePriceLTE\n      livingSpaceSizeGTE: $livingSpaceSizeGTE\n      livingSpaceSizeLTE: $livingSpaceSizeLTE\n      bathCountGTE: $bathCountGTE\n      bathCountLTE: $bathCountLTE\n      bedroomCountGTE: $bedroomCountGTE\n      bedroomCountLTE: $bedroomCountLTE\n      architectureStyle: $architectureStyle\n      lifestyle: $lifestyle\n      propertyTypeId: $propertyTypeId\n      propertyTypeIds: $propertyTypeIds\n      spaceTypeIds: $spaceTypeIds\n      tag: $tag\n      archived: $archived\n      globalProperty: $globalProperty\n      withGeo: $withGeo\n      openHouse: $openHouse\n      displayMLSListings: $displayMLSListings\n      advancedFilters: $advancedFilters\n      seasonalPriceId: $seasonalPriceId\n\n      relatedNeighborhoodPropertyId: $relatedNeighborhoodPropertyId\n      backfillMLSResults: $backfillMLSResults\n      hostname: $hostname\n      websiteId: $websiteId\n      backfillProviders: $backfillProviders\n      backfillMLSListingIds: $backfillMLSListingIds\n      backfillMLSAgentIds: $backfillMLSAgentIds\n      backfillMLSOfficeIds: $backfillMLSOfficeIds\n      backfillBoundary: $backfillBoundary\n      offset: $offset\n      limit: $limit\n      sort: $sort,\n      sortDir: $sortDir\n    ){\n      id\n      name\n      status\n      originalStatus {\n        id\n        name\n      }\n      salesPrice\n      reducedPrice\n      isPasswordProtected\n      bedroomCount\n      bathCount\n      fullBathCount\n      halfBathCount\n      threeQuarterBathCount\n      fullAddress\n      addressLine1\n      addressLine2\n      addressCity\n      addressState\n      addressCountry\n      postalCode\n      description\n      syncedAt\n      officeName\n      attributionContact\n      neighborhood {\n        id\n      }\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      seoTitle\n      seoDescription\n      slug\n      fromMLS\n      mlsId\n      mlsLogo\n      mlsAttribution\n      openHouse\n      openHouseHours\n      priceUponRequest\n      privateAddress\n      leaseProperty\n      leasePrice\n      currency\n      leaseTermFrequencyInterval\n      leaseTermFrequencyCount\n      leasePeriod\n      livingSpaceSize\n      livingSpaceUnits\n      lotAreaSize\n      lotAreaUnits\n      tags\n      latitude\n      longitude\n      soldDate\n      timeZone\n      buyerAgencyCompensation\n      buyerAgencyCompensationType\n      landIdUrl\
1772n    }\n    propertiesCount(\n    \n      agentIds: $agentIds\n      teamIds: $teamIds\n      propertyId: $propertyId\n      propertyIds: $propertyIds\n      prioritizeIds: $prioritizeIds\n      companyId: $companyId\n      network: $network\n      networkId: $networkId\n      statusId: $statusId\n      statusIds: $statusIds\n      excludeStatusId: $excludeStatusId\n      neighborhoodId: $neighborhoodId\n      neighborhoodIds: $neighborhoodIds\n      officeIds: $officeIds\n      addressState: $addressState\n      addressCity: $addressCity\n      developmentId: $developmentId\n      featuredListing: $featuredListing\n      leaseProperty: $leaseProperty\n      search: $search\n      searchTermMode: $searchTermMode\n      salesPriceGTE: $salesPriceGTE\n      salesPriceLTE: $salesPriceLTE\n      leasePriceGTE: $leasePriceGTE\n      leasePriceLTE: $leasePriceLTE\n      livingSpaceSizeGTE: $livingSpaceSizeGTE\n      livingSpaceSizeLTE: $livingSpaceSizeLTE\n      bathCountGTE: $bathCountGTE\n      bathCountLTE: $bathCountLTE\n      bedroomCountGTE: $bedroomCountGTE\n      bedroomCountLTE: $bedroomCountLTE\n      architectureStyle: $architectureStyle\n      lifestyle: $lifestyle\n      propertyTypeId: $propertyTypeId\n      propertyTypeIds: $propertyTypeIds\n      spaceTypeIds: $spaceTypeIds\n      tag: $tag\n      archived: $archived\n      globalProperty: $globalProperty\n      withGeo: $withGeo\n      openHouse: $openHouse\n      displayMLSListings: $displayMLSListings\n      advancedFilters: $advancedFilters\n      seasonalPriceId: $seasonalPriceId\n\n    ) {\n      count\n    }\n  }\n","pressReleases":"\n  query PressReleases (\n    $pressReleaseId: ID\n    $companyId: String\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n    $search: String\n    $categories: [String!]\n    $propertyId: [String!]\n    $developmentId: [String!]\n    $agentId: [String!]\n    $teamId: [String!]\n  ) {\n    pressReleases (\n      pressReleaseId: $pressReleaseId\n      companyId: $companyId\n      offset: $offset\n      limit: $limit\n      sort: $sort\n      sortDir: $sortDir\n      search: $search\n      categories: $categories\n      propertyId: $propertyId\n      developmentId: $developmentId\n      agentId: $agentId\n      teamId: $teamId\n    ) {\n      id\n      title\n      description\n      author\n      externalUrl\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      publishedAt\n      categories\n    }\n    pressReleasesCount(\n      companyId: $companyId\n      search: $search\n      categories: $categories\n      propertyId: $propertyId\n      developmentId: $developmentId\n      agentId: $agentId\n      teamId: $teamId\n    ) {\n      count\n    }\n  }\n","posts":"\n  query Posts (\n    $postId: ID\n    $companyId: String\n    $offset: Int\n    $limit: Int\n    $order: String\n    $sortDir: SortDirectionEnum\n    $search: String\n    $featured: Boolean\n    $categoryId: String\n    $categoryIds: [String!]\n    $neighborhoodId: [String!]\n    ) {\n    posts (\n      postId: $postId\n      companyId: $companyId\n      offset: $offset\n      limit: $limit\n      order: $order\n      sortDir: $sortDir\n      search: $search\n      featured: $featured\n      postStatusId: \"5f528253-abb7-484e-95c3-330269ac1102\"\n      categoryId: $categoryId\n      categoryIds: $categoryIds\n      neighborhoodId: $neighborhoodId\n    ) {\n      id\n      title\n      subtitle\n      description\n      status\n      featured\n      slug\n      categories {\n        id\n        name\n      }\n      createdAt\n      publishedAt\n      scheduledAt\n      createdBy {\n        firstName\n        lastName\n      }\n      customAuthor\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      seoTitle\n      seoDescription\n      slug\n    }\n    postsCount(\n      companyId: $companyId\n      search: $search\n      featured: $featured\n      postStatusId: \"5f528253-
1772abb7-484e-95c3-330269ac1102\"\n      categoryId: $categoryId\n      categoryIds: $categoryIds\n      neighborhoodId: $neighborhoodId\n    ) {\n      count\n    }\n  }\n","testimonials":"\n  query Testimonials(\n    $testimonialId: ID\n    $agentId: ID\n    $teamId: ID\n    $companyId: String\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n    $search: String\n  ) {\n    testimonials(\n      testimonialId: $testimonialId\n      agentId: $agentId\n      teamId: $teamId\n      companyId: $companyId\n      offset: $offset\n      limit: $limit\n      sort: $sort\n      sortDir: $sortDir\n      search: $search\n    ){\n      id\n      body\n      author\n      position\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      seoTitle\n      seoDescription\n      agents {\n        slug\n        email\n        firstName\n        lastName\n        avatar {\n          smallUrl\n          height\n          width\n        }\n      }\n    }\n    testimonialsCount(\n      companyId: $companyId\n      agentId: $agentId\n      teamId: $teamId\n      search: $search\n    ) {\n      count\n    }\n  }\n","neighborhoods":"\n  query Neighborhoods (\n    $neighborhoodId: ID\n    $companyId: String\n    $search: String\n    $tag: String\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n  ) {\n    neighborhoods (\n      neighborhoodId: $neighborhoodId\n      companyId: $companyId\n      search: $search\n      tag: $tag\n      offset: $offset\n      limit: $limit\n      sort: $sort\n      sortDir: $sortDir\n    ) {\n      id\n      name\n      description\n      descriptionShort\n      slug\n      tags\n      googlePlaceData\n      mlsLink\n      createdAt\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      seoTitle\n      seoDescription\n    }\n    neighborhoodsCount(\n      companyId: $companyId\n      search: $search\n      tag: $tag\n    ) {\n      count\n    }\n  }\n","developments":"\n  query Developments (\n    $developmentId: ID\n    $companyId: String\n    $offset: Int\n    $limit: Int\n    $sort: String\n    $sortDir: SortDirectionEnum\n    $search: String\n    $tag: [String!]\n    $agentId: [ID!]\n    $neighborhoodId: ID\n    $neighborhoodIds: [ID!]\n  ) {\n    developments (\n      developmentId: $developmentId\n      companyId: $companyId\n      offset: $offset\n      limit: $limit\n      sort: $sort\n      sortDir: $sortDir\n      search: $search\n      tag: $tag\n      agentId: $agentId\n      neighborhoodId: $neighborhoodId\n      neighborhoodIds: $neighborhoodIds\n    ) {\n      id\n      name\n      description\n      descriptionShort\n      slug\n      createdAt\n      media {\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n        height\n        width\n      }\n      googlePlaceData\n      seoTitle\n      seoDescription\n      tags\n    }\n    developmentsCount(\n      companyId: $companyId\n      search: $search\n      tag: $tag\n      agentId: $agentId\n      neighborhoodId: $neighborhoodId\n      neighborhoodIds: $neighborhoodIds\n    ) {\n      count\n    }\n  }\n","pois":"\nquery PointsOfInterest(\n  $regionId: String!,\n  $radius: Int,\n  $offset: Int,\n  $limit: Int,\n  $categories: [PoiCategoryEnum!],\n  $sortBy: PoiSortByEnum\n) {\n pois(\n     regionId: $regi
1772onId,\n     radius: $radius,\n     offset: $offset,\n     limit: $limit,\n     categories: $categories,\n     sortBy: $sortBy\n ) {\n  name\n  imageUrl\n  url\n  reviewCount\n  rating\n  price\n  displayPhone\n  distance\n  category\n  location {\n      address1\n      address2\n      address3\n      city\n      zipCode\n      country\n      state\n      }\n  }\n }\n","offices":"\n  query Offices (\n    $officeId: ID\n    $officeIds: [ID!]\n    $companyId: String\n    $slug: String\n    $sort: String\n    $sortDir: SortDirectionEnum\n    $search: String\n    $tags: [String]\n    $offset: Int\n    $limit: Int\n  ) {\n    offices (\n      officeId: $officeId\n      officeIds: $officeIds\n      companyId: $companyId\n      slug: $slug\n      sort: $sort\n      sortDir: $sortDir\n      search: $search\n      tags: $tags\n      offset: $offset\n      limit: $limit\n    ) {\n      id\n      companyId\n      name\n      slug\n      officeMlsId\n      shortDescription\n      fullDescription\n      addressLine1\n      addressLine2\n      addressCity\n      addressState\n      addressPostalCode\n      addressCountry\n      phone\n      email\n      officeHours\n      coordinates\n      googlePlaceData \n      seoTitle\n      seoDescription\n      fullAddress\n      media {\n        id\n        originalUrl\n        thumbnailUrl\n        smallUrl\n        mediumUrl\n        largeUrl\n        xLargeUrl\n        xxLargeUrl\n      }\n    }\n    officesCount(\n      companyId: $companyId\n      officeId: $officeId\n      officeIds: $officeIds\n      slug: $slug\n      search: $search\n      tags: $tags\n    ) {\n      count\n    }\n  }\n","teams":"query TeamsAndCount(\n  $offset: Int\n  $limit: Int\n  $search: String\n  $sort: String\n  $sortDir: SortDirectionEnum\n  $companyId: ID\n) {\n  teams(\n    offset: $offset\n    limit: $limit\n    sort: $sort\n    sortDir: $sortDir\n    search: $search\n    companyId: $companyId\n  ) {\n    \n  id\n  companyId\n  name\n  email\n  shortBio\n  fullBio\n  addressLine1\n  addressLine2\n  addressCity\n  addressState\n  addressCountry\n  phoneNumber1\n  phoneNumber2\n  postalCode\n  avatar {\n    id\n    thumbnailUrl\n    smallUrl\n    mediumUrl\n    largeUrl\n  }\n  urlWebsite\n  socialLinks\n  socialLinksArray\n  tags\n  seoTitle\n  seoDesc\n  slug\n  displayOrder\n\n  }\n  teamsCount(\n    search: $search\n    companyId: $companyId\n  ) {\n    count\n  }\n}"},
1773                propertyPlaceholderImage: {"id":"3b8e34db-939e-46d6-8b67-bfcd12573ef7","alt":null,"bytes":37711,"width":1920,"format":"png","height":1200,"pngUrl":"","shared":true,"curated":false,"duration":null,"largeUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","smallUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=960/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","authorUrl":null,"createdAt":"2025-08-21T16:15:58.294Z","mediumUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=1280/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","sourceUrl":null,"updatedAt":"2025-08-21T16:15:58.294Z","xLargeUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","__typename":"Media","altTagText":null,"authorName":null,"sourceName":"r2","xxLargeUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","description":null,"displayName":"property_lockup_logo","originalUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","resourceType":"image","thumbnailUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85,fit=scale-down,width=320/https://media-production.lp-cdn.com/media/c62dfffb-efd1-4496-ab7f-a54c335c8054","originalFileName":"Property_lockup_logo","cloudinaryPublicId":"c62dfffb-efd1-4496-ab7f-a54c335c8054"}
1774            },
1775            objectToQuerystring: objectToQuerystring,
1776            getPath: getPath,
1777            getMLSAutocomplete: getMLSAutocomplete,
1778            getMLSAutocompleteWithFilters: getMLSAutocompleteWithFilters,
1779            makeMlsLink: makeMlsLink,
1780            debounce: debounce,
1781        };
1782
1783        var wowOffset = 100;
1784    </script>
1784
1785    
1785<script>
1786        (() => {
1787
1788function $parcel$interopDefault(a) {
1789  return a && a.__esModule ? a.default : a;
1790}
1791// Entry point for lp-sdk bundle
1792// This file exists to ensure Parcel v2 outputs the correct filename
1793/* global window */ var $53de3c160faf5a81$exports = {};
1794/*
1795WARNING!!! This file is used both on the server and in client's web-browser
1796please don't require/import any server-side related config/functions here
1797If we need something, let's pass it as a parameter of the factory
1798*/ var $0ce6edea77f7b81a$exports = {};
1799$0ce6edea77f7b81a$exports = {
1800    getVideoFirstFrame (videoUrl) {
1801        // The default Cloudinary asset delivery URL has the following structure: https://res.cloudinary.com/<cloud_name>/<asset_type>/<delivery_type>/<transformations>/<version>/<public_id>.<extension>
1802        //  https://cloudinary.com/documentation/video_manipulation_and_delivery#transformation_url_structure
1803        // The problem is that <transformations> and <version> are optional, and <transformations> can be chained separated by '/'
1804        // One more issue to be handled https://cloudinary.com/documentation/advanced_url_delivery_options#seo_friendly_media_asset_urls
1805        const CLOUDINARY_URL = 'https://res.cloudinary.com/';
1806        const invalid = !videoUrl || !videoUrl.startsWith(CLOUDINARY_URL);
1807        if (invalid) return null;
1808        const urlComponents = videoUrl.replace(CLOUDINARY_URL, '').replace('f_auto:video', 'f_auto').split('/');
1809        // checking if <asset_type> is not video or videos
1810        if (urlComponents[1].toLowerCase().indexOf('video') === -1) return null;
1811        // Filename is last urlComponent <public_id>.<extension>
1812        let filename = urlComponents[urlComponents.length - 1];
1813        if (filename.lastIndexOf('.') > -1) filename = `${filename.slice(0, filename.lastIndexOf('.'))}.jpg`;
1814        else filename += '.jpg';
1815        urlComponents[urlComponents.length - 1] = filename;
1816        // We need to add so_0,eo_0 transformation to the url to target the first frame.
1817        // we want to find the position at which we want to insert it as a chained transformation
1818        const firstFrameTransformation = 'so_0,eo_0';
1819        let firstFrameTransformationPosition = 3;
1820        // checking cases for SEO-friendly URLs
1821        if (urlComponents[1].toLowerCase() === 'videos' && urlComponents[2] !== '') firstFrameTransformationPosition = 2;
1822        // checking the last transformation position in the url
1823        // https://cloudinary.com/documentation/transformation_reference
1824        // https://regex101.com/r/lE3W6u/1
1825        const transformationRegex = /^(?:[a-z]{1,3}|\$\w+)_\S+$/;
1826        while(firstFrameTransformationPosition < urlComponents.length - 1 && transformationRegex.test(urlComponents[firstFrameTransformationPosition]))firstFrameTransformationPosition++;
1827        urlComponents.splice(firstFrameTransformationPosition, 0, firstFrameTransformation);
1828        return CLOUDINARY_URL + urlComponents.join('/');
1829    }
1830};
1831
1832
1833/**
1834 * Create helpers with given Handlebars instance
1835 *
1836 * @param {Object} HandlebarsInstance
1837 * @param {Function} isEqual - we use different implementation if isEqual on server and on client
1838 * @return {Object}
1839 */ function $53de3c160faf5a81$var$handlebarsHelpersFactory(HandlebarsInstance, { isEqual: isEqual }) {
1840    // notice!: code below assumes list is ordered lowest to highest width
1841    const MEDIA_SIZES = [
1842        {
1843            field: 'thumbnailUrl',
1844            w: 320
1845        },
1846        {
1847            field: 'smallUrl',
1848            w: 960
1849        },
1850        {
1851            field: 'mediumUrl',
1852            w: 1280
1853        },
1854        {
1855            field: 'largeUrl',
1856            w: 1920
1857        },
1858        {
1859            field: 'xLargeUrl',
1860            w: 2560
1861        },
1862        {
1863            field: 'xxLargeUrl',
1864            w: 3456
1865        }
1866    ];
1867    const MEDIA_SIZE_FOR_SRC = 1280;
1868    const lpFormatNumber = function(number, unit, precision) {
1869        const localization = 'en-US';
1870        if (!number) return '';
1871        if (typeof number === 'string') {
1872            const trimmed = number.trim();
1873            if (/[^+\-0-9.]/.test(trimmed)) return number; // returning text 'as is' assuming it already has all formatting
1874            // eslint-disable-next-line
1875            number = parseFloat(trimmed);
1876            if (!number) return '';
1877        }
1878        const currencyPrecision = typeof precision === 'number' ? precision : 0;
1879        const currencyFractionDigits = Number.isInteger(number) ? 0 : currencyPrecision;
1880        const currencyFractionOptions = {
1881            minimumFractionDigits: currencyFractionDigits,
1882            maximumFractionDigits: currencyFractionDigits
1883        };
1884        if (unit === 'USD') return `$${number.toLocaleString(localization, currencyFractionOptions)}`;
1885        if (unit === 'CAD') return `$${number.toLocaleString(localization, currencyFractionOptions)} CAD`;
1886        if (unit === 'EUR') return `\u{20AC}${number.toLocaleString(localization, currencyFractionOptions)}`;
1887        if (unit === 'GBP') return `\xa3${number.toLocaleString(localization, currencyFractionOptions)}`;
1888        if (unit === 'PERCENT') return `${number}%`;
1889        if (typeof precision === 'number' && precision > -1) return number.toLocaleString(localization, {
1890            maximumFractionDigits: precision
1891        });
1892        return number.toLocaleString(localization);
1893    };
1894    const formatFrequency = function(freqUnit) {
1895        switch(freqUnit){
1896            case 'DAY':
1897                return 'daily';
1898            case 'MONTH':
1899                return 'monthly';
1900            case 'WEEK':
1901                return 'weekly';
1902            case 'YEAR':
1903                return 'yearly';
1904            case 'QUARTER':
1905                return 'quarterly';
1906            case 'HALF_YEAR':
1907                return 'semi-annually';
1908            case 'NIGHTLY':
1909                return 'nightly';
1910            case 'SEASONAL':
1911                return 'seasonally';
1912            default:
1913                return '';
1914        }
1915    };
1916    const formatFrequencyShort = function(freqUnit) {
1917        switch(freqUnit){
1918            case 'DAY':
1919                return 'day';
1920            case 'WEEK':
1921                return 'wk';
1922            case 'MONTH':
1923                return 'mo';
1924            case 'YEAR':
1925                return 'yr';
1926            case 'QUARTER':
1927                return '3 mos';
1928            case 'HALF_YEAR':
1929                return '6 mos';
1930            case 'NIGHTLY':
1931                return 'night';
1932            case 'SEASONAL':
1933                return 'season';
1934            default:
1935                return '';
1936        }
1937    };
1938    const formatFrequencyStd = function(freqUnit) {
1939        switch(freqUnit){
1940            case 'DAY':
1941                return 'day';
1942            case 'WEEK':
1943                return 'week';
1944            case 'MONTH':
1945                return 'month';
1946            case 'YEAR':
1947                return 'year';
1948            case 'QUARTER':
1949                return 'quarter';
1950            case 'HALF_YEAR':
1951                return '6 months';
1952            case 'NIGHTLY':
1953                return 'night';
1954            case 'SEASONAL':
1955                return 'season';
1956            default:
1957                return '';
1958        }
1959    };
1960    const formatFrequencyExt = function(unit, options) {
1961        let val;
1962        let separator;
1963        const opts = options || {};
1964        switch(opts.mode){
1965            case 'short':
1966                val = formatFrequencyShort(unit);
1967                separator = opts.frequencySeparator || '/';
1968                break;
1969            case 'standard':
1970            case 'std':
1971                val = formatFrequencyStd(unit);
1972                separator = opts.frequencySeparator || '/';
1973                break;
1974            case 'long':
1975            default:
1976                val = formatFrequency(unit);
1977                separator = opts.frequencySeparator || ' ';
1978        }
1979        if (!val) return '';
1980        if (!opts.frequencyTag && !opts.frequencyClass) return separator + val;
1981        return `${separator}<${opts.frequencyTag || 'span'}${opts.frequencyClass ? ` class="${opts.frequencyClass}"` : ''}>${val}</${opts.frequencyTag || 'span'}>`;
1982    };
1983    return {
1984        isEmpty (arg1, options) {
1985            const result = !arg1 || (typeof arg1 === 'string' ? !arg1.trim() : false) || !Object.keys(arg1).length;
1986            if (options.fn) return result ? options.fn(this) : options.inverse(this);
1987            return result;
1988        },
1989        ifEquals (arg1, arg2, options) {
1990            return isEqual(arg1, arg2) ? options.fn(this) : options.inverse(this);
1991        },
1992        'raw-helper': function(options) {
1993            return options.fn();
1994        },
1995        striptags (txt) {
1996            if (!txt) return '';
1997            // Remove HTML Comments (escaping something to not make real html comment by expression)
1998            // eslint-disable-next-line no-useless-escape,no-param-reassign
1999            txt = txt.replace(/<\!--(.|[\r\n])*?-\->/g, '');
2000            // Remove XML fragments and <style> and <svg> tags with content
2001            // eslint-disable-next-line
2002            txt = txt.replace(/<(xml|style|svg)("[^"]*"|'[^']*'|[^>])*>(.|[\r\n])*?<\/\1>/gi, '');
2003            // Replace &nbsp; with space
2004            // eslint-disable-next-line no-param-reassign
2005            txt = txt.replace(/&nbsp;/g, ' ');
2006            // Remove HTML Tags
2007            const regexp = /<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g;
2008            return txt.replace(regexp, '');
2009        },
2010        striptagsLineBreaks (txt) {
2011            if (!txt) return '';
2012            // Remove HTML Comments (escaping something to not make real html comment by expression)
2013            // eslint-disable-next-line no-useless-escape,no-param-reassign
2014            txt = txt.replace(/<\!--(.|[\r\n])*?-\->/g, '');
2015            // Remove XML fragments and <style> and <svg> tags with content
2016            // eslint-disable-next-line no-param-reassign
2017            txt = txt.replace(/<(xml|style|svg)("[^"]*"|'[^']*'|[^>])*>(.|[\r\n])*?<\/\1>/gi, '');
2018            // Replace <br> and </p> tags with line break char, skipping last </p> which is not followed by <br> or </p>
2019            // eslint-disable-next-line no-param-reassign
2020            txt = txt.replace(/(<br\s*\/?>)|(<\/p\s*>)(?=.*(<\/p\s*>|<br\s*\/?>))/g, '&#10;');
2021            // Replace &nbsp; with space
2022            // eslint-disable-next-line no-param-reassign
2023            txt = txt.replace(/&nbsp;/g, ' ');
2024            // Remove HTML Tags
2025            const regexp = /<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g;
2026            return txt.replace(regexp, '');
2027        },
2028        truncate (text, limit, suffix) {
2029            if (!text) return '';
2030            if (text.length > limit) return typeof suffix === 'string' ? text.slice(0, limit - suffix.length) + suffix : text.slice(0, limit);
2031            return text;
2032        },
2033        // eslint-disable-next-line
2034        setSubArray (items = [], start, end, subArrayName, options) {
2035            // eslint-disable-next-line
2036            options.data.root[subArrayName] = items.slice(start, end);
2037        },
2038        formatAreaUnit (areaUnit) {
2039            switch(areaUnit){
2040                case 'ACRE':
2041                    return 'Acres';
2042                case 'SQUARE_METER':
2043                    return 'Sq.M.';
2044                case 'SQUARE_YARD':
2045                    return 'Sq.Yd.';
2046                default:
2047                    return 'Sq.Ft.';
2048            }
2049        },
2050        formatFrequency: formatFrequency,
2051        formatFrequencyShort: formatFrequencyShort,
2052        lpFormatFrequency (freqUnit, options) {
2053            return formatFrequencyExt(freqUnit, options && options.hash);
2054        },
2055        subArray (index, start, end, options) {
2056            return index >= start && index < end ? options.fn(this) : options.inverse(this);
2057        },
2058        formatPropertyStatus (status, showSoldDate, date) {
2059            let formattedStatus = '';
2060            switch(status){
2061                case 'SOLD':
2062                    formattedStatus = 'Sold';
2063                    break;
2064                case 'FOR_SALE':
2065                    formattedStatus = 'For Sale';
2066                    break;
2067                case 'COMING_SOON':
2068                    formattedStatus = 'Coming Soon';
2069                    break;
2070                case 'INACTIVE':
2071                    formattedStatus = 'Inactive';
2072                    break;
2073                case 'POCKET_LISTING':
2074                    formattedStatus = 'Pocket Listing';
2075                    break;
2076                case 'PENDING':
2077                    formattedStatus = 'Pending';
2078                    break;
2079                case 'UNDER_CONTRACT':
2080                    formattedStatus = 'Under Contract';
2081                    break;
2082                case 'ACTIVE_UNDER_CONTRACT':
2083                    formattedStatus = 'Active Under Contract';
2084                    break;
2085                default:
2086                    formattedStatus = status;
2087            }
2088            // `typeof date === 'string'` matters: when called as
2089            // `{{formatPropertyStatus status}}` Handlebars passes its options object
2090            // as `showSoldDate`/`date`, and this guard keeps the legacy output.
2091            if ((formattedStatus === 'Sold' || formattedStatus === 'Leased') && showSoldDate && typeof date === 'string' && date) formattedStatus += ` on ${date}`;
2092            return formattedStatus;
2093        },
2094        formatGrade (gradeValue) {
2095            switch(gradeValue){
2096                case 'UNDERGRADUATE_COURSES':
2097                    return 'Undergrad';
2098                case 'PRE_KINDERGARTEN':
2099                    return 'PreK';
2100                case 'KINDERGARTEN':
2101                    return 'K';
2102                case 'FIRST_GRADE':
2103                    return '1st';
2104                case 'SECOND_GRADE':
2105                    return '2nd';
2106                case 'THIRD_GRADE':
2107                    return '3rd';
2108                case 'FOURTH_GRADE':
2109                    return '4th';
2110                case 'FIFTH_GRADE':
2111                    return '5th';
2112                case 'SIXTH_GRADE':
2113                    return '6th';
2114                case 'SEVENTH_GRADE':
2115                    return '7th';
2116                case 'EIGHTH_GRADE':
2117                    return '8th';
2118                case 'NINTH_GRADE':
2119                    return '9th';
2120                case 'TENTH_GRADE':
2121                    return '10th';
2122                case 'ELEVENTH_GRADE':
2123                    return '11th';
2124                case 'TWELFTH_GRADE':
2125                    return '12th';
2126                default:
2127                    return '';
2128            }
2129        },
2130        encodeURI (uri) {
2131            return encodeURI(uri);
2132        },
2133        encodeURIComponent (txt) {
2134            return encodeURIComponent(txt);
2135        },
2136        hbFormatDate (date, type) {
2137            if (!date) return '';
2138            const newDate = date === 'current' ? new Date() : new Date(date);
2139            if (Number.isNaN(newDate.getTime())) return '';
2140            const months = [
2141                'January',
2142                'February',
2143                'March',
2144                'April',
2145                'May',
2146                'June',
2147                'July',
2148                'August',
2149                'September',
2150                'October',
2151                'November',
2152                'December'
2153            ];
2154            if (type === 'YYYY' || type === 'year') return `${newDate.getFullYear()}`;
2155            if (type === 'MM/DD/YY') {
2156                let month = newDate.getMonth() + 1;
2157                if (month < 10) month = `0${month.toString()}`;
2158                return `${month}/${newDate.getDate()}/${newDate.getFullYear().toString().substr(-2)}`;
2159            }
2160            return `${months[newDate.getMonth()]} ${newDate.getDate()}, ${newDate.getFullYear()}`;
2161        },
2162        openHousesFormat (startDate, endDate, timeZone) {
2163            if (!startDate || !endDate) return '';
2164            /**
2165       * return formatted time.
2166       * @param {date} date
2167       * @return {time} time.
2168       */ const getTime = (date)=>{
2169                let hours = date.getHours();
2170                if (hours > 12) hours -= 12;
2171                const prefix = '0';
2172                let time = `${hours}:${date.getMinutes() > 9 ? date.getMinutes() : prefix + date.getMinutes()}`;
2173                if (date.getHours() > 11) time += 'PM';
2174                else time += 'AM';
2175                return time;
2176            };
2177            let tz = '';
2178            let startFDate = startDate;
2179            let endFDate = endDate;
2180            if (timeZone) {
2181                startFDate = new Date(startDate).toLocaleString('en-US', {
2182                    timeZone: timeZone
2183                });
2184                endFDate = new Date(endDate).toLocaleString('en-US', {
2185                    timeZone: timeZone
2186                });
2187                [, , , tz] = new Date(endDate).toLocaleString('en-US', {
2188                    timeZone: timeZone,
2189                    timeZoneName: 'short'
2190                }).split(' ');
2191            }
2192            const date = new Date(startFDate);
2193            const openHouseDate = date.toLocaleDateString('en-US');
2194            const time1 = getTime(date);
2195            const date2 = new Date(endFDate);
2196            const time2 = getTime(date2);
2197            return `${openHouseDate} ${time1} - ${time2} ${tz}`;
2198        },
2199        math (lvalue, operator, rvalue) {
2200            // eslint-disable-next-line
2201            lvalue = parseFloat(lvalue);
2202            // eslint-disable-next-line
2203            rvalue = parseFloat(rvalue);
2204            return ({
2205                '+': lvalue + rvalue,
2206                '-': lvalue - rvalue,
2207                '*': lvalue * rvalue,
2208                '/': lvalue / rvalue,
2209                '%': lvalue % rvalue
2210            })[operator];
2211        },
2212        findByKey (values, key, value, options) {
2213            const result = (values || []).find((entry)=>entry[key] === value);
2214            return options.fn(result);
2215        },
2216        capitalize (string, split, options) {
2217            let capitalized;
2218            if (typeof string === 'string' && string.length) capitalized = string.toLowerCase().split(split).map((w)=>w.charAt(0).toUpperCase() + w.slice(1)).join(' ').toString();
2219            return capitalized;
2220        },
2221        and (...arg) {
2222            return Array.prototype.slice.call(arg).every(Boolean);
2223        },
2224        or (...arg) {
2225            return Array.prototype.slice.call(arg, 0, -1).some(Boolean);
2226        },
2227        not (arg) {
2228            return !arg;
2229        },
2230        orderByIds (items, orderedIds, options) {
2231            let ret = '';
2232            let data = null;
2233            if (options.data) data = HandlebarsInstance.createFrame(options.data);
2234            // When passed orderedIds, filter out empty items including empty strings and
2235            // only show items (and in that order) in a loop
2236            //  If no orderedIds provided, show all items
2237            const filteredIds = (orderedIds || []).filter(Boolean);
2238            if (filteredIds && filteredIds.length) {
2239                let skippedItems = 0;
2240                ret = filteredIds.reduce((res, id, idx)=>{
2241                    const item = (items || []).find((item)=>item.id === id);
2242                    // ID doesn't exist so ditch it
2243                    if (!item) {
2244                        skippedItems += 1;
2245                        return res;
2246                    }
2247                    if (data) data.index = idx - skippedItems;
2248                    return res + options.fn(item, {
2249                        data: data
2250                    });
2251                }, '');
2252            } else for(let i = 0, j = (items || []).length; i < j; i++){
2253                if (data) data.index = i;
2254                ret += options.fn(items[i], {
2255                    data: data
2256                });
2257            }
2258            return ret;
2259        },
2260        ifIn (elem, list, options) {
2261            if (list && list.indexOf(elem) > -1) return options.fn(this);
2262            return options.inverse(this);
2263        },
2264        partial (name, options) {
2265            // Register a partial and output the content in a script for clientside rendering
2266            HandlebarsInstance.registerPartial(name, HandlebarsInstance.compile(options.fn()));
2267            // eslint-disable-next-line
2268            const script = `
2268<script type="text/x-handlebars-template" class="${name} pagination-script">${options.fn()}</${'script'}>`;
2269            return script;
2270        },
2271        numCompare (l, r, operator, options) {
2272            const operators = {
2273                '==': function(l, r) {
2274                    // eslint-disable-next-line
2275                    return l == r;
2276                },
2277                '===': function(l, r) {
2278                    return l === r;
2279                },
2280                '!=': function(l, r) {
2281                    // eslint-disable-next-line
2282                    return l != r;
2283                },
2284                '<': function(l, r) {
2285                    return l < r;
2286                },
2287                '>': function(l, r) {
2288                    return l > r;
2289                },
2290                '<=': function(l, r) {
2291                    return l <= r;
2292                },
2293                '>=': function(l, r) {
2294                    return l >= r;
2295                }
2296            };
2297            const result = operators[operator](l, r);
2298            if (result) return options.fn ? options.fn(this) : true;
2299            return options.fn ? options.inverse(this) : false;
2300        },
2301        lpFormatNumber: lpFormatNumber,
2302        arrayToHtmlList (arr, options) {
2303            // eslint-disable-next-line
2304            return arr.reduce((acc, current)=>{
2305                try {
2306                    if (typeof current === 'object' || current === null) return acc;
2307                    // eslint-disable-next-line
2308                    return acc += `<li>${current}</li>`;
2309                } catch (e) {
2310                /* empty */ }
2311            }, '');
2312        },
2313        join (array, separator, options) {
2314            if (!array || !array.join) return '';
2315            return array.join(typeof separator === 'string' ? separator : ', ');
2316        },
2317        dedupe (items, key, options) {
2318            let data = null;
2319            let skippedItems = 0;
2320            const list = new Set();
2321            if (options.data) data = HandlebarsInstance.createFrame(options.data);
2322            return (items || []).reduce((res, item, idx)=>{
2323                const val = key ? item[key] : item;
2324                // Item is unique if we're passed a key that is not defined
2325                const isUnique = !list.has(val) || key && val === undefined;
2326                if (isUnique) list.add(val);
2327                else {
2328                    skippedItems += 1;
2329                    return res;
2330                }
2331                if (data) data.index = idx - skippedItems;
2332                return res + options.fn(item, {
2333                    data: data
2334                });
2335            }, '');
2336        },
2337        JSONstringify (obj, options) {
2338            return JSON.stringify(obj);
2339        },
2340        // eslint-disable-next-line sonarjs/cognitive-complexity
2341        formatPropertyPrice (...args) {
2342            const options = args[args.length - 1];
2343            const opts = options.hash;
2344            const property = args.length > 1 ? args[0] : opts.property;
2345            const precision = opts.precision || 0;
2346            if (args.length > 2) // eslint-disable-next-line
2347            opts.mode = args[1];
2348            if (!opts.mode) opts.mode = 'short';
2349            let separator = args.length > 3 ? args[2] : opts.separator;
2350            if (typeof separator !== 'string') separator = ' | ';
2351            if (property.isPasswordProtected) return 'Exclusive Listing';
2352            let priceUponRequestText = args.length > 4 ? args[3] : opts.priceUponRequestText;
2353            if (typeof priceUponRequestText !== 'string') priceUponRequestText = 'Price Upon Request';
2354            if (property.priceUponRequest) return priceUponRequestText;
2355            let price = property.salesPrice;
2356            let reduced = null;
2357            // eslint-disable-next-line sonarjs/no-collapsible-if
2358            if (property.status !== 'SOLD' && property.status !== 'Leased') {
2359                if (property.reducedPrice) {
2360                    if (!opts.reducedClass) price = property.reducedPrice;
2361                    else reduced = property.reducedPrice;
2362                }
2363            }
2364            let result = '';
2365            if (reduced) result += `<${opts.reducedTag || 'span'} class="${opts.reducedClass}">${lpFormatNumber(reduced, property.currency, precision)}</${opts.reducedTag || 'span'}>`;
2366            if (price) {
2367                price = lpFormatNumber(price, property.currency, precision);
2368                if (opts.priceTag || opts.priceClass) result += `<${opts.priceTag || 'span'}${opts.priceClass ? ` class="${opts.priceClass}"` : ''}>${price}</${opts.priceTag || 'span'}>`;
2369                else result += price;
2370            }
2371            const leasePrice = property.leasePrice && lpFormatNumber(property.leasePrice, property.currency, precision);
2372            if (leasePrice) {
2373                if (result) result += separator;
2374                const leaseText = `${leasePrice}${formatFrequencyExt(property.leasePeriod, opts)}`;
2375                if (opts.leaseTag || opts.leaseClass) result += `<${opts.leaseTag || 'span'}${opts.leaseClass ? ` class="${opts.leaseClass}"` : ''}>${leaseText}</${opts.leaseTag || 'span'}>`;
2376                else result += leaseText;
2377            }
2378            return new HandlebarsInstance.SafeString(result);
2379        },
2380        // eslint-disable-next-line sonarjs/cognitive-complexity
2381        mediaImage (mediaSource, options = {}) {
2382            if (!mediaSource) return;
2383            const { lazy: lazy, ...attributes } = options.hash;
2384            let src = '';
2385            let srcset = '';
2386            if (typeof mediaSource === 'string') src = mediaSource;
2387            else {
2388                const srcMap = {};
2389                const { height: height, width: width, altTagText: altTagText } = mediaSource;
2390                MEDIA_SIZES.forEach((src)=>{
2391                    if (mediaSource[src.field] && !srcMap[mediaSource[src.field]]) srcMap[mediaSource[src.field]] = src.w;
2392                });
2393                const srcs = Object.keys(srcMap);
2394                if (!srcs.length) return;
2395                if (altTagText) attributes.alt = altTagText;
2396                if (height && width) {
2397                    if (height >= width) {
2398                        if (attributes.class) attributes.class += ' portrait';
2399                        else attributes.class = 'portrait';
2400                    }
2401                    if ('setDims' in options.hash) {
2402                        attributes.width = width;
2403                        attributes.height = height;
2404                    }
2405                }
2406                if (srcs.length > 1 && width && width < srcMap[srcs[srcs.length - 1]]) {
2407                    const maxSrc = srcs.findIndex((src)=>
2407srcMap[src] >= width);
2408                    srcs.splice(maxSrc + 1);
2409                    srcMap[srcs[srcs.length - 1]] = width;
2410                }
2411                if (srcs.length > 1) {
2412                    srcset = srcs.map((s)=>`${s} ${srcMap[s]}w`).join(', ');
2413                    srcs.sort((a, b)=>Math.abs(srcMap[a] - MEDIA_SIZE_FOR_SRC) - Math.abs(srcMap[b] - MEDIA_SIZE_FOR_SRC));
2414                }
2415                // eslint-disable-next-line
2416                src = srcs[0];
2417            }
2418            delete attributes.setDims;
2419            if (!srcset) delete attributes.sizes;
2420            if (!('alt' in attributes)) attributes.alt = '';
2421            if (!('loading' in attributes) && (options?.data?.root?.sectionIndex > 1 || lazy)) attributes.loading = 'lazy';
2422            const attrs = Object.keys(attributes).map((k)=>`${HandlebarsInstance.escapeExpression(k)}="${HandlebarsInstance.escapeExpression(attributes[k])}"`).join(' ');
2423            return new HandlebarsInstance.SafeString(// eslint-disable-next-line sonarjs/no-nested-template-literals
2424            `<img src="${src}"${srcset ? ` srcset="${srcset}"` : ''}${attrs ? ` ${attrs}` : ''}>`);
2425        },
2426        bgImage (mediaSource) {
2427            if (!mediaSource) return '';
2428            if (typeof mediaSource === 'string') return mediaSource;
2429            return mediaSource.largeUrl || mediaSource.url || '';
2430        },
2431        concat (...rest) {
2432            let outStr = '';
2433            // rest params are Array instances while arguments object is not
2434            for(const arg in rest)if (rest[arg] !== null && rest[arg] !== undefined && typeof rest[arg] !== 'object') outStr += rest[arg];
2435            return outStr;
2436        },
2437        setVideoExtension (uri, format) {
2438            if (!uri || !format) return '';
2439            const decodedUri = new URL(uri);
2440            if (decodedUri.host !== 'res.cloudinary.com') {
2441                // Not a cloudinary uri, do not rewrite
2442                if (decodedUri.pathname.endsWith(`.${format}`)) return uri;
2443                return '';
2444            }
2445            // Rewrite the cloudinary uri
2446            const lastPeriodIdx = decodedUri.pathname.lastIndexOf('.');
2447            let pathWithoutFormat = decodedUri.pathname;
2448            if (lastPeriodIdx !== -1) pathWithoutFormat = decodedUri.pathname.substr(0, lastPeriodIdx);
2449            decodedUri.pathname = `${pathWithoutFormat}.${format}`;
2450            return decodedUri.toString();
2451        },
2452        addVideoSources (uri) {
2453            if (!uri) return '';
2454            const VIDEO_VARIANTS = [
2455                {
2456                    format: 'webm',
2457                    codec: 'vp9',
2458                    htmlCodecs: ';codecs=vp9'
2459                },
2460                {
2461                    format: 'mp4',
2462                    codec: 'h265',
2463                    htmlCodecs: ';codecs=hvc1'
2464                },
2465                {
2466                    format: 'mp4',
2467                    codec: 'h264',
2468                    htmlCodecs: ''
2469                }
2470            ];
2471            const VIDEO_EXT_REGEXP = /\.(?:3gp|mpeg|mp4|m4v|m4p|ogv|ogg|mov|webm)$/;
2472            if (!uri.includes('res.cloudinary.com')) // keep existing or no extension for non Cloudinary urls
2473            return `<source data-src="${uri}">`;
2474            // Cap delivery at 1080p (1920px wide) while preserving aspect ratio. Width-only:
2475            // c_limit never upscales, so portrait sources are left at their native size.
2476            // No q_auto: quality is left to Cloudinary's default rather than forced down.
2477            // Note the regex below consumes any q_auto in the source URL, so it is dropped
2478            // rather than carried through.
2479            const CONSTRAINED_DELIVERY = 'w_1920,c_limit';
2480            const uriNoExt = uri.replace(VIDEO_EXT_REGEXP, '');
2481            const sources = VIDEO_VARIANTS.map((type)=>{
2482                const cloudinaryFormatUrl = `${uriNoExt.replace(/f_auto(?::video)?(?:,q_auto(?::\w+)?)?/, `f_${type.format},vc_${type.codec},${CONSTRAINED_DELIVERY}`)}.${type.format}`;
2483                return `<source data-src="${cloudinaryFormatUrl}" type="video/${type.format}${type.htmlCodecs}">`;
2484            });
2485            return sources.join('\n');
2486        },
2487        cloudinaryVideoFirstFrame: $0ce6edea77f7b81a$exports.getVideoFirstFrame,
2488        initials (text, options) {
2489            if (!text) return '';
2490            if (options?.hash?.endChar) // eslint-disable-next-line
2491            text = text.split(options.hash.endChar)[0];
2492            // eslint-disable-next-line
2493            const maxChars = +options?.hash?.maxChars || 2; // we do not allow this to be 0
2494            let result = text.match(/\b\w/g)?.slice(0, maxChars);
2495            if (!result) return '';
2496            if (options?.hash?.addText) result = result.map((item)=>item + options.hash.addText);
2497            return result.join(options?.hash?.joinWith || '').toUpperCase();
2498        },
2499        normalizePhone (phone) {
2500            if (!phone) return '';
2501            const str = String(phone).trim();
2502            return (str.startsWith('+') ? '+' : '') + str.replace(/\D/g, '');
2503        }
2504    };
2505}
2506$53de3c160faf5a81$exports = $53de3c160faf5a81$var$handlebarsHelpersFactory;
2507
2508
2509/* global window, document */ // eslint-disable-next-line import/prefer-default-export
2510class $dc851cf3939b6ef5$export$ff0712c26d5458f7 {
2511    /**
2512   * Initialize Modal Controller
2513   * @param {Object} options
2514   */ constructor(options){
2515        this.isBuilder = false;
2516        this.companyId = null;
2517        this.websiteId = null;
2518        this.pageId = null;
2519        this.shareId = null;
2520        this.pageMeta = null;
2521        this.websiteApiGatewayUrl = null;
2522        this.buyerSellerServiceUrl = null;
2523        this.leadIngesterUrl = null;
2524        this.divolteServiceUrl = null;
2525        this.eventBus = null;
2526        this.templateId = null;
2527        this.myhomeDashboardEnabled = false;
2528        this.mlsEnabled = false;
2529        this.hstValuationRedirectEnabled = false;
2530        this.googleMapsAPIKey = null;
2531    }
2532    /**
2533   * Controllers must implement a "destroy" method to be called
2534   * after page navigation to remove event handlers / cleanup
2535   */ destroy() {}
2536    /**
2537   * Set page and supporting data
2538   * @param {string} pageId
2539   * @param {Object} options
2540   */ setPage(pageId, options = {}) {
2541        this.pageId = pageId;
2542        this.shareId = options.shareId || null;
2543        this.pageMeta = {
2544            sourceResource: options.sourceResource,
2545            pageElementId: options.pageElementId,
2546            pageQueryVariables: options.pageQueryVariables || {}
2547        };
2548    }
2549    /**
2550   * Sets if we are in pagebuilder context or not
2551   * @param {boolean} isBuilder
2552   */ setIsBuilder(isBuilder) {
2553        this.isBuilder = isBuilder;
2554    }
2555    /**
2556   * Set Company and supporting data
2557   * @param {string} companyId
2558   * @param {Object} options
2559   */ setCompany(companyId, options = {}) {
2560        this.companyId = companyId;
2561    }
2562    /**
2563   * Set website and supporting data
2564   * @param {string} websiteId
2565   * @param {Object} options
2566   */ setWebsite(websiteId, options = {}) {
2567        this.websiteId = websiteId;
2568        if (options.myhomeDashboardEnabled) this.myhomeDashboardEnabled = options.myhomeDashboardEnabled;
2569        if (options.mlsEnabled) this.mlsEnabled = options.mlsEnabled;
2570        if (options.hstValuationRedirectEnabled) this.hstValuationRedirectEnabled = options.hstValuationRedirectEnabled;
2571    }
2572    /**
2573   * Set websiteApiGatewayUrl
2574   * @param {string} websiteApiGatewayUrl
2575   * @param {Object} options
2576   */ setWebsiteApiGatewayUrl(websiteApiGatewayUrl, options = {}) {
2577        this.websiteApiGatewayUrl = websiteApiGatewayUrl;
2578    }
2579    /**
2580   * Set buyerSellerServiceUrl
2581   * @param {string} buyerSellerServiceUrl
2582   * @param {Object} options
2583   */ setBuyerSellerServiceUrl(buyerSellerServiceUrl, options = {}) {
2584        this.buyerSellerServiceUrl = buyerSellerServiceUrl;
2585    }
2586    /**
2587   * Set divolteServiceUrl and supporting data
2588   * @param {string} divolteServiceUrl
2589   * @param {Object} options
2590   */ setDivolteServiceUrl(divolteServiceUrl, options = {}) {
2591        this.divolteServiceUrl = divolteServiceUrl;
2592    }
2593    /**
2594   * Set eventBusUrl
2595   * @param {string} eventBusUrl
2596   * @param {Object} options
2597   */ setEventBusUrl(eventBusUrl, options = {}) {
2598        this.eventBusUrl = eventBusUrl;
2599    }
2600    /**
2601   * Set templateId and supporting data
2602   * @param {string} templateId
2603   * @param {Object} options
2604   */ setTemplateId(templateId, options = {}) {
2605        this.templateId = templateId;
2606    }
2607    /**
2608   * Set leadIngesterUrl
2609   * @param {string} leadIngesterUrl
2610   * @param {Object} options
2611   */ setLeadIngesterUrl(leadIngesterUrl, options = {}) {
2612        this.leadIngesterUrl = leadIngesterUrl;
2613    }
2614    /**
2615   * Set googleMapsAPIKey
2616   * @param {string} googleMapsAPIKey
2617   * @param {Object} options
2618   */ setGoogleMapsAPIKey(googleMapsAPIKey, options = {}) {
2619        this.googleMapsAPIKey = googleMapsAPIKey;
2620    }
2621    /**
2622   * Set eventBus
2623   * @param {Object} options
2624   */ setEventBus({ enabled: enabled, apiKey: apiKey, url: url }) {
2625        this.eventBus = {
2626            enabled: enabled,
2627            apiKey: apiKey,
2628            url: url
2629        };
2630    }
2631}
2632
2633
2634/* eslint-disable import/prefer-default-export */ // eslint-disable-next-line import/prefer-default-export
2635class $7c391e2f7931d60d$export$3b5bd9381a52554c {
2636    /**
2637   * Initialize Base Controller at build time
2638   * @param { ConfigController } config
2639   * @param {Window} window
2640   * @param {Document} document
2641   */ constructor(config, window, document){
2642        // TODO: Listen for events from configController to update configuration
2643        this.config = config;
2644        this.window = window;
2645        this.document = document;
2646        if (!this.destroy) // With turbolinks, we want to ensure that on each page load we have the latest version of the sdk
2647        //  Controllers are deconstructed and replaced (on the window object) per request
2648        //  Controllers must use the destory method to remove event handlers to prevent undefined behavior
2649        throw new Error('Controllers must implement a deconstructor');
2650    }
2651}
2652
2653
2654// eslint-disable-next-line import/prefer-default-export
2655const $a3e97e89bbc2a366$export$f037eeffb5561205 = 2000;
2656
2657
2658class $0ead03fdb95fa9ce$export$d507f25e63650365 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
2659    /**
2660   * Initialize Modal Controller at build time
2661   * @param { ConfigController } config
2662   * @param {Window} window
2663   * @param {Document} document
2664   */ constructor(config, window, document){
2665        super(config, window, document);
2666        this.setLoginState = this.setLoginState.bind(this);
2667        this.pageId = null;
2668        this.modals = [];
2669        this.exitModalTriggered = {};
2670        this.exitModalEventListeners = [];
2671    }
2672    /**
2673   * Initialize Modal Controller at run time
2674   * Attach handlers and events to DOM
2675   * @param {Object} options
2676   */ initialize(options) {
2677        try {
2678            const { config: config, document: document } = this;
2679            this.pageId = config.pageId;
2680            this.modals = document.querySelectorAll('body > #modals > .modal');
2681            options.modals.forEach((m)=>{
2682                this._attachModalHandler(m);
2683            });
2684        } catch (e) {
2685            // eslint-disable-next-line no-console
2686            console.log(e);
2687        }
2688    }
2689    /**
2690   * Controllers must implement a "destroy" method to be called
2691   * after page navigation to remove event handlers / cleanup
2692   */ destroy() {
2693        const { document: document } = this;
2694        this.exitModalEventListeners.forEach((listener)=>{
2695            document.removeEventListener('mouseout', listener);
2696        });
2697        this.modals = [];
2698        this.exitModalTriggered = {};
2699        this.exitModalEventListeners = [];
2700    }
2701    /**
2702   * Set modal to local storage with expiration
2703   * @param {string} modalId
2704   */ setModalWithExpiry(modalId) {
2705        const { window: window } = this;
2706        const TTL = 86400000; // 24 hours
2707        const now = new Date();
2708        const expiry = now.getTime() + TTL;
2709        const key = `modal-controller-${modalId}`;
2710        try {
2711            window.localStorage.setItem(key, JSON.stringify(expiry));
2712        } catch (err) {
2713        // catch error when setting item to storage on iOS private browser
2714        }
2715    }
2716    /**
2717   * Save success login modal to local storage
2718   */ setLoginState() {
2719        const { window: window } = this;
2720        try {
2721            window.localStorage.setItem('isSignedUp', 'true');
2722        } catch (err) {
2723        // catch error when setting item to storage on iOS private browser
2724        }
2725    }
2726    /**
2727   * Get modal and check expiration
2728   * @param {string} modalId
2729   * @return {boolean}
2730   */ getModalWithExpiry(modalId) {
2731        const { window: window } = this;
2732        const storage = window.localStorage;
2733        const expirationTime = storage.getItem(`modal-controller-${modalId}`);
2734        if (!expirationTime) return false;
2735        const expiry = JSON.parse(expirationTime);
2736        const now = new Date();
2737        if (now.getTime() > expiry) {
2738            storage.removeItem(`modal-controller-${modalId}`);
2739            return false;
2740        }
2741        return true;
2742    }
2743    /**
2744   * Make a modal visible
2745   * @param {string} modalId
2746   * @param {Object} options
2747   */ show(modalId, options = {}) {
2748        // TODO: migrate logic from page.handlebars
2749        const { window: window } = this;
2750        const modalViewed = this.getModalWithExpiry(modalId);
2751        // Only show a modal if it has not been seen
2752        // Does not affect "show modal on button click"
2753        if (modalId && !modalViewed || options.forced === true) {
2754            window.lpUI.showModal(`modal-${modalId}`, options);
2755            this.setModalWithExpiry(modalId);
2756        }
2757    }
2758    /**
2759   * Attach events based on Modal type and page settings
2760   * @param {Modal} modal
2761   */ _attachModalHandler(modal) {
2762        const { pageId: pageId } = this;
2763        const { trigger: trigger, pageSpecific: pageSpecific } = modal;
2764        if (pageSpecific) {
2765            const pageIds = modal.pages.map((p)=>p.pageId);
2766            if (!pageIds.includes(pageId)) // Modal does not belong to this page
2767            return;
2768        }
2769        if (trigger === 'EXIT') this._exitModalHandler(modal);
2770        else if (trigger === 'TIMER') this._timerModalHandler(modal);
2771        else if (trigger === 'FORCED') this._forcedModalHandler(modal);
2772    }
2773    /**
2774   * Attach events for exit Modals
2775   * @param {Modal} modal
2776   */ _exitModalHandler(modal) {
2777        // eslint-disable-next-line
2778        const that = this;
2779        const { document: document, exitModalTriggered: exitModalTriggered } = this;
2780        const { modalId: modalId } = modal;
2781        /**
2782     * Handle the mouseout dom event
2783     * @param {Event} event
2784     */ function triggerExitModal(event) {
2785            if (exitModalTriggered[modalId]) return;
2786            if (!event.toElement && !event.relatedTarget) {
2787                that.show(modalId);
2788                exitModalTriggered[modalId] = true;
2789            }
2790        }
2791        document.addEventListener('mouseout', triggerExitModal);
2792        this.exitModalEventListeners.push(triggerExitModal);
2793    }
2794    /**
2795   * Attach events for timer Modals
2796   * @param {Modal} modal
2797   */ _timerModalHandler(modal) {
2798        const { modalId: modalId, timerDelay: timerDelay } = modal;
2799        setTimeout(()=>{
2800            this.show(modalId);
2801        }, timerDelay);
2802    }
2803    /**
2804   * Attach events for Forced Modals
2805   * @param {Modal} modal
2806   */ _forcedModalHandler(modal) {
2807        const { modalId: modalId } = modal;
2808        const { window: window, document: document } = this;
2809        const isLoggedIn = window.localStorage.getItem('isSignedUp') === 'true';
2810        if (!isLoggedIn) {
2811            // watch for event triggering success login
2812            const forcedModal = document.querySelector(`#modal-${modalId}`);
2813            const contactForm = forcedModal?.querySelector('form');
2814            const MODAL_CLOSE_DELAY = contactForm?.dataset.delay || (0, $a3e97e89bbc2a366$export$f037eeffb5561205);
2815            // form submit autoclose is handled by contactForms controller
2816            contactForm.addEventListener('formsubmitted', ()=>{
2817                this.setLoginState();
2818            });
2819            window.addEventListener('oauthSuccess', ()=>{
2820                this.setLoginState();
2821                contactForm.classList.add('success');
2822                setTimeout(()=>{
2823                    window.lpUI.hideModal(`modal-${modalId}`);
2824                    contactForm.reset();
2825                    contactForm.classList.remove('success');
2826                }, MODAL_CLOSE_DELAY);
2827            });
2828            this.show(modalId, {
2829                forced: true
2830            });
2831        }
2832    }
2833}
2834
2835
2836/* eslint-disable import/prefer-default-export */ /* global window */ /* eslint-disable import/prefer-default-export */ /**
2837 * Handle navigation push
2838 * @param {string} href
2839 * @param {boolean} _blank
2840 */ const $fc0a058ae42af628$export$95e8d77caafa3e06 = (href, _blank = false)=>{
2841    if (!href) return;
2842    if (_blank) {
2843        window.open(href);
2844        return;
2845    }
2846    window.location.assign(href);
2847};
2848const $fc0a058ae42af628$export$267a1435fe18b8d4 = (obj, path, defValue)=>{
2849    if (!path) return undefined;
2850    const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g);
2851    const result = pathArray.reduce((prevObj, key)=>prevObj && prevObj[key], obj);
2852    return result === undefined ? defValue : result;
2853};
2854
2855
2856
2857class $d48f9f944810f613$export$ca3218b7861b9cb0 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
2858    /**
2859   * Initialize Button Controller at build time
2860   * @param { ConfigController } config
2861   * @param {Window} window
2862   * @param {Document} document
2863   */ constructor(config, window, document){
2864        super(config, window, document);
2865        this._boundClickHandler = this._buttonClickHandler.bind(this);
2866    }
2867    /**
2868   * Initialize Button Controller at run time
2869   * Attach handlers and events to DOM
2870   * @param {Object} options
2871   */ initialize(options = {}) {
2872        try {
2873            const { document: document } = this;
2874            document.body.removeEventListener('click', this._boundClickHandler);
2875            document.body.addEventListener('click', this._boundClickHandler);
2876        } catch (e) {
2877            // eslint-disable-next-line no-console
2878            console.error(e);
2879        }
2880    }
2881    /**
2882   * Controllers must implement a "destroy" method to be called
2883   * after page navigation to remove event handlers / cleanup
2884   */ destroy() {
2885        const { document: document } = this;
2886        document.body.removeEventListener('click', this._boundClickHandler);
2887    }
2888    /**
2889   * Buttons click handler
2890   * @param {event} e
2891   */ _buttonClickHandler(e) {
2892        this._handleButtonClick(e).catch((e)=>console.error(e));
2893    }
2894    /**
2895   * Handle button click
2896   * We need special function to have easy way to detach listener
2897   * @param {Event} e
2898   */ async _handleButtonClick(e) {
2899        const { window: window, document: document } = this;
2900        const button = e.target.closest('button, a');
2901        if (!button) return;
2902        const type = button.dataset.type || '';
2903        const href = button.href || button.dataset.href || '';
2904        const target = button.target || '';
2905        const { submit: submit } = button.dataset;
2906        if (submit) {
2907            try {
2908                await this._handleSubmit(button);
2909            } catch (err) {
2910                // eslint-disable-next-line no-console
2911                console.error(err);
2912            }
2913            (0, $fc0a058ae42af628$export$95e8d77caafa3e06)(href, target === '_blank');
2914        }
2915        this._trackConversion(button);
2916        if (type === 'VIDEO') {
2917            this._handleVideoButton(button);
2918            return;
2919        }
2920        if (type === 'CONTACT_US') {
2921            this._handleContactUsButton(button);
2922            return;
2923        }
2924        if (type === 'SUBSCRIBE') {
2925            // TODO: Extend for an overwritten subscribe
2926            window.lpUI.showModal('modal-global-subscribe');
2927            return;
2928        }
2929        if (type === 'MY_ACCOUNT') {
2930            // TODO: Extend for an overwritten subscribe
2931            window.lpUI.showModal('modal-global-my-account');
2932            return;
2933        }
2934        if (type === 'SHARE_POPUP') {
2935            // TODO: Extend for an overwritten subscribe
2936            const sharePopup = button.querySelector('.share-popup');
2937            if (sharePopup) sharePopup.style.display = 'flex';
2938            e.stopPropagation(); // this may not work in current 'delegate' mode
2939            return;
2940        }
2941        // Custom modals
2942        if (type.substring(0, 6) === 'MODAL_') {
2943            const modalId = type.substring(6);
2944            window.lpUI.showModal(`modal-${modalId}`);
2945            return;
2946        }
2947        // MAILTO / TEL Event
2948        if (href?.startsWith('mailto:')) {
2949            const email = href.substring(7);
2950            // TODO: Replace with SDK method
2951            document.sendGoogleAnalyticsEvent({
2952                hitType: 'event',
2953                eventCategory: 'button',
2954                eventAction: 'click',
2955                eventLabel: 'Email',
2956                eventValue: email
2957            });
2958        } else if (href?.startsWith('tel:')) {
2959            const phoneNumber = href.substring(4);
2960            // TODO: Replace with SDK method
2961            document.sendGoogleAnalyticsEvent({
2962                hitType: 'event',
2963                eventCategory: 'button',
2964                eventAction: 'click',
2965                eventLabel: 'Phone',
2966                eventValue: phoneNumber
2967            });
2968        }
2969    }
2970    /**
2971   * Handle submit
2972   * @param {HTMLButtonElement|HTMLAnchorElement} button
2973   */ async _handleSubmit(button) {
2974        const form = button.closest('form');
2975        const { window: window } = this;
2976        if (form) return await window.luxuryPresence.contactForms.submitForm(form);
2977        return null;
2978    }
2979    _getVimeoSrc(link) {
2980        if (!link || !link.includes('vimeo.com') || link.length > 2000) return null;
2981        const matchResult = link.match(/(?:(?:www\.)?vimeo\.com\/(?:showcase\/\d+(?:\/video\/|\?video[=/])|channels\/(?:\w+\/)?|groups\/(?:[^/]*)\/videos\/|)|player\.vimeo\.com\/video\/)(\d+)(?:(?:\?.*&*h=|\/)+([\d,a-f]+))?/);
2982        if (!matchResult) return null;
2983        const [, vimeoId, vimeoHashParameter] = matchResult;
2984        let src = `https://player.vimeo.com/video/${vimeoId}?`;
2985        if (vimeoHashParameter) src += `h=${vimeoHashParameter}&`;
2986        src += 'autoplay=1';
2987        return src;
2988    }
2989    /**
2990   * Handle type video click
2991   * @param {HTMLElement} button
2992   */ // eslint-disable-next-line sonarjs/cognitive-complexity
2993    _handleVideoButton(button) {
2994        const { document: document } = this;
2995        const section = button.closest('section');
2996        // Embed youtube/vimeo video url
2997        let { src: src } = button.dataset;
2998        let youtubeId = '';
2999        if (src && (src.includes('youtube.com') || src.includes('youtu.be')) && !src.includes('youtube.com/embed')) {
3000            // test link: https://regexr.com/3anm9
3001            const youtubeRegex = /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v=)
3001)|youtu.be\/)([a-zA-Z0-9_-]{6,11})/;
3002            const youtubeResult = src.match(youtubeRegex);
3003            // eslint-disable-next-line
3004            if (youtubeResult) youtubeId = youtubeResult[1];
3005        }
3006        const vimeoSrc = this._getVimeoSrc(src);
3007        if (youtubeId) src = `https://youtube.com/embed/${youtubeId}?autoplay=1&controls=0`;
3008        else if (vimeoSrc) src = vimeoSrc;
3009        if (!src || !section) return;
3010        const isVideoFile = src.endsWith('.mp4') || src.endsWith('.webm') || src.includes('cloudinary.com');
3011        const modalHtml = `
3012      <div id="modal-${section.id}" class="modal visible">
3013        <div class="modal-content">
3014          <div class="lightbox-video">
3015            <div class="video-player">
3016              <div class="embed-container">
3017                ${isVideoFile ? `<video controls autoplay src="${src}"></video>` : `<iframe frameborder="0" allowfullscreen="1" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" title="YouTube video player" width="100%" height="100%" src="${src}"></iframe>`}
3018              </div>
3019            </div>
3020          </div>
3021        </div>
3022        <button class="close lp-close" type="button" aria-label="close modal"><span class="lp-close-icon" aria-hidden="true"></span></button>
3023      </div>
3024    `;
3025        document.body.insertAdjacentHTML('beforeend', modalHtml);
3026        const modal = document.getElementById(`modal-${section.id}`);
3027        const closeModal = modal.querySelector('.close');
3028        closeModal.addEventListener('click', ()=>{
3029            modal.remove();
3030        });
3031    }
3032    /**
3033   * Handle type contact us click
3034   * @param {HTMLElement} button
3035   */ _handleContactUsButton(button) {
3036        const { window: window, document: document } = this;
3037        // TODO: Extend for an overwritten contact us
3038        document.sendGoogleAnalyticsEvent({
3039            hitType: 'event',
3040            eventCategory: 'button',
3041            eventAction: 'click',
3042            eventLabel: 'contact'
3043        });
3044        window.lpUI.showModal('modal-global-contact-us', {
3045            scrollLock: true
3046        });
3047    }
3048    /**
3049   * Track conversion
3050   * @param {HTMLElement} button
3051   */ _trackConversion(button) {
3052        const { window: window, document: document } = this;
3053        // Conversion Tracking Options
3054        const { gtagConversionId: gtagConversionId, gtagConversionLabel: gtagConversionLabel, fbEventName: fbEventName } = button.dataset;
3055        if (gtagConversionId && gtagConversionLabel) {
3056            if (window.dataLayer && window.dataLayer.length) {
3057                const configured = window.dataLayer.some((layer)=>layer.length && layer[0] === 'config' && layer[1] === gtagConversionId);
3058                if (!configured) document.sendGoogleTagManagerEvent('config', gtagConversionId);
3059            }
3060            const sentTo = `${gtagConversionId}/${gtagConversionLabel}`;
3061            document.sendGoogleTagManagerEvent('event', 'conversion', {
3062                send_to: sentTo
3063            });
3064        }
3065        if (window.fbq && fbEventName) window.fbq('track', fbEventName, {});
3066    }
3067}
3068
3069
3070/* eslint-disable import/prefer-default-export */ 
3071class $68a2d4aa500c7a05$export$61ec8f2b6291ec31 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
3072    /**
3073   * Initialize Validation Controller at build time
3074   * @param { ConfigController } config
3075   * @param {Window} window
3076   * @param {Document} document
3077   */ constructor(config, window, document){
3078        super(config, window, document);
3079        this.validatedForms = [];
3080    }
3081    /**
3082   * Initialize Contact Form Controller at run time
3083   * Attach handlers and events to DOM
3084   * @param {Object} options
3085   */ initialize(options = {}) {
3086        try {
3087            const { window: window, document: document } = this;
3088            const { selector: selector } = options;
3089            let validatedForms = [];
3090            if (selector) validatedForms = document.querySelectorAll(`${selector} form[data-type="contact-form"]`);
3091            else validatedForms = document.querySelectorAll('form[data-type="contact-form"]');
3092            const isPhoneValidationLibRequired = !!document.querySelectorAll('input[type="tel"]').length;
3093            // we are loading the phone validation lib from the globally defined list of libs
3094            if (isPhoneValidationLibRequired && !window.libphonenumber && window?.luxuryPresence?.libs) {
3095                const { loadJs: loadJs, jsLibsMap: jsLibsMap } = window.luxuryPresence.libs;
3096                const { libphonenumber: libphonenumber } = jsLibsMap;
3097                loadJs(libphonenumber.jsSrc, this.attachValidation.bind(this, validatedForms));
3098            }
3098 else this.attachValidation(validatedForms);
3099            this.validatedForms = this.validatedForms.concat(validatedForms);
3100        } catch (e) {
3101            // eslint-disable-next-line no-console
3102            console.log(e);
3103        }
3104    }
3105    /**
3106   * Controllers must implement a "destroy" method to be called
3107   * after page navigation to remove event handlers / cleanup
3108   */ destroy() {
3109        this.validatedForms = [];
3110    }
3111    /**
3112   * Validate all forms in the document
3113   * @param {NodeListOf<HTMLFormElement>} forms
3114   */ attachValidation(forms) {
3115        forms.forEach((form)=>{
3116            const inputs = form.querySelectorAll('input, select, textarea');
3117            inputs.forEach((input)=>{
3118                this.applyFieldValidation(input);
3119            });
3120        });
3121    }
3122    /**
3123   * Field Validation Handler from global context
3124   * @param {HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement} inputField
3125   */ applyFieldValidation(inputField) {
3126        const fieldType = inputField.getAttribute('type');
3127        if (fieldType === 'tel') this._applyPhoneValidation(inputField);
3128    }
3129    /**
3130   * Phone Field Validation Handler
3131   * @param {HTMLInputElement} inputField
3132   */ _applyPhoneValidation(inputField) {
3133        const { window: window } = this;
3134        if (window.libphonenumber) {
3135            // https://codepen.io/coinscope/pen/BaXBvBp?editors=1010
3136            const phoneUtil = window.libphonenumber.isValidPhoneNumber;
3137            inputField.addEventListener('keyup', function() {
3138                if (this.hasAttribute('required') || this.value.replace(/\s/g, '').length) try {
3139                    const phoneNumber = this.value;
3140                    const region = 'US';
3141                    const isValidNumber = phoneUtil(phoneNumber, region);
3142                    if (!isValidNumber) this.setCustomValidity('Please enter a valid phone number.');
3143                    else this.setCustomValidity('');
3144                } catch (e) {
3145                    this.setCustomValidity('Please enter a valid phone number.');
3146                }
3147                else this.setCustomValidity('');
3148            });
3149        }
3150    }
3151}
3152
3153
3154
3155
3156/**
3157 * Fires the `generate_lead` Google Ads conversion on any marketing-site lead
3158 * event — lead-form submits (all routed through ContactFormController) and
3159 * social sign-in (oauth.js) — at most once per session.
3160 *
3161 * Reuses the same `generate_lead` event the Home Search Tool fires; the page
3162 * template already configures the LP Google tags, so no new Google Ads setup is
3163 * needed. Cross-tab/visitor dedupe is left to the conversion action's
3164 * Count="One" — localStorage is intentionally avoided as it would suppress a
3165 * returning visitor's later lead.
3166 */ const $3ec2bf3965f87ecc$export$78b64890ea40f4e4 = 'generate_lead';
3167const $3ec2bf3965f87ecc$export$568da12be2433b06 = 'lp_lead_form_conversion_fired';
3168function $3ec2bf3965f87ecc$var$alreadyFired(window) {
3169    try {
3170        return window.sessionStorage.getItem($3ec2bf3965f87ecc$export$568da12be2433b06) === 'true';
3171    } catch  {
3172        // sessionStorage can throw in private browsing; fail open so we still fire.
3173        return false;
3174    }
3175}
3176function $3ec2bf3965f87ecc$var$markFired(window) {
3177    try {
3178        window.sessionStorage.setItem($3ec2bf3965f87ecc$export$568da12be2433b06, 'true');
3179    } catch  {
3180    // Ignore — see alreadyFired().
3181    }
3182}
3183function $3ec2bf3965f87ecc$export$e70565180c0e6950(window, document) {
3184    if (!window || !document) return;
3185    // GA bootstrap may not have run yet (or no pixel on this page); don't throw,
3186    // and don't burn the once-per-session flag if we can't actually fire.
3187    if (typeof document.sendGoogleTagManagerEvent !== 'function') return;
3188    if ($3ec2bf3965f87ecc$var$alreadyFired(window)) return;
3189    try {
3190        // Mark fired only AFTER a successful send, so a thrown GTM call doesn't
3191        // permanently suppress the conversion for the rest of the session — and
3192        // never let an analytics failure break the caller's success flow.
3193        document.sendGoogleTagManagerEvent('event', $3ec2bf3965f87ecc$export$78b64890ea40f4e4);
3194        $3ec2bf3965f87ecc$var$markFired(window);
3195    } catch  {
3196    // Swallow — analytics must not break form submit / sign-in.
3197    }
3198}
3199
3200
3201
3202const $2aefad83322125c9$var$homeValuationRoute = '/api/v1/home-valuation';
3203class $2aefad83322125c9$export$2e2bcd8739ae039 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
3204    destroy() {
3205    //
3206    }
3207    /**
3208   * Clean address string by removing call time frame suffix and extra whitespace
3209   *
3210   * Handles 17 templates that append ", call time frame: [value]" to the address:
3211   * - TheTrailblazerSir_2, TheMasterpiece (2x), TheInspirationSir_1, TheIconSir_3
3212   * - Influencer, GlobalCollective, Evolution, CorcoranAgent_1
3213   * - CompassSE (2x), CompassPrestige (2x), CompassNavigator
3214   * - ColdwellBanker (2x), Classic
3215   *
3216   * @param {string} address - Raw address string that may contain time frame info
3217   * @return {string} - Cleaned address string
3218   */ _cleanAddressString(address) {
3219        if (!address || typeof address !== 'string') return '';
3220        let cleaned = address.trim();
3221        // Fix 1: Handle "User entered address:\n..." pattern from TheProducer templates
3222        // Extract only the user entered address, ignore geocoded part
3223        if (cleaned.includes('User entered address:')) {
3224            const match = cleaned.match(/User entered address:\s*\n?\s*([^\n]+)/);
3225            if (match && match[1]) cleaned = match[1].trim();
3226        }
3227        // Fix 2: Remove ", call time frame: ..." suffix if present (affects 17 templates)
3228        const timeFrameIndex = cleaned.indexOf(', call time frame:');
3229        if (timeFrameIndex !== -1) cleaned = cleaned.substring(0, timeFrameIndex).trim();
3230        return cleaned;
3231    }
3232    /**
3233   * Transform Google Maps address components to structured format
3234   * @param {Array} addressComponents - Google Maps address components
3235   * @return {Object} - Structured address object
3236   */ _transformAddressComponents(addressComponents) {
3237        const get = (t)=>(addressComponents.find((c)=>c.componentType === t) || {}).componentName?.text;
3238        const structuredAddress = {};
3239        const streetNumber = get('street_number');
3240        const streetName = get('route');
3241        const state = get('administrative_area_level_1');
3242        const zipcode = get('postal_code');
3243        const addressLine2 = get('subpremise');
3244        // explicit precedence for city
3245        const city = get('locality') || get('sublocality_level_1') || get('neighborhood');
3246        if (streetNumber) structuredAddress.streetNumber = streetNumber;
3247        if (streetName) structuredAddress.streetName = streetName;
3248        if (city) structuredAddress.city = city;
3249        if (state) structuredAddress.state = state;
3250        if (zipcode) structuredAddress.zipcode = zipcode;
3251        if (addressLine2) structuredAddress.addressLine2 = addressLine2;
3252        return structuredAddress;
3253    }
3254    /**
3255   * Extract address and coordinates from Google Maps validation data
3256   * @param {Object} validatedAddressData - Google Maps validation result
3257   * @return {Object} - Object containing structuredAddress and coordinates
3258   */ _extractAddressAndCoordinates(validatedAddressData) {
3259        let structuredAddress = null;
3260        let coordinates = null;
3261        if (validatedAddressData?.result) {
3262            const { result: result } = validatedAddressData;
3263            // Extract structured address components
3264            if (result.address?.addressComponents) structuredAddress = this._transformAddressComponents(result.address.addressComponents);
3265            // Extract coordinates
3266            if (result.geocode?.location) coordinates = {
3267                latitude: result.geocode.location.latitude,
3268                longitude: result.geocode.location.longitude
3269            };
3270        }
3271        return {
3272            structuredAddress: structuredAddress,
3273            coordinates: coordinates
3274        };
3275    }
3276    /**
3277   * Filter out empty string values from an object, keeping only non-empty values
3278   * @param {Object} obj - Object to filter
3279   * @return {Object} - Filtered object without empty strings
3280   */ _filterEmptyStrings(obj) {
3281        const filtered = {};
3282        for (const [key, value] of Object.entries(obj))if (value !== '' && value !== null && value !== undefined) filtered[key] = value;
3283        return filtered;
3284    }
3285    /**
3286   * Extract raw address from form data with priority fallback chain.
3287   * Order is critical to handle 38 home valuation templates with different field naming:
3288   *
3289   * IMPORTANT: contactForms.js (line 189) stores name="message" in comments_attributes[0].text
3290   * because 'message' is in DEFAULT_LEAD_FIELDS. Fields NOT in DEFAULT_LEAD_FIELDS go to content.
3291   *
3292   * Priority (most specific → most generic):
3293   * 1. address           - Pattern 1: 9 templates (explicit address, stored in content)
3294   * 2. property-address  - Pattern 3: 4 templates (dash variant with JS, stored in content)
3295   * 3. property_address  - Pattern 4: 3 templates (underscore, stored in content - handles VanguardProperties!)
3296   * 4. Property_Address  - Pattern 5: 1 template (capital P - TheProducer/HomeValuationRansomHouse, stored in content)
3297   * 5. comments_attributes[0].text - Pattern 2: ALL 17 templates with name="message" store HERE!
3298   *                                   (e.g., Evolution/HomeValuation, TheProducer/HomeValuation, etc.)
3299   * 6. message           - Pattern 6: 4 templates with JS-populated message (rare, checked last)
3300   * 7-8. homeValuationAddress, propertyAddress - Legacy/unknown formats
3301   *
3302   * Critical: Each field is cleaned BEFORE checking, so dropdown values are skipped and we try next field
3303   *
3304   * @param {Object} data - Form data
3305   * @return {string} - Raw address string (may contain trailing text like ", call time frame: ...")
3306   */ _getRawAddress(data) {
3307        const content = data.activity.content || {};
3308        const comments = data.activity.comments_attributes?.[0]?.text;
3309        const possibleFields = [
3310            content.address,
3311            content['property-address'],
3312            content.property_address,
3313            content.Property_Address,
3314            comments,
3315            content.message,
3316            content.homeValuationAddress,
3317            content.propertyAddress
3318        ];
3319        return possibleFields.map((field)=>field && this._cleanAddressString(field)).find(Boolean) || '';
3320    }
3321    /**
3322   * Logs lead-related events for monitoring
3323   * @param {string} eventType - Type of event
3324   * @param {Object} data - Form data
3325   * @param {Error} error - Optional error object
3326   */ _logLeadEvent(eventType, data, error = null) {
3327        const eventPayload = {
3328            event: eventType,
3329            companyId: this.config.companyId,
3330            websiteId: this.config.websiteId,
3331            timestamp: new Date().toISOString(),
3332            hasEmail: !!data.activity?.author_email,
3333            hasAddress: !!this._getRawAddress(data)
3334        };
3335        if (error) {
3336            // Use userMessage (sanitized) instead of raw message to prevent PII exposure
3337            // userMessage is set by _getUserFriendlyErrorMessage() which provides safe messages
3338            eventPayload.errorMessage = error.userMessage || (error.status ? `Request failed with status ${error.status}` : 'An error occurred');
3339            eventPayload.errorName = error.name;
3340            eventPayload.errorStatus = error.status;
3341        }
3342        // Log to console with structured format for log aggregation
3343        // eslint-disable-next-line no-console
3344        console.error(`[HomeValuation] ${eventType}`, JSON.stringify(eventPayload));
3345        // If PostHog is available, send event for analytics
3346        // Wrap in try/catch to prevent SDK failures from blocking submissions
3347        if (this.window.posthog) try {
3348            this.window.posthog.capture(eventType, eventPayload);
3349        } catch (posthogError) {
3350            // eslint-disable-next-line no-console
3351            console.error('[HomeValuation] PostHog capture failed:', posthogError);
3352        }
3353    }
3354    /**
3355   * Maps error types to user-friendly messages
3356   * @param {Error} error - The error object
3357   * @returns {string} - User-friendly message
3358   */ _getUserFriendlyErrorMessage(error) {
3359        if (error.name === 'AbortError' || error.message?.includes('timeout')) return 'Connection timed out. Please try again.';
3360        if (error.name === 'TypeError' && error.message?.includes('fetch')) return 'Unable to connect. Please check your internet connection and try again.';
3361        if (error.status === 503 || error.status === 502 || error.status === 504) return 'Service temporarily unavailable. Please try again in a moment.';
3362        if (error.status === 400) return 'Please check your information and try again.';
3363        return 'Something went wrong. Please try again or contact us directly.';
3364    }
3365    /**
3366   * Build formatted address string from structured address components
3367   * @param {Object} structuredAddress - Structured address object
3368   * @return {string} - Formatted address string
3369   */ _formatStructuredAddress(structuredAddress) {
3370        if (!structuredAddress || Object.keys(structuredAddress).length === 0) return '';
3371        const parts = [];
3372        // Line 1: streetNumber streetName addressLine2
3373        const line1 = [
3374            structuredAddress.streetNumber,
3375            structuredAddress.streetName,
3376            structuredAddress.addressLine2
3377        ].filter(Boolean).join(' ');
3378        parts.push(line1);
3379        // Line 2: city, state zipcode
3380        const cityState = [
3381            structuredAddress.city,
3382            structuredAddress.state
3383        ].filter(Boolean).join(', ');
3384        const line2 = [
3385            cityState,
3386            structuredAddress.zipcode
3387        ].filter(Boolean).join(' ');
3388        parts.push(line2);
3389        return parts.filter(Boolean).join(', ');
3390    }
3391    /**
3392   * Build home valuation data object
3393   * @param {Object} data - Form data
3394   * @param {string} homeValuationEstimate - Home valuation estimate
3395   * @param {Object} structuredAddress - Structured address object
3396   * @param {Object} coordinates - Coordinates object
3397   * @return {Object} - Home valuation data object
3398   */ _buildHomeValuationData(data, homeValuationEstimate, structuredAddress, coordinates) {
3399        // Build homeValuationAddress from structured address (validated by Google) if available
3400        // Format: streetNumber streetName, city, state zipcode, addressLine2
3401        const homeValuationAddress = this._formatStructuredAddress(structuredAddress) || this._getRawAddress(data);
3402        // Validate that we have an address before proceeding
3403        if (!homeValuationAddress) throw new Error('Unable to extract home valuation address from form data');
3404        // Required fields that must always be included
3405        const requiredFields = {
3406            companyId: data.companyId,
3407            homeValuationAddress: homeValuationAddress,
3408            homeValuationEstimate: homeValuationEstimate ? new Intl.NumberFormat('en-US', {
3409                style: 'currency',
3410                currency: 'USD',
3411                maximumFractionDigits: 0,
3412                minimumFractionDigits: 0
3413            }).format(homeValuationEstimate) : null,
3414            websiteId: data.page.websiteId,
3415            sourceUrl: data.activity.source_url
3416        };
3417        // Optional fields that will be filtered if empty
3418        const optionalFields = {
3419            leadEmailAddress: data.activity.author_email,
3420            leadFullName: data.activity.author_name,
3421            leadPhoneNumber: data.activity.author_phone,
3422            parcelId: data.activity.content?.parcelId,
3423            resourceId: data.page.pageMeta?.resourceId,
3424            pageId: data.page.pageId,
3425            sourceResource: data.page.pageMeta?.sourceResource,
3426            pageElementId: data.page.pageMeta?.pageElementId,
3427            formId: data.page.pageMeta?.formId,
3428            utmSource: data.activity.content?.utm_source,
3429            utmMedium: data.activity.content?.utm_medium,
3430            utmCampaign: data.activity.content?.utm_campaign,
3431            utmTerm: data.activity.content?.utm_term,
3432            utmContent: data.activity.content?.utm_content,
3433            utmId: data.activity.content?.utm_id,
3434            timeToSell: data.activity.content?.timeToSell,
3435            lookingToBuy: data.activity.content?.lookingToBuy,
3436            referrer: data.referrer,
3437            content: data.activity.content || {},
3438            fields: data.fields || {}
3439        };
3440        // Filter out empty strings from optional fields
3441        const filteredOptionalFields = this._filterEmptyStrings(optionalFields);
3442        return {
3443            ...requiredFields,
3444            ...filteredOptionalFields,
3445            // Add structured address and coordinates if they exist
3446            ...structuredAddress && {
3447                address: structuredAddress
3448            },
3449            ...coordinates && {
3450                coordinates: coordinates
3451            }
3452        };
3453    }
3454    /**
3455   * Validate address with Google Maps
3456   * @param {string} rawAddress - Raw address string
3457   * @returns {Promise<Object|null>} - Validated address data or null
3458   * @throws {Error} - If validation fails, error is thrown with userMessage
3459   */ async _validateAddressSafely(rawAddress) {
3460        if (!rawAddress) {
3461            // eslint-disable-next-line no-console
3462            console.error('Home valuation: No address found in form data');
3463            return null;
3464        }
3465        try {
3466            return await this._validateAddressWithGoogleMaps(rawAddress);
3467        } catch (error) {
3468            // eslint-disable-next-line no-console
3469            console.error('Error validating address with Google Maps:', error);
3470            // Attach user-friendly message and throw so user sees the error
3471            error.userMessage = this._getUserFriendlyErrorMessage(error);
3472            throw error;
3473        }
3474    }
3475    /**
3476   * Get home valuation estimate
3477   * @param {Object} validatedAddressData - Validated address data
3478   * @returns {Promise<number|null>} - Home valuation estimate or null
3479   * @throws {Error} - If estimate fetch fails, error is thrown with userMessage
3480   */ async _getHomeValuationEstimateSafely(validatedAddressData) {
3481        try {
3482            return await this._getHomeValuationEstimate(validatedAddressData);
3483        } catch (error) {
3484            // eslint-disable-next-line no-console
3485            console.error('Error getting home valuation estimate:', error);
3486            // Attach user-friendly message and throw so user sees the error
3487            error.userMessage = this._getUserFriendlyErrorMessage(error);
3488            throw error;
3489        }
3490    }
3491    /**
3492   * Parse response text into payload object
3493   * @param {string} text - Response text
3494   * @returns {Object} - Parsed payload
3495   */ _parseResponsePayload(text) {
3496        try {
3497            return text ? JSON.parse(text) : {};
3498        } catch  {
3499            return {
3500                raw: text
3501            };
3502        }
3503    }
3504    /**
3505   * Create error from failed response
3506   * @param {Object} payload - Response payload
3507   * @param {number} status - HTTP status code
3508   * @returns {Error} - Error object with status and payload
3509   */ _createResponseError(payload, status) {
3510        const errorMessage = payload && typeof payload === 'object' && Object.keys(payload).length ? payload.message || JSON.stringify(payload) : 'Request failed';
3511        const error = new Error(errorMessage);
3512        // Preserve payload properties if it's an object
3513        if (payload && typeof payload === 'object' && Object.keys(payload).length) Object.assign(error, payload);
3514        // Preserve numeric HTTP status - must be set after Object.assign
3515        // to ensure it takes precedence over any status in payload
3516        error.status = status;
3517        return error;
3518    }
3519    /**
3520   * Submit lead to API endpoint
3521   * @param {string} leadRoute - API endpoint URL
3522   * @param {Object} homeValuationData - Data to submit
3523   * @returns {Promise<Object>} - Submission result
3524   */ async _submitLead(leadRoute, homeValuationData) {
3525        const controller = new AbortController();
3526        const timeoutId = setTimeout(()=>controller.abort(), 10000);
3527        try {
3528            const response = await fetch(leadRoute, {
3529                method: 'POST',
3530                headers: {
3531                    'Content-Type': 'application/json'
3532                },
3533                body: JSON.stringify(homeValuationData),
3534                signal: controller.signal
3535            });
3536            clearTimeout(timeoutId);
3537            const text = await response.text();
3538            const payload = this._parseResponsePayload(text);
3539            if (!response.ok) throw this._createResponseError(payload, response.status);
3540            if (payload && payload.status === 'success' && payload.redirectUrl) {
3541                this.window.location.href = payload.redirectUrl;
3542                return {
3543                    redirected: true,
3544                    url: payload.redirectUrl
3545                };
3546            }
3547            return payload;
3548        } catch (error) {
3549            clearTimeout(timeoutId);
3550            throw error;
3551        }
3552    }
3553    /**
3554   * Submit home valuation request with Google Maps validation
3555   * @param {Object} data
3556   * @return {Promise<Object>}
3557   */ async _submitHomeValuationRequest(data) {
3558        const { config: config } = this;
3559        // Use websiteApiGatewayUrl from config
3560        if (!config.websiteApiGatewayUrl) throw new Error('websiteApiGatewayUrl not configured for home valuation');
3561        // Log submission started
3562        this._logLeadEvent('home_valuation_submission_started', data);
3563        try {
3564            // Validate address with Google Maps
3565            const rawAddress = this._getRawAddress(data);
3566            let validatedAddressData = null;
3567            try {
3568                validatedAddressData = await this._validateAddressSafely(rawAddress);
3569            } catch (error) {
3570                // Error already has userMessage from _validateAddressSafely
3571                this._logLeadEvent('home_valuation_address_validation_failed', data, error);
3572                throw error;
3573            }
3574            // Get home valuation estimate.
3575            // The estimate is best-effort: many valid properties (e.g. commercial
3576            // parcels or addresses without AVM coverage) have no estimate and the
3577            // estimate endpoint returns a non-OK status for them. A missing estimate
3578            // must never block lead capture, so we log the failure and continue with
3579            // a null estimate rather than aborting the whole submission.
3580            let homeValuationEstimate = null;
3581            try {
3582                homeValuationEstimate = await this._getHomeValuationEstimateSafely(validatedAddressData);
3583            } catch (error) {
3584                // Error already has userMessage from _getHomeValuationEstimateSafely
3585                this._logLeadEvent('home_valuation_estimate_failed', data, error);
3586                homeValuationEstimate = null;
3587            }
3588            // Extract structured address and coordinates from Google Maps validation
3589            const { structuredAddress: structuredAddress, coordinates: coordinates } = this._extractAddressAndCoordinates(validatedAddressData);
3590            const leadRoute = `${config.websiteApiGatewayUrl}${$2aefad83322125c9$var$homeValuationRoute}`;
3591            const homeValuationData = this._buildHomeValuationData(data, homeValuationEstimate, structuredAddress, coordinates);
3592            const result = await this._submitLead(leadRoute, homeValuationData);
3593            // Log success
3594            this._logLeadEvent('home_valuation_submission_success', data);
3595            return result;
3596        } catch (error) {
3597            // Ensure error has user-friendly message (may already be set by helper methods)
3598            if (!error.userMessage) error.userMessage = this._getUserFriendlyErrorMessage(error);
3599            this._logLeadEvent('home_valuation_submission_failed', data, error);
3600            throw error;
3601        }
3602    }
3603    /**
3604   * Validate address using Google Maps Address Validation API
3605   * @param {string} addressStr - The address string to validate
3606   * @returns {Promise<Object|null>} - Validated address data or null if validation fails
3607   */ async _validateAddressWithGoogleMaps(addressStr) {
3608        const { config: config, window: window } = this;
3609        // Ensure Google Maps API key is loaded
3610        let apiKey = config.googleMapsAPIKey;
3611        if (!apiKey && window.luxuryPresence?.mapApiLoader) apiKey = await window.luxuryPresence.mapApiLoader.getMapApiKey();
3612        if (!apiKey) throw new Error('Google Maps API key not configured');
3613        const controller = new AbortController();
3614        const timeoutId = setTimeout(()=>controller.abort(), 10000);
3615        try {
3616            const response = await fetch(`https://addressvalidation.googleapis.com/v1:validateAddress?key=${apiKey}`, {
3617                method: 'POST',
3618                headers: {
3619                    'Content-Type': 'application/json'
3620                },
3621                body: JSON.stringify({
3622                    address: {
3623                        addressLines: [
3624                            addressStr
3625                        ]
3626                    },
3627                    enableUspsCass: false
3628                }),
3629                signal: controller.signal
3630            });
3631            clearTimeout(timeoutId);
3632            if (!response.ok) {
3633                const error = new Error(`Address validation failed: ${response.status}`);
3634                error.status = response.status;
3635                throw error;
3636            }
3637            return response.json();
3638        } catch (error) {
3639            clearTimeout(timeoutId);
3640            throw error;
3641        }
3642    }
3643    /**
3644   * Check if structured address has all mandatory fields
3645   * @param {Object} structuredAddress - Structured address object
3646   * @return {boolean}
3647   */ _hasMandatoryAddressFields(structuredAddress) {
3648        return !!(structuredAddress.streetNumber && structuredAddress.streetName && structuredAddress.city && structuredAddress.state && structuredAddress.zipcode);
3649    }
3650    /**
3651   * Log missing mandatory address fields
3652   * @param {Object} structuredAddress - Structured address object
3653   */ _logMissingAddressFields(structuredAddress) {
3654        const missingFields = [];
3655        if (!structuredAddress.streetNumber) missingFields.push('streetNumber');
3656        if (!structuredAddress.streetName) missingFields.push('streetName');
3657        if (!structuredAddress.city) missingFields.push('city');
3658        if (!structuredAddress.state) missingFields.push('state');
3659        if (!structuredAddress.zipcode) missingFields.push('zipcode');
3660        // eslint-disable-next-line no-console
3661        console.log('Home valuation estimate skipped - missing required fields:', missingFields.join(', '), 'Available fields:', Object.keys(structuredAddress).join(', '));
3662    }
3663    /**
3664   * Build query string from structured address
3665   * @param {Object} structuredAddress - Structured address object
3666   * @return {string}
3667   */ _buildAddressQueryString(structuredAddress) {
3668        return Object.entries(structuredAddress).map(([key, value])=>`${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');
3669    }
3670    /**
3671   * GET home valuation estimate
3672   * @param {string} address
3673   * @param {Object} validatedAddressData - Google Maps validated address data
3674   * @return {Promise<number|null>}
3675   */ async _getHomeValuationEstimate(validatedAddressData = null) {
3676        const { config: config } = this;
3677        if (!config.websiteApiGatewayUrl) throw new Error('websiteApiGatewayUrl not configured');
3678        const base = `${config.websiteApiGatewayUrl}${$2aefad83322125c9$var$homeValuationRoute}`;
3679        // Check if we have validated address data
3680        if (!validatedAddressData?.result?.address?.addressComponents) return null;
3681        const structuredAddress = this._transformAddressComponents(validatedAddressData.result.address.addressComponents);
3682        // Check if all mandatory fields exist
3683        if (!this._hasMandatoryAddressFields(structuredAddress)) {
3684            this._logMissingAddressFields(structuredAddress);
3685            return null;
3686        }
3687        // Build URL with query string
3688        const qs = this._buildAddressQueryString(structuredAddress);
3689        const homeValURL = `${base}?${qs}`;
3690        const controller = new AbortController();
3691        const timeoutId = setTimeout(()=>controller.abort(), 10000);
3692        try {
3693            const response = await fetch(homeValURL, {
3694                headers: {
3695                    Accept: 'application/json'
3696                },
3697                signal: controller.signal
3698            });
3699            clearTimeout(timeoutId);
3700            if (!response.ok) {
3701                const error = new Error(`Home valuation estimate failed: ${response.status}`);
3702                error.status = response.status;
3703                throw error;
3704            }
3705            const data = await response.json();
3706            return data?.valueDollars ?? null;
3707        } catch (error) {
3708            clearTimeout(timeoutId);
3709            // Re-throw to allow retry logic to handle it
3710            throw error;
3711        }
3712    }
3713}
3714
3715
3716const $e10bd00497be8876$export$97de66002300ed70 = 'middleName';
3717// Default lead fields
3718const $e10bd00497be8876$var$DEFAULT_LEAD_FIELDS = [
3719    'name',
3720    'firstName',
3721    'lastName',
3722    $e10bd00497be8876$export$97de66002300ed70,
3723    'email',
3724    'phone',
3725    'phoneNumber',
3726    'source',
3727    'message',
3728    'mlsId',
3729    'sourceUrl'
3730];
3731class $e10bd00497be8876$export$3c5380623cf51249 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
3732    /**
3733   * Initialize Contact Form Controller at build time
3734   * @param { ConfigController } config
3735   * @param {Window} window
3736   * @param {Document} document
3737   */ constructor(config, window, document){
3738        super(config, window, document);
3739        this.forms = [];
3740        this.homeValuationService = new (0, $2aefad83322125c9$export$2e2bcd8739ae039)(config, window, document);
3741    }
3742    /**
3743   * Initialize Contact Form Controller at run time
3744   * Attach handlers and events to DOM
3745   * @param {Object} options
3746   */ initialize(options = {}) {
3747        try {
3748            const { document: document } = this;
3749            const { selector: selector } = options;
3750            let forms = [];
3751            if (selector) forms = document.querySelectorAll(`${selector} form[data-type="contact-form"]`);
3752            else forms = document.querySelectorAll('form[data-type="contact-form"]');
3753            forms.forEach((form)=>{
3754                this._attachSubmitHandler(form);
3755            // this._attachValidation(form);
3756            });
3757            this.forms = this.forms.concat(forms);
3758        } catch (e) {
3759            // eslint-disable-next-line no-console
3760            console.log(e);
3761        }
3762    }
3763    /**
3764   * Controllers must implement a "destroy" method to be called
3765   * after page navigation to remove event handlers / cleanup
3766   */ destroy() {
3767        this.forms = [];
3768    }
3769    /**
3770   * Handle submit from global context
3771   * @param {HTMLFormElement} form
3772   */ submitForm(form) {
3773        this._handleSubmit(null, form).catch((e)=>console.error(e));
3774    }
3775    /**
3776   * Attach submit event for form
3777   * @param {HTMLFormElement} contactForm
3778   */ _attachValidation(contactForm) {
3779        const { window: window } = this;
3780        const inputs = contactForm.querySelectorAll('input, select, textarea');
3781        inputs.forEach((input)=>{
3782            window.luxuryPresence.validation.applyFieldValidation(input);
3783        });
3784    }
3785    /**
3786   * Attach submit event for form
3787   * @param {HTMLFormElement} contactForm
3788   */ _attachSubmitHandler(contactForm) {
3789        contactForm.addEventListener('submit', (e)=>this._handleSubmit(e, contactForm));
3790    }
3791    /**
3792   * Extract and process form values
3793   * @param {HTMLFormElement} contactForm
3794   * @return {Object} - Processed form values
3795   */ _extractFormValues(contactForm) {
3796        const formData = new FormData(contactForm);
3797        const values = {};
3798        const nameParts = [];
3799        const nameKeyRegex = /^name(?:-\d+)?$/;
3800        formData.forEach((value, key)=>{
3801            if (typeof value === 'string') {
3802                const curr = value.trim();
3803                if (nameKeyRegex.test(key) && curr) nameParts.push(curr);
3804                const prev = values[key];
3805                values[key] = prev ? `${prev} ${curr}` : curr;
3806            } else values[key] = value;
3807        });
3808        if (nameParts.length) values.name = nameParts.join(' ').trim();
3809        else if (!values.name && values.firstName) {
3810            values.name = values.firstName;
3811            if (values.lastName) values.name += ` ${values.lastName}`;
3812        }
3813        return values;
3814    }
3815    /**
3816   * Build submission data object
3817   * @param {Object} values - Form values
3818   * @param {Object} fields - Form fields
3819   * @param {HTMLFormElement} contactForm - Form element
3820   * @return {Object} - Submission data
3821   */ _buildSubmissionData(values, fields, contactForm) {
3822        const { window: window, config: config } = this;
3823        const content = Object.keys(values).filter((key)=>!$e10bd00497be8876$var$DEFAULT_LEAD_FIELDS.includes(key)).reduce((result, key)=>{
3824            // eslint-disable-next-line
3825            result[key] = values[key];
3826            return result;
3827        }, {});
3828        const { pageId: pageId, companyId: companyId, websiteId: websiteId, pageMeta: pageMeta } = config;
3829        const utm = window.localStorage.getItem('utm_vars') || '{}';
3830        const referrer = window.localStorage.getItem('referrer') || '';
3831        const formId = this._getFormId(contactForm);
3832        return {
3833            activity: {
3834                author_email: values.email,
3835                author_name: values.name,
3836                author_phone: values.phone || values.phoneNumber,
3837                activity_source: values.source || 'CONTACT_INQUIRY',
3838                comments_attributes: [
3839                    {
3840                        text: values.message || undefined
3841                    }
3842                ],
3843                source_url: window.location.href,
3844                content: {
3845                    ...content,
3846                    ...JSON.parse(utm)
3847                }
3848            },
3849            page: {
3850                pageId: pageId,
3851                companyId: companyId,
3852                websiteId: websiteId,
3853                pageMeta: {
3854                    ...pageMeta,
3855                    formId: formId
3856                }
3857            },
3858            companyId: companyId,
3859            referrer: referrer,
3860            fields: fields
3861        };
3862    }
3863    /**
3864   * Handle successful form submission
3865   * @param {HTMLFormElement} contactForm - Form element
3866   */ _handleSubmissionSuccess(contactForm) {
3867        const { window: window } = this;
3868        const closeDelay = contactForm.dataset.delay || (0, $a3e97e89bbc2a366$export$f037eeffb5561205);
3869        contactForm.classList.remove('loading');
3870        contactForm.classList.remove('error');
3871        contactForm.classList.add('success');
3872        // TODO: Review producer and classic to deprecate "hide"
3873        contactForm.querySelectorAll('.success').forEach((el)=>el.classList.remove('hide'));
3874        contactForm.dispatchEvent(new Event('formsubmitted'));
3875        // Any successful lead submit credits the Google Ads lead conversion
3876        // (reuses the existing `generate_lead` action), once per session.
3877        (0, $3ec2bf3965f87ecc$export$e70565180c0e6950)(this.window, this.document);
3878        setTimeout(()=>{
3879            window.lpUI.hideClosestModal(contactForm);
3880            contactForm.reset();
3881            window.lpUI.sideMenuHide();
3882            contactForm.querySelectorAll('.success').forEach((el)=>el.classList.add('hide'));
3883            contactForm.classList.remove('success');
3884        }, closeDelay);
3885    }
3886    /**
3887   * Submit Contact Form Handler
3888   * @param {Event} e
3889   * @param {HTMLFormElement} contactForm
3890   * @return {Promise<Object>}
3891   */ async _handleSubmit(e, contactForm) {
3892        if (e) e.preventDefault();
3893        if (contactForm.classList.contains('loading')) // Form already submitting
3894        return;
3895        // Hide any previous error message and clear error state
3896        this._hideSubmissionError(contactForm);
3897        contactForm.classList.remove('error');
3898        contactForm.classList.add('loading');
3899        try {
3900            // Extract form values first (before async operations)
3901            const values = this._extractFormValues(contactForm);
3902            // TODO: HoneyPot should still send request
3903            if (values.middleName) {
3904                contactForm.classList.remove('loading');
3905                return;
3906            }
3907            const fields = this._getFields(contactForm);
3908            const data = this._buildSubmissionData(values, fields, contactForm);
3909            await this._submitLeadRequest(data);
3910            this._sendGAEvent(data);
3911            this._handleSubmissionSuccess(contactForm);
3912        } catch (err) {
3913            // eslint-disable-next-line no-console
3914            console.error('Form submission failed:', err);
3915            contactForm.dispatchEvent(new Event('formsubmiterror'));
3916            contactForm.classList.remove('loading');
3917            contactForm.classList.add('error');
3918            // Show user-friendly error message if available (from home valuation service)
3919            if (err.userMessage) this._showSubmissionError(contactForm, err.userMessage);
3920            else this._showSubmissionError(contactForm, 'Something went wrong. Please try again.');
3921        }
3922    }
3923    /**
3924   * Alias anonymous user with canonical ID using event bus
3925   * Links the user's anonymous browsing session to their canonical identity
3926   * @param {Object} data - Form submission data
3927   * @private
3928   */ _aliasUserWithEventBus(data) {
3929        try {
3930            // Check if event bus library and required methods are available
3931            if (!this.window.eventBusProvider?.alias || !this.window.eventBusProvider?.isIdentified || !this.window.eventBusProvider?.getDistinctId || !this.window.LuxuryPresenceEventBus?.generateUUIDv5FromCompanyEmail) return; // Event bus or required methods not available
3932            // Skip if user is already identified
3933            if (this.window.eventBusProvider.isIdentified()) {
3934                console.log('[EventBus] User already identified, skipping alias');
3935                return;
3936            }
3937            const email = data.activity?.author_email;
3938            const { companyId: companyId } = this.config;
3939            if (!email || !companyId) {
3940                console.warn('[EventBus] Missing required data for user alias');
3941                return;
3942            }
3943            // Get the anonymous distinct ID from PostHog
3944            const anonId = this.window.eventBusProvider.getDistinctId();
3945            if (!anonId) {
3946                console.warn('[EventBus] No anonymous ID available for alias');
3947                return;
3948            }
3949            // Generate deterministic canonical ID from company + email
3950            const canonicalId = this.window.LuxuryPresenceEventBus.generateUUIDv5FromCompanyEmail(companyId, email);
3951            // Create alias linking anonymous ID to canonical ID
3952            this.window.eventBusProvider.alias({
3953                anonId: anonId,
3954                canonicalId: canonicalId
3955            });
3956            console.log('[EventBus] User aliased with canonical ID');
3957        } catch (error) {
3958            // Never block form submission due to analytics errors
3959            console.error('[EventBus] User alias failed:', error);
3960        }
3961    }
3962    /**
3963   * Send Lead Request
3964   * @param {Object} data
3965   * @return {Promise<Object>}
3966   */ async _submitLeadRequest(data) {
3967        const { config: config } = this;
3968        // Alias user with event bus before submitting the lead
3969        this._aliasUserWithEventBus(data);
3970        if (config.myhomeDashboardEnabled && (data.activity?.activity_source === 'HOME_VALUATION' || data.activity?.activity_source === 'HOME_VALUE')) return this.homeValuationService._submitHomeValuationRequest(data);
3971        const leadRoute = `${config.leadIngesterUrl}/api/v1/leads`;
3972        return fetch(leadRoute, {
3973            method: 'POST',
3974            headers: {
3975                'Content-Type': 'application/json'
3976            },
3977            body: JSON.stringify(data)
3978        }).then((response)=>{
3979            if (!response.ok) return response.json().then((error)=>{
3980                throw error;
3981            });
3982            return response.json();
3983        });
3984    }
3985    /**
3986   * Send GA event
3987   * @param {Object} data
3988   */ _sendGAEvent(data) {
3989        const { document: document } = this;
3990        let event = {
3991            hitType: 'event',
3992            eventCategory: 'button',
3993            eventAction: 'click'
3994        };
3995        switch(data.activity.activity_source){
3996            case 'NEWSLETTER_SIGNUP':
3997                event.eventLabel = 'Newsletter';
3998                document.sendGoogleTagManagerEvent('event', 'newsletter_signup');
3999                break;
4000            case 'HOME_SEARCH':
4001                event.eventLabel = 'HomeSearch';
4002                document.sendGoogleTagManagerEvent('event', 'home_search');
4003                break;
4004            case 'HOME_VALUE':
4005            case 'HOME_VALUATION':
4006                event.eventLabel = 'HomeValue';
4007                document.sendGoogleTagManagerEvent('event', 'home_valuation');
4008                break;
4009            case 'EBOOK':
4010                event.eventLabel = 'Ebook';
4011                document.sendGoogleTagManagerEvent('event', 'ebook_download');
4012                break;
4013            case 'CONTACT_INQUIRY':
4014            default:
4015                // for contact forms, Marketing has requested that they see a page-view of 'thank-you' as indication of success
4016                // Note that this will break if we have actual page with url of /thank-you
4017                event = {
4018                    hitType: 'pageview',
4019                    page: '/thank-you'
4020                };
4021                document.sendGoogleTagManagerEvent('event', 'contact_inquiry');
4022                break;
4023        }
4024        document.sendGoogleAnalyticsEvent(event);
4025    }
4026    /**
4027   * Gather fields / schema for form, used for display in CRM
4028   * @param {HTMLFormElement} form
4029   * @return {Object}
4030   */ _getFields(form) {
4031        const inputs = form.querySelectorAll('input, select, textarea');
4032        const fields = {};
4033        inputs.forEach((input)=>{
4034            const { id: id, name: name, type: inputType } = input;
4035            if (name === $e10bd00497be8876$export$97de66002300ed70) // Honeypot continue
4036            return true;
4037            let label = '';
4038            if (id) {
4039                const labelNode = form.querySelector(`label[for='${id}']`);
4040                if (labelNode) label = labelNode.textContent.trim();
4041                else if (input.placeholder) label = input.placeholder.trim();
4042            }
4043            fields[name] = {
4044                label: label,
4045                type: input.tagName,
4046                inputType: input.tagName === 'INPUT' ? inputType : 'text'
4047            };
4048        });
4049        return fields;
4050    }
4051    /**
4052   * Figure out relevant section or div ID for form
4053   * @param {HTMLFormElement} form
4054   * @return {string}
4055   */ _getFormId(form) {
4056        const SELECTORS = "section[id^='section-'], footer[id], .modal[id^='modal-']";
4057        const parent = form.closest(SELECTORS);
4058        return parent?.id ? this._cleanFormId(parent.id) : '';
4059    }
4060    /**
4061   * Remove prefix from formID
4062   * @param {string} formId
4063   * @return {string}
4064   */ _cleanFormId(formId) {
4065        const PREFIXES = [
4066            'section-',
4067            'modal-'
4068        ];
4069        for (const prefix of PREFIXES){
4070            if (formId.startsWith(prefix)) return formId.substring(prefix.length);
4071        }
4072        return formId;
4073    }
4074    /**
4075   * Show submission error message on form
4076   * @param {HTMLFormElement} form
4077   * @param {string} message
4078   */ _showSubmissionError(form, message) {
4079        const errorEl = form.querySelector('.submission-error-message');
4080        if (errorEl) {
4081            errorEl.textContent = message || 'Something went wrong. Please try again.';
4082            errorEl.style.display = 'block';
4083        }
4084    }
4085    /**
4086   * Hide submission error message on form
4087   * @param {HTMLFormElement} form
4088   */ _hideSubmissionError(form) {
4089        const errorEl = form.querySelector('.submission-error-message');
4090        if (errorEl) errorEl.style.display = 'none';
4091    }
4092}
4093
4094
4095
4096const $ea6901fdf47e0ec1$var$CALLBACK = '__googleMapsCallback';
4097const $ea6901fdf47e0ec1$var$GOOGLE_MAPS_URL = 'https://maps.googleapis.com/maps/api/js';
4098const $ea6901fdf47e0ec1$export$76299006759be400 = 1024;
4099const $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS = 3;
4100const $ea6901fdf47e0ec1$var$KEY_RETRY_BASE_DELAY_MS = 300;
4101const $ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG = 'lp_map_key_failed';
4102class $ea6901fdf47e0ec1$export$3c19195edca3fa5c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
4103    /**
4104   * Initialize Button Controller at build time
4105   * @param { ConfigController } config
4106   * @param {Window} window
4107   * @param {Document} document
4108   */ constructor(config, window, document){
4109        super(config, window, document);
4110        this.retries = 3;
4111        this.callbacks = [];
4112        this.id = `__googleMapsScriptId${Date.now()}`;
4113        this._apiKey = '';
4114        this.reset();
4115    }
4116    /**
4117   * Set the Google Maps api key
4118   * @param {string} apiKey
4119   */ set apiKey(apiKey) {
4120        this._apiKey = apiKey;
4121        this.config.setGoogleMapsAPIKey(apiKey);
4122    }
4123    /**
4124   * Get the Google Maps api key
4125   * @return {string}
4126   */ get apiKey() {
4127        return this._apiKey;
4128    }
4129    /**
4130   * Reset the loader state.
4131   */ reset() {
4132        this.deleteScript();
4133        this.done = false;
4134        this.loading = false;
4135        this.failed = false;
4136        this.errors = [];
4137        this.onerrorEvent = null;
4138    }
4139    /**
4140   * Destroy
4141   */ destroy() {
4142        this.reset();
4143    }
4144    /**
4145   * get map api Key
4146   * @return {Promise<string>}
4147   */ async getMapApiKey() {
4148        if (this.apiKey) return this.apiKey;
4149        const hadPreviousFailure = this._hadPreviousFailure();
4150        let recoveryReported = false;
4151        for(let attempt = 1; attempt <= $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS; attempt += 1){
4152            const reportRecovery = hadPreviousFailure && !recoveryReported;
4153            try {
4154                // eslint-disable-next-line no-await-in-loop
4155                const response = await fetch(this._getMapKeyUrl(attempt, reportRecovery));
4156                // The request reached the server, so a recovery marker on it was
4157                // delivered and must not be repeated on later attempts or pages. A
4158                // rejected fetch never arrived, so the marker moves to the next
4159                // attempt.
4160                recoveryReported = recoveryReported || reportRecovery;
4161                this._setFailureFlag(false);
4162                if (!response.ok) throw new Error(`Failed to fetch API key: ${response.status}`);
4163                // eslint-disable-next-line no-await-in-loop
4164                const code = await response.text();
4165                if (!code) return '';
4166                this.apiKey = code;
4167                return this.apiKey;
4168            } catch (e) {
4169                // eslint-disable-next-line no-console
4170                console.error(e);
4171                if (attempt < $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS) // eslint-disable-next-line no-await-in-loop
4172                await this._delay($ea6901fdf47e0ec1$var$KEY_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
4173            }
4174        }
4175        this._setFailureFlag(true);
4176        return '';
4177    }
4178    /**
4179   * Build the map key request url. Retries carry their attempt number, and a
4180   * single request per session carries the recovery marker, so both are
4181   * countable in existing request logs without new infrastructure.
4182   * @param {number} attempt 1-based attempt number
4183   * @param {boolean} reportRecovery tag this request as following a session
4184   *   in which every attempt failed
4185   * @return {string}
4186   */ _getMapKeyUrl(attempt, reportRecovery) {
4187        const params = [];
4188        if (attempt > 1) params.push(`attempt=${attempt}`);
4189        if (reportRecovery) params.push('recovered_after_failure=1');
4190        const query = params.length ? `?${params.join('&')}` : '';
4191        return `${this._getBaseUrl()}/api/v1/map${query}`;
4192    }
4193    /**
4194   * Whether an earlier attempt in this session exhausted all retries.
4195   * @return {boolean}
4196   */ _hadPreviousFailure() {
4197        try {
4198            return this.window.sessionStorage.getItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG) === '1';
4199        } catch (e) {
4200            // Storage can throw when disabled (private browsing); absence of the
4201            // flag is the safe default.
4202            return false;
4203        }
4204    }
4205    /**
4206   * Record or clear the session-level key fetch failure flag.
4207   * @param {boolean} failed
4208   */ _setFailureFlag(failed) {
4209        try {
4210            if (failed) this.window.sessionStorage.setItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG, '1');
4211            else this.window.sessionStorage.removeItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG);
4212        } catch (e) {
4213        // Storage unavailable - reporting is best effort, never fatal.
4214        }
4215    }
4216    /**
4217   * @param {number} ms
4218   * @return {Promise}
4219   */ _delay(ms) {
4220        return new Promise((resolve)=>{
4221            this.window.setTimeout(resolve, ms);
4222        });
4223    }
4224    /**
4225   * CreateUrl returns the Google Maps JavaScript API script url ].
4226   * @return {string}
4227   */ async createUrl() {
4228        const apiKey = await this.getMapApiKey();
4229        // Google Maps loads successfully without a key and then fails at call time
4230        // with NoApiKeys, which produces a broken map and no load error. Refuse
4231        // instead, so the failure surfaces to the caller.
4232        if (!apiKey) throw new Error('Refusing to load Google Maps without an API key');
4233        let url = $ea6901fdf47e0ec1$var$GOOGLE_MAPS_URL;
4234        url += `?callback=${$ea6901fdf47e0ec1$var$CALLBACK}`;
4235        url += `&key=${apiKey}`;
4236        url += `&libraries=places`;
4237        return url;
4238    }
4239    /**
4240   * Set the script on document.
4241   */ async setScript() {
4242        if (this.document.getElementById(this.id)) {
4243            this.callback();
4244            return;
4245        }
4246        let url;
4247        try {
4248            url = await this.createUrl();
4249        } catch (e) {
4250            // eslint-disable-next-line no-console
4251            console.error(e);
4252            this.failed = true;
4253            this.loading = false;
4254            this.onerrorEvent = e;
4255            this.callback();
4256            return;
4257        }
4258        const script = this.document.createElement('script');
4259        script.id = this.id;
4260        script.type = 'text/javascript';
4261        script.src = url;
4262        script.onerror = this.loadErrorCallback.bind(this);
4263        script.defer = true;
4264        script.async = true;
4265        this.document.head.appendChild(script);
4266    }
4267    /**
4268   * Function to be called if script tag fails
4269   * @param {Error} e
4270   */ loadErrorCallback(e) {
4271        this.errors.push(e);
4272        if (this.errors.length <= this.retries) {
4273            const delay = this.errors.length * 2 ** this.errors.length;
4274            // eslint-disable-next-line no-console
4275            console.log(`Failed to load Google Maps script, retrying in ${delay} ms.`);
4276            setTimeout(()=>{
4277                this.deleteScript();
4278                this.setScript().catch((e)=>console.error(e));
4279            }, delay);
4280        } else {
4281            this.failed = true;
4282            this.onerrorEvent = e;
4283            this.callback();
4284        }
4285    }
4286    /**
4287   * Delete the script tag
4288   */ deleteScript() {
4289        const script = this.document.getElementById(this.id);
4290        if (script) script.remove();
4291    }
4292    /**
4293   * Load the Google Maps JavaScript API script and return a Promise.
4294   * @return {Promise}
4295   */ load() {
4296        return this.loadPromise();
4297    }
4298    /**
4299   * Load the Google Maps JavaScript API script and return a Promise.
4300   * @return {Promise}
4301   */ loadPromise() {
4302        return new Promise((resolve, reject)=>{
4303            this.loadCallback((err)=>{
4304                if (!err) resolve();
4305                else reject(err);
4306            });
4307        });
4308    }
4309    /**
4310   * Load the Google Maps JavaScript API script with a callback.
4311   * @param {Function<Event>} fn
4312   */ loadCallback(fn) {
4313        this.callbacks.push(fn);
4314        this.execute();
4315    }
4316    /**
4317   * Sets the callback function that will be sent as part of the script URL.
4318   */ setCallback() {
4319        this.window.__googleMapsCallback = this.callback.bind(this);
4320    }
4321    /**
4322   * Reset if failed
4323   */ resetIfRetryingFailed() {
4324        if (this.failed) this.reset();
4325    }
4326    /**
4327   * This is the function that we set the callback parameter to.
4328   */ callback() {
4329        this.done = true;
4330        this.loading = false;
4331        this.callbacks.forEach((cb)=>{
4332            cb(this.onerrorEvent);
4333        });
4334        this.callbacks = [];
4335    }
4336    /**
4337   * Set the script a if needed; set the callback
4338   */ execute() {
4339        if (this.window.google && this.window.google.maps && this.window.google.maps.version) // Google Maps already loaded
4340        this.callback();
4341        this.resetIfRetryingFailed();
4342        if (this.done) this.callback();
4343        else if (this.loading) ;
4344        else {
4345            this.loading = true;
4346            this.setCallback();
4347            this.setScript().catch((e)=>console.error(e));
4348        }
4349    }
4350    /**
4351   * get base url based on current config
4352   * @return {string}
4353   */ _getBaseUrl() {
4354        // Special handling for page builder since no wag available
4355        const { isBuilder: isBuilder, websiteApiGatewayUrl: websiteApiGatewayUrl } = this.config;
4356        return isBuilder ? websiteApiGatewayUrl : '';
4357    }
4358    /**
4359   * Resize static map requests to the max 1024px while preserving aspect ratio
4360   * @param {number} width
4361   * @param {number} height
4362   * @return {{width, height}}
4363   */ resizeStaticMapDimensions(width, height) {
4364        if (width <= $ea6901fdf47e0ec1$export$76299006759be400 && height <= $ea6901fdf47e0ec1$export$76299006759be400) return {
4365            width: width,
4366            height: height
4367        };
4368        // Size param ignored if dimensions exceed STATIC_MAP_MAX_DIM
4369        const ratio = Math.min($ea6901fdf47e0ec1$export$76299006759be400 / width, $ea6901fdf47e0ec1$export$76299006759be400 / height);
4370        return {
4371            width: parseInt(width * ratio),
4372            height: parseInt(height * ratio)
4373        };
4374    }
4375    /**
4376   * Convert theme to static api param object
4377   * @param {Object} theme
4378   * @return {Object}
4379   */ convertThemeToStaticApiUrl(theme) {
4380        // https://developers.google.com/maps/documentation/maps-static/style-reference
4381        // Google Maps Static API uses a special syntax for it's urls based on the interactive map styles
4382        return theme.map((t)=>{
4383            const styles = t.stylers.reduce((acc, s)=>{
4384                const visibility = s.visibility ? `visibility:${s.visibility}` : '';
4385                const color = s.color ? `color:${s.color.replace('#', '0x')}` : '';
4386                const lightness = s.lightness ? `lightness:${s.lightness}` : '';
4387                return `${acc}|${visibility}${color}${lightness}`;
4388            }, '');
4389            const element = t.elementType ? `|element:${t.elementType}` : '';
4390            return `feature:${t.featureType}${element}${styles}`;
4391        });
4392    }
4393    /**
4394   * generate digital signature for url
4395   * @param {string} queryString to sign
4396   * @return {Promise<string>} digitally signed url
4397   */ async getMapApiSignedUrl(queryString) {
4398        try {
4399            const response = await fetch(`${this._getBaseUrl()}/api/v1/map/signature?${queryString}`);
4400            if (!response.ok) throw new Error('Failed to fetch signed URL');
4401            const { url: url } = await response.json();
4402            return url;
4403        } catch (e) {
4404            // eslint-disable-next-line no-console
4405            console.error(e);
4406            return '';
4407        }
4408    }
4409    /**
4410   * Generate static map url
4411   * @param {number} lat
4412   * @param {number} lng
4413   * @param {number} zoom
4414   * @param {Object} theme
4415   * @param {number} srcWidth
4416   * @param {number} srcHeight
4417   * @return {string}
4418   */ generateStaticMapUrl(lat, lng, zoom, theme, srcWidth, srcHeight) {
4419        const baseUrl = 'https://maps.googleapis.com/maps/api/staticmap';
4420        const { width: width, height: height } = this.resizeStaticMapDimensions(srcWidth, srcHeight);
4421        const query = {
4422            center: `${lat},${lng}`,
4423            zoom: zoom,
4424            scale: 2,
4425            size: `${width}x${height}`,
4426            key: this.apiKey
4427        };
4428        if (theme) query.style = this.convertThemeToStaticApiUrl(theme);
4429        const params = new URLSearchParams();
4430        Object.entries(query).forEach(([key, value])=>{
4431            if (Array.isArray(value)) value.forEach((v)=>params.append(key, v.toString()));
4432            else params.append(key, value.toString());
4433        });
4434        return `${baseUrl}?${params.toString()}`;
4435    }
4436    /**
4437   * Generate static map url with digital signature
4438   * @param {Object} {
4439   *  srcWidth {number}, required
4440   *  srcHeight {number}, required
4441   *  theme {array},
4442   *  center: `${lat},${lng}`, required
4443   *  zoom: number, required
4444   *  markers: `${lat},${lng}`,
4445   *  scale: number,
4446   *  otherQueryParams... (these must match what is compatible with google maps static api query params)
4447   * }
4448   * @return {Promise<string>} digitally signed url
4449   */ async generateDigitallySignedStaticMapUrl({ srcWidth: srcWidth, srcHeight: srcHeight, theme: theme, ...query }) {
4450        const { width: width, height: height } = this.resizeStaticMapDimensions(srcWidth, srcHeight);
4451        const queryParams = {
4452            ...query,
4453            size: `${width}x${height}`
4454        };
4455        if (theme) queryParams.style = this.convertThemeToStaticApiUrl(theme);
4456        const params = new URLSearchParams();
4457        Object.entries(queryParams).forEach(([key, value])=>{
4458            if (Array.isArray(value)) value.forEach((v)=>params.append(key, v.toString()));
4459            else params.append(key, value.toString());
4460        });
4461        const queryString = params.toString();
4462        try {
4463            // fetch digitally signed url
4464            return await this.getMapApiSignedUrl(queryString);
4465        } catch (e) {
4466            console.error(e);
4467            return '';
4468        }
4469    }
4470}
4471
4472
4473/* eslint-disable import/prefer-default-export */ 
4474
4475class $0a0ad49f13c0b8fd$export$ba9afeb75f20f616 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
4476    // constructor is not needed as it is inherited from BaseController
4477    /**
4478   * Controllers must implement a "destroy" method to be called
4479   * after page navigation to remove event handlers / cleanup
4480   */ destroy() {}
4481    /**
4482   * Places (re-places) a value into the query string under specified key
4483   *   or removes it if new value is null or undefined
4484   * @param {string} key
4485   * @param {string|null|undefined|object|array} value
4486   * @param {string} url - defaults to window.location.href
4487   * @return {string}
4488   */ // eslint-disable-next-line sonarjs/cognitive-complexity
4489    updateQueryString(key, value, url) {
4490        // https://stackoverflow.com/questions/5999118/how-can-i-add-or-update-a-query-string-parameter
4491        if (!url) // eslint-disable-next-line
4492        url = this.window.location.href;
4493        let re = new RegExp(`([?&])${key}=.*?(&|#|$)`, 'i');
4494        let replacement = '';
4495        if (typeof value !== 'undefined' && value !== null) {
4496            if (Array.isArray(value)) {
4497                if (value.length) replacement = this.serializeArray(key, value);
4498            } else if (typeof value === 'object') {
4499                re = new RegExp(`([?&])${key}\\[[^=]*\\]=.*?(&|#|$)`, 'i');
4500                replacement = this.serializeObj(value, '', key);
4501            } else replacement = `${key}=${encodeURIComponent(value)}`;
4502        }
4503        const hash = url.split('#');
4504        let result = hash[0];
4505        if (re.test(url)) {
4506            let clean = result;
4507            replacement = replacement ? `$1${replacement}$2` : '$1';
4508            while(re.test(clean)){
4509                result = clean.replace(re, replacement);
4510                clean = clean.replace(re, '$1');
4511            }
4512            result = result.replace(/(&|\?)$/, '');
4513        } else if (replacement) {
4514            const separator = result.indexOf('?') !== -1 ? '&' : '?';
4515            result += `${separator}${replacement}`;
4516        }
4517        if (typeof hash[1] !== 'undefined' && hash[1] !== null) result += `#${hash[1]}`;
4518        return result;
4519    }
4520    /**
4521   * Returns variable from query string specified by parameter name
4522   * @param {string} name
4523   * @param {string} url defaults to window.location.href
4524   * @return {string|null}
4525   */ getParameterByName(name, url) {
4526        if (!url) // eslint-disable-next-line
4527        url = this.window.location.href;
4528        // eslint-disable-next-line
4529        name = name.replace(/[[\]]/g, '\\$&');
4530        const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
4531        let results = Array.from(RegExp.prototype[Symbol.matchAll].call(regex, url)).flat();
4532        // check for object like syntax where the last value can be an array eg. advancedFilters[query][statusIds][in][0] or advancedFilters[query][city]
4533        if (!results.length) {
4534            const objRegex = new RegExp(`[?&]${name}(\\[.*?\\])=(.*?)(?=&|#|$)`, 'g');
4535            results = Array.from(RegExp.prototype[Symbol.matchAll].call(objRegex, url)).flat();
4536            return this._parseParamToObject(results, name === 'advancedFilters');
4537        }
4538        // For multiple param values, eg arrays
4539        /* Results from regex match all come in this form:
4540    [ '&advancedFilters[query][statusIds][in]=uuid-segundo-123', '[query][statusIds][in]', 'uuid-segundo-123' ]
4541    So using every third value will be the actual value and the second value will be the path
4542    */ if (results.length > 3) return results.reduce((acc, value, index)=>{
4543            if ((index + 1) % 3 === 0) acc.push(decodeURIComponent(value.replace(/\+/g, ' ')));
4544            return acc;
4545        }, []);
4546        if (!results[2]) return '';
4547        return decodeURIComponent(results[2].replace(/\+/g, ' '));
4548    }
4549    /**
4550   * Generates section specific key to store page number in the URL
4551   * @param {string} sectionDomId
4552   * @return {string}
4553   */ makePageKey(sectionDomId) {
4554        return sectionDomId.replace('section-', '').replace(/-/g, '');
4555    }
4556    /**
4557   * Generates specific key to store parameter in the URL
4558   * uses prevsiouly calculated baseKey for section specific parameters
4559   * @param {Object} formParam
4560   * @param {string} baseKey pre-calculated base for section specific parameters
4561   * @return {string}
4562   */ makeParamKey(formParam, baseKey) {
4563        return formParam.global ? formParam.urlKey : `${baseKey}-${formParam.urlKey}`;
4564    }
4565    /**
4566   * Gets a set of parameters from window query string
4567   * always returns value of "page" parameter if present
4568   * @param {Object[]} formConfig
4569   * @param {string} sectionDomId
4570   * @return {Object}
4571   */ deserializeParams(formConfig, sectionDomId) {
4572        const params = {};
4573        const urlPageKey = this.makePageKey(sectionDomId);
4574        const page = this.getParameterByName(urlPageKey);
4575        if (page) params.page = parseInt(page);
4576        if (Array.isArray(formConfig)) formConfig.forEach((formParam)=>{
4577            const key = this.makeParamKey(formParam, urlPageKey);
4578            let urlValue = this.getParameterByName(key);
4579            if (formParam.type === 'int') {
4580                urlValue = parseInt(urlValue);
4581                // eslint-disable-next-line
4582                if (!isFinite(urlValue)) urlValue = null;
4583            } else if (formParam.type === 'bool' || formParam.type === 'boolean') urlValue = // eslint-disable-next-line
4584            urlValue === 'true' ? true : urlValue === 'false' ? false : null;
4585            else if (formParam.type === 'json') try {
4586                urlValue = JSON.parse(urlValue);
4587            } catch (e) {
4588            // no need to do anything
4589            }
4590            params[formParam.formKey || formParam.param] = urlValue;
4591        });
4592        return params;
4593    }
4594    /**
4595   * Serializes set of parameters defined by formConfig into the URL
4596   * adding or replacing or removing required parameters
4597   * @param {Object[]} formConfig
4598   * @param {string} sectionDomId
4599   * @param {Object} params
4600   * @return {string}
4601   */ serializeParams(formConfig, sectionDomId, params) {
4602        let result = this.window.location.href;
4603        const urlPageKey = this.makePageKey(sectionDomId);
4604        result = this.updateQueryString(urlPageKey, params.page, result);
4605        if (Array.isArray(formConfig)) formConfig.forEach((formParam)=>{
4606            const key = this.makeParamKey(formParam, urlPageKey);
4607            let value = params[formParam.formKey || formParam.param];
4608            if (formParam.type === 'json' && value !== null && typeof value !== 'undefined') value = JSON.stringify(value);
4609            result = this.updateQueryString(key, value, result);
4610        });
4611        return result;
4612    }
4613    /**
4614   * Formats small number for slider values
4615   * @param {number} value
4616   * @param {string} currency
4617   * @return {string}
4618   */ formatSliderAtom(value, currency = '') {
4619        const formattedValue = Number.isInteger(value) ? value : value.toFixed(2);
4620        return currency + formattedValue;
4621    }
4622    /**
4623   * Formats a number for slider values
4624   * @param {number} value
4625   * @param {string} currency
4626   * @param {string} delimiter
4627   * @return {string}
4628   */ formatSliderValue(value, currency = '', delimiter = '') {
4629        if (value < 1000) return this.formatSliderAtom(value, currency);
4630        if (value < 1000000) return `${this.formatSliderAtom(value / 1000, currency)}${delimiter}K`;
4631        return `${this.formatSliderAtom(value / 1000000, currency)}${delimiter}M`;
4632    }
4633    /**
4634   * Format price slider range
4635   * @param {number} value
4636   * @param {Object} range
4637   * @param {string} currency
4638   * @param {Object} options
4639   * @return {string}
4640   */ formatSliderPriceRange(value, range, currency, options) {
4641        if (range.min === value && value !== 0) return `${options.lowPrefix}${this.formatSliderValue(value, currency, ' ')}`;
4642        if (range.max === value) return `${this.formatSliderValue(value, currency, ' ')}${options.highSuffix}`;
4643        return `${this.formatSliderValue(value, currency, ' ')}`;
4644    }
4645    /**
4646   * Format area slider range
4647   * @param {number} value
4648   * @param {Object} range
4649   * @param {string} suffix
4650   * @param {Object} options
4651   * @return {string}
4652   */ formatSliderAreaRange(value, range, suffix, options) {
4653        if (range.min === value && value !== 0) return `${options.lowPrefix}${this.formatSliderValue(value)} ${suffix}`;
4654        if (range.max === value) return `${this.formatSliderValue(value)}${options.highSuffix} ${suffix}`;
4655        return `${this.formatSliderValue(value)} ${suffix}`;
4656    }
4657    /**
4658   * Utility function to get properties search parameters from a set of jQuery objects
4659   * @param {Object} options
4660   * @param {jQuery|HTMLElement} [options.queryElement]
4661   * @param {jQuery|HTMLElement} [options.priceSliderElement]
4662   * @param {jQuery|HTMLElement} [options.areaSliderElement]
4663   * @param {jQuery|HTMLElement} [options.neighborhoodSelect]
4664   * @return {Object}
4665   */ // eslint-disable-next-line sonarjs/cognitive-complexity
4666    getSearchFormValues(options) {
4667        const { queryElement: queryElement, priceSliderElement: priceSliderElement, areaSli
4667derElement: areaSliderElement, neighborhoodSelect: neighborhoodSelect } = options;
4668        const result = {};
4669        if (queryElement) result.search = queryElement.value || null;
4670        if (priceSliderElement) {
4671            const priceValues = priceSliderElement.value.split(';');
4672            const priceMinLimit = parseInt(priceSliderElement.dataset.min);
4673            const priceMaxLimit = parseInt(priceSliderElement.dataset.max);
4674            const priceMin = parseInt(priceValues[0]);
4675            const priceMax = parseInt(priceValues[1]);
4676            result.priceMin = priceMin !== priceMinLimit ? priceMin : null;
4677            result.priceMax = priceMax !== priceMaxLimit ? priceMax : null;
4678        }
4679        if (areaSliderElement) {
4680            const areaValues = areaSliderElement.value.split(';');
4681            const areaMinLimit = parseInt(areaSliderElement.dataset.min);
4682            const areaMaxLimit = parseInt(areaSliderElement.dataset.max);
4683            const areaMin = parseInt(areaValues[0]);
4684            const areaMax = parseInt(areaValues[1]);
4685            result.areaMin = areaMin !== areaMinLimit ? areaMin : null;
4686            result.areaMax = areaMax !== areaMaxLimit ? areaMax : null;
4687        }
4688        if (neighborhoodSelect) result.neighborhoodId = neighborhoodSelect.value || null;
4689        return result;
4690    }
4691    /**
4692   * Add supports for object typeof values to be encoded on URL
4693   * Ref: https://stackoverflow.com/questions/1714786/query-string-encoding-of-a-javascript-object
4694   * @param {*} obj
4695   * @param {string} prefix
4696   * @param {string} baseParam used for grouping in case of nested objects
4697   * @returns
4698   */ // eslint-disable-next-line sonarjs/cognitive-complexity
4699    serializeObj(obj, prefix = '', baseParam = '') {
4700        const result = [];
4701        for(const prop in obj)if (obj.hasOwnProperty(prop)) {
4702            const value = obj[prop];
4703            let k;
4704            if (baseParam) {
4705                const newPrefix = prefix ? `[${prefix}][${prop}]` : `[${prop}]`;
4706                k = `${baseParam}${newPrefix}`;
4707            } else k = prefix ? `${prefix}[${prop}]` : prop;
4708            if (value !== null && Array.isArray(value)) {
4709                if (value.length) result.push(this.serializeArray(k, value));
4710            } else if (value !== null && typeof value === 'object') result.push(this.serializeObj(value, k));
4711            else result.push(`${k}=${encodeURIComponent(value)}`);
4712        }
4713        return result.join('&');
4714    }
4715    /**
4716   * Adds support for array values to be encoded on URL
4717   * @param {string} key
4718   * @param {Array} value
4719   * @param {string} baseParam
4720   */ serializeArray(key, value, baseParam = '') {
4721        const result = [];
4722        value.forEach((val)=>{
4723            const paramName = baseParam ? `${baseParam}${key}` : key;
4724            result.push(`${paramName}=${encodeURIComponent(val)}`);
4725        });
4726        return result.join('&');
4727    }
4728    /**
4729   * Private method to process string search values.
4730   * @param {Array} results comes from regex matchAll.
4731   * @param {Boolean} isAdvancedFilters flag to determine if the search is for advanced filters.
4732   * @returns
4733   */ _parseParamToObject(results, isAdvancedFilters = false) {
4734        if (!results.length) return null;
4735        const obj = {};
4736        for(let i = 0; i < results.length; i++)/* Results from regex match all come in this form:
4737      [ '&advancedFilters[query][statusIds][in]=uuid-segundo-123', '[query][statusIds][in]', 'uuid-segundo-123' ]
4738      So using every third value will be the actual value and the second value will be the path
4739    */ if ((i + 1) % 3 === 0) {
4740            const value = decodeURIComponent(results[i].replace(/\+/g, ' '));
4741            const path = results[i - 1];
4742            Object.assign(obj, this._setObjectPath(path, value, obj, isAdvancedFilters));
4743        }
4744        return obj;
4745    }
4746    /** *
4747   * Private method to set object value given a path
4748   * @param {String} path
4749   * @param {*} value
4750   * @param {Object} baseObj
4751   * @param {Boolean} isAdvancedFilters flag to determine if the search is for advanced filters.
4752   */ _setObjectPath(path, value, baseObj, isAdvancedFilters = false) {
4753        // eslint-disable-next-line
4754        const keys = path.split(/[\[\]]/).filter(Boolean);
4755        const afArrayKeys = [
4756            'in',
4757            'nin',
4758            'btw',
4759            'ciin',
4760            'cinin'
4761        ];
4762        const obj = {};
4763        let ref = obj;
4764        const valueExists = (0, $fc0a058ae42af628$export$267a1435fe18b8d4)(baseObj, keys.join('.'));
4765        keys.forEach((key, index)=>{
4766            if (index === keys.length - 1) {
4767                if (valueExists) ref[key] = Array.isArray(valueExists) ? [
4768                    ...valueExists,
4769                    value
4770                ] : [
4771                    valueExists,
4772                    value
4773                ];
4774                else ref[key] = isAdvancedFilters && afArrayKeys.includes(key) ? [
4775                    value
4776                ] : value;
4777            } else {
4778                ref[key] = baseObj[key] ? baseObj[key] : {};
4779                ref = ref[key];
4780            }
4781        });
4782        return obj;
4783    }
4784}
4785
4786
4787/* eslint-disable import/prefer-default-export */ 
4788class $2b1790aa32f109d1$export$43e435c053a109f6 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
4789    /**
4790   * Initialize Expand Slider Controller at build time
4791   * @param { ConfigController } config
4792   * @param {Window} window
4793   * @param {Document} document
4794   */ constructor(config, window, document){
4795        super(config, window, document);
4796        this._createLightbox = this._createLightbox.bind(this);
4797        this.expandSliders = [];
4798    }
4799    /**
4800   * Initialize Expand Slider Controller at run time
4801   * Attach handlers and events to DOM
4802   * @param {Object} options
4803   */ initialize(options = {}) {
4804        try {
4805            const { document: document } = this;
4806            const expandSliders = document.querySelectorAll('.has-mobile-expand');
4807            expandSliders.forEach((block)=>{
4808                this._addExpandButton(block);
4809            });
4810            this.expandSliders = this.expandSliders.concat(expandSliders);
4811        } catch (e) {
4812            // eslint-disable-next-line no-console
4813            console.log(e);
4814        }
4815    }
4816    /**
4817   * Controllers must implement a "destroy" method to be called
4818   * after page navigation to remove event handlers / cleanup
4819   */ destroy() {
4820        const { document: document } = this;
4821        document.querySelectorAll('.lp-expand-btn, .lp-expand-btn-wrapper').forEach((element)=>element.remove());
4822        this.expandSliders = [];
4823    }
4824    /**
4825   * Create expand button for sliders
4826   * @param {HTMLElement} slider
4827   */ _addExpandButton(slider) {
4828        const { document: document } = this;
4829        const section = slider.closest('section[id]');
4830        const appendTargetSelector = slider.dataset.append;
4831        let expandBtn = section.querySelector('.lp-expand-btn');
4832        if (!expandBtn) {
4833            expandBtn = document.createElement('button');
4834            expandBtn.className = 'lp-expand-btn';
4835            expandBtn.setAttribute('aria-label', 'Open a lightbox');
4836            expandBtn.innerHTML = `<span class="lp-i lp-i--expand-alt" aria-hidden="true"></span>`;
4837            if (appendTargetSelector) {
4838                const appendTarget = section.querySelector(appendTargetSelector);
4839                if (appendTarget) appendTarget.appendChild(expandBtn);
4840            } else {
4841                const wrapper = document.createElement('div');
4842                wrapper.className = 'lp-expand-btn-wrapper';
4843                wrapper.style.position = 'relative';
4844                wrapper.appendChild(expandBtn);
4845                slider.parentNode.insertBefore(wrapper, slider.nextSibling);
4846            }
4847        }
4848        expandBtn.addEventListener('click', ()=>{
4849            this._createLightbox({
4850                slider: slider,
4851                section: section
4852            });
4853        });
4854    }
4855    /**
4856   * Creates a lightbox modal for displaying slider images in a larger view.
4857   *
4858   * @param {Object} params - The parameters for the function.
4859   * @param {HTMLElement} params.slider - The slider element containing images.
4860   * @param {HTMLElement} params.section - The section element related to the slider.
4861   * @param {number} [params.initialIndex] - Optional index of the image to show initially.
4862   */ _createLightbox({ slider: slider, section: section, initialIndex: initialIndex }) {
4863        const { window: window, document: document } = this;
4864        const modalId = `lightbox-for-${section?.id}`;
4865        const isSlickAvailable = window.$ && window.$.fn.slick;
4866        const isSectionSlickInitialized = isSlickAvailable && slider.slick;
4867        const isSplideAvailable = typeof window.Splide === 'function';
4868        const isSectionSplideInitialized = slider.classList.contains('is-initialized') && slider.classList.contains('splide');
4869        if (typeof window.lpUI.requestScrollLock === 'function') window.lpUI.requestScrollLock(modalId);
4870        else document.body.style.overflow = 'hidden';
4871        function createSlickLightbox() {
4872            const slickOverlayOptions = {
4873                arrows: true,
4874                dots: false,
4875                infinite: true,
4876                draggable: true,
4877                prevArrow: '<button type="button" class="lp-lightbox-arrow--prev lp-lightbox-arrow" aria-label="Previous"></button>',
4878                nextArrow: '<button type="button" class="lp-lightbox-arrow--next lp-lightbox-arrow" aria-label="Next"></button>'
4879            };
4880            const modal = document.createElement('div');
4881            modal.id = modalId;
4882            modal.className = 'lp-lightbox';
4883            modal.setAttribute('tabindex', '-1');
4884            modal.setAttribute('role', 'dialog');
4885            modal.setAttribute('aria-modal', 'true');
4886            modal.innerHTML = `
4887        <button class="lp-lightbox__close" aria-label="close modal"></button>
4888        <div class="lp-lightbox__content">
4889          <div class="lp-lightbox__carousel"></div>
4890        </div>
4891      `;
4892            document.body.appendChild(modal);
4893            const overlaySlider = modal.querySelector('.lp-lightbox__carousel');
4894            modal.classList.add('show');
4895            let sourceImages;
4896            if (isSectionSlickInitialized) {
4897                sourceImages = slider.slick.$slides.find('img');
4898                slickOverlayOptions.initialSlide = slider.slick?.currentSlide || 0;
4899                sourceImages.each(function() {
4900                    window.$('.lp-lightbox__carousel').append(window.$(this).clone(false).removeAttr('style').wrap('<div class="lp-lightbox__slide"></div>').parent());
4901                });
4902            } else {
4903                sourceImages = slider.querySelectorAll('img');
4904                sourceImages.forEach((img)=>{
4905                    const imgClone = img.cloneNode(true);
4906                    imgClone.removeAttribute('style');
4907                    const slide = document.createElement('div');
4908                    slide.className = 'lp-lightbox__slide';
4909                    slide.appendChild(imgClone);
4910                    overlaySlider.appendChild(slide);
4911                });
4912            }
4913            window.$(overlaySlider).slick(slickOverlayOptions);
4914            // Focus modal after it's created
4915            setTimeout(()=>{
4916                modal.focus();
4917            }, 100);
4918            // Keyboard navigation handler
4919            const handleKeydown = (e)=>{
4920                if (!modal.classList.contains('show')) return;
4921                const prevArrow = modal.querySelector('.lp-lightbox-arrow--prev');
4922                const nextArrow = modal.querySelector('.lp-lightbox-arrow--next');
4923                const closeBtn = modal.querySelector('.lp-lightbox__close');
4924                if (e.key === 'ArrowLeft' && prevArrow) {
4925                    e.preventDefault();
4926                    prevArrow.click();
4927                } else if (e.key === 'ArrowRight' && nextArrow) {
4928                    e.preventDefault();
4929                    nextArrow.click();
4930                } else if (e.key === 'Escape' && closeBtn) {
4931                    e.preventDefault();
4932                    closeBtn.click();
4933                }
4934            };
4935            document.addEventListener('keydown', handleKeydown);
4936            modal.querySelector('.lp-lightbox__close').addEventListener('click', ()=>{
4937                document.removeEventListener('keydown', handleKeydown);
4938                modal.classList.remove('show');
4939                const currentSlide = overlaySlider?.slick ? window.$(overlaySlider).slick('slickCurrentSlide') : 0;
4940                if (overlaySlider?.slick) window.$(overlaySlider).slick('unslick');
4941                if (isSectionSlickInitialized) window.$(slider).slick('slickGoTo', currentSlide);
4942                if (typeof window.lpUI.releaseScrollLock === 'function') window.lpUI.releaseScrollLock(modalId);
4943                else document.body.style.overflow = '';
4944                modal.remove();
4945            });
4946        }
4947        function createSplideLightbox() {
4948            const splideOptions = {
4949                rewind: true,
4950                arrows: true,
4951                arrowPath: '',
4952                type: 'loop',
4953                clones: 1,
4954                pagination: false,
4955                perPage: 1,
4956                perMove: 1
4957            };
4958            const modal = document.createElement('div');
4959            modal.id = modalId;
4960            modal.className = 'lp-lightbox';
4961            modal.setAttribute('tabindex', '-1');
4962            modal.setAttribute('role', 'dialog');
4963            modal.setAttribute('aria-modal', 'true');
4964            modal.innerHTML = `
4965      <button class="lp-lightbox__close" aria-label="close modal"></button>
4966      <div class="lp-lightbox__content">
4967        <div class="lp-lightbox__carousel splide" role="group" aria-label="Image Gallery">
4968          <div class="splide__arrows">
4969            <button class="splide__arrow splide__arrow--prev lp-lightbox-arrow lp-lightbox-arrow--prev"></button>
4970            <button class="splide__arrow splide__arrow--next lp-lightbox-arrow lp-lightbox-arrow--next"></button>
4971          </div>
4972          <div class="splide__track">
4973            <ul class="splide__list"></ul>
4974          </div>
4975        </div>
4976      </div>
4977    `;
4978            if (typeof window.lpUI.requestScrollLock === 'function') window.lpUI.requestScrollLock(modalId);
4979            else document.body.style.overflow = 'hidden';
4980            document.body.appendChild(modal);
4981            const overlaySlider = modal.querySelector('.lp-lightbox__carousel');
4982            const overlaySliderList = overlaySlider.querySelector('.splide__list');
4983            modal.classList.add('show');
4984            let sourceImages;
4985            if (isSectionSplideInitialized) sourceImages = slider.querySelectorAll('.splide__slide:not(.splide__slide--clone) img');
4986            else sourceImages = slider.querySelectorAll('img');
4987            sourceImages.forEach((img)=>{
4988                const imgClone = img.cloneNode(true);
4989                imgClone.removeAttribute('style');
4990                const slide = document.createElement('li');
4991                slide.className = 'lp-lightbox__slide splide__slide';
4992                slide.appendChild(imgClone);
4993                overlaySliderList.appendChild(slide);
4994            });
4995            const overlaySplide = new window.Splide(overlaySlider, splideOptions);
4996            overlaySplide.mount();
4997            // Navigate to initial index if provided
4998            if (typeof initialIndex !== 'undefined' && initialIndex >= 0) overlaySplide.go(initialIndex);
4999            // Focus modal after it's created and mounted
5000            setTimeout(()=>{
5001                modal.focus();
5002            }, 100);
5003            // Keyboard navigation handler
5004            const handleKeydown = (e)=>{
5005                if (!modal.classList.contains('show')) return;
5006                const prevArrow = modal.querySelector('.splide__arrow--prev');
5007                const nextArrow = modal.querySelector('.splide__arrow--next');
5008                const closeBtn = modal.querySelector('.lp-lightbox__close');
5009                if (e.key === 'ArrowLeft' && prevArrow) {
5010                    e.preventDefault();
5011                    prevArrow.click();
5012                } else if (e.key === 'ArrowRight' && nextArrow) {
5013                    e.preventDefault();
5014                    nextArrow.click();
5015                } else if (e.key === 'Escape' && closeBtn) {
5016                    e.preventDefault();
5017                    closeBtn.click();
5018                }
5019            };
5020            document.addEventListener('keydown', handleKeydown);
5021            modal.querySelector('.lp-lightbox__close').addEventListener('click', ()=>{
5022                document.removeEventListener('keydown', handleKeydown);
5023                modal.classList.remove('show');
5024                if (overlaySplide) overlaySplide.destroy();
5025                if (typeof window.lpUI.releaseScrollLock === 'function') window.lpUI.releaseScrollLock(modalId);
5026                else document.body.style.overflow = '';
5027                modal.remove();
5028            });
5029        }
5030        if (isSlickAvailable && !isSectionSplideInitialized) createSlickLightbox();
5031        else if (isSplideAvailable) createSplideLightbox();
5032        else {
5033            window.luxuryPresence.libs.loadCss(window.luxuryPresence.libs.jsLibsMap.splide.cssSrc);
5034            window.luxuryPresence.libs.loadJs(window.luxuryPresence.libs.jsLibsMap.splide.jsSrc, ()=>{
5035                createSplideLightbox();
5036                window.luxuryPresence.libs.jsLibsMap.splide.isLoaded = true;
5037            });
5038        }
5039    }
5040}
5041
5042
5043/* eslint-disable import/prefer-default-export */ 
5044class $4f184d9bd3037f15$export$7a6215890afba974 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5045    // constructor is not needed as it is inherited from BaseController
5046    /**
5047   * Destroy
5048   */ destroy() {
5049        if (!this.window.divolte) this.window.divolteLp = function() {
5050            (this.window.divolteLp.q = this.window.divolteLp.q || []).push(// eslint-disable-next-line prefer-rest-params
5051            arguments);
5052        };
5053    }
5054    /**
5055   * Initialize divolte controller
5056   * @param {Object} options
5057   */ initialize(options = {}) {
5058        const { divolteServiceUrl: divolteServiceUrl } = this.config;
5059        if (!divolteServiceUrl || this.window.divolte) return;
5060        this.loadScript();
5061    }
5062    /**
5063   * loads divolte
5064   */ loadScript() {
5065        const { divolteServiceUrl: divolteServiceUrl } = this.config;
5066        const script = this.document.createElement('script');
5067        script.id = 'divolte-script';
5068        script.type = 'text/javascript';
5069        script.defer = true;
5070        script.async = true;
5071        script.src = `${divolteServiceUrl}/divolte.js`;
5072        this.document.head.appendChild(script);
5073        script.addEventListener('load', this.executeQueue.bind(this));
5074    }
5075    /**
5076   * executeQueue
5077   */ executeQueue() {
5078        (this.window.divolteLp.q || []).forEach(([methodName, params])=>{
5079            this[methodName](params);
5080        });
5081        this.window.divolteLp = this.divolteLp.bind(this);
5082    }
5083    /**
5084   * divolteLp
5085   * @param {string} name
5086   * @param {Object} params
5087   */ divolteLp(name, params) {
5088        try {
5089            this[name](params);
5090        } catch (error) {
5091            // eslint-disable-next-line no-console
5092            console.log(error);
5093        }
5094    }
5095    /**
5096   * sendLpEvent
5097   * @param {string} name
5098   * @param {Object} params
5099   */ sendLpEvent(name, params) {
5100        // Events must be defined in divolte schema! To ensure correct usage, event names are validated here.
5101        if (!name.includes('pageView')) {
5102            // Event not defined
5103            // eslint-disable-next-line no-console
5104            console.log(`${name} IS NOT SUPPORTED`);
5105            return;
5106        }
5107        const { companyId: companyId, templateId: templateId, websiteId: websiteId, pageId: pageId, shareId: shareId, pageMeta: pageMeta } = this.config;
5108        const baseParams = {
5109            companyId: companyId,
5110            templateId: templateId,
5111            websiteId: websiteId,
5112            pageId: pageId,
5113            shareId: shareId,
5114            pageMeta: pageMeta
5115        };
5116        this.window.divolte.signal(name, Object.assign(baseParams, params));
5117    }
5118    /**
5119   * sendLpPageView
5120   */ sendLpPageView() {
5121        this.sendLpEvent('pageView', {});
5122    }
5123}
5124
5125
5126/* eslint-disable import/prefer-default-export */ 
5127const $102039871668a1df$var$EVENT_BUS_SCRIPT = 'event-bus-js.js';
5128const $102039871668a1df$var$EVENT_BUS_VERSION = 'v2.8.0';
5129const $102039871668a1df$var$EVENT_BUS_DEFAULT_SOURCE = 'frontend://website-render-engine';
5130class $102039871668a1df$export$e22e4b1be0bb6c61 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5131    // eslint-disable-next-line @typescript-eslint/no-useless-constructor
5132    constructor(config, window, document){
5133        super(config, window, document);
5134    }
5135    /**
5136   * Initialize EventBus controller
5137   * @param {Object} options
5138   */ initialize(options = {}) {
5139        const enabled = options.enabled !== undefined ? options.enabled : this.config.eventBus?.enabled;
5140        if (enabled && this.config.eventBus?.apiKey && this.config.eventBus?.url) this.loadScript();
5141    }
5142    /**
5143   * loads eventBus script
5144   */ loadScript() {
5145        const { eventBusUrl: eventBusUrl } = this.config;
5146        const script = this.document.createElement('script');
5147        script.id = 'posthog-script';
5148        script.type = 'text/javascript';
5149        script.defer = true;
5150        script.async = true;
5151        script.src = `${eventBusUrl}/${$102039871668a1df$var$EVENT_BUS_VERSION}/${$102039871668a1df$var$EVENT_BUS_SCRIPT}`;
5152        this.document.head.appendChild(script);
5153        script.addEventListener('load', this.executeQueue.bind(this));
5154    }
5155    /**
5156   * executeQueue - Process queued eventBusLp calls
5157   */ executeQueue() {
5158        // Initialize the event bus provider using the global EventBusJS
5159        if (this.window.LuxuryPresenceEventBus) this.window.eventBusProvider = this.window.LuxuryPresenceEventBus.createEventBusProvider({
5160            apiKey: this.config.eventBus.apiKey,
5161            host: this.config.eventBus.url,
5162            defaultSource: $102039871668a1df$var$EVENT_BUS_DEFAULT_SOURCE
5163        });
5164        (this.window.eventBusLp.q || []).forEach(([methodName, params])=>{
5165            this[methodName](params);
5166        });
5167        // Replace queue function with real function
5168        this.window.eventBusLp = this.eventBusLp.bind(this);
5169    }
5170    /**
5171   * Destroy
5172   */ destroy() {
5173        if (!this.window.eventBusProvider) {
5174            // Reset to queue function if no provider exists
5175            this.window.eventBusLp = function() {
5176                (this.window.eventBusLp.q = this.window.eventBusLp.q || []).push(// eslint-disable-next-line prefer-rest-params
5177                arguments);
5178            };
5179            return;
5180        }
5181        this.window.eventBusProvider.shutdown();
5182    }
5183    /**
5184   * sendLpEvent
5185   * @param {string} eventType
5186   * @param {Object} data
5187   */ sendLpEvent(eventType, data) {
5188        // Events must be defined in event-bus schema! To ensure correct usage, event types are validated here.
5189        if (eventType !== 'user.activity.page.viewed') {
5190            // Event type not defined
5191            // eslint-disable-next-line no-console
5192            console.log(`${eventType} IS NOT SUPPORTED`);
5193            return;
5194        }
5195        if (!this.window.eventBusProvider) return;
5196        const { companyId: companyId } = this.config;
5197        const eventData = {
5198            company: companyId,
5199            data: {}
5200        };
5201        try {
5202            this.window.eventBusProvider.capture(eventType, eventData);
5203        } catch (error) {
5204            // eslint-disable-next-line no-console
5205            console.log('EventBus capture error:', error);
5206        }
5207    }
5208    /**
5209   * eventBusLp
5210   * @param {string} name
5211   * @param {Object} params
5212   */ eventBusLp(name, params) {
5213        try {
5214            this[name](params);
5215        } catch (error) {
5216            // eslint-disable-next-line no-console
5217            console.log(error);
5218        }
5219    }
5220    /**
5221   * sendLpPageView
5222   */ sendLpPageView() {
5223        this.sendLpEvent('user.activity.page.viewed', {});
5224    }
5225}
5226
5227
5228/* eslint-disable import/prefer-default-export */ 
5229
5230const $0d25a3fa2e0f4f92$var$EVENT_NAME = 'oauthSuccess';
5231class $0d25a3fa2e0f4f92$export$b718a981691eae5c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5232    /**
5233   * Initialize Button Controller at build time
5234   * @param { ConfigController } config
5235   * @param {Window} window
5236   * @param {Document} document
5237   */ constructor(config, window, document){
5238        super(config, window, document);
5239        this.successListeners = [];
5240        this._listenToMessages = this._listenToMessages.bind(this);
5241        this._listenToOneTapMessage = this._listenToOneTapMessage.bind(this);
5242    }
5243    /**
5244   * Initialize OAuth Controller at run time
5245   * Swap out special buttons for the iframe
5246   * @param {Object} options
5247   */ initialize(options = {}) {
5248        try {
5249            // handle google one tap
5250            if (options.googleSignOnEnabled && !options.iframe) this._renderGoogleOneTap();
5251            // handle google sign in buttons
5252            this.document.querySelectorAll('div[data-signin-type="google-sign-in"]').forEach((el)=>this._convertGoogleSignIn(el));
5253            // handle facebook sign in buttons
5254            this.document.querySelectorAll('div[data-signin-type="facebook-sign-in"]').forEach((el)=>this._convertFacebookSignIn(el));
5255        } catch (e) {
5256            // eslint-disable-next-line no-console
5257            console.log(e);
5258        }
5259    }
5260    /**
5261   * Controllers must implement a "destroy" method to be called
5262   * after page navigation to remove event handlers / cleanup
5263   */ destroy() {
5264        this.successListeners.forEach((callback)=>{
5265            this.window.removeEventListener('message', this._listenToMessages);
5266            this.window.removeEventListener('message', this._listenToOneTapMessage);
5267            this.window.removeEventListener($0d25a3fa2e0f4f92$var$EVENT_NAME, this.window[callback]);
5268        });
5269    }
5270    /**
5271   * Convert google one tap
5272   */ _renderGoogleOneTap() {
5273        if (!this._isGoogleOneTapOnCooldown()) {
5274            const dummyEl = this.document.createElement('div');
5275            // eslint-disable-next-line no-undef
5276            google.accounts.id.initializeIntermediate({
5277                src: this._buildUrlAndCopyAttributes(dummyEl, dummyEl, 'googleOneTap')
5278            });
5279            this.window.localStorage.removeItem('googleOneTapExpiration');
5280            this.window.addEventListener('message', this._listenToOneTapMessage);
5281        }
5282    }
5283    /**
5284   * Listening for messages from BSS one tap iframes
5285   * @param {MessageEvent} e
5286   */ _listenToOneTapMessage(e) {
5287        const messageTypes = {
5288            SHOW_INTERMEDIATE_IFRAME: 'show_intermediate_iframe',
5289            HIDE_INTERMEDIATE_IFRAME: 'hide_intermediate_iframe'
5290        };
5291        const iframeId = 'onetap_google_intermediate_iframe';
5292        const { buyerSellerServiceUrl: buyerSellerServiceUrl } = this.config;
5293        const { data: data, origin: origin } = e;
5294        const { type: type, height: height, event: event, source: source, token: token } = data;
5295        if (type === messageTypes.SHOW_INTERMEDIATE_IFRAME || type === messageTypes.HIDE_INTERMEDIATE_IFRAME) {
5296            const bssIframe = this.document.getElementById(iframeId);
5297            if (bssIframe) {
5298                bssIframe.style.height = height;
5299                bssIframe.style.display = type === messageTypes.SHOW_INTERMEDIATE_IFRAME ? 'unset' : 'none';
5300            }
5301        }
5302        // these events are generated by our code in the bss iframe
5303        if (origin === buyerSellerServiceUrl && source === 'GOOGLE_SIGN_ON') {
5304            if (event === 'success') {
5305                this._setExpirationLsItem(86400000); // 24 hours
5306                this._handleQualifyingQuestionsModal(token);
5307            } else if (event === 'cancel') this._setExpirationLsItem(7200000); // 2 hours
5308        }
5309    }
5310    /**
5311   * Set expiration local storage item for google one tap
5312   * @param {number} ms
5313   */ _setExpirationLsItem(ms) {
5314        const expiration = new Date().getTime() + ms;
5315        this.window.localStorage.setItem('googleOneTapExpiration', expiration);
5316    }
5317    /**
5318   * Check if google one tap is expired
5319   * @return {boolean}
5320   */ _isGoogleOneTapOnCooldown() {
5321        const expirationTime = this.window.localStorage.getItem('googleOneTapExpiration');
5322        return Number(expirationTime) > new Date().getTime();
5323    }
5324    /**
5325   * Convert google sign in buttons
5326   * @param {HTMLElement} el
5327   */ _convertGoogleSignIn(el) {
5328        this._replaceWithIframe('googleSignIn', el);
5329    }
5330    /**
5331   * Convert google sign in buttons
5332   * @param {HTMLElement} el
5333   */ _convertFacebookSignIn(el) {
5334        this._replaceWithIframe('facebookSignIn', el);
5335    }
5336    /**
5337   * Convert google sign in buttons
5338   * @param {'googleSignIn' | 'facebookSignIn'} provider
5339   * @param {HTMLElement} el
5340   */ _replaceWithIframe(provider, el) {
5341        this._attachSuccessCallback(el);
5342        const iframe = this.document.createElement('iframe');
5343        iframe.src = this._buildUrlAndCopyAttributes(el, iframe, provider);
5344        iframe.dataset.isSocialOauthButton = true;
5345        el.replaceWith(iframe);
5346    }
5347    /**
5348   * Listening for messages from BSS iframes
5349   * @param {Event} e
5350   */ _listenToMessages(e) {
5351        const { buyerSellerServiceUrl: buyerSellerServiceUrl } = this.config;
5352        // eslint-disable-next-line sonarjs/no-collapsible-if
5353        if (e.origin === buyerSellerServiceUrl) {
5354            if (e.data.event === 'success') {
5355                const event = new Event($0d25a3fa2e0f4f92$var$EVENT_NAME);
5356                this.window.dispatchEvent(event);
5357                // Registration / social sign-in is a lead event — credit the conversion.
5358                (0, $3ec2bf3965f87ecc$export$e70565180c0e6950)(this.window, this.document);
5359                this.successListeners.forEach((callback)=>{
5360                    if (this.window[callback]) this.window[callback](event);
5361                    else // eslint-disable-next-line no-console
5362                    console.error(`Callback function ${callback} not found on window object`);
5363                });
5364                this.document.documentElement.classList.add('is-login-success');
5365            }
5366        }
5367    }
5368    /**
5369   * Attach callback to iframe
5370   * @param {HTMLElement} el
5371   */ _attachSuccessCallback(el) {
5372        this.window.addEventListener('message', this._listenToMessages);
5373        const callbackFunction = el.dataset.onSuccessFunctionName;
5374        if (callbackFunction) this.successListeners.push(callbackFunction);
5375    }
5376    /**
5377   * Build Iframe URL
5378   * @param {HTMLElement} source
5379   * @param {HTMLElement} target
5380   * @param {string} provider
5381   * @return {string}
5382   */ _buildUrlAndCopyAttributes(source, target, provider) {
5383        const { buyerSellerServiceUrl: buyerSellerServiceUrl, companyId: companyId, websiteId: websiteId, pageId: pageId, pageMeta: pageMeta } = this.config;
5384        const { location: location } = this.window;
5385        const sourceUrl = location.origin + location.pathname;
5386        const destination = new URL(`${buyerSellerServiceUrl}/buttons/${provider}`);
5387        const utm = this.window.localStorage.getItem('utm_vars');
5388        const referrer = this.window.localStorage.getItem('referrer');
5389        destination.searchParams.append('companyId', companyId);
5390        destination.searchParams.append('websiteId', websiteId);
5391        destination.searchParams.append('pageId', pageId);
5392        destination.searchParams.append('sourceUrl', sourceUrl);
5393        destination.searchParams.append('pageMeta', JSON.stringify(pageMeta));
5394        if (utm) destination.searchParams.append('utm', utm);
5395        if (referrer) destination.searchParams.append('referrer', referrer);
5396        // Google and Facebook Attributes used to style the social button
5397        const RESERVED_ATTRIBUTES = [
5398            'data-size',
5399            'data-width',
5400            'data-text',
5401            'data-button-type',
5402            'data-shape',
5403            'data-layout',
5404            'data-max-rows',
5405            'data-use-continue-as',
5406            'data-type',
5407            'data-theme',
5408            'data-logo_alignment',
5409            'data-locale'
5410        ];
5411        Array.from(source.attributes).forEach((attribute)=>{
5412            if (RESERVED_ATTRIBUTES.includes(attribute.nodeName)) destination.searchParams.append(attribute.nodeName, attribute.nodeValue);
5413            else target.setAttribute(attribute.nodeName === 'id' ? 'data-id' : attribute.nodeName, attribute.nodeValue);
5414        });
5415        return destination.toString();
5416    }
5417    /**
5418   * Decode a JWT token to extract payload information
5419   * @param {string} token - The JWT token to decode
5420   * @return {Object|null} The decoded payload object or null if decoding fails
5421   */ _decodeToken(token) {
5422        try {
5423            const parts = token.split('.');
5424            const payload = parts[1];
5425            const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
5426            const padding = 4 - base64.length % 4;
5427            const padded = padding === 4 ? base64 : base64 + '='.repeat(padding);
5428            return JSON.parse(atob(padded));
5429        } catch (error) {
5430            return null;
5431        }
5432    }
5433    /**
5434   * Handle qualifying questions modal showing for Google Sign On
5435   * Decodes the JWT token to extract user email and shows the modal if available
5436   * @param {string} token - The JWT token containing user information
5437   */ _handleQualifyingQuestionsModal(token) {
5438        if (token && this.window.luxuryPresence && this.window.luxuryPresence.qualifyingQuestionsModal) {
5439            // Decoding only for lead attribution, fine to skip signature verification
5440            const decoded = this._decodeToken(token);
5441            if (decoded && decoded.email) this.window.luxuryPresence.qualifyingQuestionsModal.showModal(decoded.email, 'Google Sign On');
5442        }
5443    }
5444}
5445
5446
5447/* eslint-disable import/prefer-default-export */ 
5448class $dcf72769f009ff26$export$b900d6fe921fd49c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5449    /**
5450   * Initialize Qualifying Questions Modal Controller at build time
5451   * @param { ConfigController } config
5452   * @param {Window} window
5453   * @param {Document} document
5454   */ constructor(config, window, document){
5455        super(config, window, document);
5456        this.showModal = this.showModal.bind(this);
5457        this.hasModalBeenSubmitted = this.hasModalBeenSubmitted.bind(this);
5458        this.modalId = 'qualifying-questions-modal';
5459        this.cookieKey = 'qualifyingQuestionsModalSubmitted';
5460        this.qualifyingQuestionsModalEnabled = true;
5461        // Store references for cleanup
5462        this.eventListeners = [];
5463        this.timeouts = [];
5464    }
5465    initialize(options = {}) {
5466        this.qualifyingQuestionsModalEnabled = options.qualifyingQuestionsModalEnabled ?? this.qualifyingQuestionsModalEnabled;
5467        if (!this.qualifyingQuestionsModalEnabled) return;
5468        this.attachModalCloseListeners();
5469    }
5470    destroy() {
5471        // Remove all stored event listeners
5472        this.eventListeners.forEach(({ element: element, event: event, handler: handler })=>{
5473            if (element && element.removeEventListener) element.removeEventListener(event, handler);
5474        });
5475        this.timeouts.forEach((timeoutId)=>{
5476            clearTimeout(timeoutId);
5477        });
5478        this.restoreBodyScroll();
5479        this.eventListeners = [];
5480        this.timeouts = [];
5481    }
5482    /**
5483   * Check if modal has been submitted using cookie-based deduplication
5484   * @return {boolean}
5485   */ hasModalBeenSubmitted() {
5486        const cookieValue = this.getCookie(this.cookieKey);
5487        return cookieValue === 'true';
5488    }
5489    /**
5490   * Set cookie to prevent modal from showing again
5491   */ setModalSubmittedCookie() {
5492        this.setCookie(this.cookieKey, 'true', 365); // 1 year
5493    }
5494    showModal(email, triggerSource) {
5495        if (!this.qualifyingQuestionsModalEnabled || this.hasModalBeenSubmitted()) return;
5496        this.updateEmailValue(email);
5497        this.updateTriggerSourceValue(triggerSource);
5498        this.showModalElement();
5499    }
5500    /**
5501   * Get modal element with error handling
5502   * @return {Element|null}
5503   */ getModalElement() {
5504        const modal = this.document.getElementById(this.modalId);
5505        if (!modal) console.error('Modal element not found:', this.modalId);
5506        return modal;
5507    }
5508    updateEmailValue(email) {
5509        const modal = this.getModalElement();
5510        if (!modal) return;
5511        const emailInput = modal.querySelector('input[name="email"]');
5512        if (emailInput && typeof email === 'string') emailInput.value = email;
5513    }
5514    updateTriggerSourceValue(triggerSource) {
5515        const modal = this.getModalElement();
5516        if (!modal) return;
5517        const triggerSourceInput = modal.querySelector(`#${this.modalId}-triggerSource`);
5518        if (triggerSourceInput && typeof triggerSource === 'string') triggerSourceInput.value = triggerSource;
5519    }
5520    showModalElement() {
5521        const modal = this.getModalElement();
5522        if (!modal) return;
5523        modal.style.display = 'flex';
5524        this.blockBodyScroll();
5525    }
5526    /**
5527   * Helper method to get cookie value
5528   * @param {string} name
5529   * @return {string|null}
5530   */ getCookie(name) {
5531        const value = `; ${this.document.cookie}`;
5532        const parts = value.split(`; ${name}=`);
5533        if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift());
5534        return null;
5535    }
5536    /**
5537   * Helper method to set cookie
5538   * @param {string} name
5539   * @param {string} value
5540   * @param {number} days
5541   */ setCookie(name, value, days) {
5542        let expires = '';
5543        if (days) {
5544            const date = new Date();
5545            date.setTime(date.getTime() + days * 86400000);
5546            expires = `; expires=${date.toUTCString()}`;
5547        }
5548        let attrs = '; path=/; SameSite=Lax';
5549        if (this.window && this.window.location && this.window.location.protocol === 'https:') attrs += '; Secure';
5550        this.document.cookie = `${name}=${encodeURIComponent(value || '')}${expires}${attrs}`;
5551    }
5552    blockBodyScroll() {
5553        this._prevOverflow = this.document.body.style.overflow;
5554        this.document.body.style.overflow = 'hidden';
5555    }
5556    restoreBodyScroll() {
5557        this.document.body.style.overflow = this._prevOverflow || '';
5558        this._prevOverflow = null;
5559    }
5560    attachModalCloseListeners() {
5561        const modal = this.getModalElement();
5562        if (!modal) return;
5563        // Listen for form submission success (when modal closes automatically)
5564        const form = this.document.getElementById(`${this.modalId}-form`);
5565        if (form) {
5566            const formSubmittedHandler = ()=>{
5567                // Set cookie to prevent showing again and hide modal
5568                this.setModalSubmittedCookie();
5569                const timeoutId = setTimeout(()=>{
5570                    modal.style.display = 'none';
5571                    this.restoreBodyScroll();
5572                }, 100);
5573                this.timeouts.push(timeoutId);
5574            };
5575            form.addEventListener('formsubmitted', formSubmittedHandler);
5576            this.eventListeners.push({
5577                element: form,
5578                event: 'formsubmitted',
5579                handler: formSubmittedHandler
5580            });
5581        }
5582        // Listen for close button clicks
5583        const closeButton = modal.querySelector('[data-dismiss="modal"]');
5584        if (closeButton) {
5585            const closeButtonHandler = ()=>{
5586                modal.style.display = 'none';
5587                this.restoreBodyScroll();
5588            };
5589            closeButton.addEventListener('click', closeButtonHandler);
5590            this.eventListeners.push({
5591                element: closeButton,
5592                event: 'click',
5593                handler: closeButtonHandler
5594            });
5595        }
5596        // Listen for backdrop clicks
5597        const backdropClickHandler = (e)=>{
5598            // Check if click is on the modal backdrop (not on the modal content)
5599            if (e.target === modal || e.target.id === this.modalId) {
5600                modal.style.display = 'none';
5601                this.restoreBodyScroll();
5602            }
5603        };
5604        modal.addEventListener('click', backdropClickHandler);
5605        this.eventListeners.push({
5606            element: modal,
5607            event: 'click',
5608            handler: backdropClickHandler
5609        });
5610    }
5611}
5612
5613
5614/* eslint-disable import/prefer-default-export */ 
5615class $50eefeef8d1f2372$export$8a2bf06fbae4dde extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5616    constructor(configController, window, document){
5617        super(configController, window, document);
5618        this.isValidating = false;
5619        this.lastValidationResult = null;
5620        this.lastValidationTime = null;
5621        this.validationCacheDuration = 300000; // 5 minutes
5622    }
5623    /**
5624   * Destroy
5625   */ destroy() {
5626        this.isValidating = false;
5627        this.lastValidationResult = null;
5628        this.lastValidationTime = null;
5629    }
5630    /**
5631   * Validate user session using GraphQL validSession query
5632   * @param {Object} options - Options for session validation
5633   * @param {boolean} options.useCache - Whether to use cached validation result
5634   * @returns {Promise<boolean>} - true if session is valid, false otherwise
5635   */ async validateSession(options = {}) {
5636        const { useCache: useCache = true } = options;
5637        if (useCache && this.lastValidationResult !== null && this.lastValidationTime) {
5638            const timeSinceLastValidation = Date.now() - this.lastValidationTime;
5639            if (timeSinceLastValidation < this.validationCacheDuration) return this.lastValidationResult;
5640        }
5641        if (this.isValidating) return this.lastValidationResult !== null ? this.lastValidationResult : false;
5642        this.isValidating = true;
5643        const query = `
5644      query {
5645        validSession {
5646          success
5647        }
5648      }
5649    `;
5650        try {
5651            // query from same domain as the website
5652            const response = await this.window.fetch(`/graphql`, {
5653                method: 'POST',
5654                headers: {
5655                    'Content-Type': 'application/json'
5656                },
5657                credentials: 'include',
5658                body: JSON.stringify({
5659                    query: query
5660                })
5661            });
5662            if (!response.ok) {
5663                // eslint-disable-next-line no-console
5664                console.error('SessionController: HTTP error during session validation', response.status);
5665                this.lastValidationResult = false;
5666                this.lastValidationTime = Date.now();
5667                return false;
5668            }
5669            const data = await response.json();
5670            if (data.errors) {
5671                this.lastValidationResult = false;
5672                this.lastValidationTime = Date.now();
5673                return false;
5674            }
5675            const isValid = data.data?.validSession?.success === true;
5676            this.lastValidationResult = isValid;
5677            this.lastValidationTime = Date.now();
5678            return isValid;
5679        } catch (error) {
5680            // eslint-disable-next-line no-console
5681            console.error('SessionController: Error validating session', error);
5682            this.lastValidationResult = false;
5683            this.lastValidationTime = Date.now();
5684            return false;
5685        } finally{
5686            this.isValidating = false;
5687        }
5688    }
5689    /**
5690   * Clear validation cache
5691   */ clearCache() {
5692        this.lastValidationResult = null;
5693        this.lastValidationTime = null;
5694    }
5695}
5696
5697
5698/* eslint-disable import/prefer-default-export */ 
5699function $396d9f0ca7465335$export$48d5542b9e3ba39(document) {
5700    const match = document.cookie.match(/cookieyes-consent=([^;]+)/);
5701    if (!match) return false;
5702    try {
5703        const cookieValue = decodeURIComponent(match[1]);
5704        if (cookieValue.includes(',')) {
5705            const segments = cookieValue.split(',').map((c)=>c.trim());
5706            if (segments.some((s)=>s.includes(':'))) return segments.some((s)=>s === 'analytics:yes');
5707            return segments.includes('analytics');
5708        }
5709        return cookieValue.includes('analytics');
5710    } catch (error) {
5711        return false;
5712    }
5713}
5714/**
5715 * Consent providers. Each entry isolates the only things that differ between
5716 * integrations: the change-event name, how to read the *initial* analytics
5717 * consent, and how to interpret a change event's detail. Everything else
5718 * (loading/removing trackers, lifecycle) is shared by the controller.
5719 */ const $396d9f0ca7465335$var$PROVIDERS = {
5720    // Third-party CookieYes banner.
5721    cookieyes: {
5722        eventName: 'cookieyes_consent_update',
5723        hasAnalyticsConsent: (document)=>$396d9f0ca7465335$export$48d5542b9e3ba39(document),
5724        isAnalyticsAccepted: (detail)=>Array.isArray(detail?.accepted) && detail.accepted.includes('analytics')
5725    },
5726    // LP in-house consent widget (lp-consent-widget). It exposes resolved state on
5727    // window.__lpConsent and emits `lp_consent_update` with detail.choices.
5728    'lp-consent': {
5729        eventName: 'lp_consent_update',
5730        hasAnalyticsConsent: (_document, window)=>!!window.__lpConsent?.state?.c?.analytics,
5731        isAnalyticsAccepted: (detail)=>!!detail?.choices?.analytics
5732    }
5733};
5734class $396d9f0ca7465335$export$bb018224876724b9 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) {
5735    constructor(config, window, document){
5736        super(config, window, document);
5737        this.consentListener = null;
5738        this.eventName = null;
5739    }
5740    /**
5741   * Destroy and cleanup event listeners
5742   */ destroy() {
5743        if (this.consentListener && this.eventName) {
5744            this.document.removeEventListener(this.eventName, this.consentListener);
5745            this.consentListener = null;
5746        }
5747    }
5748    /**
5749   * Load PostHog and Divolte scripts (idempotent — guarded by element id).
5750   */ loadScript() {
5751        if (!this.document.getElementById('posthog-script')) this.window.luxuryPresence.eventBus.initialize({
5752            enabled: this.config.eventBus?.enabled
5753        });
5754        if (!this.document.getElementById('divolte-script')) this.window.luxuryPresence.divolte.initialize({});
5755    }
5756    /**
5757   * Remove PostHog and Divolte scripts (used on consent withdrawal).
5758   */ removeScripts() {
5759        this.window.luxuryPresence?.eventBus?.destroy?.();
5760        this.window.luxuryPresence?.divolte?.destroy?.();
5761        this.document.getElementById('posthog-script')?.remove();
5762        this.document.getElementById('divolte-script')?.remove();
5763    }
5764    /**
5765   * Initialize the consent controller for a given provider.
5766   * @param {{ provider: 'cookieyes' | 'lp-consent' }} options
5767   */ async initialize(options = {}) {
5768        const provider = $396d9f0ca7465335$var$PROVIDERS[options.provider];
5769        if (!provider) return;
5770        this.eventName = provider.eventName;
5771        const isAuthenticated = await this.window.luxuryPresence.session.validateSession();
5772        if (provider.hasAnalyticsConsent(this.document, this.window) || isAuthenticated) this.loadScript();
5773        if (!this.consentListener) {
5774            this.consentListener = (eventData)=>{
5775                if (provider.isAnalyticsAccepted(eventData.detail)) this.loadScript();
5776                else this.removeScripts();
5777            };
5778            this.document.addEventListener(provider.eventName, this.consentListener);
5779        }
5780    }
5781}
5782
5783
5784/* global window */ /* eslint-disable import/prefer-default-export */ /**
5785 * Checks if the current site should redirect homeowner valuation submissions to HST.
5786 * Returns true and performs the redirect if all three gate conditions are met.
5787 * Returns false if the redirect did not fire (caller should continue with existing flow).
5788 *
5789 * @param {string} address - The human-readable address string from the form
5790 * @returns {boolean}
5791 */ function $0ae243a777665fd3$var$checkHstRedirect(address) {
5792    const { config: config } = window.luxuryPresence;
5793    if (config.hstValuationRedirectEnabled && config.mlsEnabled && config.myhomeDashboardEnabled) {
5794        window.location.href = `/home-search/home-valuation?address=${encodeURIComponent(address)}`;
5795        return true;
5796    }
5797    return false;
5798}
5799const $0ae243a777665fd3$export$4225ff17959c7313 = {
5800    checkHstRedirect: $0ae243a777665fd3$var$checkHstRedirect,
5801    destroy () {}
5802};
5803
5804
5805const $fa0280e505379701$export$1fd2b467a3644d37 = new (0, $dc851cf3939b6ef5$export$ff0712c26d5458f7)({});
5806const $fa0280e505379701$export$e12694e911a05f40 = new (0, $0ead03fdb95fa9ce$export$d507f25e63650365)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5807const $fa0280e505379701$export$3de614e59a842917 = new (0, $d48f9f944810f613$export$ca3218b7861b9cb0)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5808const $fa0280e505379701$export$fb9b298fdbf31455 = new (0, $68a2d4aa500c7a05$export$61ec8f2b6291ec31)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5809const $fa0280e505379701$export$178cc3119b453c2a = new (0, $e10bd00497be8876$export$3c5380623cf51249)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5810const $fa0280e505379701$export$9376af1a01686f2 = new (0, $ea6901fdf47e0ec1$export$3c19195edca3fa5c)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5811const $fa0280e505379701$export$94d36f806562393e = new (0, $0a0ad49f13c0b8fd$export$ba9afeb75f20f616)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5812const $fa0280e505379701$export$89e66d1faf94651e = new (0, $2b1790aa32f109d1$export$43e435c053a109f6)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5813const $fa0280e505379701$export$7743b07270cd6d6c = new (0, $4f184d9bd3037f15$export$7a6215890afba974)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5814const $fa0280e505379701$export$40a7039551318c37 = new (0, $102039871668a1df$export$e22e4b1be0bb6c61)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5815const $fa0280e505379701$export$8a0bbf7e7652fcfc = new (0, $0d25a3fa2e0f4f92$export$b718a981691eae5c)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5816const $fa0280e505379701$export$b313b3f6544c97a3 = new (0, $dcf72769f009ff26$export$b900d6fe921fd49c)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5817const $fa0280e505379701$export$b526bc4ac03268ef = new (0, $50eefeef8d1f2372$export$8a2bf06fbae4dde)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5818const $fa0280e505379701$export$c0affdb0a7a2ef6 = new (0, $396d9f0ca7465335$export$bb018224876724b9)($fa0280e505379701$export$1fd2b467a3644d37, window, document);
5819
5820
5821/**
5822 * Attach controller to window for usage
5823 * @param {string} key
5824 * @param {any} controller
5825 */ function $89a8a84b77163415$var$attachController(key, controller) {
5826    if (window.luxuryPresence[key]) try {
5827        // New version of sdk, destroy previous
5828        window.luxuryPresence[key].destroy();
5829    } catch (e) {
5830        // eslint-disable-next-line no-console
5831        console.log(e);
5832    }
5833    window.luxuryPresence[key] = controller;
5834}
5835$89a8a84b77163415$var$attachController('config', (0, $fa0280e505379701$export$1fd2b467a3644d37));
5836$89a8a84b77163415$var$attachController('modals', (0, $fa0280e505379701$export$e12694e911a05f40));
5837$89a8a84b77163415$var$attachController('buttons', (0, $fa0280e505379701$export$3de614e59a842917));
5838$89a8a84b77163415$var$attachController('validation', (0, $fa0280e505379701$export$fb9b298fdbf31455));
5839$89a8a84b77163415$var$attachController('contactForms', (0, $fa0280e505379701$export$178cc3119b453c2a));
5840$89a8a84b77163415$var$attachController('mapApiLoader', (0, $fa0280e505379701$export$9376af1a01686f2));
5841$89a8a84b77163415$var$attachController('pagination', (0, $fa0280e505379701$export$94d36f806562393e));
5842$89a8a84b77163415$var$attachController('expandSliders', (0, $fa0280e505379701$export$89e66d1faf94651e));
5843$89a8a84b77163415$var$attachController('divolte', (0, $fa0280e505379701$export$7743b07270cd6d6c));
5844$89a8a84b77163415$var$attachController('eventBus', (0, $fa0280e505379701$export$40a7039551318c37));
5845$89a8a84b77163415$var$attachController('oauth', (0, $fa0280e505379701$export$8a0bbf7e7652fcfc));
5846$89a8a84b77163415$var$attachController('qualifyingQuestionsModal', (0, $fa0280e505379701$export$b313b3f6544c97a3));
5847$89a8a84b77163415$var$attachController('session', (0, $fa0280e505379701$export$b526bc4ac03268ef));
5848$89a8a84b77163415$var$attachController('consent', (0, $fa0280e505379701$export$c0affdb0a7a2ef6));
5849$89a8a84b77163415$var$attachController('redirects', (0, $0ae243a777665fd3$export$4225ff17959c7313));
5850// methods for existing elements (can be removed later after elements updated)
5851window.luxuryPresence.formatSliderPriceRange = (0, $fa0280e505379701$export$94d36f806562393e).formatSliderPriceRange.bind((0, $fa0280e505379701$export$94d36f806562393e));
5852window.luxuryPresence.formatSliderAreaRange = (0, $fa0280e505379701$export$94d36f806562393e).formatSliderAreaRange.bind((0, $fa0280e505379701$export$94d36f806562393e));
5853// method below doesn't use 'this', but just to be safe in case of further method updates
5854window.luxuryPresence.getSearchFormValues = (0, $fa0280e505379701$export$94d36f806562393e).getSearchFormValues.bind((0, $fa0280e505379701$export$94d36f806562393e));
5855window.luxuryPresence.handlebarsHelpersFactory = function(handlebarsInstance) {
5856    return (0, (/*@__PURE__*/$parcel$interopDefault($53de3c160faf5a81$exports
5856)))(handlebarsInstance, {
5857        isEqual (a, b) {
5858            // eslint-disable-next-line
5859            return a == b;
5860        }
5861    });
5862};
5863
5864
5865
5866})();
5867//# sourceMappingURL=lp-sdk.js.map
5868
5869    </script>
5869
5870
5871    
5871<script>
5872        var lpGlobalInitialized = false;
5873
5874        function lpGlobalInit () {
5875          if (lpGlobalInitialized) {
5876            return;
5877          }
5878            lpGlobalInitialized = true;
5879            // Initialize wow animation plugin only according to turbolinks
5880            var wow;
5881            if (window.WOW) {
5882                wow = new WOW({
5883                    animateClass: 'animated',
5884                    offset: wowOffset,
5885                    live: false,
5886                    callback: function(box) {}
5887                });
5888            }
5889            // Initialize handlebar helpers only once
5890            function handlebarsInit() {
5891              if (!window.Handlebars) {
5892                return;
5893              }
5894              HandlebarsIntl.registerWith(Handlebars);
5895              Handlebars.registerHelper(window.luxuryPresence.handlebarsHelpersFactory(Handlebars));
5896            }
5897
5898            handlebarsInit();
5899
5900              var modalContentUrl = "/modals.html";
5901                const modalsContainer = document.getElementById('modals');
5902                if (modalsContainer) {
5903                  fetch(modalContentUrl).then(function(res) {
5904                    if (!res.ok) {
5905                      throw new Error(`HTTP error! Status: ${res.status}`);
5906                    }
5907                    return res.text();
5908                  }).then(function(resultText) {
5909                    modalsContainer.innerHTML = resultText;
5910
5911                    // now we need to execute all script elements
5912                    Array.from(modalsContainer.getElementsByTagName('script')).forEach(function (s) {
5913                      const script  = document.createElement("script");
5914                      script.text = s.innerHTML;
5915                      Array.from(s.attributes).forEach(function (a) {
5916                        script.setAttribute(a.name, a.value);
5917                      })
5918                      s.parentNode.replaceChild(script, s);
5919                    });
5920
5921                    try {
5922                      window.luxuryPresence.modals.initialize(window.luxuryPresence._modalIncludes);
5923                      window.luxuryPresence.contactForms.initialize({ selector: '#modals' });
5924                      window.luxuryPresence.validation.initialize({ selector: '#modals' });
5925                      window.luxuryPresence.oauth.initialize({
5926                        googleSignOnEnabled: true,
5927                        iframe: false });
5928                    } catch (e) {
5929                      console.log(e);
5930                    }
5931                    document.querySelectorAll('.modals > .modal .close').forEach(closeModalBtn => {
5932                      closeModalBtn.addEventListener('click', function() {
5933                        window.lpUI.hideClosestModal(closeModalBtn);
5934                      });
5935                    });
5936                  }).catch((e) => console.log(e));
5937                }
5938            /* Initialize Luxury Presence SDK */
5939            try {
5940                window.luxuryPresence.config.setCompany("bba607a7-df71-48c9-84ae-e87d443d6b5b", {});
5941                window.luxuryPresence.config.setWebsite("ae45f4e2-58fe-4d52-921e-febac4ac146e", {
5942                    myhomeDashboardEnabled: true,
5943                    mlsEnabled: true,
5944                    hstValuationRedirectEnabled: true
5945                });
5946                const url = new URL(window.location.href);
5947                const shareId = url.searchParams.get('shareId');
5948                window.luxuryPresence.config.setPage("e3f92ef5-826b-4f96-a83c-eba75b69dd7b", {
5949                    sourceResource: "",
5950                    pageElementId: "",
5951                    pageQueryVariables: {},
5952                    shareId: "",
5953                });
5954                window.luxuryPresence.config.setWebsiteApiGatewayUrl("https://wgw.luxurypresence.com", {});
5955                window.luxuryPresence.config.setBuyerSellerServiceUrl("https://bss.luxurypresence.com", {});
5956                    window.luxuryPresence.config.setDivolteServiceUrl("https://t.luxurypresence.com", {});
5957                  window.luxuryPresence.config.setEventBusUrl("https://cdn.luxurypresence.com/scripts/event-bus-js", {});
5958                  window.luxuryPresence.config.setEventBus({
5959                    enabled: true,
5960                    apiKey: "phc_PMYT31xlmXBaTCwpIRx1v6RrpLVZIuP47N3mOT6KLnr",
5961                    url: "https://p.luxurypresence.com",
5962                  });
5963                window.luxuryPresence.config.setTemplateId("1d3967df-14f2-449d-87b7-bd68bf93906f", {});
5964                window.luxuryPresence.config.setLeadIngesterUrl("https://leads.luxurypresence.com", {});
5965                window.luxuryPresence.buttons.initialize({});
5966                    window.luxuryPresence.eventBus.initialize({});
5967                window.luxuryPresence.contactForms.initialize({});
5968                window.luxuryPresence.validation.initialize({});
5969                window.luxuryPresence.expandSliders.initialize({});
5970                window.luxuryPresence.oauth.initialize({ googleSignOnEnabled: true, iframe: false });
5971                window.luxuryPresence.qualifyingQuestionsModal.initialize({ qualifyingQuestionsModalEnabled: true });
5972                      window.luxuryPresence.divolte.initialize({});
5973            } catch (e) {
5974                console.log(e);
5975            }
5976
5977            /* Inject Section Specific Javascript */
5978                try {
5979(function init(sectionDomId) {
5980  const section = document.getElementById(sectionDomId);
5981  const contactTitle = section.querySelector('.js-contact-title');
5982  const emailInput = section.querySelector('.js-email-input');
5983  const emailRegex = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~\-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+/;
5984  emailInput.addEventListener('input', function () {
5985    if (emailRegex.test(this.value)) {
5986      this.setCustomValidity('');
5987    } else {
5988      this.setCustomValidity('Please enter a valid email address.');
5989    }
5990    this.reportValidity();
5991  });
5992  const inputName = section.querySelector('.js-input-name');
5993  inputName.addEventListener('keyup', function () {
5994    if (this.value.replaceAll(/\d/g, "").trim().split(" ").length < 2 || this.value.replaceAll(/\d/g, "").trim() === "") {
5995      this.setCustomValidity("Please input your first name and last name.");
5996    } else {
5997      this.setCustomValidity("");
5998    }
5999  });
6000  function setHttp(link) {
6001    if (link.search(/^http[s]?\:\/\/|\//) == -1) {
6002      link = 'https://' + link;
6003    }
6004    return link;
6005  }
6006  const socialLinks = section.querySelectorAll('.lp-socials__link, .contact-form-modal-details__socials-l
6006ink');
6007  socialLinks.forEach(linkElement => {
6008    const href = linkElement.getAttribute('href');
6009    if (href) {
6010      linkElement.setAttribute('href', setHttp(href));
6011    }
6012  });
6013  if (contactTitle.length < 1) return;
6014  let words = contactTitle.textContent.split(" ");
6015  if (words.length > 1) {
6016    contactTitle.innerHTML = `<span class="contact__title-top">${words[0]} </span><span class="contact__title-bottom">${words.splice(1).join(" ")}</span>`;
6017  }
6018  const addRedirectToForm = () => {
6019    const redirectLink = document.getElementById(`${sectionDomId}`).querySelector('.js-redirect-link');
6020    const form = document.getElementById(`${sectionDomId}`).querySelector('.js-form');
6021    function redirectPage(link) {
6022      if (link) {
6023        const rawHref = link.getAttribute('href');
6024        link.setAttribute('href', setHttp(rawHref));
6025        link.click();
6026      }
6027    }
6028    function setHttp(link) {
6029      if (link.search(/^http[s]?\:\/\/|\//) == -1) {
6030        link = 'http://' + link;
6031      }
6032      return link;
6033    }
6034    form.addEventListener("reset", function () {
6035      redirectPage(redirectLink);
6036    });
6037  };
6038  addRedirectToForm();
6039})('modal-global-contact-us');
6040} catch(e) {
6041console.log(e);
6042}
6043                
6044                try {
6045(function init(sectionDomId) {
6046  (function () {
6047    const observer = new IntersectionObserver(entries => {
6048      entries.forEach(entry => {
6049        if (entry.isIntersecting) entry.target.classList.add('is-in-viewport');
6050      });
6051    }, {
6052      threshold: 0.5
6053    });
6054    const initialElements = document.querySelectorAll('[data-animate="true"]');
6055    initialElements.forEach(element => observer.observe(element));
6056    const container = document.querySelector('.data-container');
6057    if (container) {
6058      const mutationObserver = new MutationObserver(mutations => {
6059        mutations.forEach(mutation => {
6060          if (mutation.type === 'childList') {
6061            mutation.addedNodes.forEach(node => {
6062              if (node.nodeType === 1 && node.getAttribute('data-animate') === 'true') observer.observe(node);
6063            });
6064          }
6065        });
6066      });
6067      mutationObserver.observe(container, {
6068        childList: true,
6069        subtree: true
6070      });
6071    }
6072  })();
6073  const sectionSelector = document.getElementById(sectionDomId);
6074  const searchToggleSelector = sectionSelector.querySelector('.js-search-toggle-btn');
6075  const searchWrapperSelector = sectionSelector.querySelector('.js-header-search');
6076  const header = sectionSelector.querySelector('.js-header');
6077  let lastScrollTop = 0;
6078  const subNavOpeners = sectionSelector.querySelectorAll('.js-subnav-opener');
6079  subNavOpeners.forEach(opener => {
6080    opener.addEventListener('click', function (e) {
6081      e.preventDefault();
6082      e.stopPropagation();
6083      const parent = opener.parentElement;
6084      subNavOpeners.forEach(otherOpener => {
6085        if (otherOpener !== opener) {
6086          otherOpener.parentElement.classList.remove('header-navigation__item--sub-nav--opened');
6087        }
6088      });
6089      parent.classList.toggle('header-navigation__item--sub-nav--opened');
6090    });
6091  });
6092  document.addEventListener('click', function (e) {
6093    if (!e.target.closest('.js-subnav-opener') && !e.target.closest('.header-navigation__item--sub-nav--opened')) {
6094      subNavOpeners.forEach(opener => {
6095        opener.parentElement.classList.remove('header-navigation__item--sub-nav--opened');
6096      });
6097    }
6098  });
6099  function initHeaderColors() {
6100    try {
6101      var colorStr = window.getComputedStyle(header).getPropertyValue("--backgroundColor");
6102      var bgColor = makeColor(colorStr);
6103      var isDark = (bgColor.rgba.r * 299 + bgColor.rgba.g * 587 + bgColor.rgba.b * 114) / 1000 < 128;
6104      sectionSelector.classList.add('is-background-color-' + (isDark ? 'dark' : 'light'));
6105    } catch (e) {}
6106  }
6107  function makeColor(str) {
6108    var color = {
6109      rgba: {
6110        r: 0,
6111        g: 0,
6112        b: 0,
6113        a: 0
6114      }
6115    };
6116    if (str && str.match) {
6117      var m = str.match(/rgba?\s*\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\.0-9]+))?\)/);
6118      if (m) {
6119        color.rgba.r = parseInt(m[1]);
6120        color.rgba.g = parseInt(m[2]);
6121        color.rgba.b = parseInt(m[3]);
6122        color.rgba.a = parseFloat(m[4]);
6123        if (isNaN(color.rgba.a)) {
6124          color.rgba.a = 1;
6125        }
6126      }
6127    }
6128    return color;
6129  }
6130  initHeaderColors();
6131  var navEl = document.querySelector('nav > header') || document.querySelector('nav');
6132  var navbarHeight = navEl ? navEl.offsetHeight : 0;
6133  if (navEl) {
6134    if (window.ResizeObserver) {
6135      new ResizeObserver(function (entries) {
6136        if (!entries.length) return;
6137        navbarHeight = entries[0].target.offsetHeight;
6138      }).observe(navEl);
6139    } else {
6140      window.addEventListener('resize', function () {
6141        navbarHeight = navEl.offsetHeight;
6142      });
6143    }
6144  }
6145  function isLocomotiveActive() {
6146    return document.body.hasAttribute('data-scroll-container');
6147  }
6148  function updateHeaderVisibility(currentScrollTop) {
6149    if (!searchWrapperSelector || searchWrapperSelector.style.display !== 'block') {
6150      if (currentScrollTop === 0) header.classList.remove('header--hide');else if (currentScrollTop > lastScrollTop) header.classList.add('header--hide');else header.classList.remove('header--hide');
6151    }
6152    lastScrollTop = currentScrollTop;
6153  }
6154  function customHeaderHideShow(currentScrollTop) {
6155    if (!navEl) return;
6156    if (currentScrollTop > 0) {
6157      navEl.classList.add('scroll');
6158    } else {
6159      navEl.classList.remove('scroll');
6160    }
6161    if (currentScrollTop > lastScrollTop && currentScrollTop > navbarHeight) {
6162      document.documentElement.style.setProperty('--global-header-height', '0px');
6163    } else {
6164      document.documentElement.style.setProperty('--global-header-height', navbarHeight + 'px');
6165    }
6166  }
6167  window.addEventListener('scroll', function () {
6168    if (isLocomotiveActive()) return;
6169    var currentScrollTop = window.scrollY || document.documentElement.scrollTop;
6170    updateHeaderVisibility(currentScrollTop);
6171  });
6172  var isTicking = false;
6173  var latestLocoScrollY = 0;
6174  window.addEventListener('locomotive-scroll', function (e) {
6175    latestLocoScrollY = e.detail.scrollY;
6176    if (!isTicking) {
6177      window.requestAnimationFrame(function () {
6178        customHeaderHideShow(latestLocoScrollY);
6179        updateHeaderVisibility(latestLocoScrollY);
6180        isTicking = false;
6181      });
6182      isTicking = true;
6183    }
6184  });
6185  if (searchToggleSelector !== null) {
6186    searchToggleSelector.addEventListener('click', function () {
6187      if (searchWrapperSelector.style.display === 'block') {
6188        searchWrapperSelector.style.display = 'none';
6189      } else {
6190        searchWrapperSelector.style.display = 'block';
6191        header.classList.remove('header--hide');
6192      }
6193    });
6194    document.addEventListener('click', function (evt) {
6195      if (!searchToggleSelector.contains(evt.target) && !searchWrapperSelector.contains(evt.target)) searchWrapperSelector.style.display = 'none';
6196    });
6197  }
6198  window.luxuryPresence.mapApiLoader.load().then(() => {
6199    if (!searchWrapperSelector) return;
6200    const templateHTML = sectionSelector.querySelector('.js-card-template')?.innerHTML;
6201    const itemTemplate = templateHTML && Handlebars.compile(templateHTML);
6202    const searchMls = searchWrapperSelector.dataset.searchMls === 'true';
6203    const searchProperties = searchWrapperSelector.dataset.searchProperties === 'true';
6204    const selectedCountries = searchWrapperSelector.dataset.locations;
6205    const searchInputSelector = sectionSelector.querySelector('.js-header-search-input');
6206    const searchIconSelector = sectionSelector.querySelector('.js-header-btn-search');
6207    const closeIconSelector = sectionSelector.querySelector('.js-header-btn-close');
6208    const searchResultsSelector = sectionSelector.querySelector('.js-header-search-results-holder');
6209    const resultsContainerSelector = sectionSelector.querySelector('.js-header-results-container');
6210    const loaderSelector = sectionSelector.querySelector('.js-header-spinner');
6211    const predefinedSelector = sectionSelector.querySelector('.js-header-search-results-predefined');
6212    const nothingFoundSelector = sectionSelector.querySelector('.js-header-spinner-nothing-found');
6213    const service = new google.maps.places.AutocompleteService();
6214    const geocoder = new google.maps.Geocoder();
6215    var keyword;
6216    var leasePropertyState = false;
6217    var leasePropertySearched;
6218    var isLoading = false;
6219    var newSearchTimer;
6220    var placesResult = {};
6221    function updateSearchDisplay() {
6222      var hasResults = !!resultsContainerSelector.innerHTML;
6223      var hasPredefined = predefinedSelector.querySelectorAll('a:not(.not-processed)').length > 0;
6224      nothingFoundSelector.style.display = 'none';
6225      if (hasResults) {
6226        predefinedSelector.style.display = 'none';
6227        loaderSelector.style.display = 'none';
6228        resultsContainerSelector.style.display = 'block';
6229      } else if (isLoading) {
6230        resultsContainerSelector.style.display = 'none';
6231        predefinedSelector.style.display = 'none';
6232        loaderSelector.style.display = 'block';
6233      } else if (hasPredefined) {
6234        resultsContainerSelector.style.display = 'none';
6235        loaderSelector.style.display = 'none';
6236        predefinedSelector.style.display = 'block';
6237      } else {
6238        resultsContainerSelector.style.display = 'none';
6239        loaderSelector.style.display = 'none';
6240        predefinedSelector.style.display = 'none';
6241        if (keyword) nothingFoundSelector.style.display = 'block';
6242      }
6243    }
6244    function moveSelection(up) {
6245      var count = resultsContainerSelector.innerHTML ? resultsContainerSelector : predefinedSelector;
6246      var links = count.querySelectorAll('.results-link');
6247      if (!links.length) return;
6248      var idx = -1;
6249      links.forEach((link, i) => {
6250        if (idx === -1 && link.classList.contains('header-search-results__link--selected')) idx = i;
6251      });
6252      var newIdx;
6253      if (up) {
6254        newIdx = idx - 1;
6255        if (newIdx < 0) newIdx = links.length - 1;
6256      } else {
6257        newIdx = idx + 1;
6258        if (newIdx > links.length - 1) newIdx = 0;
6259      }
6260      if (newIdx !== idx) {
6261        searchResultsSelector.querySelector('.header-search-results__link--selected')?.classList.remove('header-search-results__link--selected');
6262        links[newIdx].classList.add('header-search-results__link--selected');
6263      }
6264    }
6265    function startSearch() {
6266      const term = searchInputSelector.value;
6267      if (term === keyword && leasePropertySearched === leasePropertyState) return;
6268      leasePropertySearched = leasePropertyState;
6269      keyword = term;
6270      if (term) doSearch(term, leasePropertySearched);else setResults(null);
6271    }
6272    function mlsSearch(term) {
6273      var query = {
6274        omnibox: term,
6275        limit: 5
6276      };
6277      return superagent.get(window.location.protocol + '//' + window.location.host + '/home-search/listings.json').query(query).then(function (res) {
6278        if (!Array.isArray(res.body)) return [];
6279        return res.body.map(function (item) {
6280          return {
6281            id: item.id,
6282            display_address: [item.address_1, item.city, [item.state, item.postal_code].filter(function (i) {
6283              return i;
6284            }).join(' ')].filter(function (i) {
6285              return i;
6286            }).join(', ')
6287          };
6288        });
6289      }, function (e) {
6290        console.log(e);
6291        return [];
6292      });
6293    }
6294    function resolveGeoBounds(placeId, description) {
6295      return new Promise(function (resolve, reject) {
6296        geocoder.geocode({
6297          'placeId': placeId
6298        }, function (results, status) {
6299          if (status != 'OK') return resolve(null);
6300          var result = results[0];
6301          var bounds = new google.maps.LatLngBounds();
6302          bounds.extend(result.geometry.viewport.getSouthWest());
6303          bounds.extend(result.geometry.viewport.getNorthEast());
6304          result.geometry.bounds = bounds.toJSON();
6305          var placeUrl = window.luxuryPresence.makeMlsLink(result);
6306          return resolve({
6307            placeUrl: placeUrl,
6308            description: description
6309          });
6310        });
6311      });
6312    }
6313    function addRestrictions(request) {
6314      switch (selectedCountries) {
6315        case 'Worldwide':
6316          return request;
6317        case 'US & Canada':
6318          request.componentRestrictions = {
6319            country: ['us', 'ca']
6320          };
6321          return request;
6322        default:
6323          request.componentRestrictions = {
6324            country: 'us'
6325          };
6326          return request;
6327      }
6328    }
6329    function resolveAutocomplete(term, deeper) {
6330      var request = addRestrictions({
6331        input: term,
6332        types: deeper ? ['geocode'] : ['(regions)'],
6333        limit: 1
6334      });
6335      return new Promise(function (resolve, reject) {
6336        service.getPlacePredictions(request, function (results, status) {
6337          if (status !== google.maps.places.PlacesServiceStatus.OK) {
6338            resolve(null);
6339            return;
6340          }
6341          if (!Array.isArray(results)) {
6342            resolve(null);
6343            return;
6344          }
6345          if (deeper) {
6346            var allowedTypes = {
6347              'neighborhood': true,
6348              'administrative_area_level_3': true,
6349              'administrative_area_level_4': true,
6350              'administrative_area_level_5': true,
6351              'sublocality_level_1': true,
6352              'sublocality_level_2': true,
6353              'sublocality_level_3': true
6354            };
6355            results = results.filter(function (res) {
6356              return res.types.find(t => allowedTypes[t]);
6357            });
6358          }
6359          if (!results.length) {
6360            resolve(null);
6361            return;
6362          }
6363          resolve(results);
6364        });
6365      });
6366    }
6367    function placesSearch(term, ignoreInput) {
6368      if (placesResult.term !== term) {
6369        placesResult = {
6370          term: term,
6371          result: resolveAutocomplete(term).then(function (results) {
6372            if (!ignoreInput && term !== keyword) return null;
6373            if (ignoreInput && !results) return resolveAutocomplete(term, true);
6374            return results;
6375          }).then(function (results) {
6376            if (!ignoreInput && term !== keyword || !results) return [];
6377            var geoResultPromises = results.map(function (result) {
6378              return resolveGeoBounds(result.place_id, result.description);
6379            });
6380            return Promise.all(geoResultPromises).then(function (geoLinks) {
6381              return geoLinks.filter(function (i) {
6382                return i;
6383              }).slice(0, 3);
6384            });
6385          })
6386        };
6387      }
6388      return placesResult.result;
6389    }
6390    function propertiesSearch(term) {
6391      var payload = {
6392        companyId: window.luxuryPresence.defaults.companyId,
6393        search: term,
6394        offset: 0,
6395        limit: 4,
6396        statusIds: ["5f528253-abb7-484e-95c3-330269ac1105", "959c11cf-8655-4f91-874c-292b0ab7ea6b", "a0012964-4f51-4430-abf8-6547c5ab6441", "df04ccbe-4621-4140-a504-ee1a17430bb7", "88b4ace6-f39b-4b25-a051-8f6dba976833", "96031d77-bbe5-4de3-90d8-1e4e70de8ca8"]
6397      };
6398      return superagent.post(window.luxuryPresence.defaults.apiGatewayUrl + '/graphql').send({
6399        query: window.luxuryPresence.defaults.gql.properties,
6400        variables: payload
6401      }).then(function (res) {
6402        return (res.body.data || {}).properties || [];
6403      }, function (err) {
6404        return [];
6405      });
6406    }
6407    function doSearch(term, leaseProperty) {
6408      isLoading = true;
6409      updateSearchDisplay();
6410      Promise.all([searchMls ? mlsSearch(term, leaseProperty) : [], searchMls ? placesSearch(term) : [], searchProperties ? propertiesSearch(term, leaseProperty) : []]).then(function (res) {
6411        if (term !== keyword) return;
6412        setResults(res[0], res[1], res[2], leaseProperty);
6413      });
6414    }
6415    function makeResultsBlockHtml(title, elementClass, links) {
6416      if (!links || !links.length) return '';else return '<div class="header-search-results__block"><div class="header-search-results__title">' + title + '</div><div class="' + elementClass + '">' + links.join('') + '</div></div>';
6417    }
6418    function setResults(mlsResults, placesResults, propertiesResults, leaseProperty) {
6419      searchResultsSelector.querySelector('.header-search-results__link--selected')?.classList.remove('header-search-results__link--selected');
6420      isLoading = false;
6421      updateSearchDisplay();
6422      if (!mlsResults) {
6423        resultsContainerSelector.innerHTML = '';
6424        updateSearchDisplay();
6425        return;
6426      }
6427      if (!mlsResults.length && !placesResults.length && !propertiesResults.length) {
6428        updateSearchDisplay();
6429        return;
6430      }
6431      var propertiesHtml = makeResultsBlockHtml('Featured Properties', 'header-properties', propertiesResults.map(function (result) {
6432        return itemTemplate(result);
6433      }));
6434      var placesHtml = makeResultsBlockHtml('Locations', '', placesResults.map(function (result) {
6435        return `<a class="header-search-results__link lp-icon" href="${result.placeUrl}${leaseProperty ? '&lease_property=true' : ''}">${result.description}</a>`;
6436      }));
6437      var mlsHtml = makeResultsBlockHtml('Address', '', mlsResults.map(function (result) {
6438        return `<a href="/home-search/listings/${result.id}" class="header-search-results__link lp-icon">${result.display_address}</a>`;
6439      }));
6440      resultsContainerSelector.innerHTML = propertiesHtml + placesHtml + mlsHtml;
6441      updateSearchDisplay();
6442    }
6443    var neighborhoods = null;
6444    function fetchNeighborhoods() {
6445      var url = window.luxuryPresence.defaults.apiGatewayUrl;
6446      var gqlQuery = 'query ($companyId: String, $offset: Int, $limit: Int) {neighborhoods (companyId: $companyId, offset: $offset, limit: $limit) {id, name, mlsLink, googlePlaceData}}';
6447      var payload = {};
6448      payload.offset = 0;
6449      payload.limit = 100;
6450      payload.companyId = window.luxuryPresence.defaults.companyId;
6451      return superagent.post(url + '/graphql').withCredentials().send({
6452        query: gqlQuery,
6453        variables: payload
6454      }).then(function (res) {
6455        neighborhoods = res.body.data && res.body.data.neighborhoods;
6456        if (neighborhoods && !neighborhoods.length) {
6457          neighborhoods = null;
6458        }
6459      });
6460    }
6461    function setPredefinedNeighborhoods() {
6462      return fetchNeighborhoods().then(function () {
6463        if (!neighborhoods) return;
6464        var placesHtml = makeResultsBlockHtml('Locations', neighborhoods.map(function (item) {
6465          return `<a class="header-search-results__link lp-icon" href="${item.mlsLink}${leasePropertyState ? '&lease_property=true' : ''}">${item.googlePlaceData && item.googlePlaceData.formatted_address || item.name}</a>`;
6466        }));
6467        predefinedSelector.innerHTML = placesHtml;
6468        updateSearchDisplay();
6469      });
6470    }
6471    if (searchMls) setPredefinedNeighborhoods();
6472    closeIconSelector.style.opacity = '0';
6473    closeIconSelector.style.pointerEvents = 'none';
6474    searchInputSelector.setAttribute('inputmode', 'search');
6475    searchInputSelector.addEventListener('input', function () {
6476      if (this.value === '') {
6477        closeIconSelector.style.opacity = '0';
6478        closeIconSelector.style.pointerEvents = 'none';
6479        searchIconSelector.style.opacity = '1';
6480        searchIconSelector.style.pointerEvents = 'auto';
6481      } else {
6482        closeIconSelector.style.opacity = '1';
6483        closeIconSelector.style.pointerEvents = 'auto';
6484        searchIconSelector.style.opacity = '0';
6485        searchIconSelector.style.pointerEvents = 'none';
6486      }
6487      window.clearTimeout(newSearchTimer);
6488      newSearchTimer = window.setTimeout(startSearch, 300);
6489    });
6490    searchInputSelector.addEventListener('keydown', function (ev) {
6491      if (ev.which === 38) {
6492        ev.preventDefault();
6493        moveSelection(true);
6494        return false;
6495      }
6496      if (ev.which === 40) {
6497        ev.preventDefault();
6498        moveSelection();
6499        return false;
6500      }
6501      if (ev.which === 13) {
6502        let $lnk = searchResultsSelector.querySelector('.header-search-results__link--selected');
6503        if ($lnk) {
6504          $lnk.click();
6505          searchActive = false;
6506          updateSearchDisplay();
6507        } else {
6508          $searchBtn.click();
6509        }
6510      }
6511    });
6512    closeIconSelector.addEventListener('click', function () {
6513      searchInputSelector.value = '';
6514      searchInputSelector.dispatchEvent(new Event('input'));
6515      searchActive = false;
6516      updateSearchDisplay();
6517    });
6518    searchResultsSelector.addEventListener('mouseenter', function (ev) {
6519      searchResultsSelector.querySelector('.header-search-results__link--selected')?.classList.remove('header-search-results__link--selected');
6520    });
6521    function outsideClickHandler(e) {
6522      if (searchWrapperSelector.contains(e.target)) return;
6523      searchActive = false;
6524      updateSearchDisplay();
6525    }
6526    document.addEventListener('click', outsideClickHandler);
6527  });
6528})('global-navbar');
6529} catch(e) {
6530console.log(e);
6531}
6532                try {
6533(function init(sectionDomId, options) {
6534  var elementSelector = options.elementSelector || 'nav';
6535  var element = document.querySelector(elementSelector);
6536  var sections = document.querySelectorAll('body > section');
6537  var subNavContainers = element.querySelectorAll('.sub-nav');
6538  var initialBackgroundColor = options.initialBackgroundColor || element.style.backgroundColor;
6539  var backgroundColorScroll = options.backgroundColorScroll || '#191919';
6540  var fontColor = options.fontColor || '#fff';
6541  var fontColorScroll = options.fontColorScroll || '#000';
6542  var didScroll = false;
6543  var lastScrollTop = 0;
6544  var delta = 5;
6545
6546  // eslint-disable-next-line sonarjs/no-collapsible-if
6547  if (wow) {
6548    // Wowjs might not trigger for position fixed elements
6549    if (window.scrollY > 0) {
6550      element.querySelectorAll('.wow').forEach(el => wow.show(el));
6551    }
6552  }
6553  function adjustNavPinState() {
6554    // Remove 'visible' class from all subNavContainers
6555    for (let i = 0; i < subNavContainers.length; i++) {
6556      subNavContainers[i].classList.remove('visible');
6557    }
6558    if (window.scrollY > 0) {
6559      element.style.backgroundColor = backgroundColorScroll;
6560      element.style.color = fontColorScroll;
6561      element.classList.add('scroll');
6562    } else {
6563      element.style.backgroundColor = initialBackgroundColor;
6564      element.style.color = fontColor;
6565      element.classList.remove('scroll');
6566    }
6567  }
6568  adjustNavPinState();
6569  function onScroll() {
6570    didScroll = true;
6571  }
6572  window.addEventListener('scroll', onScroll);
6573
6574  // eslint-disable-next-line
6575  var debounceInterval = setInterval(() => {
6576    if (didScroll) {
6577      // eslint-disable-next-line
6578      hasScrolled();
6579      didScroll = false;
6580    }
6581  }, 250);
6582  function hasScrolled() {
6583    adjustNavPinState();
6584    // eslint-disable-next-line
6585    var navbarHeight = element.offsetHeight;
6586    // eslint-disable-next-line
6587    var st = window.scrollY;
6588
6589    // Make sure they scroll more than delta
6590    if (Math.abs(lastScrollTop - st) <= delta) {
6591      return;
6592    }
6593    if (st > lastScrollTop && st > navbarHeight) {
6594      // Scroll Down
6595      element.style.transform = `translateY(-${navbarHeight}px) scaleY(0)`;
6596      document.documentElement.style.setProperty('--global-header-height', '0px');
6597
6598      // Some sections "follow" the navbar with class sticky (i.e. Producer search)
6599      sections.forEach(section => {
6600        if (section.classList.contains('sticky')) {
6601          section.style.top = '0px';
6602        }
6603      });
6604    } else {
6605      // Scroll Up
6606      // eslint-disable-next-line
6607      if (st + window.innerHeight < document.documentElement.scrollHeight) {
6608        element.style.transform = `translateY(0) scaleY(1)`;
6609        document.documentElement.style.setProperty('--global-header-height', `${navbarHeight}px`);
6610        sections.forEach(section => {
6611          if (section.classList.contains('sticky')) {
6612            section.style.top = `${navbarHeight}px`;
6613          }
6614        });
6615      }
6616    }
6617    lastScrollTop = st;
6618  }
6619})('NAVBAR', JSON.parse("{\"fontColor\":\"#161515\",\"elementSelector\":\".header\",\"fontColorScroll\":\"#fff\",\"backgroundColorScroll\":\"rgba(26,26,26, .8)\",\"initialBackgroundColor\":\"#fff\"}"));
6620} catch(e) {
6621console.log(e);
6622}
6623                try {
6624(function init(sectionDomId) {
6625  if (sectionDomId === "main-section") sectionDomId = "global-sidemenu";
6626  var sidemenu = document.getElementById(sectionDomId);
6627  var openers = sidemenu.querySelectorAll('.js-sub-nav-opener');
6628  var items = sidemenu.querySelectorAll('.js-idemenu-navigation-item');
6629  var watermark = document.querySelector('.js-sidemenu-watermark');
6630  var onShow = function () {
6631    window.lpUI.requestScrollLock(sectionDomId);
6632  };
6633  var onHide = function () {
6634    window.lpUI.releaseScrollLock(sectionDomId);
6635  };
6636  sidemenu.addEventListener('lpui-show', onShow);
6637  sidemenu.addEventListener('lpui-hide', onHide);
6638  openers.forEach(function (opener) {
6639    opener.addEventListener('click', function (event) {
6640      event.preventDefault();
6641      this.classList.toggle('sidemenu-navigation__link--active');
6642      this.classList.toggle('sidemenu-navigation__link--sub-nav-active');
6643    });
6644  });
6645  document.body.addEventListener('click', function (evt) {
6646    if (!evt.target.closest('.sidemenu') && !evt.target.closest('.js-sidemenu-opener')) {
6647      window.lpUI.sideMenuHide();
6648    }
6649  });
6650  const handleLinkClick = function (href) {
6651    if (href && href.match(/^#[^#].*$/)) {
6652      window.lpUI.sideMenuHide();
6653    }
6654  };
6655  const mainNavLinks = sidemenu.querySelectorAll('.sidemenu-navigation__link');
6656  mainNavLinks.forEach(function (link) {
6657    link.addEventListener('click', function (event) {
6658      const href = this.getAttribute('href');
6659      handleLinkClick(href);
6660    });
6661  });
6662  const subNavLinks = sidemenu.querySelectorAll('.sidemenu-navigation-sub-nav__link');
6663  subNavLinks.forEach(function (link) {
6664    link.addEventListener('click', function (event) {
6665      const href = this.getAttribute('href');
6666      handleLinkClick(href);
6667    });
6668  });
6669  if (watermark) {
6670    items.forEach(function (item, index) {
6671      item.setAttribute("data-id", index <= 9 ? "0" + (index + 1) : index + 1);
6672    });
6673    items.forEach(function (item) {
6674      item.addEventListener('mouseenter', function () {
6675        watermark.setAttribute("data-id", item.getAttribute("data-id"));
6676        watermark.style.opacity = 1;
6677      });
6678      item.addEventListener('mouseleave', function () {
6679        watermark.style.opacity = 0;
6680      });
6681    });
6682  }
6683})('global-sidemenu');
6684} catch(e) {
6685console.log(e);
6686}
6687                
6688                try {
6689(function init(sectionDomId) {
6690  const sectionDom = document.getElementById(sectionDomId);
6691  const backToTopBtn = sectionDom.querySelector('.js-back-to-top');
6692  backToTopBtn?.addEventListener('click', () => {
6693    window.scrollTo({
6694      top: 0,
6695      behavior: 'smooth'
6696    });
6697  });
6698})('global-footer');
6699} catch(e) {
6700console.log(e);
6701}
6702                
6703                try {
6704(function init(sectionDomId) {
6705  const customDropdownHTML = `
6706  <div class="custom-select" role="presentation">
6707    <button class="custom-select-toggle" type="button" aria-haspopup="true" aria-expanded="false" role="combobox"></button>
6708    <div class="custom-select-menu"><div class="custom-select-content"></div></div>
6709  </div>`;
6710  const hideOriginalSelect = originalSelect => {
6711    originalSelect.classList.remove(...originalSelect.classList);
6712    originalSelect.classList.add("sr-only");
6713  };
6714  const openCustomSelect = customSelectToggle => {
6715    let customSelectMenu = customSelectToggle.nextElementSibling;
6716    customSelectMenu.classList.add("open");
6717    customSelectToggle.classList.add("open");
6718    customSelectToggle.ariaExpanded = true;
6719  };
6720  const closeCustomSelect = customSelectToggle => {
6721    let customSelectMenu = customSelectToggle.nextElementSibling;
6722    customSelectMenu.classList.remove("open");
6723    customSelectToggle.classList.remove("open");
6724    customSelectToggle.ariaExpanded = false;
6725  };
6726  const inheritAttributes = (originalSelect, customSelectToggle, customSelectMenu) => {
6727    customSelectToggle.className = customSelectToggle.className.concat(' ', originalSelect.className);
6728    customSelectToggle.id = originalSelect.getAttribute("id") + "custom";
6729    customSelectToggle.dataset.name = originalSelect.getAttribute("name");
6730    customSelectMenu.setAttribute("aria-labelledby", customSelectToggle.id);
6731  };
6732  const initiateQuerySelectors = customSelect => {
6733    let customSelectToggle = customSelect.querySelector('.custom-select-toggle'),
6734      customSelectMenu = customSelect.querySelector('.custom-select-menu'),
6735      customSelectContent = customSelect.querySelector('.custom-select-content');
6736    return {
6737      customSelectToggle,
6738      customSelectMenu,
6739      customSelectContent
6740    };
6741  };
6742  const initiateToggleText = (originalSelect, customSelectToggle) => {
6743    const dataLabelOption = originalSelect.querySelector("[data-label]");
6744    const isMultiple = originalSelect?.multiple;
6745    if (!isMultiple) {
6746      const toggleText = dataLabelOption && dataLabelOption.dataset.label || originalSelect.querySelector(":checked")?.textContent || originalSelect.querySelector("option")?.textContent;
6747      customSelectToggle.classList.add("is-placeholder");
6748      customSelectToggle.innerHTML = toggleText;
6749    } else {
6750      const placeholderText = dataLabelOption && dataLabelOption.dataset.label || originalSelect.querySelector("option")?.textContent || "Select";
6751      const selectedOptions = Array.from(originalSelect.querySelectorAll("option:checked")).filter(opt => opt.value !== "");
6752      if (selectedOptions.length === 0) {
6753        customSelectToggle.innerHTML = placeholderText;
6754        customSelectToggle.classList.add("is-placeholder");
6755      } else if (selectedOptions.length === 1) {
6756        customSelectToggle.innerHTML = selectedOptions[0].textContent;
6757        customSelectToggle.classList.remove("is-placeholder");
6758      } else {
6759        customSelectToggle.innerHTML = `${selectedOptions[0].textContent} +${selectedOptions.length - 1}`;
6760        customSelectToggle.classList.remove("is-placeholder");
6761      }
6762    }
6763  };
6764  const convertOptionsToButtons = (originalSelect, customSelectContent) => {
6765    originalSelect.querySelectorAll('option').forEach(option => {
6766      const button = createButtonFromOption(option);
6767      customSelectContent.appendChild(button);
6768    });
6769  };
6770  const createButtonFromOption = option => {
6771    let button = document.createElement('button');
6772    button.className = "custom-select-item";
6773    button.setAttribute("role", "option");
6774    button.setAttribute("type", "button");
6775    button.textContent = option.textContent;
6776    button.setAttribute('value', option.value);
6777    if (option.disabled) {
6778      button.setAttribute("disabled", "true");
6779    }
6780    if (option.selected && option.value !== "") {
6781      button.classList.add("is-selected");
6782      button.setAttribute("aria-selected", "true");
6783    }
6784    return button;
6785  };
6786  const initiateEventListeners = (originalSelect, customSelectToggle, customSelectMenu) => {
6787    const isMultiple = originalSelect?.multiple;
6788    originalSelect.addEventListener("focus", function () {
6789      openCustomSelect(customSelectToggle);
6790      customSelectToggle.focus();
6791    });
6792    customSelectToggle.addEventListener("click", function () {
6793      if (customSelectToggle.getAttribute("aria-expanded") === "true") {
6794        closeCustomSelect(customSelectToggle);
6795      } else {
6796        openCustomSelect(customSelectToggle);
6797      }
6798    });
6799    customSelectMenu.addEventListener("click", function (event) {
6800      if (event.target.classList.contains('custom-select-item')) {
6801        const clickedValue = event.target.value;
6802        const clickedOption = originalSelect.querySelector(`option[value="${clickedValue}"]`);
6803        const placeholderOption = originalSelect.querySelector("[data-label]");
6804        const placeholderText = placeholderOption?.dataset.label || originalSelect.querySelector("option")?.textContent || "Select";
6805        if (!isMultiple) {
6806          let opts = customSelectMenu.querySelectorAll(".is-selected");
6807          [].forEach.call(opts, function (el) {
6808            el.classList.remove("is-selected");
6809          });
6810          event.target.classList.add("is-selected");
6811          clickedOption.selected = true;
6812          customSelectToggle.innerHTML = clickedOption.textContent;
6813          if (clickedValue === "" || event.target.classList.contains("is-placeholder")) {
6814            customSelectToggle.classList.add("is-placeholder");
6815          } else {
6816            customSelectToggle.classList.remove("is-placeholder");
6817          }
6818          let changeEvent = new Event('change', {
6819            bubbles: true
6820          });
6821          originalSelect.dispatchEvent(changeEvent);
6822          closeCustomSelect(customSelectToggle);
6823        } else {
6824          if (clickedValue === "") {
6825            customSelectMenu.querySelectorAll(".is-selected").forEach(el => {
6826              el.classList.remove("is-selected");
6827              el.setAttribute("aria-selected", "false");
6828            });
6829            originalSelect.querySelectorAll("option").forEach(opt => opt.selected = false);
6830            customSelectToggle.innerHTML = placeholderText;
6831            customSelectToggle.classList.add("is-placeholder");
6832          } else {
6833            const isCurrentlySelected = event.target.classList.contains("is-selected");
6834            event.target.classList.toggle("is-selected");
6835            event.target.setAttribute("aria-selected", (!isCurrentlySelected).toString());
6836            clickedOption.selected = !isCurrentlySelected;
6837            const allItem = customSelectMenu.querySelector('.custom-select-item[value=""]');
6838            if (allItem) {
6839              allItem.classList.remove("is-selected");
6840              allItem.setAttribute("aria-selected", "false");
6841            }
6842            const allOption = originalSelect.querySelector('option[value=""]');
6843            if (allOption) allOption.selected = false;
6844            const selectedItems = customSelectMenu.querySelectorAll(".custom-select-item.is-selected");
6845            if (selectedItems.length === 0) {
6846              customSelectToggle.innerHTML = placeholderText;
6847              customSelectToggle.classList.add("is-placeholder");
6848            } else if (selectedItems.length === 1) {
6849              customSelectToggle.innerHTML = selectedItems[0].textContent;
6850              customSelectToggle.classList.remove("is-placeholder");
6851            } else {
6852              customSelectToggle.innerHTML = `${selectedItems[0].textContent} +${selectedItems.length - 1}`;
6853              customSelectToggle.classList.remove("is-placeholder");
6854            }
6855          }
6856          let changeEvent = new Event('change', {
6857            bubbles: true
6858          });
6859          originalSelect.dispatchEvent(changeEvent);
6860        }
6861      }
6862    });
6863    document.addEventListener("click", function (event) {
6864      if (!customSelectMenu.contains(event.target) && !customSelectToggle.contains(event.target)) {
6865        closeCustomSelect(customSelectToggle);
6866      }
6867    });
6868  };
6869  const createCustomSelect = originalSelect => {
6870    const customSelect = document.createElement('div');
6871    customSelect.innerHTML = customDropdownHTML;
6872    const {
6873      customSelectToggle,
6874      customSelectMenu,
6875      customSelectContent
6876    } = initiateQuerySelectors(customSelect);
6877    inheritAttributes(originalSelect, customSelectToggle, customSelectMenu);
6878    hideOriginalSelect(originalSelect);
6879    initiateToggleText(originalSelect, customSelectToggle);
6880    convertOptionsToButtons(originalSelect, customSelectContent);
6881    initiateEventListeners(originalSelect, customSelectToggle, customSelectMenu);
6882    return customSelect;
6883  };
6884  const setCustomSelectValue = (originalSelect, value) => {
6885    let customSelect = originalSelect.nextElementSibling;
6886    let customSelectToggle = customSelect.querySelector(".custom-select-toggle");
6887    let customSelectContent = customSelect.querySelector(".custom-select-content");
6888    if (!customSelectContent) return;
6889    let selectedOption = value ? Array.from(customSelectContent.children).find(function (b) {
6890      return b.value === value;
6891    }) : customSelectContent.firstChild;
6892    if (!selectedOption) {
6893      return;
6894    }
6895    if (selectedOption.classList.contains("is-disabled")) return;
6896    let elementNumber = Array.from(selectedOption.parentNode.children).indexOf(selectedOption);
6897    let linkedOption = originalSelect.querySelectorAll("option")[elementNumber];
6898    linkedOption.selected = true;
6899    selectedOption.classList.add("is-selected");
6900    selectedOption.parentNode.querySelectorAll(".custom-select-item").forEach(el => {
6901      if (el !== selectedOption) {
6902        el.classList.remove("is-selected");
6903      }
6904    });
6905    closeCustomSelect(customSelectToggle);
6906    customSelectToggle.innerHTML = linkedOption.innerHTML;
6907    if (linkedOption.value) {
6908      customSelectToggle.classList.remove("is-placeholder");
6909      if (linkedOption.value !== "") {
6910        customSelect.classList.add("has-selection");
6911      } else {
6912        customSelect.classList.remove("has-selection");
6913      }
6914    } else {
6915      customSelect.classList.remove("has-selection");
6916      customSelectToggle.classList.add("is-placeholder");
6917    }
6918  };
6919  const customSelect = originalSelect => {
6920    const customSelect = createCustomSelect(originalSelect);
6921    originalSelect.insertAdjacentElement('afterend', customSelect);
6922    return customSelect;
6923  };
6924  const resetCustomSelect = originalSelect => {
6925    const customSelectEl = originalSelect.nextElementSibling;
6926    const customSelectToggle = customSelectEl?.querySelector('.custom-select-toggle');
6927    const customSelectContent = customSelectEl?.querySelector('.custom-select-content');
6928    if (!customSelectToggle || !customSelectContent) return;
6929    const placeholderOption = originalSelect.querySelector("[data-label]");
6930    const placeholderText = placeholderOption?.dataset.label || originalSelect.querySelector("option")?.textContent || "Select";
6931    customSelectContent.querySelectorAll('.custom-select-item').forEach(item => {
6932      item.classList.remove('is-selected');
6933      item.setAttribute('aria-selected', 'false');
6934    });
6935    originalSelect.querySelectorAll('option').forEach(opt => opt.selected = false);
6936    customSelectToggle.innerHTML = placeholderText;
6937    customSelectToggle.classList.add('is-placeholder');
6938    const customSelectWrapper = customSelectEl.querySelector('.custom-select');
6939    if (customSelectWrapper) {
6940      customSelectWrapper.classList.remove('has-selection');
6941    }
6942  };
6943  const section = document.getElementById(sectionDomId);
6944  const closeBtn = section.querySelector(".js-close-btn");
6945  const connectBtn = section.querySelector(".js-btn-connect");
6946  const popUp = section.querySelector(".js-pop-up");
6947  const btnHolder = section.querySelector(".js-btn-holder");
6948  const form = section.querySelector(".js-form");
6949  const successMessage = section.querySelector(".js-success");
6950  const selects = document.querySelectorAll(".floating-contact-button select.js-select");
6951  selects.forEach(function (el) {
6952    customSelect(el);
6953  });
6954  const inputName = form.querySelector('.js-input-name');
6955  inputName.addEventListener('keyup', function () {
6956    if (this.value.replaceAll(/\d/g, "").trim().split(" ").length < 2 || this.value.replaceAll(/\d/g, "").trim() === "") {
6957      this.setCustomValidity("Please input your first name and last name.");
6958    } else {
6959      this.setCustomValidity("");
6960    }
6961  });
6962  form.addEventListener("reset", function () {
6963    successMessage.style.display = "block";
6964    form.style.display = "none";
6965  });
6966  window.addEventListener("scroll", function () {
6967    if (window.scrollY >= 150 && window.getComputedStyle(popUp).display !== "block") btnHolder.classList.add("floating-contact-button__btn-holder--visible");else btnHolder.classList.remove("floating-contact-button__btn-holder--visible");
6968  });
6969  closeBtn.addEventListener("click", function () {
6970    popUp.style.display = "none";
6971    btnHolder.classList.add("floating-contact-button__btn-holder--visible");
6972  });
6973  connectBtn.addEventListener("click", function () {
6974    popUp.style.display = "block";
6975    btnHolder.classList.remove("floating-contact-button__btn-holder--visible");
6976  });
6977})('global-mobile-contact');
6978} catch(e) {
6979console.log(e);
6980}
6981                
6982                try {
6983(function init(sectionDomId) {
6984  const scrollSection = document.getElementById(`${sectionDomId}`).querySelector('.js-scroll-section');
6985  const introBtn = document.getElementById(`${sectionDomId}`).querySelector('.jsScrollBtn');
6986  introBtn.addEventListener("click", function (e) {
6987    e.preventDefault();
6988    window.scrollTo({
6989      top: scrollSection.offsetTop + scrollSection.offsetHeight,
6990      behavior: "smooth"
6991    });
6992  });
6993})('section-2d2580ef-5c09-4535-96fc-598bf76a02df', 'undefined');
6994} catch(e) {
6995console.log(e);
6996}
6997                try {
6998(function init(sectionDomId) {
6999  const section = document.getElementById(sectionDomId);
7000  const emailInput = section.querySelector('.js-email-input');
7001  const emailRegex = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~\-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+/;
7002  emailInput.addEventListener('input', function () {
7003    if (emailRegex.test(this.value)) {
7004      this.setCustomValidity('');
7005    } else {
7006      this.setCustomValidity('Please enter a valid email address.');
7007    }
7008    this.reportValidity();
7009  });
7010  const inputName = section.querySelector('.js-input-name');
7011  inputName.addEventListener('keyup', function () {
7012    if (this.value.replaceAll(/\d/g, "").trim().split(" ").length < 2 || this.value.replaceAll(/\d/g, "").trim() === "") {
7013      this.setCustomValidity("Please input your first name and last name.");
7014    } else {
7015      this.setCustomValidity("");
7016    }
7017  });
7018  const addRedirectToForm = () => {
7019    const redirectLink = document.getElementById(`${sectionDomId}`).querySelector('.js-redirect-link');
7020    const form = document.getElementById(`${sectionDomId}`).querySelector('.js-form');
7021    function redirectPage(link) {
7022      if (link) {
7023        const rawHref = link.getAttribute('href');
7024        link.setAttribute('href', setHttp(rawHref));
7025        link.click();
7026      }
7027    }
7028    function setHttp(link) {
7029      if (link.search(/^http[s]?\:\/\/|\//) == -1) {
7030        link = 'http://' + link;
7031      }
7032      return link;
7033    }
7034    form.addEventListener("reset", function () {
7035      redirectPage(redirectLink);
7036    });
7037  };
7038  addRedirectToForm();
7039})('section-38f572f9-08ff-41a8-be87-094800542ec9', 'undefined');
7040} catch(e) {
7041console.log(e);
7042}
7043                try {
7044(function init(sectionDomId) {})('section-8a4a6b14-8bd9-4c11-bcb3-41a529fb04d0', 'undefined');
7045} catch(e) {
7046console.log(e);
7047}
7048                try {
7049(function init(sectionDomId, options) {
7050  let section = null;
7051  switch (sectionDomId) {
7052    case 'NAVBAR':
7053      section = document.querySelector('body > nav, #global-navbar');
7054      break;
7055    case 'FOOTER':
7056      section = document.querySelector('body > footer, #global-footer');
7057      break;
7058    case 'SIDEMENU':
7059      section = document.querySelector('body > div.sidemenu, #global-sidemenu');
7060      break;
7061    case 'CONTACT':
7062      section = document.querySelector('#modal-global-contact-us');
7063      break;
7064    case 'MOBILE_CONTACT':
7065      section = document.querySelector('body > div.mobile-contact-wrapper, #global-mobile-contact');
7066      break;
7067    case 'SUBSCRIBE':
7068      // Subscribe Not Implemented
7069      section = null;
7070      break;
7071    case 'ACCOUNT':
7072      // Account Not Implemented
7073      section = null;
7074      break;
7075    default:
7076      section = document.querySelector('#' + sectionDomId);
7077  }
7078  if (!section) {
7079    return;
7080  }
7081  var url = window.luxuryPresence.defaults.routerUrl;
7082  var companyId = window.luxuryPresence.defaults.companyId;
7083  var limit = options.limit || 8;
7084  if (typeof limit === 'string') {
7085    limit = parseInt(limit, 10) || 8; // this NaN protection also filters out 0 - this is expected
7086  }
7087  var templateSelector = options.templateSelector || '.jsIGTemplate';
7088  var containerSelector = options.containerSelector || '.jsIGContainer';
7089  var hasDataClass = options.hasDataClass || 'has-data';
7090  var hideActivateMessage = options.hasDataClass || false;
7091  var payload = {
7092    companyId: companyId,
7093    limit: limit
7094  };
7095  if (options.resourceId && typeof options.resourceId === 'string' && !options.resourceId.match(/^{{.*}}$/)) {
7096    payload.resourceId = options.resourceId;
7097    // Federated enum values are uppercase (AGENT/TEAM); element configs carry lowercase
7098    payload.resource = String(options.resource || 'agent').toUpperCase();
7099    payload.fallbackToNoResource = options.fallbackToNoResource === 'true' || options.fallbackToNoResource === true;
7100  }
7101  var query = 'query InstagramFeed (\n' + '  $companyId: ID!\n' + '  $instagramAuthorizationId: ID\n' + '  $username: String\n' + (payload.resourceId ? '$resource: InstagramContentAuthResourceEnum\n $resourceId: ID\n $fallbackToNoResource: Boolean' : '') + '  $limit: Int\n' + ') {\n' + '  instagramContentFeed (\n' + '  companyId: $companyId\n' + '  instagramAuthorizationId: $instagramAuthorizationId\n' + '  username: $username\n' + (payload.resourceId ? 'resource: $resource\n resourceId: $resourceId\n fallbackToNoResource: $fallbackToNoResource' : '') + '  limit: $limit\n' + '  ) {\n' + '    active\n' + '    feedUrl\n' + '    username\n' + '    items {\n' + '      id\n' + '      caption\n' + '      commentsCount\n' + '      likeCount\n' + '      mediaType\n' + '      mediaUrl\n' + '      permalink\n' + '      shortcode\n' + '      thumbnailUrl\n' + '      timestamp\n' + '      username\n' + '    }\n' + '  }\n' + '}\n';
7102  var templateHTML = section.querySelector(templateSelector)?.innerHTML || '';
7103  var template = Handlebars.compile(templateHTML);
7104  var container = section.querySelector(containerSelector);
7105  if (options.variables) {
7106    Object.keys(options.variables).forEach(function (key) {
7107      if (options.variables.hasOwnProperty(key) && (typeof options.variables[key] !== 'string' || !options.variables[key].match(/^{{.*}}$/))) {
7108        payload[key] = options.variables[key];
7109      }
7110    });
7111  }
7112  function getData() {
7113    var feed = {
7114      error: true
7115    };
7116    if (payload.companyId == null || payload.companyId === '') {
7117      // instagramContentFeed requires companyId (ID!) — nothing to fetch without it.
7118      // Checked after the options.variables merge, which may override the default.
7119      // Deferred so element listeners (attached after this template runs) still receive it.
7120      setTimeout(function () {
7121        section.dispatchEvent(new CustomEvent('ig-data', {
7122          detail: feed
7123        }));
7124      }, 0);
7125      return;
7126    }
7127    superagent.post(url + '/graphql').send({
7128      query: query,
7129      variables: payload
7130    }).then(res => {
7131      try {
7132        if (!res.body.errors) {
7133          feed = res.body.data.instagramContentFeed;
7134          if (!feed.active) {
7135            if (!hideActivateMessage && sectionDomId === 'section-temp' && container) {
7136              if (payload.resourceId) {
7137                container.innerHTML = '<div style="text-align: center">Instagram account is not connected to selected ' + payload.resource + '.<br /> Connect it on the ' + payload.resource + ' page</div>';
7138              } else {
7139                container.innerHTML = '<div style="text-align: center">Instagram account is not connected.<br /> Connect it on <a href="/profile">Profile page</a></div>';
7140              }
7141            }
7142          } else {
7143            if (feed.items.length) {
7144              if (hasDataClass) {
7145                section.classList.add(hasDataClass);
7146              }
7147              const feedName = feed.username;
7148              section.querySelectorAll('.jsIGLink').forEach(link => link.setAttribute('href', feed.feedUrl));
7149              section.querySelectorAll('.jsIGName').forEach(name => {
7150                name.textContent = '@' + feedName;
7151                name.setAttribute('title', '@' + feedName);
7152              });
7153              if (container && template) {
7154                container.innerHTML = template(feed);
7155              }
7156            }
7157          }
7158        }
7159      } catch (e) {}
7160      section.dispatchEvent(new CustomEvent('ig-data', {
7161        detail: feed
7162      }));
7163    }).catch(e => {
7164      console.log('err', e);
7165      section.dispatchEvent(new CustomEvent('ig-data', {
7166        detail: feed
7167      }));
7168    });
7169  }
7170  getData();
7171})('section-bdc20bac-df92-415d-b33f-0bbba2991620', JSON.parse("{\"limit\":11,\"resource\":\"agent\",\"resourceId\":\"{{id}}\",\"fallbackToNoResource\":\"{{{fallbackToNoResource}}}\",\"companyId\":\"bba607a7-df71-48c9-84ae-e87d443d6b5b\",\"usePageResource\":false,\"sectionIndex\":4}"));
7172} catch(e) {
7173console.log(e);
7174}
7175                try {
7176(function init(sectionDomId) {
7177  const section = document.getElementById(sectionDomId);
7178  const slider = section.querySelector(".js-slider");
7179  section.addEventListener("ig-data", function () {
7180    var splide = new Splide(slider, {
7181      rewind: true,
7182      arrows: false,
7183      type: 'loop',
7184      padding: '20%',
7185      gap: '16px',
7186      pagination: false,
7187      clones: 1,
7188      perPage: 1,
7189      perMove: 1,
7190      destroy: true,
7191      breakpoints: {
7192        768: {
7193          destroy: false
7194        }
7195      }
7196    });
7197    splide.mount();
7198  });
7199})('section-bdc20bac-df92-415d-b33f-0bbba2991620', 'undefined');
7200} catch(e) {
7201console.log(e);
7202}
7203
7204            var { body } = document;
7205            var globalNav = body.querySelector(':scope > nav');
7206            var globalSideMenu = body.querySelector(':scope > div.sidemenu');
7207
7208            document.querySelectorAll('body > .modal .close').forEach(modalCloseBtn => {
7209                modalCloseBtn.addEventListener('click', function() {
7210                window.lpUI.hideClosestModal(modalCloseBtn);
7211              });
7212            });
7213
7214            window.addEventListener('click', function() {
7215                document.querySelectorAll('.share-popup').forEach(sharedPopup => {
7216                    sharedPopup.style.display = 'none' ;
7217                });
7218            });
7219
7220            /* Misc Partials / Addons */
7221            function initWOW() {
7222                if (wow) {
7223                    wow.init();
7224                    wow.scrollHandler();
7225                    setTimeout(function () {
7226                        const wowHideStyle = document.getElementById('wow-hide-elements');
7227                        if(wowHideStyle) {
7228                            wowHideStyle.disabled = true;
7229                        }
7230                    }, 1);
7231                }
7232            }
7233
7234            const wowHideElements =  document.getElementById('wow-hide-elements');
7235            if (wowHideElements) {
7236               wowHideElements.disabled = false;
7237            }
7238
7239                initWOW();
7240
7241            /* Generic Navbar Handling */
7242            globalNav?.querySelectorAll('.hamburger-component').forEach(hamburgerComponent => {
7243                hamburgerComponent.addEventListener('click', function() {
7244                window.lpUI.sideMenuToggle();
7245              });
7246            });
7247            globalSideMenu?.querySelectorAll('.toggle').forEach(toggleEl => {
7248                toggleEl.addEventListener('click', function() {
7249                window.lpUI.sideMenuToggle();
7250              });
7251            });
7252
7253            document.querySelectorAll('body > nav .sub-nav-container > a, body > div.sidemenu .sub-nav-container > a').forEach(linkEl => {
7254                linkEl.addEventListener('click', function(e) {
7255                  e.preventDefault();
7256                  e.stopPropagation();
7257                  var subNav = linkEl.parentElement.querySelector(':scope > .sub-nav');
7258                  if (subNav && subNav.classList.contains('visible')){
7259                    subNav.classList.remove('visible');
7260                  } else {
7261                    globalNav?.querySelectorAll('.sub-nav-container .sub-nav').forEach(globalSubNav => {
7262                      globalSubNav.classList.remove('visible');
7263                    });
7264                    globalSideMenu?.querySelectorAll('.sub-nav').forEach(sideMenuSubNav => {
7265                        sideMenuSubNav.classList.remove('visible');
7266                    });
7267                    subNav?.classList.add('visible');
7268                  }
7269                });
7270            });
7271            window.addEventListener('click', function() {
7272                document.querySelectorAll('nav .sub-nav.visible, .sidemenu .sub-nav.visible').forEach(subNavEl => {
7273                    subNavEl.classList.remove('visible');
7274                });
7275            });
7276
7277        }
7278
7279        document.addEventListener('DOMContentLoaded', lpGlobalInit);
7280
7281    </script>
7281
7282
7283    
7283<script type="module">
7284    function selectorExists(selector) {
7285        return document.querySelector(selector) !== null;
7286    }
7287
7288    // Function to initialize the third-party library
7289    function initParoller(selector = '.my-paroller') {
7290        var $parollerElements = $(selector);
7291        if ($parollerElements.length > 0 && typeof $parollerElements.paroller === 'function') {
7292            $parollerElements.paroller();
7293        }
7294    }
7295
7296    const parollerSelector = '.my-paroller';
7297
7298    if (selectorExists(parollerSelector)) {
7299        window.luxuryPresence.libs.loadJs(window.luxuryPresence.libs.jsLibsMap.paroller.jsSrc, function() {
7300            initParoller(parollerSelector);
7301            window.luxuryPresence.libs.jsLibsMap.paroller.isLoaded = true;
7302        });
7303    }
7304    </script>
7304
7305
7306            <!-- Google Tag Manager (noscript) -->
vendor: 80 bytes, lines 7306-7307
7306
7307            <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
7307GTM-T9SFQGHZ
vendor: 107 bytes, lines 7307-7309
7307"
7308            height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
7309            
7309<!-- End Google Tag Manager -->
7310        
7311                
7311<script
7312                    src="https://cdn.luxurypresence.com/scripts/a11y-widget/latest/widget.js"
7313                    data-website-id="ae45f4e2-58fe-4d52-921e-febac4ac146e"
7314                    
7315                    defer></script>
vendor: 1 bytes, line 7315
7315
7316<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a46729c16b31d94c',t:'MTc5MTMxNTg5MQ=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
7316<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"d2a8f4b3d65944edb8fcd6ffce49ee5e","spa":2}' crossorigin="anonymous"></script>
7316
7317</body>
7318</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.