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 | South Florida Real Estate | The Gobin Group</title> 10 <meta property="og:title" content="Contact Us | South Florida Real Estate | The Gobin Group"> 11 <meta name="twitter:title" content="Contact Us | South Florida Real Estate | The Gobin Group"> 12 <meta name="description" content="Get in touch with The Gobin Group - Your go-to choice for top-tier Florida Real Estate services. Reach out to our experts today for all your real estate needs!"> 13 <meta property="og:description" content="Get in touch with The Gobin Group - Your go-to choice for top-tier Florida Real Estate services. Reach out to our experts today for all your real estate needs!"> 14 <meta name="twitter:description" content="Get in touch with The Gobin Group - Your go-to choice for top-tier Florida Real Estate services. Reach out to our experts today for all your real estate needs!"> 15 <meta property="og:image" content="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/5683ba9f-8354-4c98-93ef-a6e83f0891b4"> 16 <meta name="twitter:image" content="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/5683ba9f-8354-4c98-93ef-a6e83f0891b4"> 17 <meta property="og:url" content="https://denisegobin.com/contact"> 18 <link rel="canonical" href="https://denisegobin.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 <style>@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Regular.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Regular.woff') format('woff');font-weight: 400;font-style: normal;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Italic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Italic.woff') format('woff');font-weight: 400;font-style: italic;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBold.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBold.woff') format('woff');font-weight: 600;font-style: normal;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBoldItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBoldItalic.woff') format('woff');font-weight: 600;font-style: italic;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Bold.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-Bold.woff') format('woff');font-weight: 700;font-style: normal;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-BoldItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-BoldItalic.woff') format('woff');font-weight: 700;font-style: italic;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBold.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBold.woff') format('woff');font-weight: 500;font-style: normal;}@font-face {font-family: 'CompassSerif';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBoldItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSerif/CompassSerif-SemiBoldItalic.woff') format('woff');font-weight: 500;font-style: italic;}</style><style>@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Regular.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Regular.woff') format('woff');font-weight: 400;font-style: normal;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Italic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Italic.woff') format('woff');font-weight: 400;font-style: italic;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Medium.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Medium.woff') format('woff');font-weight: 500;font-style: normal;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-MediumItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-MediumItalic.woff') format('woff');font-weight: 500;font-style: italic;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Bold.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Bold.woff') format('woff');font-weight: 700;font-style: normal;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-BoldItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-BoldItalic.woff') format('woff');font-weight: 700;font-style: italic;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Medium.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-Medium.woff') format('woff');font-weight: 600;font-style: normal;}@font-face {font-family: 'CompassSans';src: url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-MediumItalic.woff2') format('woff2'),url('https://s3-us-west-2.amazonaws.com/static-lp/fonts/compass/CompassSans/CompassSans-MediumItalic.woff') format('woff');font-weight: 600;font-style: italic;}</style> 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:CompassSerif,serif;--global-primary-font-family-short:CompassSerif;--global-secondary-font-family:CompassSans,sans-serif;--global-secondary-font-family-short:CompassSans;--global-body-padding:0px;--global-background-color:#fff;--global-body-font-size:16px;--global-h1-font-size:70px;--global-h2-font-size:43px;--global-h3-font-size:30px;--global-h4-font-size:21px;--global-h5-font-size:17px;--global-h6-font-size:16px;--global-section-padding:96px;}@media (max-width: 768px){:root{--global-section-padding:64px;}}body{padding:0px;background-color:#fff;font-family:CompassSans,sans-serif;font-size:16px;}@media (min-width: 768px){body{padding:0px 0px 0px 0px;}}h1,h2,h3,h4,h5,h6,button{font-family:CompassSerif,serif;}h1{font-size:70px;}h2{font-size:43px;}h3{font-size:30px;}h4{font-size:21px;}h5{font-size:17px;}h6{font-size:16px;}</style> 30 <link rel="stylesheet" type="text/css" href="https://styles.luxurypresence.com/producer/index.css" /> 31 <style id="website-css">.redesign .btn--small{padding:20px 46px;}.lp-btn{padding:20px 46px!important;}button.newsletter-signup__form-item{line-height:1;font-weight:700;}#modal-global-contact-us .contact-form .section-message form .submitButton{padding:14px 20px;}body>div.mobile-contact-wrapper .mobile-contact.with-search div.buttons-holder{bottom:150px;}@media only screen and (max-width: 768px){iframe[name='widgetCta']{bottom:55px!important;right:15px!important;}}iframe[name="widgetCta"]{bottom:70px!important;right:15px!important;}h1,.lp-h1,h2,.lp-h2,h3,.lp-h3,h4,.lp-h4,h5,.lp-h5,div#global-sidemenu.sidemenu a,nav#global-navbar a,div#global-sidemenu.sidemenu button,nav#global-navbar button{text-transform:uppercase;}nav#global-navbar .header .logo .logo__img{max-height:100px;max-width:320px;}@media(max-width: 568px){nav#global-navbar .header .logo .logo__img{max-width:250px;}}nav#global-navbar.scroll .header div.navbar .logo img.light{display:none!important;}nav#global-navbar.scroll .header div.navbar .logo img.dark{display:block!important;}nav#global-navbar.scroll .header{background-color:#fff;}nav#global-navbar.scroll .header li.navigation__item a.navigation__link{color:#000;}nav#global-navbar.scroll .header button.hamburger-component.hamburger{color:#000;}nav#global-navbar .header .sub-nav__link{background:rgba(255,255,255, 1);color:#000;}nav#global-navbar .header .sub-nav__link:hover{background:#000;color:#fff;}nav#global-navbar .navbar .sub-nav ul{background:unset;}body>div.sidemenu .wrapper{width:100vw;height:100vh;background-image:url("https://media-production.lp-cdn.com/media/be422ede-ea58-4e27-aa93-c823173af8cc");-webkit-background-size:cover;background-size:cover;-webkit-background-position:center;background-position:center;background-repeat:no-repeat;}@media(max-width:767px){body>div.sidemenu .wrapper{background:#FFF!important;}}
31#global-sidemenu a:hover{color:#1a1a1a;-webkit-transform:translate(0px, -2px);-moz-transform:translate(0px, -2px);-ms-transform:translate(0px, -2px);transform:translate(0px, -2px);}#modal-global-contact-us .redesign .link:after{background-color:#fff;}#modal-global-contact-us .close{top:4vh;}#modal-global-contact-us .contact-form .info-zone .type_user,#modal-global-contact-us .contact-form .info-zone .type_user:nth-of-type(2){margin-bottom:21px!important;}#modal-global-contact-us .contact-form .section-message label{color:#fff!important;}#modal-global-contact-us .lp-input-group .lp-input{border-color:#fff!important;}#modal-global-contact-us .contact-form .section-message:after{background:#fff!important;}#modal-global-contact-us .section-message label{text-transform:uppercase;}@media(max-width: 568px){#modal-global-contact-us .modal-content .info-zone ul.lp-socials{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}}@media (max-width: 768px){#global-footer .footer .info-wrap .type_user{margin-bottom:21px;}}@media (min-width: 1201px){#global-footer .footer .info-wrap .type_user{margin-bottom:21px;}}footer#global-footer .container .info-wrap svg path{fill:#000;}footer#global-footer .container .info-privacy{border-top-color:#ccc;}@media (max-width: 768px){footer#global-footer .container .info-privacy .copy_zone{border-color:#ccc;}}@media (min-width: 769px){#global-footer .text_footer .images_box img{margin-top:220px!important;margin-bottom:auto!important;}}footer .footer.no_newsletter .info-wrap-contact h4{margin-top:-5px;}footer#global-footer .text_footer .luxury-text a.link{color:#000;font-weight:400;}footer#global-footer .text_footer .luxury-text a.link:after{background-color:#000;}footer#global-footer .container .info-privacy a{font-weight:400;}footer#global-footer .lp-link:after{background-color:#000;}footer#global-footer{background-position-x:5%!important;background-repeat:no-repeat;-webkit-background-size:25%!important;background-size:25%!important;background-image:url('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/b96afe03-09e4-42aa-ad7d-1fea28ba06dc');background-position-y:65%!important;background-attachment:fixed;}@media only screen and (max-width: 768px){footer#global-footer{background-image:none;}}@media only screen and (min-width: 769px){.popup-modal.with-image .popup-modal__form .close{color:#000!important;opacity:1!important;}}@media only screen and (max-width: 768px){.popup-modal.with-image .popup-modal__form .close{color:#000!important;opacity:1!important;}}body>div.mobile-contact-wrapper{z-index:9999!important;}body>div.mobile-contact-wrapper .connect-btn{border:2px solid #000!important;background-color:#fff!important;color:#000!important;}body>div.mobile-contact-wrapper .connect-btn:hover{border-color:#000!important;background-color:#000!important;color:#fff!important;}body>div.mobile-contact-wrapper .search-btn{border:2px solid #000!important;background-color:#fff!important;color:#000!important;}body>div.mobile-contact-wrapper .search-btn:hover{border-color:#000!important;background-color:#000!important;color:#fff!important;}body>div.mobile-contact-wrapper .contact-form__item .lp-input{color:#000;opacity:1;border-color:#000;}body>div.mobile-contact-wrapper h3{color:#000;}body>div.mobile-contact-wrapper .lp-tcr-content{color:#000;}body>div.mobile-contact-wrapper .lp-btn.lp-btn--dark.lp-btn--filled{border:2px solid #000!important;background-color:#fff!important;color:#000!important;}body>div.mobile-contact-wrapper .lp-btn.lp-btn--dark.lp-btn--filled:hover{border-color:#000!important;background-color:#000!important;color:#fff!important;}body>div.mobile-contact-wrapper .pop-up .close-btn{color:#000!important;}body>div.mobile-contact-wrapper .pop-up .close-btn:before{-webkit-filter:none;filter:none;}body>div.mobile-contact-wrapper .pop-up .lp-container{background-color:#fff!important;border:1px solid #000;}@media only screen and (max-width:768px){body>div.mobile-contact-wrapper .pop-up .lp-container{padding-top:96px;}}</style> 32 <style id="wow-hide-elements">.wow{visibility:hidden!important}</style> 33 <style id="page-css"> 34 #section-02c84b7e-634c-47be-91b2-a3796ee118a3{color:rgba(255, 255, 255, 1);--fontColor:rgba(255, 255, 255, 1);--fontColor_H:0;--fontColor_S:0%;--fontColor_L:100%;--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.4));background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('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/5683ba9f-8354-4c98-93ef-a6e83f0891b4');background-repeat:no-repeat;-webkit-background-position:center;background-position:center;-webkit-background-size:cover;background-size:cover;}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 div.custom-intro{height:50vh;}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;height:600px;-webkit-box-pack:center;-ms-flex-pack:center;
34-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro .container{z-index:1;text-align:center;max-width:900px;}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro__title{margin-bottom:0px;font-weight:400;margin-bottom:24px;}@media (max-width: 768px){#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro__title{font-size:32px;}}@media (max-width: 360px){#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro__title{font-size:22px;}}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro__subtitle{font-weight:400;white-space:pre-line;font-size:21px;line-height:1.57;}@media (max-width: 768px){#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .custom-intro__subtitle{font-size:18px;}}#section-02c84b7e-634c-47be-91b2-a3796ee118a3 .description{margin-bottom:15px;}@media (min-width: 960px) and (orientation: landscape){#section-02c84b7e-634c-47be-91b2-a3796ee118a3{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('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/5683ba9f-8354-4c98-93ef-a6e83f0891b4');}}@media (min-width: 1280px) and (orientation: landscape){#section-02c84b7e-634c-47be-91b2-a3796ee118a3{background-image:linear-gradient(var(--gradient-color), var(--gradient-color)),url('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/5683ba9f-8354-4c98-93ef-a6e83f0891b4');}}@media (min-width: 1920px) and (orientation: landscape){#section-02c84b7e-634c-47be-91b2-a3796ee118a3{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/5683ba9f-8354-4c98-93ef-a6e83f0891b4');}}@media (min-width: 2560px) and (orientation: landscape){#section-02c84b7e-634c-47be-91b2-a3796ee118a3{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/5683ba9f-8354-4c98-93ef-a6e83f0891b4');}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725{color:#000;--fontColor:#000;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:0%;--fontColor_A:1;--fontColor_darkenDir:1;--bgColor:#ffffff;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:100%;--bgColor_A:1;--bgColor_darkenDir:-1;--section-padding-bottom:calc(4 / 4 * var(--global-section-padding));background-color:#ffffff;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 div.custom-form__header{max-width:900px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 label.lp-label{text-transform:uppercase;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 div.custom-form{padding-top:96px;padding-bottom:96px;}@media(max-width: 568px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 div.custom-form{padding-top:64px;padding-bottom:64px;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725.modal.is-background-color-light>button.close{padding:5px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725.modal.is-background-color-light>button.close:before{content:'';width:100%;display:block;padding-bottom:100%;-webkit-clip-path:polygon(8% 0, 50% 42%, 92% 0, 100% 8%, 58% 50%, 100% 92%, 92% 100%, 50% 58%, 8% 100%, 0 92%, 42% 50%, 0 8%);clip-path:polygon(8% 0, 50% 42%, 92% 0, 100% 8%, 58% 50%, 100% 92%, 92% 100%, 50% 58%, 8% 100%, 0 92%, 42% 50%, 0 8%);background-color:#000;-webkit-transition:all .3s ease;transition:all .3s ease;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725.modal.is-background-color-light>button.close:hover:before{-webkit-transform:scale(1.2);-moz-transform:scale(1.2);-ms-transform:scale(1.2);transform:scale(1.2);}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725.modal.is-background-color-light>button.close>img,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725.modal.is-background-color-light>button.close .lp-close-icon{display:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .elem-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-left:-16px;margin-right:-16px;-webkit-box-flex-wrap:nowrap;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}@media (max-width: 767px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .elem-row{-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}}
34#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .elem-col{min-height:1px;padding-left:16px;padding-right:16px;}@media (max-width: 767px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .elem-col{-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%;max-width:unset;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .form-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;margin-left:-16px;margin-right:-16px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .form-col{padding-left:16px;padding-right:16px;-webkit-flex:1 1 400px;-ms-flex:1 1 400px;flex:1 1 400px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .form-col:last-child .custom-form__group{margin-bottom:20px;}@media (min-width: 768px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .form-col:last-child .custom-form__group{margin-bottom:30px;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-label{text-transform:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-label.field-required:after{content:' *';}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form{padding-top:80px;padding-bottom:80px;}@media (max-width: 767px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form{padding-top:50px;padding-bottom:50px;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__img-col{margin-bottom:30px;}@media (min-width: 768px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__img-col{margin-bottom:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;}}@media (min-width: 768px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__form-col{-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto;}}@media (min-width: 992px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__form-col{-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__header{max-width:600px;margin-left:auto;margin-right:auto;margin-bottom:50px;text-align:center;}@media (max-width: 767px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__header{margin-bottom:30px;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__heading{margin-bottom:24px;}@media (max-width: 767px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__heading{margin-bottom:13px;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__description{margin-bottom:0;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__img-block{width:100%;height:430px;background:currentColor center/cover no-repeat;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__img-block img{height:100%;width:100%;object-fit:cover;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__download-form{width:100%;margin-bottom:0;}@media (min-width: 992px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__download-form{height:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}}@media (min-width: 768px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__footer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__container{max-width:1160px;margin-left:auto;margin-right:auto;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .form-field-descr{opacity:0.5;margin-top:8px;font-size:82%;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-btn-icons{width:0;-webkit-transition:width .3s ease;transition:width .3s ease;display:inline-block;float:left;line-height:inherit;overflow:visible;position:relative;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-btn-icons:before{content:'';display:inline-block;width:0px;height:1em;vertical-align:middle;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-btn-icons .lp-btn-icon-loading{position:absolute;display:block;width:0;height:17px;opacity:0;top:50%;left:0;-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);-webkit-transition:width .3s ease,opacity .3s ease;transition:width .3s ease,opacity .3s ease;overflow:hidden;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-btn-icons .lp-btn-icon-loading:before{content:none;display:block;background-color:currentColor;width:17px;height:17px;-webkit-clip-path:path('M8.5 0A 8.5 8.5 0 1 1 1.89 3.15L 4.23 5.04A 5.5 5.5 0 1 0 8.5 3Z');clip-path:path('M8.5 0A 8.5 8.5 0 1 1 1.89 3.15L 4.23 5.04A 5.5 5.5 0 1 0 8.5 3Z');-webkit-animation:i-spin 2s linear infinite;animation:i-spin 2s linear infinite;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-btn-icons .lp-btn-icon-success{position:absolute;display:block;width:0;height:17px;opacity:0;top:50%;left:0;-webkit-transform:translateY(-50%) scale(1.02);-moz-transform:translateY(-50%) scale(1.02);-ms-transform:translateY(-50%) scale(1.02);transform:translateY(-50%) scale(1.02);-webkit-transition:width .3s ease,opacity .3s ease;transition:width .3s ease,opacity .3s ease;background-color:currentColor;-webkit-clip-path:path('M0 8.5 A 8.5 8.5 0 0 1 17 8.5 A 8.5 8.5 0 0 1 0 8.5 H 1.2 A 7.3 7.3 0 1 0 15.8 8.5 A 7.3 7.3 0 1 0 1.2 8.5 H0 m5.201-.344L7.4 10.35l4.436-4.45c.311-.202.58-.191.807.033.227.225.25.488.072.788L7.85 11.59c-.14.141-.291.212-.451.212-.16 0-.31-.061-.45-.183L4.338 8.99c-.192-.311-.172-.58.06-.806.231-.226.5-.235.803-.027');clip-path:path('M0 8.5 A 8.5 8.5 0 0 1 17 8.5 A 8.5 8.5 0 0 1 0 8.5 H 1.2 A 7.3 7.3 0 1 0 15.8 8.5 A 7.3 7.3 0 1 0 1.2 8.5 H0 m5.201-.344L7.4 10.35l4.436-4.45c.311-.202.58-.191.807.033.227.225.25.488.072.788L7.85 11.59c-.14.141-.291.212-.451.212-.16 0-.31-.061-.45-.183L4.338 8.99c-.192-.311-.172-.58.06-.806.231-.226.5-.235.803-.027');}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading input,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success input,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading select,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success select,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading button,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success button{pointer-events:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading .lp-btn-icons,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success .lp-btn-icons{width:27px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading .lp-btn-icons .lp-btn-icon-loading,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success .lp-btn-icons .lp-btn-icon-loading{width:17px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading .lp-btn-icons .lp-btn-icon-success,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success .lp-btn-icons .lp-btn-icon-success{width:17px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading .lp-btn-icons .lp-btn-icon-loading{opacity:1;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .loading .lp-btn-icons .lp-btn-icon-loading:before{content:'';}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .success .lp-btn-icons .lp-btn-icon-success{opacity:1;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .js-backup-email{display:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-h-pot{height:0;overflow:hidden;visibility:hidden;position:absolute;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .visually-hidden{position:absolute;overflow:hidden;clip:rect(0 0 0 0);width:1px;height:1px;margin:-1px;padding:0;border:0;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-content{max-height:210px;overflow-y:auto;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-input-group .uf-cus-sel-toggle{width:100%;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel{position:relative;width:100%;--optionHoverColor:hsl(var(--bgColor_H), calc(var(--bgColor_S) + 6% * var(--bgColor_darkenDir)), calc(var(--bgColor_L) + 14% * var(--bgColor_darkenDir)));}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-toggle{position:relative;display:block;width:100%;font-family:inherit;text-align:left;text-transform:none;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:all .25s;transition:all .25s;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-toggle.is-placeholder{color:#999;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-toggle:after{box-sizing:border-box;content:"";position:absolute;right:20px;top:50%;margin-top:0;height:10px;width:10px;border-top:2px solid currentColor;border-left:2px solid currentColor;-webkit-transform:rotateZ(-135deg) translateY(10px);-moz-transform:rotateZ(-135deg) translateY(10px);-ms-transform:rotateZ(-135deg) translateY(10px);transform:rotateZ(-135deg) translateY(10px);-webkit-transition:all .2s;transition:all .2s;}@media (min-width: 992px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-toggle:after{right:25px;}}.uf-cus-sel.open #section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-toggle:after{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-menu{display:none;position:absolute;width:calc(100% + var(--uf-border-left, 0px) + var(--uf-border-right, 0px));top:100%;left:calc(0px - var(--uf-border-left, 0px));z-index:1;}@media (max-width: 768px){#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-menu{position:relative;top:auto;}}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-content{width:100%;background-color:var(--bgColor, #000);border:1px solid #979797;border-top:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item{display:block;width:100%;padding:11px 24px;border:solid 1px transparent;background:transparent;border-radius:0;color:inherit;font-family:inherit;font-size:inherit;line-height:24px;text-align:left;text-transform:none;-webkit-transition:all .25s;transition:all .25s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item:focus,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item:hover{background-color:var(--optionHoverColor, #262222);}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item.is-selected{font-weight:700;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item.is-disabled,#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .uf-cus-sel-item:disabled{display:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-text--subtitle{margin-left:auto;margin-right:auto;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkbox-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse;gap:8px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkbox-container .lp-label{opacity:1;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkboxes-label{font-size:14px;line-height:1.43;font-weight:600;margin-bottom:0;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkboxes-description{font-size:14px;line-height:1.43;font-weight:400;margin-bottom:0;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkbox-item{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:10px;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .custom-form__checkbox-label{cursor:pointer;font-size:inherit;line-height:1.4;margin:0;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725>div:last-child{padding-bottom:calc(4 / 4 * var(--global-section-padding))!important;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-input::-webkit-input-placeholder{text-transform:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-input::-moz-placeholder{text-transform:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-input:-ms-input-placeholder{text-transform:none;}#section-a6ae58a0-a07f-4664-a9fd-fe7d60274725 .lp-input::placeholder{text-transform:none;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8{color:rgba(255, 255, 255, 1);--fontColor:rgba(255, 255, 255, 1);--fontColor_H:0;--fontColor_S:0%;--fontColor_L:100%;--fontColor_A:1;--fontColor_darkenDir:-1;--bgColor:rgba(0, 0, 0, 1);--bgColor_H:0;--bgColor_S:0%;--bgColor_L:0%;--bgColor_A:1;--bgColor_darkenDir:1;background-color:rgba(0, 0, 0, 1);}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 div.gallery-component__col .gallery-card__title{text-align:center;text-transform:uppercase;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 div.gallery-component{padding-top:96px;padding-bottom:46px;}@media (max-width: 768px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 div.gallery-component{padding-bottom:44px;padding-top:64px;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component{padding-top:30px;padding-bottom:10px;}@media (min-width: 769px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component{padding:80px 0 60px;}}
34@media (min-width: 1200px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component{padding:80px 0 30px;}}@media (max-width: 767px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__container{padding-left:20px;padding-right:20px;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header{margin-bottom:30px;max-width:640px;margin-left:auto;margin-right:auto;text-align:center;}@media (min-width: 768px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header{margin-bottom:50px;}}@media (min-width: 1200px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header{margin-bottom:70px;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header img{max-width:260px;height:auto;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header img:not(:only-child){margin-bottom:30px;}@media (min-width: 768px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__header img:not(:only-child){margin-bottom:50px;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__heading{margin-bottom:20px;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__lead{margin-bottom:0;font-size:20px;line-height:1.4;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__row{margin-left:-7px;margin-right:-7px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__col{width:100%;margin-bottom:20px;padding:0 7px;}@media (min-width: 768px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__col{max-width:33.333333%;-webkit-flex-basis:33.333333%;-ms-flex-preferred-size:33.333333%;flex-basis:33.333333%;}}@media (min-width: 1200px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__col{max-width:25%;-webkit-flex-basis:25%;-ms-flex-preferred-size:25%;flex-basis:25%;margin-bottom:50px;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__col:first-child{margin-left:auto;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component__col:last-child{margin-right:auto;}@media (min-width: 992px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component .cols-2 .gallery-component__col{max-width:50%;-webkit-flex-basis:50%;-ms-flex-preferred-size:50%;flex-basis:50%;}}@media (min-width: 1200px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component .cols-3 .gallery-component__col{max-width:33.333333%;-webkit-flex-basis:33.333333%;-ms-flex-preferred-size:33.333333%;flex-basis:33.333333%;}}@media (min-width: 992px){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-component .cols-4 .gallery-component__col{max-width:25%;-webkit-flex-basis:25%;-ms-flex-preferred-size:25%;flex-basis:25%;}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card{position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:flex-end;-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;padding:20px 15px;-webkit-text-decoration:none;text-decoration:none;overflow:hidden;cursor:pointer;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:after{content:"";width:0;padding-top:121.5%;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:before{content:"";position:absolute;left:0;bottom:0;width:100%;height:100%;background-color:transparent;background-image:linear-gradient(to bottom, rgba(0, 0, 0, 0) 76.6%, #000000);opacity:0.6;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transition:background-color .3s;transition:background-color .3s;z-index:1;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:focus{outline:none;}@media (hover: hover) and (pointer: fine){#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:hover:before{background-color:#000;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:hover .gallery-card__title{-webkit-transform:translateY(-51px);-moz-transform:translateY(-51px);-ms-transform:translateY(-51px);transform:translateY(-51px);}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:hover .gallery-card__title:after{opacity:.3;-webkit-transform:translateY(20px);-moz-transform:translateY(20px);-ms-transform:translateY(20px);transform:translateY(20px);}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card:hover .gallery-card__preview img{-webkit-transform:scale(1.05);-moz-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05);}}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card__title{position:relative;width:100%;margin-bottom:0;color:#fff;letter-spacing:0;text-shadow:none;z-index:1;
34-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:all .3s;transition:all .3s;text-transform:none;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card__title:after{content:"";position:absolute;left:0;bottom:0;width:100%;border-bottom:1px solid currentColor;opacity:0;-webkit-transition:all .3s;transition:all .3s;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card__preview{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;}#section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8 .gallery-card__preview>img{width:100%;height:100%;object-fit:cover;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transition:-webkit-transform .75s ease-out;transition:transform .75s ease-out;}#section-56d00219-b3d8-459e-8dda-281976e80716{color:#FFFFFF;--fontColor:#FFFFFF;--fontColor_H:0;--fontColor_S:0%;--fontColor_L:100%;--fontColor_A:1;--fontColor_darkenDir:-1;--bgColor:#000000;--bgColor_H:0;--bgColor_S:0%;--bgColor_L:0%;--bgColor_A:1;--bgColor_darkenDir:1;background-color:#000000;}#section-56d00219-b3d8-459e-8dda-281976e80716 div.ig-feed.redesign .slick-arrow{border:2px solid currentColor;}#section-56d00219-b3d8-459e-8dda-281976e80716 div.ig-feed{padding-bottom:86px;}@media(max-width: 768px){#section-56d00219-b3d8-459e-8dda-281976e80716 div.ig-feed{padding-bottom:64px;}}#section-56d00219-b3d8-459e-8dda-281976e80716 div.video-icon::before{border-color:transparent transparent transparent #000;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed{padding:80px 0;}#section-56d00219-b3d8-459e-8dda-281976e80716 .title{margin:0 20px 0 0;}#section-56d00219-b3d8-459e-8dda-281976e80716 .instagram-link{display:block;margin:0 20px 0 0;color:var(--global-primary-font-color);}#section-56d00219-b3d8-459e-8dda-281976e80716 .instagram-link .instagram-name{display:inline;margin:0;}#section-56d00219-b3d8-459e-8dda-281976e80716 .title+.instagram-link{margin-top:5px;}#section-56d00219-b3d8-459e-8dda-281976e80716 .top-wrapper{margin-bottom:20px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:flex-end;-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;}#section-56d00219-b3d8-459e-8dda-281976e80716 .top-right{margin-left:auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;}#section-56d00219-b3d8-459e-8dda-281976e80716 .follow-button{margin:20px 0 0 0;display:block;}#section-56d00219-b3d8-459e-8dda-281976e80716 .nav-button{margin-top:20px;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;width:42px;color:#1a1a1a;border:1px solid currentColor;cursor:pointer;transition-property:color,background-color,border-color;transition-duration:.3s;transition-timing-function:ease;}#section-56d00219-b3d8-459e-8dda-281976e80716 .nav-button.slick-disabled{opacity:0.6;pointer-events:none;cursor:default;}#section-56d00219-b3d8-459e-8dda-281976e80716 .nav-button:not(.slick-disabled):hover{background-color:#1a1a1a;border-color:#1a1a1a;color:#fff;}#section-56d00219-b3d8-459e-8dda-281976e80716 .top-nav-prev{margin-left:30px;}#section-56d00219-b3d8-459e-8dda-281976e80716 .top-nav-next{margin-left:10px;}#section-56d00219-b3d8-459e-8dda-281976e80716 .hidden-control{display:none;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi{position:relative;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 3);padding:10px;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single:first-child,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi:first-child{margin-left:auto;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single:last-child,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi:last-child{margin-right:auto;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single.type2,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi.type2{width:calc(100% / 5 * 2);}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single.type3,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi.type3{width:calc(100% / 2);}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single.type4,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi.type4{width:calc(100% / 2);}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single.type5,#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi.type5{width:100%;}@media (max-width: 440px){#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-container{padding:0;width:100%;}}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-feed{width:calc(100% + 20px);position:relative;
34left:-10px;overflow:hidden;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-slider{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item__img{position:absolute;left:-1px;top:-1px;bottom:-1px;right:-1px;background:center/cover no-repeat;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item__info{position:absolute;top:0;left:0;bottom:0;right:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;padding:10%;overflow:hidden;color:#fff;text-align:center;background-color:rgba(0, 0, 0, 0.8);opacity:0;-webkit-transition:opacity .3s ease;transition:opacity .3s ease;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item:hover .ig-feed-item__info{opacity:1;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item__caption{text-overflow:ellipsis;-webkit-line-clamp:4;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;}#section-56d00219-b3d8-459e-8dda-281976e80716 .video-icon{position:absolute;width:50px;height:50px;background-color:#fff;left:50%;top:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);border-radius:50%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-transition:opacity .2s ease;transition:opacity .2s ease;opacity:1;}#section-56d00219-b3d8-459e-8dda-281976e80716 .video-icon::before{content:'';display:block;width:0px;height:0px;border-style:solid;position:relative;left:1px;border-width:7.5px 0px 7.5px 11px;border-color:transparent transparent transparent #292826;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item:hover .video-icon{opacity:0;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single .ig-feed-item__info{padding:15%;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-single .ig-feed-item__caption{-webkit-line-clamp:7;}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed-item{background-color:var(--tileColor, #000);display:block;width:100%;padding-bottom:125%;overflow:hidden;position:relative;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi::before{content:'';display:block;width:100%;padding-bottom:125%;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi-content{padding:10px;position:absolute;width:100%;height:100%;left:0;top:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;overflow:hidden;}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi-content .ig-feed-item{width:calc(50% - 10px);padding-bottom:calc(62.5% - 12.5px);}#section-56d00219-b3d8-459e-8dda-281976e80716 .slide-multi-content .ig-feed-item:nth-child(n + 3){-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;}#section-56d00219-b3d8-459e-8dda-281976e80716 .bottom-controls{width:100%;display:none;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}#section-56d00219-b3d8-459e-8dda-281976e80716 .bottom-nav-button{-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;margin:20px 10px 0;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;
34-webkit-justify-content:center;justify-content:center;width:48px;height:48px;color:#1a1a1a;border:1px solid currentColor;cursor:pointer;}#section-56d00219-b3d8-459e-8dda-281976e80716 .bottom-nav-button.slick-disabled{opacity:0.6;pointer-events:none;cursor:default;}@media (max-width: 767px){#section-56d00219-b3d8-459e-8dda-281976e80716 .top-right,#section-56d00219-b3d8-459e-8dda-281976e80716 .top-left{width:100%;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}#section-56d00219-b3d8-459e-8dda-281976e80716 .title,#section-56d00219-b3d8-459e-8dda-281976e80716 .instagram-link{margin-right:0;text-align:center;}#section-56d00219-b3d8-459e-8dda-281976e80716 .top-nav-prev,#section-56d00219-b3d8-459e-8dda-281976e80716 .top-nav-next{display:none;}#section-56d00219-b3d8-459e-8dda-281976e80716 .bottom-controls{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}}#section-56d00219-b3d8-459e-8dda-281976e80716 .ig-feed{display:none;}#section-56d00219-b3d8-459e-8dda-281976e80716 .has-data .ig-feed{display:block;}#section-56d00219-b3d8-459e-8dda-281976e80716.has-data .ig-feed,#section-56d00219-b3d8-459e-8dda-281976e80716#section-temp .ig-feed{display:block;}#modal-global-contact-us .close{z-index:11;}#modal-global-contact-us .description{margin-bottom:15px;}#modal-global-contact-us .close:focus{outline:0;}#modal-global-contact-us .contact-form{padding:70px 0;width:100%;min-height:100vh;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;color:var(--colorTxt, #ffffff);-webkit-background-size:cover;background-size:cover;}#modal-global-contact-us .contact-form:after{content:'';position:absolute;display:block;background-color:rgba(2, 5, 7, 0.85);height:100%;width:100%;z-index:0;}#modal-global-contact-us .contact-form.loading textarea,#modal-global-contact-us .contact-form.loading input,#modal-global-contact-us .contact-form.loading label,#modal-global-contact-us .contact-form.loading button{pointer-events:none;opacity:.5;}#modal-global-contact-us .contact-form.loading .submit-icon{display:inline-block;}#modal-global-contact-us .contact-form .submit-icon{display:none;}#modal-global-contact-us .contact-form .contact-form-close{width:40px;height:50px;display:block;padding:0;border:none;background-color:transparent;cursor:pointer;position:absolute;right:50px;top:50px;z-index:110;}@media (max-width: 560px){#modal-global-contact-us .contact-form .contact-form-close{right:20px;top:20px;width:30px;height:40px;}}#modal-global-contact-us .contact-form .contact-form-close:before,#modal-global-contact-us .contact-form .contact-form-close:after{content:'';display:block;width:40px;height:1px;background-color:#fff;position:absolute;left:50%;top:50%;}@media (max-width: 560px){#modal-global-contact-us .contact-form .contact-form-close:before,#modal-global-contact-us .contact-form .contact-form-close:after{width:30px;}}#modal-global-contact-us .contact-form .contact-form-close:before{-webkit-transform:translate(-50%, -50%) rotate(45deg);-moz-transform:translate(-50%, -50%) rotate(45deg);-ms-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);}#modal-global-contact-us .contact-form .contact-form-close:after{-webkit-transform:translate(-50%, -50%) rotate(-45deg);-moz-transform:translate(-50%, -50%) rotate(-45deg);-ms-transform:translate(-50%, -50%) rotate(-45deg);transform:translate(-50%, -50%) rotate(-45deg);}#modal-global-contact-us .contact-form .container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;max-width:1440px;width:100%;padding:0 160px;margin:0 auto;z-index:10;}@media (max-width: 1320px){#modal-global-contact-us .contact-form .container{padding:0 80px;}}@media (max-width: 1200px){#modal-global-contact-us .contact-form .container{padding:0 30px;}}@media (max-width: 900px){#modal-global-contact-us .contact-form .container{-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}}
34@media (max-width: 560px){#modal-global-contact-us .contact-form .container{padding:0 20px;}}#modal-global-contact-us .contact-form h2{margin:0 0 18px 0;padding:0;}@media (max-width: 560px){#modal-global-contact-us .contact-form h2{margin:0 0 24px 0;}}#modal-global-contact-us .contact-form .section-details{width:50%;}@media (max-width: 1200px){#modal-global-contact-us .contact-form .section-details{padding-right:30px;}}@media (max-width: 900px){#modal-global-contact-us .contact-form .section-details{width:100%;padding-right:0;max-width:700px;margin-bottom:38px;}}#modal-global-contact-us .contact-form .section-message{width:50%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;position:relative;}@media (max-width: 1200px){#modal-global-contact-us .contact-form .section-message{padding-left:30px;}}@media (max-width: 900px){#modal-global-contact-us .contact-form .section-message{width:100%;padding-left:0;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}}#modal-global-contact-us .contact-form .section-message:after{content:'';position:absolute;display:block;width:1px;background:#999999;height:calc(100% + 50px);left:0;top:-20px;}@media (max-width: 900px){#modal-global-contact-us .contact-form .section-message:after{display:none;}}#modal-global-contact-us .contact-form .section-message form{max-width:435px;width:100%;}#modal-global-contact-us .contact-form .section-message form .submitButton{width:auto;}@media (max-width: 560px){#modal-global-contact-us .contact-form .section-message form .submitButton{width:100%;}}@media (max-width: 900px){#modal-global-contact-us .contact-form .section-message form{max-width:700px;}}#modal-global-contact-us .contact-form .section-message form.loading textarea,#modal-global-contact-us .contact-form .section-message form.loading input,#modal-global-contact-us .contact-form .section-message form.loading label,#modal-global-contact-us .contact-form .section-message form.loading button{pointer-events:none;opacity:.5;}#modal-global-contact-us .contact-form .section-message form.loading .label-loading{display:inline;}#modal-global-contact-us .contact-form .section-message form.loading .label-success,#modal-global-contact-us .contact-form .section-message form.loading .label-initial{display:none;}#modal-global-contact-us .contact-form .section-message form.loading .submit-icon{display:inline-block;}#modal-global-contact-us .contact-form .section-message form.success .label-loading,#modal-global-contact-us .contact-form .section-message form.success .label-initial{display:none;}#modal-global-contact-us .contact-form .section-message form.success .label-success{display:inline;}#modal-global-contact-us .contact-form .section-message .label-loading,#modal-global-contact-us .contact-form .section-message .label-success{display:none;}#modal-global-contact-us .contact-form .section-message .submit-icon{display:none;}#modal-global-contact-us .contact-form .section-message h2{margin-bottom:28px;}#modal-global-contact-us .contact-form .section-message .form-group_modal{-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:39px;}#modal-global-contact-us .contact-form .section-message .form-group_modal input{border:none;border-bottom:1px solid #c0c0c0;display:block;width:100%;background:transparent;color:#ffffff;height:22px;font-size:16px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .section-message .form-group_modal input{height:25px;}}#modal-global-contact-us .contact-form .section-message .form-group-textarea{margin-bottom:30px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .section-message .form-group-textarea{margin-bottom:23px;}}#modal-global-contact-us .contact-form .section-message label{display:block;width:100%;line-height:1.63;letter-spacing:1px;color:#c0c0c0;font-weight:bold;text-transform:uppercase;}#modal-global-contact-us .contact-form .section-message textarea{resize:none;height:105px;width:100%;background:transparent;border:solid 1px #ffffff;margin:23px 0 0 0;color:#ffffff;padding:10px;font-size:16px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .section-message textarea{margin:10px 0 0 0;height:89px;}}#modal-global-contact-us .contact-form .info-zone h4{margin:0 0 16px 0;}@media (max-width: 560px){#modal-global-contact-us .contact-form .info-zone h4{margin:0 0 13px 0;}}#modal-global-contact-us .contact-form .info-zone .type_user:nth-of-type(2){margin-bottom:30px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .info-zone .type_user{margin-bottom:58px;}}#modal-global-contact-us .contact-form .info-zone_contact{margin-bottom:23px;}#modal-global-contact-us .contact-form .info-zone_contact:nth-last-child(2){margin-bottom:30px;}#modal-global-contact-us .contact-form .info-zone_contact_cell{position:relative;padding-left:45px;margin-bottom:22px;font-weight:bold;font-size:14px;max-width:90%;letter-spacing:1.5px;text-transform:uppercase;}@media (max-width: 560px){#modal-global-contact-us .contact-form .info-zone_contact_cell{padding-left:0;}}#modal-global-contact-us .contact-form .info-zone_contact_cell:last-of-type{margin-bottom:0;}#modal-global-contact-us .contact-form .info-zone_contact_cell i{position:absolute;
34left:0;top:0;display:block;}@media (max-width: 560px){#modal-global-contact-us .contact-form .info-zone_contact_cell i{position:relative;margin-bottom:7px;}}#modal-global-contact-us .contact-form .info-zone_contact_cell i svg path{fill:var(--colorTxt);}#modal-global-contact-us .contact-form .info-zone_contact_cell div{padding:0;}#modal-global-contact-us .contact-form .info-zone_contact_cell .contact_title{line-height:1;margin-bottom:5px;}#modal-global-contact-us .contact-form .info-zone_contact_link{color:var(--colorTxt);}@media (max-width: 560px){#modal-global-contact-us .contact-form .info-zone .type_user:nth-of-type(2){margin-bottom:58px;}}@media (max-width: 560px){#modal-global-contact-us .contact-form .hours_box{margin-bottom:52px;}}#modal-global-contact-us .contact-form .socials_zone{padding-left:45px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .socials_zone{padding-left:0;}}#modal-global-contact-us .contact-form .socials_zone li{margin-bottom:10px;}#modal-global-contact-us .contact-form .socials_zone li:not(:last-child){padding-right:34px;}@media (max-width: 560px){#modal-global-contact-us .contact-form .socials_zone li:not(:last-child){padding-right:12px;}}#modal-global-contact-us .contact-form .success-message.success{margin-top:15px;color:var(--colorTxt);position:absolute;}#modal-global-contact-us .contact-form .success-message.hide{opacity:0;}#modal-global-contact-us .contact-form.one_contact .info-zone .type_user{margin-bottom:73px;}@media (max-width: 768px){#modal-global-contact-us .contact-form.one_contact .info-zone .type_user{margin-bottom:51px;}}@media (max-width: 560px){#modal-global-contact-us .contact-form.one_contact .info-zone .type_user{margin-bottom:40px;}}#modal-global-contact-us .contact-form.one_contact .hours_box{margin-bottom:38px;}#modal-global-contact-us .contact-form.no_icon .info-zone_contact_cell{padding-left:0;}#modal-global-contact-us .contact-form.no_icon .info-zone_contact_cell i{display:none;}#modal-global-contact-us .contact-form.no_icon .socials_zone{padding-left:0;}#modal-global-contact-us .contact-form .pre-line{white-space:pre-line;}#modal-global-contact-us .lp-input-group{margin-bottom:40px;}#modal-global-contact-us .lp-input-group.m16{margin-bottom:16px;}#modal-global-contact-us .lp-disclaimer{margin-top:0;}#modal-global-contact-us .lp-input{border-color:#ffffff;}#modal-global-contact-us .lp-input:focus,#modal-global-contact-us .lp-input:active{border-color:#5e5e5e;}nav{color:#fff;-webkit-transition:0.2s -webkit-transform ease;transition:0.2s transform ease;z-index:102;}nav.scroll .logo .logo__img.light{display:block;}nav.scroll .logo .logo__img.dark{display:none;}nav .header{height:100px;-webkit-transform:translateY(24px);-moz-transform:translateY(24px);-ms-transform:translateY(24px);transform:translateY(24px);}@media (max-width: 768px){nav .header{-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}}nav .header .container{max-width:1440px;padding:0 15px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;}@media (max-width: 1024px){nav .header .container{padding:0 15px;}}nav .header .navbar{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;min-height:70px;padding:8px 0 7px;width:100%;}nav .header .logo{z-index:911;position:relative;margin-right:10px;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}nav .header .logo a{overflow:hidden;display:inline-block;}nav .header .logo img{max-width:100%;max-height:52px;vertical-align:top;object-fit:contain;}@media (max-width: 1024px){nav .header .logo img{max-height:50px;}}nav .header .logo img.dark{display:none;}@media(max-width: 1024px){nav .header .logo img.dark{display:none!important;}}nav .header .logo img.light{display:block;}@media(max-width: 1024px){nav .header .logo img.light{display:inline-block!important;}}
34nav .header .logo__link{-webkit-animation-duration:1s;animation-duration:1s;overflow:hidden;}nav .header .logo__img.light{display:block;}nav .header .logo__img.dark{display:none;}nav .header .navigation{margin-left:auto;color:inherit;}@media (max-width: 1024px){nav .header .navigation{display:none;}}nav .header .navigation ul{position:relative;list-style-type:none;padding-left:0;margin-bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}nav .header .navigation ul li a span,nav .header .navigation ul li button span{position:relative;white-space:nowrap;}nav .header .navigation ul li a span:after,nav .header .navigation ul li button span:after{content:'';position:absolute;display:block;height:1px;background-color:#c6c6c6;width:0;bottom:0;left:0;-webkit-transition:all .2s ease;transition:all .2s ease;}nav .header .navigation ul li a:hover span:after,nav .header .navigation ul li button:hover span:after{width:100%;-webkit-transition:all .2s ease;transition:all .2s ease;}nav .header .navigation__item{padding:0;margin:0;}nav .header .navigation__link{display:block;padding:12px 13px;color:inherit;position:relative;font-size:13px;line-height:1.08;font-weight:700;letter-spacing:1.5px;background-color:transparent;border:none;cursor:pointer;text-align:left;text-transform:uppercase;}@media (max-width: 1280px){nav .header .navigation__link{padding:19px 10px;font-size:11.5px;}}nav .header .navigation__link .sub-nav-container .navigation__link:hover{background:#000000;}nav .header .navigation .sub-nav{position:absolute;bottom:0;padding:0;opacity:0;visibility:hidden;-webkit-transition:all .2s ease;transition:all .2s ease;-webkit-transform:translate(0, calc(100% + -10px));-moz-transform:translate(0, calc(100% + -10px));-ms-transform:translate(0, calc(100% + -10px));transform:translate(0, calc(100% + -10px));}nav .header .navigation .sub-nav ul{margin:0;padding:12px 0;display:block;background-color:rgba(26, 26, 26, .75);max-width:300px;}nav .header .navigation .sub-nav__item{position:relative;display:block;margin:0;text-align:left;}nav .header .navigation .sub-nav__item:last-child{border-bottom-color:transparent;}nav .header .navigation .sub-nav__link{display:block;max-width:300px;color:#ffffff;margin:0;line-height:1;letter-spacing:1.5px;padding:19px 13px;-webkit-transition:all .2s ease;transition:all .2s ease;}nav .header .navigation .sub-nav.visible{opacity:1;visibility:visible;-webkit-transform:translate(0, 100%);-moz-transform:translate(0, 100%);-ms-transform:translate(0, 100%);transform:translate(0, 100%);}nav .header .navigation .sub-nav.visible+.navigation__link{background:#000000;}nav .header .hamburger{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:none;padding:28px 13px;background-color:transparent;color:inherit;vertical-align:middle;cursor:pointer;outline:none;z-index:915;opacity:1;}nav .header .hamburger__bars{position:relative;display:block;width:26px;height:2px;background-color:currentColor;-webkit-transition:0.2s -webkit-transform ease;transition:0.2s transform ease;}nav .header .hamburger__bars:before,nav .header .hamburger__bars:after{content:'';display:block;width:26px;height:2px;background-color:currentColor;position:absolute;left:0;top:0;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:0.2s -webkit-transform ease;transition:0.2s transform ease;}nav .header .hamburger__bars:before{-webkit-transform:translateY(-9px);-moz-transform:translateY(-9px);-ms-transform:translateY(-9px);transform:translateY(-9px);}nav .header .hamburger__bars:after{-webkit-transform:translateY(9px);-moz-transform:translateY(9px);-ms-transform:translateY(9px);transform:translateY(9px);}nav .header .hamburger:hover{text-shadow:.5px 0 0,-.5px 0 0;}nav .header .hamburger:hover .hamburger__bars:before{-webkit-transform:translateY(-7px);-moz-transform:translateY(-7px);-ms-transform:translateY(-7px);transform:translateY(-7px);}nav .header .hamburger:hover .hamburger__bars:after{-webkit-transform:translateY(7px);-moz-transform:translateY(7px);-ms-transform:translateY(7px);transform:translateY(7px);}nav .header .hamburger.active .hamburger__bars{-webkit-transform:rotate(135deg);-moz-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);opacity:0;}nav .header .hamburger.active .hamburger__bars:before{display:none;}nav .header .hamburger.active .hamburger__bars:after{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg);}nav .content-container{-webkit-transition:0.2s all ease;transition:0.2s all ease;}nav.scroll .content-container,nav .scroll .content-container{-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}nav.scroll .content-container .navigation__link,nav .scroll .content-container .navigation__link{visibility:visible!important;}nav.scroll .content-container .navigation .sub-nav,nav .scroll .content-container .navigation .sub-nav{-webkit-transform:translate(0, calc(100% + -10px));-moz-transform:translate(0, calc(100% + -10px));-ms-transform:translate(0, calc(100% + -10px));transform:translate(0, calc(100% + -10px));}nav.scroll .content-container .navigation .sub-nav ul,nav .scroll .content-container .navigation .sub-nav ul{padding:0;}nav.scroll .content-container .navigation .sub-nav.visible,nav .scroll .content-container .navigation .sub-nav.visible{opacity:1;visibility:visible;-webkit-transform:translate(0, calc(100% + 23px));-moz-transform:translate(0, calc(100% + 23px));-ms-transform:translate(0, calc(100% + 23px));transform:translate(0, calc(100% + 23px));}nav .dark-opening{background-color:rgb(26, 26, 26)!important;}nav nav.dark-opening .header{margin-top:0;}nav #ctaShowButton,nav #ctaMessage{display:none!important;}nav #ctaShowButton{display:none;opacity:0;pointer-events:none;}nav .search{cursor:pointer;}nav .search svg{display:block;}nav .buttons-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;
34-webkit-justify-content:flex-end;justify-content:flex-end;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}body>div.sidemenu{background-color:#fff;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;}body>div.sidemenu{width:auto!important;left:auto!important;right:-100%;top:0;background-color:transparent;-webkit-transition:right .3s;transition:right .3s;display:block;}body>div.sidemenu:not(.visible){pointer-events:none;visibility:hidden;}body>div.sidemenu.visible{right:0;}body>div.sidemenu .sidebar{position:relative;width:400px;height:100vh;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding-top:40px;padding-bottom:100px;background-color:var(--bgColor, #fff);color:var(--fontColor, #000);font-family:var(--global-primary-font-family);font-size:21px;line-height:1.333333;letter-spacing:.5px;-webkit-transition:all .3s ease-in;transition:all .3s ease-in;}@media (max-width: 767px){body>div.sidemenu .sidebar{width:270px;font-size:18px;}}body>div.sidemenu .sidebar__content{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100%;width:100%;padding-left:40px;padding-right:40px;text-align:center;overflow-y:auto;}@media (max-width: 767px){body>div.sidemenu .sidebar__content{-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;padding-left:20px;padding-right:20px;}}body>div.sidemenu .sidebar__close{position:absolute;right:30px;top:30px;display:inline-block;width:38px;height:38px;padding:10px;border:none;border-radius:0;background:transparent;color:inherit;z-index:1;cursor:pointer;}body>div.sidemenu .sidebar__close:before,body>div.sidemenu .sidebar__close:after{content:'';display:block;width:22px;height:2px;background-color:currentColor;position:absolute;left:50%;top:50%;}body>div.sidemenu .sidebar__close:before{-webkit-transform:translate(-50%, -50%) rotate(45deg);-moz-transform:translate(-50%, -50%) rotate(45deg);-ms-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);}body>div.sidemenu .sidebar__close:after{-webkit-transform:translate(-50%, -50%) rotate(-45deg);-moz-transform:translate(-50%, -50%) rotate(-45deg);-ms-transform:translate(-50%, -50%) rotate(-45deg);transform:translate(-50%, -50%) rotate(-45deg);}@media (max-width: 767px){body>div.sidemenu .sidebar__close{right:10px;top:10px;}}body>div.sidemenu .sidebar__close:focus{outline:none;}body>div.sidemenu .sidebar__nav{list-style:none;padding:0;margin:auto 0;}body>div.sidemenu .sidebar__nav-item{margin:0;padding-top:4px;padding-bottom:4px;border-bottom:1px solid hsla( 35 var(--bgColor_H, 0), 36 var(--bgColor_S, 0%), 37 calc(50% + (var(--bgColor_L, 100%) - 50%) * 0.9), 38 var(--bgColor_A, 1) 39 );}body>div.sidemenu .sidebar__nav-link{display:inline-block;padding:10px;border:none;border-radius:0;background:transparent;text-transform:none;-webkit-transition:all .25s;transition:all .25s;cursor:pointer;color:inherit;}body>div.sidemenu .sidebar__nav-link:focus{outline:none;}body>div.sidemenu .sidebar__subnav{list-style:none;padding:4px 0 10px;margin:0;font-size:17px;}@media (max-width: 767px){body>div.sidemenu .sidebar__subnav{font-size:14px;letter-spacing:.3px;}}body>div.sidemenu .sidebar__subnav-item{margin-bottom:10px;}body>div.sidemenu .sidebar__subnav-item:last-child{margin-bottom:0;}body>div.sidemenu .sidebar__subnav-link{display:inline-block;padding:0;border:none;border-radius:0;background:transparent;text-transform:none;opacity:.7;-webkit-transition:all .25s;transition:all .25s;cursor:pointer;color:inherit;}body>div.sidemenu .sidebar__subnav-link:focus{outline:none;}body>div.sidemenu .sub-nav{visibility:hidden;opacity:0;max-height:0;-webkit-transition:all .3s;transition:all .3s;}body>div.sidemenu .sub-nav.visible{display:block;visibility:visible;opacity:1;max-height:100vh;}body>div.sidemenu .sub-nav.visible+.main-nav{color:#7a7a7a;}body>div.sidemenu .sub-nav.visible+.main-nav:after{margin-left:40px;border-bottom:2px solid var(--fontColor, #7a7a7a);border-right:2px solid var(--fontColor, #7a7a7a);}body>div.sidemenu .sub-nav-container{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse;}body>div.sidemenu .sub-nav-container:hover .main-nav:after{border-bottom:2px solid var(--fontColor, #7a7a7a);border-right:2px solid var(--fontColor, #7a7a7a);}body>div.sidemenu .sub-nav-container .main-nav{position:relative;display:inline-block;}body>div.sidemenu .sub-nav-container .main-nav:after{content:'';display:inline-block;position:relative;width:8px;height:8px;margin-left:25px;-webkit-transform:rotate(45deg) translateX(-100%);-moz-transform:rotate(45deg) translateX(-100%);-ms-transform:rotate(45deg) translateX(-100%);transform:rotate(45deg) translateX(-100%);border-bottom:2px solid var(--fontColor, #000000);border-right:2px solid var(--fontColor, #000000);top:0;bottom:auto;left:auto;-webkit-transition:0.5s all ease;transition:0.5s all ease;background-color:transparent;}body>div.sidemenu #main-section .sidebar{-webkit-transform:translateX(0);-moz-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}footer{background-color:#fff;color:#000000;--fontColor:#000000;--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;--greyColor:hsla( 40var(--fontColor_H), 41var(--fontColor_S), 42calc(var(--fontColor_L) + (50% - var(--fontColor_L)) * 0.445), 43var(--fontColor_A));}footer .redesign .inp--dark-bg input{color:var(--fontColor);border-color:hsla( 44 var(--fontColor_H), 45 var(--fontColor_S), 46 calc(var(--fontColor_L) + (50% - var(--fontColor_L)) * 0.445), 47 var(--fontColor_A));}footer .redesign .inp--dark-bg input:hover{border-color:var(--fontColor);}footer .redesign .inp+.inp{margin-top:24px;}footer .redesign .btn--primary-light{border-color:var(--fontColor);color:var(--fontColor);}footer .redesign .btn--primary-light:hover{background-color:var(--fontColor);color:var(--bgColor);}footer.is-background-color-light .redesign .btn--primary-light{border-width:1px;}footer .redesign .socials--grey{-webkit-box-pack:end;-ms-flex-pack:end;
47-webkit-justify-content:flex-end;justify-content:flex-end;}footer .redesign .socials--grey .socials__link{background-color:hsla( 48 var(--bgColor_H), 49 var(--bgColor_S), 50 calc(var(--bgColor_L) + (50% - var(--bgColor_L)) * 0.15), 51 var(--bgColor_A));color:var(--greyColor);}footer .redesign .socials--grey .socials__link svg{fill:var(--greyColor);}footer .redesign .socials--grey .socials__link:hover{background-color:hsla( 52 var(--bgColor_H), 53 var(--bgColor_S), 54 calc(var(--bgColor_L) + (50% - var(--bgColor_L)) * 0.4), 55 var(--bgColor_A));color:var(--fontColor);}footer .redesign .socials--grey .socials__link:hover svg{fill:var(--fontColor);}footer .redesign.footer .grey-text{color:var(--fontColor);}footer .footer{position:relative;padding-top:60px;padding-bottom:30px;}@media (max-width: 560px){footer .footer{padding-top:10px;}}@media (max-width: 500px){footer .footer{padding-bottom:70px;}}footer .footer .text_content_wrap p{margin-bottom:15px;}footer .footer .text_content_wrap p:last-of-type{margin-bottom:0;}footer .footer .container{max-width:1440px;}@media (max-width: 768px){footer .footer .container{padding-left:25px;padding-right:25px;}}@media (max-width: 560px){footer .footer .container{padding-left:20px;padding-right:20px;}}footer .footer h3{margin:0 0 15px 0;}footer .footer h5{text-transform:capitalize;}footer .footer .info-wrap{margin-bottom:40px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}footer .footer .info-wrap .agent_box{width:70%;}@media (max-width: 1280px){footer .footer .info-wrap .agent_box{width:50%;}}@media (max-width: 768px){footer .footer .info-wrap .agent_box{width:100%;}}footer .footer .info-wrap .newsletter_box{width:30%;}@media (max-width: 1280px){footer .footer .info-wrap .newsletter_box{width:50%;}}@media (max-width: 768px){footer .footer .info-wrap .newsletter_box{width:100%;}}footer .footer .info-wrap .newsletter_box--padding{padding-top:44px;}@media (max-width: 768px){footer .footer .info-wrap .newsletter_box--padding{padding-top:0;}}footer .footer .info-wrap .newsletter_box .contact_title{margin-bottom:13px;line-height:1.6;}@media (max-width: 768px){footer .footer .info-wrap .newsletter_box .info-wrap-contact_cell{margin-bottom:0;padding-left:0;}}@media (max-width: 768px){footer .footer .info-wrap .newsletter_box .icon_text{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:22px;position:relative;}footer .footer .info-wrap .newsletter_box .icon_text i{position:relative;width:30px;margin-right:20px;}footer .footer .info-wrap .newsletter_box .icon_text .contact_title{margin-bottom:0;}}@media (max-width: 768px){footer .footer .info-wrap .newsletter_box .info-wrap-contact_zone{margin-bottom:0;}}footer .footer .info-wrap-contact{position:relative;}footer .footer .info-wrap-contact_zone{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;margin-bottom:39px;}@media (max-width: 768px){footer .footer .info-wrap-contact_zone{margin-bottom:21px;}footer .footer .info-wrap-contact_zone:last-child{margin-bottom:51px;}}footer .footer .info-wrap-contact_zone i{position:absolute;left:0;display:block;}footer .footer .info-wrap-contact_zone i svg path{fill:currentColor;}footer .footer .info-wrap-contact_zone h4{margin:0 0 13px 0;width:100%;}footer .footer .info-wrap-contact_cell{position:relative;padding-left:50px;width:400px;font-size:14px;text-transform:uppercase;font-weight:bold;letter-spacing:1.5px;}@media (max-width: 1280px){footer .footer .info-wrap-contact_cell:first-of-type{margin-bottom:21px;}}footer .footer .info-wrap-contact_cell .contact_title{line-height:1;margin-bottom:5px;}footer .footer .info-wrap-contact_link{color:var(--greyColor);position:relative;}@media (max-width: 560px){footer .footer .info-wrap-contact_link{letter-spacing:0;}}footer .footer .hvr_animation{position:relative;-webkit-text-decoration:none!important;text-decoration:none!important;}footer .footer .hvr_animation:after{content:'';position:absolute;
55left:0;bottom:0;width:0%;height:1px;background:var(--greyColor);-webkit-transition:.3s linear;transition:.3s linear;}footer .footer .hvr_animation:hover:after{width:100%;}footer .footer .hvr_animation.underlined:after{width:100%;}footer .footer .hvr_animation.underlined:hover:after{width:0%;}footer .footer .form-content{padding:0!important;}footer .footer .form-content label{color:var(--fontColor);text-transform:none;letter-spacing:1;}footer .footer .form-content input{padding:2px 24px 2px 0;}footer .footer .form-content .subscribe_btn{margin-top:20px;position:relative;}footer .footer .form-content .subscribe_btn i{font-size:18px;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);opacity:0;}footer .footer .form-content.success i{opacity:1;}footer .footer .form-content.success .subscribe_btn span{opacity:0;}footer .footer .form-content.success .hide{opacity:0;}footer .footer .form-content.success .hide +span{opacity:1;}footer .footer .text_footer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;margin-bottom:39px;}@media (max-width: 1280px){footer .footer .text_footer{-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}}@media (max-width: 560px){footer .footer .text_footer{text-align:center;}}footer .footer .text_footer p{white-space:normal;}footer .footer .text_footer .images_box{max-width:186px;width:100%;margin-right:43px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}@media (max-width: 560px){footer .footer .text_footer .images_box{margin:0 auto 20px auto;}}@media (max-width: 1280px){footer .footer .text_footer .img_size{margin-bottom:20px;}}@media (max-width: 560px){footer .footer .text_footer .img_size{margin-bottom:0;}}footer .footer .text_footer .img_size img{width:100%;height:100%;object-fit:contain;}footer .footer .first_text_footer .img_size{width:100%;height:63px;}footer .footer .first_text_footer .img_size img{width:100%;height:100%;object-fit:contain;}@media (max-width: 768px){footer .footer .first_text_footer{margin-bottom:51px;}}footer .footer .second_text_footer .first_img_size{width:45px;height:45px;margin-right:15px;}footer .footer .second_text_footer .second_img_size{width:100px;height:45px;}@media (max-width: 560px){footer .footer .second_text_footer{margin-bottom:21px;}}footer .footer .info-privacy{padding-top:45px;padding-bottom:30px;border-top:1px solid hsla( 56 var(--bgColor_H), 57 var(--bgColor_S), 58 calc(var(--bgColor_L) + (50% - var(--bgColor_L)) * 0.55), 59 var(--bgColor_A));}@media (max-width: 768px){footer .footer .info-privacy{padding-top:0;border-top:none;}}footer .footer .info-privacy__row{-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}footer .footer .info-privacy .copy_zone{font-size:18px;}@media (min-width: 1350px){footer .footer .info-privacy .copy_zone{text-align:center;}}@media (min-width: 1281px){footer .footer .info-privacy .copy_zone{padding-top:8px;padding-bottom:8px;}}@media (max-width: 768px){footer .footer .info-privacy .copy_zone{text-align:center;margin-bottom:10px;padding-top:45px;border-top:1px solid hsla( 60 var(--bgColor_H), 61 var(--bgColor_S), 62 calc(var(--bgColor_L) + (50% - var(--bgColor_L)) * 0.55), 63 var(--bgColor_A));}}footer .footer .info-privacy .copy_zone a{color:var(--greyColor);}footer .footer .info-privacy .powered_zone{font-size:18px;}@media (min-width: 1281px){footer .footer .info-privacy .powered_zone{padding-top:8px;padding-bottom:8px;}}@media (max-width: 1280px){footer .footer .info-privacy .powered_zone{text-align:center;}}@media (max-width: 768px){footer .footer .info-privacy .powered_zone{text-align:center;margin-bottom:24px;}}footer .footer .info-privacy .powered_zone a{color:var(--greyColor);}@media (min-width: 1281px){footer .footer .info-privacy .socials_zone{-webkit-box-flex-wrap:nowrap;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}@media (max-width: 1280px){footer .footer .info-privacy .socials_zone{width:100%;margin-top:20px;-webkit-box-pack:start;-ms-flex-pack:start;
63-webkit-justify-content:flex-start;justify-content:flex-start;}}@media (max-width: 768px){footer .footer .info-privacy .socials_zone{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;margin-top:0;margin-bottom:20px;}footer .footer .info-privacy .socials_zone li{padding:0 7px 10px 7px;}}footer .footer.one_contact .type_user{margin-bottom:73px;}@media (max-width: 768px){footer .footer.one_contact .type_user{margin-bottom:51px;}}footer .footer.no_newsletter h3{margin-bottom:46px;}footer .footer.no_newsletter .newsletter_box{display:none;}footer .footer.no_newsletter .info-wrap-contact{width:calc(70% + 230px);width:100%;padding-left:230px;}@media (max-width: 1200px){footer .footer.no_newsletter .info-wrap-contact{padding-left:0;}}@media (max-width: 768px){footer .footer.no_newsletter .info-wrap-contact{width:100%;}}@media (max-width: 1200px){footer .footer.no_newsletter .info-wrap-contact_cell{width:50%;}}@media (max-width: 768px){footer .footer.no_newsletter .info-wrap-contact_cell{width:100%;}}footer .footer.no_newsletter .info-wrap-contact h4{position:absolute;margin-top:-8px;left:0;max-width:200px;}@media (max-width: 1200px){footer .footer.no_newsletter .info-wrap-contact h4{position:relative;left:auto;max-width:100%;width:100%;margin-bottom:20px;margin-top:0;}}@media (max-width: 768px){footer .footer.no_newsletter .info-wrap-contact h4{position:relative;left:auto;max-width:100%;}}footer .footer.no_newsletter .info-wrap-contact_zone:first-of-type{margin-bottom:71px;}@media (max-width: 1200px){footer .footer.no_newsletter .info-wrap-contact_zone:first-of-type{margin-bottom:39px;}}@media (max-width: 768px){footer .footer.no_newsletter .info-wrap-contact_zone:first-of-type{margin-bottom:51px;}}footer .footer.no_newsletter .info-wrap-contact_zone:last-child{margin-bottom:0;}footer .footer.no_icon .info-wrap-contact_cell{padding-left:0;}footer .footer.no_icon .info-wrap-contact_cell i{display:none;}footer .footer.no-names .info-wrap-contact{padding-left:0;}footer .form-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;margin-left:-15px;margin-right:-15px;}@media (min-width: 1281px){footer .form-row{-webkit-box-flex-wrap:nowrap;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}@media (max-width: 900px){footer .form-row{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}}footer .form-col{-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%;padding-left:15px;padding-right:15px;}@media (min-width: 768px){footer .form-col{-webkit-flex:1 1 0;-ms-flex:1 1 0;flex:1 1 0;}}@media (min-width: 768px){footer .form-col--socials{-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%;}}@media (min-width: 1281px){footer .form-col--socials{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;}}@media (max-width: 768px){footer .form-col--socials{-webkit-order:-1;-ms-flex-order:-1;order:-1;}}@media (min-width: 1281px){footer .form-col--xl-auto{-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;}}footer .additional-links-separator{display:block;width:100%;height:0;overflow:hidden;}@media (min-width: 768px){footer .additional-links-separator{display:inline;width:auto;height:auto;}footer .additional-links-separator:before{content:"|";}}footer .h-pot{height:0;width:0;overflow:hidden;visibility:hidden;}footer .img-wrap{max-width:100px;width:100%;display:block;margin-right:20px;}@media (max-width: 900px){footer .img-wrap{margin-right:0;margin-bottom:10px;}}footer .img-wrap img{width:100%;object-fit:cover;}footer .powered-box{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;}@media (max-width: 900px){footer .powered-box{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}}footer .form-col--copyright{-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;margin:10px 0;}footer .luxury-link{white-space:nowrap;}footer .footer__disclaimers{padding-top:24px;padding-bottom:24px;}@media (max-width: 900px){footer .footer__disclaimers{text-align:center;}}body>div.mobile-contact-wrapper{z-index:200;position:relative;}body>div.mobile-contact-wrapper .lp-ico:before{content:'';width:1em;height:1em;background-color:currentColor;-webkit-background-size:cover;background-size:cover;display:block;-webkit-mask-position:center;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-transition:all .3s;transition:all .3s;}body>div.mobile-contact-wrapper .lp-ico-search:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewB
63ox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.6231 21.3002L17.1372 16.8143M19.5606 10.9877C19.5606 15.5441 15.8669 19.2377 11.3106 19.2377C6.75421 19.2377 3.06055 15.5441 3.06055 10.9877C3.06055 6.43135 6.75421 2.73769 11.3106 2.73769C15.8669 2.73769 19.5606 6.43135 19.5606 10.9877Z' stroke='black' stroke-width='1.82813' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.6231 21.3002L17.1372 16.8143M19.5606 10.9877C19.5606 15.5441 15.8669 19.2377 11.3106 19.2377C6.75421 19.2377 3.06055 15.5441 3.06055 10.9877C3.06055 6.43135 6.75421 2.73769 11.3106 2.73769C15.8669 2.73769 19.5606 6.43135 19.5606 10.9877Z' stroke='black' stroke-width='1.82813' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.6231 21.3002L17.1372 16.8143M19.5606 10.9877C19.5606 15.5441 15.8669 19.2377 11.3106 19.2377C6.75421 19.2377 3.06055 15.5441 3.06055 10.9877C3.06055 6.43135 6.75421 2.73769 11.3106 2.73769C15.8669 2.73769 19.5606 6.43135 19.5606 10.9877Z' stroke='black' stroke-width='1.82813' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}body>div.mobile-contact-wrapper .lp-ico-arrow-top:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='17' height='16' viewBox='0 0 17 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.8716 9.99976L8.87158 5.99976L4.87158 9.99976' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='17' height='16' viewBox='0 0 17 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.8716 9.99976L8.87158 5.99976L4.87158 9.99976' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='17' height='16' viewBox='0 0 17 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.8716 9.99976L8.87158 5.99976L4.87158 9.99976' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}body>div.mobile-contact-wrapper .lp-ico-scroll-top:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 3H3M12 21V7M12 7L5 14M12 7L19 14' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 3H3M12 21V7M12 7L5 14M12 7L19 14' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 3H3M12 21V7M12 7L5 14M12 7L19 14' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");}body>div.mobile-contact-wrapper .lp-ico-close:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.5986 6.32617L5.59863 18.3262M5.59863 6.32617L17.5986 18.3262' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.5986 6.32617L5.59863 18.3262M5.59863 6.32617L17.5986 18.3262' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.5986 6.32617L5.59863 18.3262M5.59863 6.32617L17.5986 18.3262' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E ");}body>div.mobile-contact-wrapper .lp-ico-phone:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.8
63699 6.57142C14.7459 6.74157 15.551 7.16808 16.1821 7.79637C16.8132 8.42465 17.2416 9.22612 17.4126 10.0982M13.8699 3C15.6899 3.20128 17.3871 4.01265 18.6827 5.3009C19.9784 6.58914 20.7955 8.27768 21 10.0893M10.4412 13.592C9.36357 12.5192 8.51264 11.3061 7.88843 10.0118C7.83474 9.90047 7.80789 9.84481 7.78726 9.77437C7.71397 9.52405 7.76662 9.21668 7.91909 9.00469C7.962 8.94504 8.01326 8.894 8.11578 8.79194C8.42933 8.47979 8.58611 8.32372 8.6886 8.16677C9.07515 7.57491 9.07515 6.81189 8.6886 6.22002C8.58611 6.06308 8.42933 5.90701 8.11578 5.59486L7.94101 5.42087C7.46438 4.94637 7.22607 4.70912 6.97012 4.58024C6.4611 4.32392 5.85996 4.32392 5.35093 4.58024C5.09499 4.70912 4.85667 4.94637 4.38004 5.42087L4.23867 5.56161C3.76367 6.03449 3.52617 6.27093 3.34478 6.59239C3.1435 6.94909 2.99878 7.5031 3.00001 7.91222C3.00111 8.28092 3.07295 8.53291 3.21664 9.03688C3.98881 11.7453 5.44574 14.3009 7.58743 16.4331C9.72911 18.5652 12.2963 20.0156 15.0168 20.7843C15.523 20.9274 15.7761 20.9989 16.1465 21C16.5575 21.0012 17.114 20.8571 17.4723 20.6568C17.7952 20.4762 18.0327 20.2397 18.5077 19.7669L18.649 19.6261C19.1257 19.1516 19.364 18.9144 19.4934 18.6596C19.7509 18.1528 19.7509 17.5544 19.4934 17.0476C19.364 16.7928 19.1257 16.5556 18.649 16.0811L18.4743 15.9071C18.1607 15.5949 18.0039 15.4388 17.8463 15.3368C17.2518 14.952 16.4853 14.952 15.8908 15.3368C15.7332 15.4388 15.5764 15.5949 15.2628 15.9071C15.1603 16.0091 15.1091 16.0602 15.0491 16.1029C14.8362 16.2547 14.5274 16.3071 14.276 16.2341C14.2052 16.2136 14.1493 16.1869 14.0375 16.1334C12.7374 15.512 11.5189 14.6648 10.4412 13.592Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.8699 6.57142C14.7459 6.74157 15.551 7.16808 16.1821 7.79637C16.8132 8.42465 17.2416 9.22612 17.4126 10.0982M13.8699 3C15.6899 3.20128 17.3871 4.01265 18.6827 5.3009C19.9784 6.58914 20.7955 8.27768 21 10.0893M10.4412 13.592C9.36357 12.5192 8.51264 11.3061 7.88843 10.0118C7.83474 9.90047 7.80789 9.84481 7.78726 9.77437C7.71397 9.52405 7.76662 9.21668 7.91909 9.00469C7.962 8.94504 8.01326 8.894 8.11578 8.79194C8.42933 8.47979 8.58611 8.32372 8.6886 8.16677C9.07515 7.57491 9.07515 6.81189 8.6886 6.22002C8.58611 6.06308 8.42933 5.90701 8.11578 5.59486L7.94101 5.42087C7.46438 4.94637 7.22607 4.70912 6.97012 4.58024C6.4611 4.32392 5.85996 4.32392 5.35093 4.58024C5.09499 4.70912 4.85667 4.94637 4.38004 5.42087L4.23867 5.56161C3.76367 6.03449 3.52617 6.27093 3.34478 6.59239C3.1435 6.94909 2.99878 7.5031 3.00001 7.91222C3.00111 8.28092 3.07295 8.53291 3.21664 9.03688C3.98881 11.7453 5.44574 14.3009 7.58743 16.4331C9.72911 18.5652 12.2963 20.0156 15.0168 20.7843C15.523 20.9274 15.7761 20.9989 16.1465 21C16.5575 21.0012 17.114 20.8571 17.4723 20.6568C17.7952 20.4762 18.0327 20.2397 18.5077 19.7669L18.649 19.6261C19.1257 19.1516 19.364 18.9144 19.4934 18.6596C19.7509 18.1528 19.7509 17.5544 19.4934 17.0476C19.364 16.7928 19.1257 16.5556 18.649 16.0811L18.4743 15.9071C18.1607 15.5949 18.0039 15.4388 17.8463 15.3368C17.2518 14.952 16.4853 14.952 15.8908 15.3368C15.7332 15.4388 15.5764 15.5949 15.2628 15.9071C15.1603 16.0091 15.1091 16.0602 15.0491 16.1029C14.8362 16.2547 14.5274 16.3071 14.276 16.2341C14.2052 16.2136 14.1493 16.1869 14.0375 16.1334C12.7374 15.512 11.5189 14.6648 10.4412 13.592Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.8699 6.57142C14.7459 6.74157 15.551 7.16808 16.1821 7.79637C16.8132 8.42465 17.2416 9.22612 17.4126 10.0982M13.8699 3C15.6899 3.20128 17.3871 4.01265 18.6827 5.3009C19.9784 6.58914 20.7955 8.27768 21 10.0893M10.4412 13.592C9.36357 12.5192 8.51264 11.3061 7.88843 10.0118C7.83474 9.90047 7.80789 9.84481 7.78726 9.77437C7.71397 9.52405 7.76662 9.21668 7.91909 9.00469C7.962 8.94504 8.01326 8.894 8.11578 8.79194C8.42933 8.47979 8.58611 8.32372 8.6886 8.16677C9.07515 7.57491 9.07515 6.81189 8.6886 6.22002C8.58611 6.06308 8.42933 5.90701 8.11578 5.59486L7.94101 5.42087C7.46438 4.94637 7.22607 4.70912 6.97012 4.58024C6.4611 4.32392 5.85996 4.32392 5.35093 4.58024C5.09499 4.70912 4.85667 4.94637 4.38004 5.42087L4.23867 5.56161C3.76367 6.03449 3.52617 6.27093 3.34478 6.59239C3.1435 6.94909 2.99878 7.5031 3.00001 7.91222C3.00111 8.28092 3.07295 8.53291 3.21664 9.03688C3.98881 11.7453 5.44574 14.3009 7.58743 16.4331C9.72911 18.5652 12.2963 20.0156 15.0168 20.7843C15.523 20.9274 15.7761 20.9989 16.1465 21C16.5575 21.0012 17.114 20.8571 17.4723 20.6568C17.7952 20.4762 18.0327 20.2397 18.5077 19.7669L18.649 19.6261C19.1257 19.1516 19.364 18.9144 19.4934 18.6596C19.7509 18.1528 19.7509 17.5544 19.4934 17.0476C19.364 16.7928 19.1257 16.5556 18.649 16.0811L18.4743 15.9071C18.1607 15.5949 18.0039 15.4388 17.8463 15.3368C17.2518 14.952 16.4853 14.952 15.8908 15.3368C15.7332 15.4388 15.5764 15.5949 15.2628 15.9071C15.1603 16.0091 15.1091 16.0602 15.0491 16.1029C14.8362 16.2547 14.5274 16.3071 14.276 16.2341C14.2052 16.2136 14.1493 16.1869 14.0375 16.1334C12.7374 15.512 11.5189 14.6648 10.4412 13.592Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}body>div.mobile-contact-wrapper .lp-ico-sms:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 11.5C21.0034 12.8199 20.6951 14.1219 20.1 15.3C19.3944 16.7117 18.3098 17.8992 16.9674 18.7293C15.6251 19.5594 14.0782 19.9994 12.5 20C11.1801 20.0034 9.87812 19.6951 8.7 19.1L3 21L4.9 15.3C4.30493 14.1219 3.99656 12.8199 4 11.5C4.00061 9.92176 4.44061 8.37485 5.27072 7.03255C6.10083 5.69025 7.28825 4.60557 8.7 3.9C9.87812 3.30493 11.1801 2.99656 12.5 3H13C15.0843 3.11499 17.053 3.99476 18.5291 5.47086C20.0052 6.94695 20.885 8.91565 21 11V11.5Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 11.5C21.0034 12.8199 20.6951 14.1219 20.1 15.3C19.3944 16.7117 18.3098 17.8992 16.9674 18.7293C15.6251 19.5594 14.0782 19.9994 12.5 20C11.1801 20.0034 9.87812 19.6951 8.7 19.1L3 21L4.9 15.3C4.30493 14.1219 3.99656 12.8199 4 11.5C4.00061 9.92176 4.44061 8.37485 5.27072 7.03255C6.10083 5.69025 7.28825 4.60557 8.7 3.9C9.87812 3.30493 11.1801 2.99656 12.5 3H13C15.0843 3.11499 17.053 3.99476 18.5291 5.47086C20.0052 6.94695 20.885 8.91565 21 11V11.5Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21 11.5C21.0034 12.8199 20.6951 14.1219 20.1 15.3C19.3944 16.7117 18.3098 17.8992 16.9674 18.7293C15.6251 19.5594 14.0782 19.9994 12.5 20C11.1801 20.0034 9.87812 19.6951 8.7 19.1L3 21L4.9 15.3C4.30493 14.1219 3.99656 12.8199 4 11.5C4.00061 9.92176 4.44061 8.37485 5.27072 7.03255C6.10083 5.69025 7.28825 4.60557 8.7 3.9C9.87812 3.30493 11.1801 2.99656 12.5 3H13C15.0843 3.11499 17.053 3.99476 18.5291 5.47086C20.0052 6.94695 20.885 8.91565 21 11V11.5Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}body>div.mobile-contact-wrapper .lp-ico-email:before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.5 18L14.85
6371 12M9.14286 12L2.50003 18M2 7L10.1649 12.7154C10.8261 13.1783 11.1567 13.4097 11.5163 13.4993C11.8339 13.5785 12.1661 13.5785 12.4837 13.4993C12.8433 13.4097 13.1739 13.1783 13.8351 12.7154L22 7M6.8 20H17.2C18.8802 20 19.7202 20 20.362 19.673C20.9265 19.3854 21.3854 18.9265 21.673 18.362C22 17.7202 22 16.8802 22 15.2V8.8C22 7.11984 22 6.27976 21.673 5.63803C21.3854 5.07354 20.9265 4.6146 20.362 4.32698C19.7202 4 18.8802 4 17.2 4H6.8C5.11984 4 4.27976 4 3.63803 4.32698C3.07354 4.6146 2.6146 5.07354 2.32698 5.63803C2 6.27976 2 7.11984 2 8.8V15.2C2 16.8802 2 17.7202 2.32698 18.362C2.6146 18.9265 3.07354 19.3854 3.63803 19.673C4.27976 20 5.11984 20 6.8 20Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.5 18L14.8571 12M9.14286 12L2.50003 18M2 7L10.1649 12.7154C10.8261 13.1783 11.1567 13.4097 11.5163 13.4993C11.8339 13.5785 12.1661 13.5785 12.4837 13.4993C12.8433 13.4097 13.1739 13.1783 13.8351 12.7154L22 7M6.8 20H17.2C18.8802 20 19.7202 20 20.362 19.673C20.9265 19.3854 21.3854 18.9265 21.673 18.362C22 17.7202 22 16.8802 22 15.2V8.8C22 7.11984 22 6.27976 21.673 5.63803C21.3854 5.07354 20.9265 4.6146 20.362 4.32698C19.7202 4 18.8802 4 17.2 4H6.8C5.11984 4 4.27976 4 3.63803 4.32698C3.07354 4.6146 2.6146 5.07354 2.32698 5.63803C2 6.27976 2 7.11984 2 8.8V15.2C2 16.8802 2 17.7202 2.32698 18.362C2.6146 18.9265 3.07354 19.3854 3.63803 19.673C4.27976 20 5.11984 20 6.8 20Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M21.5 18L14.8571 12M9.14286 12L2.50003 18M2 7L10.1649 12.7154C10.8261 13.1783 11.1567 13.4097 11.5163 13.4993C11.8339 13.5785 12.1661 13.5785 12.4837 13.4993C12.8433 13.4097 13.1739 13.1783 13.8351 12.7154L22 7M6.8 20H17.2C18.8802 20 19.7202 20 20.362 19.673C20.9265 19.3854 21.3854 18.9265 21.673 18.362C22 17.7202 22 16.8802 22 15.2V8.8C22 7.11984 22 6.27976 21.673 5.63803C21.3854 5.07354 20.9265 4.6146 20.362 4.32698C19.7202 4 18.8802 4 17.2 4H6.8C5.11984 4 4.27976 4 3.63803 4.32698C3.07354 4.6146 2.6146 5.07354 2.32698 5.63803C2 6.27976 2 7.11984 2 8.8V15.2C2 16.8802 2 17.7202 2.32698 18.362C2.6146 18.9265 3.07354 19.3854 3.63803 19.673C4.27976 20 5.11984 20 6.8 20Z' stroke='white' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}body>div.mobile-contact-wrapper a{-webkit-text-decoration:none;text-decoration:none;}body>div.mobile-contact-wrapper .btn-holder{bottom:-50px;left:19px;position:fixed;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:13px;opacity:0;-webkit-transition:all .3s;transition:all .3s;}@media (max-width: 1024px){body>div.mobile-contact-wrapper .btn-holder{right:19px;padding:0 48px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}}body>div.mobile-contact-wrapper .btn-holder.visible{bottom:28px;opacity:1;}body>div.mobile-contact-wrapper .search-btn{width:48px;height:48px;border-radius:999px;font-size:0;line-height:0;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-transition:all .3s;transition:all .3s;padding:12px;color:#141414;background:#fff;}@media (max-width: 1024px){body>div.mobile-contact-wrapper .search-btn{position:absolute;left:0;bottom:0;}}body>div.mobile-contact-wrapper .search-btn:before{width:24px;height:24px;}body>div.mobile-contact-wrapper .connect-btn{height:48px;padding:0 24px;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:4px;text-transform:uppercase;border-radius:25px;color:var(--pillTextColor);background:var(--pillBackgroundColor);border:1px solid rgba(255, 255, 255, 0.2);cursor:pointer;font-size:10px;font-style:normal;font-weight:500;line-height:16px;letter-spacing:0.4px;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;-webkit-transition:all .4s;transition:all .4s;box-shadow:0 0 0 0 rgba(255, 255, 255, 0.2);-webkit-animation:pulsate 2s ease infinite;animation:pulsate 2s ease infinite;}body>div.mobile-contact-wrapper .connect-btn:before{width:16px;height:16px;}body>div.mobile-contact-wrapper .pop-up{display:none;position:fixed;bottom:0;left:0;width:100%;-webkit-transition:all .3s;transition:all .3s;border-radius:16px 16px 0 0;color:var(--textColor);background:var(--backgroundColor);}@media (min-width: 1025px){body>div.mobile-contact-wrapper .pop-up{max-width:637px;border-radius:16px;bottom:28px;left:19px;}}body>div.mobile-contact-wrapper .pop-up .lp-container{padding-top:24px;padding-bottom:24px;-webkit-box-pack:center;-ms-flex-pack:center;
63-webkit-justify-content:center;justify-content:center;}@media (min-width: 1025px){body>div.mobile-contact-wrapper .pop-up .lp-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-top:40px;padding-bottom:40px;min-height:450px;padding-left:56px;padding-right:56px;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}}body>div.mobile-contact-wrapper .pop-up .close-btn{width:44px;height:44px;background-color:transparent;border-color:transparent;display:block;margin:24px auto 0;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--textColor);cursor:pointer;padding:10px;border:0;}body>div.mobile-contact-wrapper .pop-up .close-btn:before{width:24px;height:24px;}@media (min-width: 1025px){body>div.mobile-contact-wrapper .pop-up .close-btn{position:absolute;top:14px;right:12px;margin:0;}}body>div.mobile-contact-wrapper .pop-up .icon-btn{width:44px;height:44px;border-radius:999px;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-left:8px;color:var(--textColor);position:relative;}body>div.mobile-contact-wrapper .pop-up .icon-btn:after{position:absolute;bottom:0;width:100%;left:0;border-radius:999px;
63height:100%;content:'';border:solid 1px var(--textColor);opacity:.3;}body>div.mobile-contact-wrapper .pop-up .icon-btn:before{width:24px;height:24px;}body>div.mobile-contact-wrapper .success-block{display:none;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}@media (min-width: 1025px){body>div.mobile-contact-wrapper .success-block{-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;}}body>div.mobile-contact-wrapper .success-block .lp-btn{margin-top:24px;}body>div.mobile-contact-wrapper .contact-form{margin:0;}@media (max-width: 1024px){body>div.mobile-contact-wrapper .contact-form__item{width:100%;}}body>div.mobile-contact-wrapper .contact-form__item .lp-input{width:100%;}body>div.mobile-contact-wrapper .contact-form__item .is-placeholder{color:#818181;}body>div.mobile-contact-wrapper .contact-form__item+.contact-form__item{margin-top:16px;}body>div.mobile-contact-wrapper .contact-form.show-success .contact-form__container,body>div.mobile-contact-wrapper .contact-form.success .contact-form__container{display:none;}body>div.mobile-contact-wrapper .contact-form.show-success .success-block,body>div.mobile-contact-wrapper .contact-form.success .success-block{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}body>div.mobile-contact-wrapper .contact-form .lp-disclaimer{margin-top:16px;}body>div.mobile-contact-wrapper .contact-form .lp-h3{margin-bottom:16px;}body>div.mobile-contact-wrapper .success-message{font-size:22px;}@-webkit-keyframes pulsate{0%{box-shadow:0 0 0 0 rgba(255, 255, 255, 0.2);}50%{box-shadow:0 0 4px 6px rgba(255, 255, 255, .5);}100%{box-shadow:0 0 12px 12px rgba(255, 255, 255, 0);}} 64 </style> 65 <style id="custom-style-css">.button-style-1{color:rgba(0,0,0,1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(0,0,0,1)!important;}.button-style-1:hover{color:rgba(255,255,255,1)!important;background-color:rgba(0,0,0,1)!important;border-color:rgba(0, 0, 0, 1)!important;}.hyperlink-style-1{color:rgba(0, 0, 0, 1)!important;}.hyperlink-style-1:hover{color:rgba(26, 26, 26, 1)!important;}.social_icons-style-1 a{border-color:rgba(0, 0, 0, 1)!important;background-color:rgba(0, 0, 0, 0)!important;color:rgba(0, 0, 0, 1)!important;}.social_icons-style-1 a:hover{border-color:rgba(0, 0, 0, 1)!important;background-color:rgba(0, 0, 0, 1)!important;color:rgba(255,255,255,1)!important;}.social_icons-style-1 a i{color:inherit!important;}
65.social_icons-style-1 a svg,.social_icons-style-1 a svg path{fill:currentColor!important;}.pagination-style-1 li a{color:rgba(0, 0, 0, 1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(0, 0, 0, 0)!important;}.pagination-style-1 li a:hover{color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 1)!important;border-color:rgba(0, 0, 0, 1)!important;}.pagination-style-1 li.active a{color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 1)!important;border-color:rgba(0, 0, 0, 1)!important;}.button-style-2{color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(255, 255, 255, 1)!important;}.button-style-2:hover{color:rgba(0, 0, 0, 1)!important;background-color:rgba(255, 255, 255, 1)!important;border-color:rgba(255, 255, 255, 1)!important;}.pagination-style-2 li a{color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(0, 0, 0, 0)!important;}.pagination-style-2 li a:hover{color:rgba(0, 0, 0, 1)!important;background-color:rgba(255, 255, 255, 1)!important;border-color:rgba(255,255,255,1)!important;}.pagination-style-2 li.active a{color:rgba(0, 0, 0, 1)!important;background-color:rgba(255, 255, 255, 1)!important;border-color:rgba(255,255,255,1)!important;}.hyperlink-style-2{color:rgba(255, 255, 255, 1)!important;}.hyperlink-style-2:hover{color:rgba(255, 255, 255, 0.7)!important;}.social_icons-style-2 a{border-color:rgba(255, 255, 255, 1)!important;background-color:rgba(0, 0, 0, 0)!important;color:rgba(255, 255, 255, 1)!important;}.social_icons-style-2 a:hover{border-color:rgba(255, 255, 255, 1)!important;background-color:rgba(255, 255, 255, 1)!important;color:rgba(0, 0, 0, 1)!important;}.social_icons-style-2 a i{color:inherit!important;}
65.social_icons-style-2 a svg,.social_icons-style-2 a svg path{fill:currentColor!important;}.button-style-5{color:rgba(255, 255, 255, 1)!important;background-color:#000000!important;border-color:#000000!important;}.button-style-5:hover{color:#000000!important;background-color:rgba(0, 0, 0, 0.01)!important;border-color:#000000!important;}.button-style-6{color:#000000!important;background-color:#FFFFFF!important;border-color:rgba(255, 255, 255, 1)!important;}.button-style-6:hover{color:#FFFFFF!important;background-color:rgba(0, 0, 0, 0)!important;border-color:#FFFFFF!important;}.button-style-7{color:rgba(255, 255, 255, 1)!important;background-color:rgba(233, 22, 29, 1)!important;border-color:rgba(233, 22, 29, 1)!important;}.button-style-7:hover{color:rgba(233, 22, 29, 1)!important;background-color:rgba(0, 0, 0, 0)!important;border-color:rgba(233, 22, 29, 1)!important;}</style> 66 67 68
68<script> 69 (function utmParse() { 70 const url = new URL(window.location.href); 71 if (url.search) { 72 const utm = url.search.split(/\?|&/g).reduce((acc, current) => { 73 const matched = current.match(/utm_(content|campaign|medium|source|term|id)|gclid/g); 74 if (matched) { 75 acc[matched[0]] = current.replace(`${matched[0]}=`, ''); 76 } 77 return acc; 78 }, {}); 79 if (Object.keys(utm).length) { 80 window.localStorage.setItem('utm_vars', JSON.stringify(utm)); 81 } else { 82 // Remove old utm vars 83 window.localStorage.removeItem('utm_vars'); 84 } 85 } 86 // Set referrer in local storage 87 // This is meant to be stored once to avoid self-referrals and to have the first referrer only. 88 if (!window.localStorage.getItem('referrer')) { 89 // Capture the Referrer URL 90 const referrer = document.referrer; 91 if (referrer) { 92 // Only store the referrer if it comes from outside the current domain (to avoid self-referrals) 93 const currentDomain = window.location.hostname; 94 const referrerDomain = new URL(referrer).hostname; 95 96 if (referrerDomain !== currentDomain) { 97 // Store it in localStorage 98 localStorage.setItem('referrer', referrer); 99 } 100 } 101 } 102 })(); 103 </script>
103 104 <!-- Bing Webmaster Tools Verification -->
105<script> 106 // Check if on the homepage before the body loads 107 if (window.location.pathname === '/' || window.location.pathname === '/index.html') { 108 document.write('<meta name="msvalidate.01" content="9444E455BC3D007F3F70BCA3F6F54DD2" />'); 109 } 110</script>
110 111 112 <!-- GOOGLE TRANSLATE STYLES are moved to external CSS --> 113</head> 114<body> 115 <div id="google_translate_element" style="display: none"></div> 116 117 <div id="global-loader" style="height:100%;width:100%;position:fixed;z-index:9999;left:0;top:0;background-color:rgba(255, 255, 255, 1);overflow-x:hidden;transition:1s;"> 118 <div style="position:absolute;height:100vh;text-align:center;bottom:0;left:0;right: 0;display:flex;align-items:center;"> 119 <img style="margin:0 auto;" src="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/8ab9f4fb-89c4-43c5-a8ad-aaf7eb3be956" /> 120 </div> 121 </div> 122
122<script> 123 if (window.sessionStorage.getItem('global_loading_displayed') === 'yes') { 124 (function () { 125 document.getElementById('global-loader').remove(); 126 })(); 127 } 128 </script>
128 129 130 <nav id="global-navbar" data-el-id="43e7a874-fb1e-4cdd-91fe-eb6bf5b9179b"> 131 <div class="redesign"> 132 <div class="content-container header"> 133 <div class="container header__container"> 134 <div class="navbar"> 135 <div class="logo"> 136 <a href="/" class="logo__link"> 137 <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/32c082a0-e184-4e12-a96e-d21e49649e43" 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/32c082a0-e184-4e12-a96e-d21e49649e43 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/32c082a0-e184-4e12-a96e-d21e49649e43 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/32c082a0-e184-4e12-a96e-d21e49649e43 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/32c082a0-e184-4e12-a96e-d21e49649e43 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/32c082a0-e184-4e12-a96e-d21e49649e43 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/32c082a0-e184-4e12-a96e-d21e49649e43 3456w" class="logo__img light" alt=""> 138 <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/947293ae-4ee4-4df4-a4bb-d1090c82cf83" 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 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/947293ae-4ee4-4df4-a4bb-d1090c82cf83 3456w" class="logo__img dark" alt=""> 139 </a> 140 </div> 141 <div class="navigation"> 142 <ul> 143 <li class="navigation__item"> 144 <a href="/team" class="navigation__link wow fadeInUp" data-wow-delay="2.0"><span>Meet the Team</span></a> 145 </li> 146 <li class="navigation__item sub-nav-container"> 147 <a href="#" class="navigation__link wow fadeInUp">Properties</a> 148 <div class="sub-nav"> 149 <ul> 150 <li class="sub-nav__item"><a href="/properties/sale" class="nav-link sub-nav__link feature"><span>Featured Properties</span></a></li> 151 <li class="sub-nav__item"><a href="/properties/sold" class="nav-link sub-nav__link feature"><span>Past Transactions</span></a></li> 152 </ul> 153 </div> 154 </li> 155 <li class="navigation__item"> 156 <a href="/neighborhoods" class="navigation__link wow fadeInUp" data-wow-delay="2.2"><span>Neighborhoods</span></a> 157 </li> 158 <li class="navigation__item"> 159 <a href="/home-search/listings" class="navigation__link wow fadeInUp" data-wow-delay="2.3"><span>Home Search</span></a> 160 </li> 161 <li class="navigation__item"> 162 <a href="/home-valuation" class="navigation__link wow fadeInUp" data-wow-delay="2.4"><span>Home Valuation</span></a> 163 </li> 164 <li class="navigation__item"> 165 <a data-type="CONTACT_US" class="navigation__link wow fadeInUp"><span>CONTACT Us</span></a> 166 </li> 167 <li class="navigation__item"> 168 <a href="tel:9545531089" class="navigation__link wow fadeInUp" data-wow-delay="2.6"><span>(954) 553-1089 </span></a> 169 </li> 170 </ul> 171 </div> 172 <div class="buttons-wrapper"> 173 <button type="button" class="hamburger-component hamburger">
174 <span class="hamburger__bars"></span> 175 </button> 176 </div> 177 </div> 178 </div> 179 </div> 180</div> 181 182 </nav> 183 <div id="global-sidemenu" class="sidemenu" data-el-id="11fa925d-d2dd-4213-a0fa-d46f769e2c18"> 184 <div class="sidebar"> 185 186 <button class="toggle sidebar__close close"></button> 187 <div class="sidebar__content"> 188 189 <ul class="sidebar__nav"> 190 <li class="sidebar__nav-item"> 191 <a href="/" class="sidebar__nav-link">Home</a> 192 </li> 193 <li class="sidebar__nav-item"> 194 <a href="/team" class="sidebar__nav-link">Meet the Team</a> 195 </li> 196 <li class="sidebar__nav-item sub-nav-container"> 197 <div class="sub-nav"> 198 <ul class="sidebar__subnav"> 199 <li class="sidebar__subnav-item"><a href="/properties/sale" class="sidebar__subnav-link">Featured Properties</a></li> 200 <li class="sidebar__subnav-item"><a href="/properties/sold" class="sidebar__subnav-link">Past Transactions</a></li> 201 </ul> 202 </div> 203 <a href="#" class="sidebar__nav-link link main-nav">Properties</a> 204 </li> 205 <li class="sidebar__nav-item"> 206 <a href="/home-search/listings" class="sidebar__nav-link">Home Search</a> 207 </li> 208 <li class="sidebar__nav-item"> 209 <a href="/home-valuation" class="sidebar__nav-link">Home Valuation</a> 210 </li> 211 <li class="sidebar__nav-item"> 212 <a href="/neighborhoods" class="sidebar__nav-link">Neighborhoods</a> 213 </li> 214 <li class="sidebar__nav-item"> 215 <a href="/testimonials" class="sidebar__nav-link">Testimonials</a> 216 </li> 217 <li class="sidebar__nav-item sub-nav-container"> 218 <div class="sub-nav"> 219 <ul class="sidebar__subnav"> 220 <li class="sidebar__subnav-item"><a href="/buyers-guide" class="sidebar__subnav-link">Buyer's Guide</a></li> 221 <li class="sidebar__subnav-item"><a href="/sellers-guide" class="sidebar__subnav-link">Seller's Guide</a></li> 222 </ul> 223 </div> 224 <a href="#" class="sidebar__nav-link link main-nav">Resources</a> 225 </li> 226 <li class="sidebar__nav-item"> 227 <a href="/concierge" class="sidebar__nav-link">Compass Concierge</a> 228 </li> 229 <li class="sidebar__nav-item"> 230 <a href="/blog" class="sidebar__nav-link">Blog</a> 231 </li> 232 <li class="sidebar__nav-item"> 233 <a href="/press" class="sidebar__nav-link">Press</a> 234 </li> 235 <li class="sidebar__nav-item"> 236 <a href="/contact" class="sidebar__nav-link">Contact Us</a> 237 </li> 238 <li class="sidebar__nav-item"> 239 <a href="/home-search/account" class="sidebar__nav-link">My Search Portal</a> 240 </li> 241 </ul> 242 </div> 243</div> 244 </div> 245 <div id="global-mobile-contact" class="mobile-contact-wrapper" data-el-id="befe5af2-a6ca-4119-924a-a85d96d36b51"> 246 <div class="btn-holder" 247style=" 248--backgroundColor: rgba(255, 255, 255, 1); 249--textColor: rgba(26, 26, 26, 1); 250--pillTextColor: rgba(26, 26, 26, 1); 251--pillBackgroundColor: rgba(255, 255, 255, 1);"> 252 253 <button type="button" class="connect-btn lp-ico lp-ico-arrow-top visible">Contact Us</button> 254</div> 255 256 257<div class="pop-up" style="--backgroundColor: rgba(255, 255, 255, 1); --textColor: rgba(26, 26, 26, 1);"> 258 <div class="lp-container"> 259 <form data-type="contact-form" class="contact-form"> 260 <div class="contact-form__container"> 261 <h3 class="lp-h3">Leave a Message</h3> 262 263 <div class="contact-form__content"> 264 <div class="contact-form__inputs-container"> 265 <div class="contact-form__item"> 266 <input 267 id="__FullName" 268 type="text" name="name" 269 class="lp-input lp-input--light" 270 required 271 placeholder="Full Name"> 272 </div> 273 <div class="contact-form__item"> 274 <input 275 id="__Email" 276 type="email" name="email" 277 class="lp-input js-email-input lp-input--light" 278 required 279 placeholder="Email"> 280 </div> 281 <div class="contact-form__item"> 282 <input
283 class="lp-input lp-input--light" 284 type="tel" 285 placeholder="Phone" 286 id="__Phone" 287 name="phone" 288 required> 289 </div> 290 291 <div class="contact-form__item input-group-select"> 292 <select name="interest" id="-field-interest" placeholder="Interest" 293 class="lp-input dropdown-select js-select js-form-element lp-input--light" required> 294 <option value="" disabled selected data-label="Interest">Interested in...</option> 295 <option value="Selling & Buying">Selling & Buying</option> 296 <option value="Selling">Selling</option> 297 <option value="Buying">Buying</option> 298 <option value="Renting">Renting</option> 299 <option value="Other">Other</option> 300 </select> 301 <label for="-field-interest" class="lp-label sr-only">Interest</label> 302 </div> 303 304 <div class="contact-form__item"> 305 <textarea 306 name="message" 307 rows="4" 308 id="__Message" 309 class="lp-input lp-input--light" 310 placeholder="Message" 311 required></textarea> 312 </div> 313 <div class="lp-disclaimer"> <label style='display: none;' for='-termsAccepted'>Opt In/Disclaimer Consent:</label> 314 <label class='lp-tcr-content'> 315 <span class='lp-tcr-checkbox'> 316 <input 317 type='checkbox' 318 id='-termsAccepted' 319 name='termsAccepted' 320 oninvalid="this.setCustomValidity('Please accept the terms and conditions')" 321 oninput="this.setCustomValidity('')" 322 required 323 /></span> 324 <span class='lp-tcr-message'> 325 326 I agree to be contacted by 327 The Gobin Group 328 via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance. 329 You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary. 330 <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>. 331 </span> 332 </label> 333 334</div> 335 <button type="submit" class="lp-btn lp-btn--filled lp-btn--dark submit contact-form__item">Submit</button> 336 337 <div class="lp-h-pot"> 338 <input id="__newsSignMiddleName" name="middleName" value="" autocomplete="off" tabindex="-1"> 339 </div> 340 341 <input style="display: none;" type="text" name="source" value="CONTACT_INQUIRY" /> 342 <input type="hidden" name="button_text" value="Contact Us"> 343 </div> 344 </div> 345 </div> 346 347 348 <div class="success-block"> 349 <h3 class="lp-h3 success-message">Thank you for your message. We will be in touch with you shortly.</h3> 350 351 </div> 352 </form> 353 354 <button type="button" class="close-btn lp-ico lp-ico-close"></button> 355 356 357 </div> 358</div> 359 360 361 </div> 362 <section class="image-section is-font-color-light is-background-color-light" id="section-02c84b7e-634c-47be-91b2-a3796ee118a3" data-el-id="e6c6941b-dd32-4d6b-b4aa-56593f2d58bb"> 363 <div class="redesign custom-intro"> 364 <div class="container"> 365 <h1 class="custom-intro__title">Contact Us</h1> 366 367 </div> 368</div> 369 370</section> 371<section id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725" class="solid-section is-font-color-dark is-background-color-light" data-el-id="ee03b9c1-ce78-4c15-86a1-10124375dc59"> 372 <div class="custom-form redesign" id="js-contact-form"> 373 <div class="lp-container custom-form__container"> 374 375 <div class="custom-form__header"> 376 <h2 class="lp-h2 custom-form__heading">Submit a Message</h2> 377 <div class="custom-form__lead lp-text--subtitle">Fill out the form below to learn more about buying or selling a house in your area.</div> 378 </div> 379 <div class="elem-row custom-form__row"> 380 <div class="elem-col custom-form__img-col"> 381 <div class="custom-form__img-block"> 382 <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/245d6daf-8d58-45b9-a365-67d246467ffe" 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/245d6daf-8d58-45b9-a365-67d246467ffe 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/245d6daf-8d58-45b9-a365-67d246467ffe 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/245d6daf-8d58-45b9-a365-67d246467ffe 1280w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/245d6daf-8d58-45b9-a365-67d246467ffe 1920w" alt="Image Form" sizes="(max-width: 768px) 100vw, 50vw" loading="lazy"> 383 </div> 384 </div> 385 <div class="elem-col custom-form__form-col"> 386 <form class="custom-form__download-form" data-type="contact-form" data-delay="6000"> 387 <div class="form-row custom-form__form-row"> 388 389 <div class="h-pot lp-h-pot"> 390 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-middleName">Middle Name</label> 391 <input id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-middleName" name="middleName" value="" autocomplete="off" tabindex="-1"> 392 </div> 393 394 <div class="form-col js-backup-email"> 395 <div class="lp-form-group custom-form__group">
396 <div class="lp-input-group"> 397 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-required-email-field" class="lp-label field-required">Email</label> 398 <input type="email" id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-required-email-field" name="email" class="lp-input lp-input--dark js-form-element js-backup-field" placeholder="Email *" required> 399 </div> 400 </div> 401 </div> 402 403 404 <div class="form-col"> 405 <div class="lp-form-group custom-form__group"> 406 <div class="lp-input-group"> 407 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-0" class="lp-label field-required">Full Name</label> 408 <input type="text" id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-0" name="name" class="lp-input lp-input--dark js-form-element" placeholder="Full Name *" required> 409 </div> 410 </div> 411 </div> 412 <div class="form-col"> 413 <div class="lp-form-group custom-form__group"> 414 <div class="lp-input-group"> 415 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-1" class="lp-label">Phone</label> 416 <input type="tel" id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-1" name="phone" class="lp-input lp-input--dark js-form-element" placeholder="Phone"> 417 </div> 418 </div> 419 </div> 420 <div class="form-col"> 421 <div class="lp-form-group custom-form__group"> 422 <div class="lp-input-group"> 423 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-2" class="lp-label field-required">Email</label> 424 <input type="email" id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-2" name="email" class="lp-input lp-input--dark js-form-element" placeholder="Email *" required> 425 </div> 426 </div> 427 </div> 428 <div class="form-col"> 429 <div class="lp-form-group custom-form__group"> 430 <div class="lp-input-group"> 431 <label for="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-3" class="lp-label field-required">Message</label> 432 <textarea name="message" rows="4" id="section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-field-3" class="lp-input lp-input--dark js-form-element" placeholder="Message *" required></textarea> 433 </div> 434 </div> 435 </div> 436 </div> 437 438 <div class="lp-disclaimer"> <label style='display: none;' for='section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-termsAccepted'>Opt In/Disclaimer Consent:</label> 439 <label class='lp-tcr-content'> 440 <span class='lp-tcr-checkbox'> 441 <input 442 type='checkbox' 443 id='section-a6ae58a0-a07f-4664-a9fd-fe7d60274725-termsAccepted' 444 name='termsAccepted' 445 oninvalid="this.setCustomValidity('Please accept the terms and conditions')" 446 oninput="this.setCustomValidity('')" 447 required 448 /></span> 449 <span class='lp-tcr-message'> 450 451 I agree to be contacted by 452 The Gobin Group 453 via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance. 454 You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary. 455 <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>. 456 </span> 457 </label> 458 459</div> 460 461 <div class="custom-form__footer"> 462 <button type="submit" class="lp-btn lp-btn--dark lp-btn--filled lp-btn--mob-full-width custom-form__submit-btn button-style-1"> 463 <span class="lp-btn-icons"> 464 <span class="lp-btn-icon-loading"></span> 465 <span class="lp-btn-icon-success"></span> 466 </span> 467 Submit 468 </button> 469 </div> 470 </form> 471 </div> 472 </div> 473 </div> 474 475</div> 476 477 478</section> 479<section id="section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8" class="solid-section is-font-color-light is-background-color-dark" data-el-id="ee87d271-1520-42d7-88f2-27f85a797fa1"> 480 <div class="gallery-component redesign"> 481 <div class="lp-container gallery-component__container"> 482 <div class="row gallery-component__row cols-3"> 483 484 <div class="gallery-component__col"> 485 <a class="gallery-card" 486 href="/" > 487 <div class="gallery-card__preview"> 488 <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/846fad57-3e93-43a7-9fe8-f8fd230be57f" 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/846fad57-3e93-43a7-9fe8-f8fd230be57f 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/846fad57-3e93-43a7-9fe8-f8fd230be57f 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/846fad57-3e93-43a7-9fe8-f8fd230be57f 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/846fad57-3e93-43a7-9fe8-f8fd230be57f 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/846fad57-3e93-43a7-9fe8-f8fd230be57f 2000w" class="portrait" alt="" loading="lazy"> 489 </div> 490 <h3 class="lp-h3 gallery-card__title">Home</h3> 491 </a> 492 </div> 493 494 495 <div class="gallery-component__col"> 496 <a class="gallery-card" 497 href="/team" > 498 <div class="gallery-card__preview"> 499 <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/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6" 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/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6 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/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6 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/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6 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/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/548f4df9-ff61-4d84-ab4b-0d1ddbf1dcd6 2000w" class="portrait" alt="" loading="lazy"> 500 </div> 501 <h3 class="lp-h3 gallery-card__title">Meet the Team</h3> 502 </a> 503 </div> 504 505 506 <div class="gallery-component__col"> 507 <a class="gallery-card" 508 href="/home-search/listings" > 509 <div class="gallery-card__preview"> 510 <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/7c32476c-e805-456b-97a8-0d4b442e9728" 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/7c32476c-e805-456b-97a8-0d4b442e9728 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/7c32476c-e805-456b-97a8-0d4b442e9728 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/7c32476c-e805-456b-97a8-0d4b442e9728 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/7c32476c-e805-456b-97a8-0d4b442e9728 1920w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/7c32476c-e805-456b-97a8-0d4b442e9728 2000w" class="portrait" alt="" loading="lazy"> 511 </div> 512 <h3 class="lp-h3 gallery-card__title">Home Search</h3> 513 </a> 514 </div> 515 516 </div> 517 </div> 518</div> 519 520 521</section> 522<section id="section-56d00219-b3d8-459e-8dda-281976e80716" class="solid-section is-font-color-light is-background-color-dark" data-el-id="5db65d6a-01e9-4ee3-babf-2748e074a284"> 523
523<script type="text/x-handlebars-template" class="jsIGItem"> 524 <a href="{{permalink}}" target="_blank" class="ig-feed-item insta-type-{{mediaType}}"> 525 <div class="ig-feed-item__img" style="background-image: url('{{#ifEquals mediaType 'VIDEO'}}{{thumbnailUrl}}{{^}}{{mediaUrl}}{{/ifEquals}}');"></div> 526 <div class="ig-feed-item__info"><div class="ig-feed-item__caption">{{caption}}</div></div> 527 {{#ifEquals mediaType 'VIDEO'}}<div class="video-icon"></div>{{/ifEquals}} 528 </a> 529</script>
529 530<div class="ig-feed redesign"> 531 <div class="ig-feed-top lp-container"> 532 <div class="top-wrapper"> 533 <div class="top-left"> 534 <h3 class="lp-h3 title">Follow Us on Instagram</h3> 535 <a href="#" target="_blank" class="instagram-link jsIGLink"><h4 class="lp-h4 instagram-name jsIGName"></h4></a> 536 </div> 537 <div class="top-right"> 538 <a href="#" target="_blank" class="lp-btn lp-btn--dark lp-btn--outline lp-btn--mob-full-width follow-button jsIGLink button-style-2">Follow Us</a> 539 <a class="nav-button top-nav-prev hidden-control button-style-2"> 540 <svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.099 13.25l-5.25-5.775L7.099 1.7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 541 </a> 542 <a class="nav-button top-nav-next hidden-control button-style-2"> 543 <svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.90137 1.75L7.15137 7.525L1.90137 13.3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 544 </a> 545 </div> 546 </div> 547 </div> 548 <div class="lp-container ig-feed-container "> 549 <div class="ig-feed-feed" data-limit="33"> 550 </div> 551 </div> 552 <div class="bottom-controls"> 553 <a class="bottom-nav-button bottom-nav-prev button-style-2"> 554 <svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.099 13.25l-5.25-5.775L7.099 1.7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 555 </a> 556 <a class="bottom-nav-button bottom-nav-next button-style-2"> 557 <svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.90137 1.75L7.15137 7.525L1.90137 13.3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 558 </a> 559 </div> 560</div> 561 562</section> 563 564 <div id="modals" class="modals"></div> 565 <footer id="global-footer" class="is-font-color-dark is-background-color-light" data-el-id="874a9373-949d-4275-b72f-04c2a6ec373b"> 566 <div class="footer redesign no_newsletter "> 567 <div class="container"> 568 <h3>The Gobin Group</h3> 569 <div class="info-wrap"> 570 <div class="info-wrap-contact agent_box"> 571 <div class="info-wrap-contact_zone type_user"> 572 <h4 class="serif">Contact Us</h4> 573 <div class="info-wrap-contact_cell"> 574 <i> 575 <svg width="30" height="19" viewBox="0 0 30 19" fill="none" xmlns="http://www.w3.org/2000/svg"> 576 <path d="M2 0C0.903517 0 0 0.903517 0 2V16.6667C0 17.7631 0.903517 18.6667 2 18.6667H28C29.0965 18.6667 30 17.7631 30 16.6667V2C30 0.903517 29.0965 0 28 0H2ZM2.4375 1.33333H27.5625L15.6458 11.4896C15.3389 11.7512 14.6612 11.7512 14.3542 11.4896L2.4375 1.33333ZM1.33333 2.13542L10.1979 9.6979L1.33333 16.5729V2.13542ZM28.6667 2.13542V16.5729L19.8021 9.6979L28.6667 2.13542ZM11.2396 10.5833L13.4896 12.5C14.3543 13.2369 15.6457 13.2369 16.5104 12.5L18.7604 10.5833L27.4687 17.3333H2.53125L11.2396 10.5833Z" fill="#1A1A1A" /> 577 </svg> 578 </i> 579 <p class="contact_title">Email</p> 580 <a href="/cdn-cgi/l/email-protection#f296979c9b8197b2959d909b9c8097dc919d9f" class="lp-link info-wrap-contact_link grey-text hyperlink-style-1"><span class="__cf_email__" data-cfemail="c5a1a0abacb6a085a2aaa7acabb7a0eba6aaa8">[email protected]</span></a> 581 </div> 582 <div class="info-wrap-contact_cell"> 583 <i><svg width="30" height="25" viewBox="0 0 30 25" fill="none" xmlns="http://www.w3.org/2000/svg"> 584 <path fill-rule="evenodd" clip-rule="evenodd" d="M10.7964 8.1207H19.2036V8.7279C19.2036 10.8195 20.9082 12.5259 23.001 12.5259H24.741L25.2852 20.7051C25.3776 22.1235 24.2868 23.2719 22.8822 23.2719H7.0032C5.5944 23.2719 4.5084 22.1085 4.6002 20.7039C4.782 17.9895 4.9152 15.23
58413 5.154 12.5265H6.9996C9.0918 12.5265 10.797 10.8207 10.797 8.7285V8.1207H10.7964ZM11.46 16.5807C11.46 14.6565 13.0188 13.0977 14.943 13.0977C16.8666 13.0977 18.4254 14.6571 18.4254 16.5807C18.4254 18.5055 16.8678 20.0631 14.943 20.0631C13.02 20.0637 11.46 18.5043 11.46 16.5807ZM14.943 12.0381C12.4344 12.0381 10.4004 14.0721 10.4004 16.5807C10.4004 19.0887 12.435 21.1233 14.943 21.1233C17.4486 21.1233 19.485 19.0869 19.485 16.5807C19.485 14.0727 17.451 12.0381 14.943 12.0381ZM9.0846 4.8363C8.22 4.8363 7.512 5.5443 7.512 6.4089V8.7285C7.512 9.0093 7.2804 9.2415 6.999 9.2415H1.5726C1.2906 9.2415 1.0596 9.0111 1.0596 8.7285V6.9285C1.0596 6.4797 1.1628 6.0945 1.3902 5.7069C1.896 4.8465 2.7294 4.1013 3.795 3.4749C9.279 0.2517 20.7192 0.2523 26.2044 3.4749C27.2706 4.1013 28.104 4.8465 28.6098 5.7069C28.8354 6.0921 28.9398 6.4815 28.9398 6.9285V8.7285C28.9398 9.0111 28.71 9.2415 28.4268 9.2415H23.0004C22.719 9.2415 22.4874 9.0093 22.4874 8.7285V6.4089C22.4874 5.5425 21.7806 4.8363 20.9148 4.8363H9.0846ZM8.571 6.4089C8.571 6.1263 8.8026 5.8965 9.0846 5.8965H20.9154C21.1968 5.8965 21.429 6.1275 21.429 6.4089V8.7285C21.429 9.5943 22.1352 10.3017 23.001 10.3017H28.4274C29.292 10.3017 30 9.5931 30 8.7285V6.9285C30 6.2835 29.8464 5.7291 29.5206 5.1729C28.9188 4.1493 27.9564 3.2799 26.7384 2.5641C20.9214 -0.8547 9.0798 -0.8547 3.2622 2.5641C2.0436 3.2799 1.0812 4.1487 0.48 5.1729C0.153 5.7291 0 6.2835 0 6.9279V8.7279C0 9.5925 0.7092 10.3011 1.5726 10.3011H6.999C7.8648 10.3011 8.571 9.5937 8.571 8.7279V6.4089ZM9.7368 7.5915V8.7285C9.7368 10.2387 8.5092 11.4669 6.999 11.4669H4.6686C4.3914 11.4669 4.164 11.6799 4.1412 11.9511C3.8892 14.8347 3.7386 17.7435 3.5448 20.6331C3.4116 22.6425 4.989 24.3315 7.0032 24.3315H22.8822C24.882 24.3315 26.475 22.6575 26.3406 20.6343L25.7622 11.9607C25.7436 11.6811 25.5102 11.4675 25.2342 11.4675L23.001 11.4663C21.4902 11.4663 20.2632 10.2375 20.2632 8.7279V7.5909C20.2632 7.2981 20.0262 7.0611 19.7334 7.0611H10.2666C9.9738 7.0611 9.7368 7.2987 9.7368 7.5915Z" fill="#1A1A1A" /> 585 </svg></i> 586 <p class="contact_title">Phone Number</p> 587 <a href="tel:9545531089" class="lp-link info-wrap-contact_link grey-text hyperlink-style-1">(954) 553-1089 </a> 588 </div> 589 </div> 590 <div class="info-wrap-contact_zone"> 591 <div class="info-wrap-contact_cell"> 592 <i> 593 <svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg"> 594 <path d="M29.9821 6.49489C29.7931 6.35756 29.679 6.32046 29.4572 6.39228L20.298 9.41368L16.1952 8.03558L15.8172 9.41525L19.7644 10.7038V28.1462L9.89831 25.7069V22.1034H8.71438V25.7515L1.21616 28.2532V15.3945H0.0322266V29.2729C0.0322266 29.5077 0.130098 29.7279 0.321106 29.8645C0.445418 29.9541 0.585911 29.9999 0.735086 29.9999C0.814804 29.9999 0.890971 29.9868 0.967926 29.96L9.48433 27.029L20.1792 29.7887C20.3224 29.8254 20.4751 29.8171 20.6152 29.7654L29.8104 26.2235C30.0942 26.1177 30.0251 25.8466 30.0251 25.5431V7.08291C30.0251 6.85086 30.17 6.63144 29.9821 6.49489ZM28.8412 25.0388L20.9483 28.0361V10.7065L28.8412 8.08649V25.0388Z" fill="#1A1A1A" /> 595 <path d="M6.57515 19.1142C6.6671 19.422 6.95006 19.6323 7.2713 19.6323C7.59215 19.6323 7.87511 19.422 7.96746 19.1142C8.67742 16.7514 10.0393 15.2447 11.3559 13.788C12.9944 11.9747 14.5422 10.2615 14.5422 7.2717C14.5422 3.39788 11.1451 0 7.2713 0C3.39827 0 0 3.39748 0 7.2717C0 10.2615 1.54819 11.9747 3.18674 13.788C4.50328 15.2447 5.86479 16.7514 6.57515 19.1142ZM7.2713 1.45426C10.316 1.45426 13.0883 4.22663 13.0883 7.2717C13.0883 9.70191 11.7852 11.1435 10.2769 12.8121C9.2461 13.9534 8.10992 15.2096 7.2713 16.9199C6.43229 15.2096 5.29651 13.953 4.2657 12.8121C2.75698 11.1432 1.45426 9.70191 1.45426 7.2717C1.45426 4.22663 4.22663 1.45426 7.2713 1.45426Z" fill="#1A1A1A" /> 596 <path d="M7.26193 10.1616C8.8705 10.1616 10.1795 8.86084 10.1795 7.26175C10.1795 5.66305 8.87089 4.3623 7.26193 4.3623C5.65297 4.3623 4.34473 5.66305 4.34473 7.26175C4.34512 8.86084 5.65336 10.1616 7.26193 10.1616ZM7.26193 5.81657C8.06898 5.81657 8.72527 6.46536 8.72527 7.26175C8.72527 8.05932 8.06898 8.70733 7.26193 8.70733C6.45528 8.70733 5.79899 8.05893 5.79899 7.26175C5.79899 6.46536 6.45528 5.81657 7.26193 5.81657Z" fill="#1A1A1A" /> 597 </svg> 598 </i> 599 <p class="info-wrap-contact_title">Address</p> 600 <p class="info-wrap-contact_link grey-text"><p>1200 E Las Olas Blvd Ste 103 <br>Fort Lauderdale, FL 33301</p></p> 601 </div> 602 </div> 603 </div> 604 </div> 605 <div class="text_footer first_text_footer"> 606 <div class="images_box"> 607 <div class="img_size"> 608 <img src="https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/ca33bb92-66d9-4dfe-9a49-f87dacefd9b3" 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/ca33bb92-66d9-4dfe-9a49-f87dacefd9b3 320w, https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/ca33bb92-66d9-4dfe-9a49-f87dacefd9b3 806w" alt="Footer Image" sizes="200px"> 609 </div> 610 </div> 611 <div class="luxury-text"> 612 <div class="grid-container"><!-- Row 1 --> 613<div class="grid-item"><a class="link" href="../">Home</a></div> 614<div class="grid-item"><a class="link" href="../team">Meet the Team</a></div> 615<div class="grid-item"><a class="link" href="../properties/sale">Featured Properties</a></div> 616<div class="grid-item"><a class="link" href="../properties/sold">Past transactions</a></div> 617<div class="grid-item"><a class="link" href="../home-search/listings">Home Search</a></div> 618<div class="grid-item"><a class="link" href="../home-valuation">Home Valuation</a></div> 619<div class="grid-item"><a class="link" href="../neighborhoods">Neighborhoods</a></div> 620<div class="grid-item"><a class="link" href="../testimonials">Testimonials</a></div> 621<div class="grid-item"><a class="link" href="../buyers-guide">
621Buyer's Guide</a></div> 622<div class="grid-item"><a class="link" href="../sellers-guide">Seller's Guide</a></div> 623<div class="grid-item"><a class="link" href="../concierge">Compass Concierge</a></div> 624<div class="grid-item"><a class="link" href="../blog">Blog</a></div> 625<div class="grid-item"><a class="link" href="../press">Press</a></div> 626<div class="grid-item"><a class="link" href="../contact">Contact Us</a></div> 627<div class="grid-item"><a class="link" href="../home-search/auth/sign_in">Search Portal</a></div> 628</div> 629<div id="ipql"> 630<p id="iaa1">The Gobin Group is a team of real estate agents affiliated with Compass. <a class="link" style="text-transform: none;" href="https://www.compass.com/" target="_blank" rel="noopener">Compass</a> Florida, LLC d/b/a Compass is a licensed real estate broker and abides by equal housing opportunity laws. All material presented herein is intended for informational purposes only. Information is compiled from sources deemed reliable but is subject to errors, omissions, changes in price, condition, sale, or withdrawal without notice. No statement is made as to accuracy of any description. All measurements and square footages are approximate. This is not intended to solicit property already listed. Nothing herein shall be construed as legal, accounting or other professional advice outside the realm of real estate brokerage.<br><img id="iivu" src="https://res.cloudinary.com/luxuryp/images/f_auto,q_auto/atey8q45g4nbzeqjggpc/realtor-eho-logo-07232021-update-dark" width="100px;" height="auto"></p> 631</div> 632<style>* { box-sizing: border-box; } body {margin: 0;}ul{list-style:inherit;}#iaa1{font-size:12px;}#iivu{margin-top:10px;} 633.grid-container { 634 display: grid; 635 grid-template-columns: repeat(5, 1fr); 636 grid-template-rows: repeat(3, minmax(auto, auto)); 637 gap: 12px; 638 padding: 30px 0 50px 0; 639 background: #fff; 640width: 90%; 641} 642 643 644.grid-item { 645 background: #fff; 646 color: #000; 647 display: flex; 648 justify-content: flex-start; 649 align-items: center; 650 font-size: 14px; 651margin-bottom: 10px; 652grid-auto-flow: dense; 653} 654 655.link { 656text-transform: uppercase; 657} 658 659/* Tablet (2 columns) */ 660@media (max-width: 1024px) { 661 .grid-container { 662 grid-template-columns: repeat(2, 1fr); 663 } 664} 665 666/* Mobile (1 column) */ 667@media (max-width: 600px) { 668 .grid-container { 669 grid-template-columns: repeat(1, 1fr); 670 padding: 30px 0 30px 0; 671 width: 100%; 672 } 673 .grid-item{ 674 justify-content: center; 675 } 676} 677</style> 678 </div> 679 </div> 680 <div class="text_footer second_text_footer"> 681 <div class="text_content_wrap"> 682 <div> 683 <div> </div> 684<style>* { box-sizing: border-box; } body {margin: 0;}ul{list-style:inherit;}</style> 685 </div> 686 </div> 687 </div> 688 <div class="info-privacy"> 689 <div class="form-row info-privacy__row"> 690 691 <div class="form-col form-col--powered powered-box"> 692 <div class="img-wrap"> 693 <img src="https://media-production.lp-cdn.com/media/b517d231-d9f5-4e15-870d-852a977c9204" alt=""> 694 </div> 695 <div class="powered_zone"> 696 Real Estate Website Design by <a href="https://www.luxurypresence.com/real-estate-website-design/" target="_blank" class="lp-link grey-text luxury-link underlined hyperlink-style-1">Luxury Presence</a> 697 </div> 698 </div> 699 700 <div class="form-col form-col--copyright"> 701 <div class="copy_zone"> 702 <span class="copy_words">Copyright ©</span> <span class="auto-year-update">2026</span> 703 | <a href="/terms-and-conditions" class="lp-link grey-text hyperlink-style-1">Privacy Policy</a> 704 705 </div> 706 </div> 707 708 <div class="form-col form-col--socials"> 709 <ul class="lp-socials social_icons-style-1 socials socials--grey socials_zone"> 710 711 <li> 712 <a 713 href="https://www.facebook.com/askdenisegobin" 714 class="lp-socials__link socials__item socials__link wow fadeInUp" 715 data-wow-delay="0s" 716 target="_blank" 717 aria-label="FACEBOOK" 718 >
719 <span class="lp-i lp-i--facebook" aria-hidden="true"></span> 720 </a> 721 </li> 722 <li> 723 <a 724 href="https://www.instagram.com/denisegobin" 725 class="lp-socials__link socials__item socials__link wow fadeInUp" 726 data-wow-delay="0.1s" 727 target="_blank" 728 aria-label="INSTAGRAM" 729 > 730 <span class="lp-i lp-i--instagram" aria-hidden="true"></span> 731 </a> 732 </li> 733 <li> 734 <a 735 href="https://www.linkedin.com/in/denisegobin/" 736 class="lp-socials__link socials__item socials__link wow fadeInUp" 737 data-wow-delay="0.2s" 738 target="_blank" 739 aria-label="LINKEDIN" 740 > 741 <span class="lp-i lp-i--linkedin" aria-hidden="true"></span> 742 </a> 743 </li> 744 <li> 745 <a 746 href="https://www.zillow.com/profile/denise760" 747 class="lp-socials__link socials__item socials__link wow fadeInUp" 748 data-wow-delay="0.3s" 749 target="_blank" 750 aria-label="ZILLOW" 751 > 752 <span class="lp-i lp-i--zillow" aria-hidden="true"></span> 753 </a> 754 </li> 755 <li> 756 <a 757 href="https://www.compass.com/agents/denise-gobin/?referrer=omnibox" 758 class="lp-socials__link socials__item socials__link wow fadeInUp" 759 data-wow-delay="0.4s" 760 target="_blank" 761 aria-label="BROKERAGE" 762 > 763 <svg width="20" height="20" viewBox="0 0 60.14 60"><path d="M29.86 0a30 30 0 00.28 60 30.03 30.03 0 0030-30A30 30 0 0029.86 0zm.28 8a22.03 22.03 0 0122 22 22 22 0 11-22-22zm7.18 9.17l-20 20 5.65 5.66 20-20z" /></svg> 764 </a> 765 </li> 766 </ul> </div> 767 </div> 768 </div> 769 </div> 770</div> 771 772 </footer> 773 774 <div id="modal-global-contact-us" class="modal " 775 data-el-id="" 776 style="background-color: ;" 777 > 778 <div class="modal-content"> 779 <div class="contact-form redesign " style="background-image: url('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/5683ba9f-8354-4c98-93ef-a6e83f0891b4')"> 780 <div class="container"> 781 <div class="section-details" style="--colorTxt: #ffffff"> 782 <h2>Contact Details</h2> 783 784 <div class="info-zone"> 785 786 <div class="info-zone_contact type_user"> 787 <h4 class="serif">The Gobin Group</h4> 788 <div class="info-zone_contact_cell"> 789 <i> 790 <svg width="30" height="25" viewBox="0 0 30 25" fill="none" xmlns="http://www.w3.org/2000/svg"> 791 <path fill-rule="evenodd" clip-rule="evenodd" d="M10.7964 8.1207H19.2036V8.7279C19.2036 10.8195 20.9082 12.5259 23.001 12.5259H24.741L25.2852 20.7051C25.3776 22.1235 24.2868 23.2719 22.8822 23.2719H7.0032C5.5944 23.2719 4.5084 22.1085 4.6002 20.7039C4.782 17.9895 4.9152 15.2313 5.154 12.5265H6.9996C9.0918 12.5265 10.797 10.8207 10.797 8.7285V8.1207H10.7964ZM11.46 16.5807C11.46 14.6565 13.0188 13.0977 14.943 13.0977C16.8666 13.0977 18.4254 14.6571 18.4254 16.5807C18.4254 18.5055 16.8678 20.0631 14.943 20.0631C13.02 20.0637 11.46 18.5043 11.46 16.5807ZM14.943 12.0381C12.4344 12.0381 10.4004 14.0721 10.4004 16.5807C10.4004 19.0887 12.435 21.1233 14.943 21.1233C17.4486 21.1233 19.485 19.0869 19.485 16.5807C19.485 14.0727 17.451 12.0381 14.943 12.0381ZM9.0846 4.8363C8.22 4.8363 7.512 5.5443 7.512 6.4089V8.7285C7.512 9.0093 7.2804 9.2415 6.999 9.2415H1.5726C1.2906 9.2415 1.0596 9.0111 1.0596 8.7285V6.9285C1.0596 6.4797 1.1628 6.0945 1.3902 5.7069C1.896 4.8465 2.7294 4.1013 3.795 3.4749C9.279 0.2517 20.7192 0.2523 26.2044 3.4749C27.2706 4.1013 28.104 4.8465 28.6098 5.7069C28.8354 6.0921 28.9398 6.48
79115 28.9398 6.9285V8.7285C28.9398 9.0111 28.71 9.2415 28.4268 9.2415H23.0004C22.719 9.2415 22.4874 9.0093 22.4874 8.7285V6.4089C22.4874 5.5425 21.7806 4.8363 20.9148 4.8363H9.0846ZM8.571 6.4089C8.571 6.1263 8.8026 5.8965 9.0846 5.8965H20.9154C21.1968 5.8965 21.429 6.1275 21.429 6.4089V8.7285C21.429 9.5943 22.1352 10.3017 23.001 10.3017H28.4274C29.292 10.3017 30 9.5931 30 8.7285V6.9285C30 6.2835 29.8464 5.7291 29.5206 5.1729C28.9188 4.1493 27.9564 3.2799 26.7384 2.5641C20.9214 -0.8547 9.0798 -0.8547 3.2622 2.5641C2.0436 3.2799 1.0812 4.1487 0.48 5.1729C0.153 5.7291 0 6.2835 0 6.9279V8.7279C0 9.5925 0.7092 10.3011 1.5726 10.3011H6.999C7.8648 10.3011 8.571 9.5937 8.571 8.7279V6.4089ZM9.7368 7.5915V8.7285C9.7368 10.2387 8.5092 11.4669 6.999 11.4669H4.6686C4.3914 11.4669 4.164 11.6799 4.1412 11.9511C3.8892 14.8347 3.7386 17.7435 3.5448 20.6331C3.4116 22.6425 4.989 24.3315 7.0032 24.3315H22.8822C24.882 24.3315 26.475 22.6575 26.3406 20.6343L25.7622 11.9607C25.7436 11.6811 25.5102 11.4675 25.2342 11.4675L23.001 11.4663C21.4902 11.4663 20.2632 10.2375 20.2632 8.7279V7.5909C20.2632 7.2981 20.0262 7.0611 19.7334 7.0611H10.2666C9.9738 7.0611 9.7368 7.2987 9.7368 7.5915Z" fill="#1A1A1A"/> 792 </svg> 793 </i> 794 <p class="contact_title">Phone</p> 795 <a href="tel:(954) 553-1089 " class="lp-link info-zone_contact_link link hyperlink-style-2">(954) 553-1089 </a> 796 </div> 797 <div class="info-zone_contact_cell"> 798 <i> 799 <svg width="30" height="19" viewBox="0 0 30 19" fill="none" xmlns="http://www.w3.org/2000/svg"> 800 <path d="M2 0C0.903517 0 0 0.903517 0 2V16.6667C0 17.7631 0.903517 18.6667 2 18.6667H28C29.0965 18.6667 30 17.7631 30 16.6667V2C30 0.903517 29.0965 0 28 0H2ZM2.4375 1.33333H27.5625L15.6458 11.4896C15.3389 11.7512 14.6612 11.7512 14.3542 11.4896L2.4375 1.33333ZM1.33333 2.13542L10.1979 9.6979L1.33333 16.5729V2.13542ZM28.6667 2.13542V16.5729L19.8021 9.6979L28.6667 2.13542ZM11.2396 10.5833L13.4896 12.5C14.3543 13.2369 15.6457 13.2369 16.5104 12.5L18.7604 10.5833L27.4687 17.3333H2.53125L11.2396 10.5833Z" fill="#1A1A1A"/> 801 </svg> 802 </i> 803 <p class="contact_title">Email</p> 804 <a href="/cdn-cgi/l/email-protection#5236373c3b213712353d303b3c20377c313d3f" class="lp-link info-zone_contact_link link hyperlink-style-2"><span class="__cf_email__" data-cfemail="cfabaaa1a6bcaa8fa8a0ada6a1bdaae1aca0a2">[email protected]</span></a> 805 </div> 806 </div> 807 <div class="info-zone_contact"> 808 <div class="info-zone_contact_cell"> 809 <i> 810 <svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg"> 811 <path d="M29.9821 6.49489C29.7931 6.35756 29.679 6.32046 29.4572 6.39228L20.298 9.41368L16.1952 8.03558L15.8172 9.41525L19.7644 10.7038V28.1462L9.89831 25.7069V22.1034H8.71438V25.7515L1.21616 28.2532V15.3945H0.0322266V29.2729C0.0322266 29.5077 0.130098 29.7279 0.321106 29.8645C0.445418 29.9541 0.585911 29.9999 0.735086 29.9999C0.814804 29.9999 0.890971 29.9868 0.967926 29.96L9.48433 27.029L20.1792 29.7887C20.3224 29.8254 20.4751 29.8171 20.6152 29.7654L29.8104 26.2235C30.0942 26.1177 30.0251 25.8466 30.0251 25.5431V7.08291C30.0251 6.85086 30.17 6.63144 29.9821 6.49489ZM28.8412 25.0388L20.9483 28.0361V10.7065L28.8412 8.08649V25.0388Z" fill="#1A1A1A"/> 812 <path d="M6.57515 19.1142C6.6671 19.422 6.95006 19.6323 7.2713 19.6323C7.59215 19.6323 7.87511 19.422 7.96746 19.1142C8.67742 16.7514 10.0393 15.2447 11.3559 13.788C12.9944 11.9747 14.5422 10.2615 14.5422 7.2717C14.5422 3.39788 11.1451 0 7.2713 0C3.39827 0 0 3.39748 0 7.2717C0 10.2615 1.54819 11.9747 3.18674 13.788C4.50328 15.2447 5.86479 16.7514 6.57515 19.1142ZM7.2713 1.45426C10.316 1.45426 13.0883 4.22663 13.0883 7.2717C13.0883 9.70191 11.7852 11.1435 10.2769 12.8121C9.2461 13.9534 8.10992 15.2096 7.2713 16.9199C6.43229 15.2096 5.29651 13.953 4.2657 12.8121C2.75698 11.1432 1.45426 9.70191 1.45426 7.2717C1.45426 4.22663 4.22663 1.45426 7.2713 1.45426Z" fill="#1A1A1A"/> 813 <path d="M7.26193 10.1616C8.8705 10.1616 10.1795 8.86084 10.1795 7.26175C10.1795 5.66305 8.87089 4.3623 7.26193 4.3623C5.65297 4.3623 4.34473 5.66305 4.34473 7.26175C4.34512 8.86084 5.65336 10.1616 7.26193 10.1616ZM7.26193 5.81657C8.06898 5.81657 8.72527 6.46536 8.72527 7.26175C8.72527 8.05932 8.06898 8.70733 7.26193 8.70733C6.45528 8.70733 5.79899 8.05893 5.79899 7.26175C5.79899 6.46536 6.45528 5.81657 7.26193 5.81657Z" fill="#1A1A1A"/> 814 </svg> 815 </i> 816 <p class="info-wrap-contact_title">Address</p> 817 <p class="info-zone_contact_link pre-line">1200 E Las Olas Blvd Ste 103 818 Fort Lauderdale, FL 33301</p> 819 </div> 820 </div> 821 <div class="info-zone_contact"> 822 <div class="info-zone_contact_cell"> 823 <p class="pre-line"><div></div><style>* { box-sizing: border-box; } body {margin: 0;}ul{list-style:inherit;}</style></p> 824 </div> 825 </div> 826 <ul class="lp-socials social_icons-style-2 socials socials--grey socials_zone footer__c
826ontact-column"> 827 828 <li> 829 <a 830 href="https://www.facebook.com/askdenisegobin" 831 class="lp-socials__link socials__item wow fadeInUp socials__link" 832 data-wow-delay="0s" 833 target="_blank" 834 aria-label="FACEBOOK" 835 > 836 <span class="lp-i lp-i--facebook" aria-hidden="true"></span> 837 </a> 838 </li> 839 <li> 840 <a 841 href="https://www.instagram.com/denisegobin" 842 class="lp-socials__link socials__item wow fadeInUp socials__link" 843 data-wow-delay="0.1s" 844 target="_blank" 845 aria-label="INSTAGRAM" 846 > 847 <span class="lp-i lp-i--instagram" aria-hidden="true"></span> 848 </a> 849 </li> 850 <li> 851 <a 852 href="https://www.linkedin.com/in/denisegobin/" 853 class="lp-socials__link socials__item wow fadeInUp socials__link" 854 data-wow-delay="0.2s" 855 target="_blank" 856 aria-label="LINKEDIN" 857 > 858 <span class="lp-i lp-i--linkedin" aria-hidden="true"></span> 859 </a> 860 </li> 861 <li> 862 <a 863 href="https://www.zillow.com/profile/denise760" 864 class="lp-socials__link socials__item wow fadeInUp socials__link" 865 data-wow-delay="0.3s" 866 target="_blank" 867 aria-label="ZILLOW" 868 > 869 <span class="lp-i lp-i--zillow" aria-hidden="true"></span> 870 </a> 871 </li> 872 <li> 873 <a 874 href="https://www.compass.com/agents/denise-gobin/?referrer=omnibox" 875 class="lp-socials__link socials__item wow fadeInUp socials__link" 876 data-wow-delay="0.4s" 877 target="_blank" 878 aria-label="BROKERAGE" 879 > 880 <svg width="20" height="20" viewBox="0 0 60.14 60"><path d="M29.86 0a30 30 0 00.28 60 30.03 30.03 0 0030-30A30 30 0 0029.86 0zm.28 8a22.03 22.03 0 0122 22 22 22 0 11-22-22zm7.18 9.17l-20 20 5.65 5.66 20-20z" /></svg> 881 </a> 882 </li> 883 </ul> </div> 884 </div> 885 <div class="section-message"> 886 <form data-type="contact-form"> 887 <h2>Submit a Message</h2> 888 <div class="h-pot"> 889 <label for="-middleName">Middle Name</label> 890 <input id="-middleName" name="middleName" value="" autocomplete="off" tabindex="-1"> 891 </div> 892 893 894 <div class="lp-input-group"> 895 <label for="prod-name" class="lp-label">Name</label> 896 <input id="prod-name" name="name" value="" required="" class="lp-in
896put lp-input--light"> 897 </div> 898 <div class="lp-input-group"> 899 <label for="prod-email" class="lp-label">Email</label> 900 <input id="prod-email" type="email" name="email" value="" required="" class="lp-input lp-input--light"> 901 </div> 902 <div class="lp-input-group"> 903 <label for="prod-phone" class="lp-label">Phone</label> 904 <input id="prod-phone" type="tel" name="phoneNumber" value="" required="" class="lp-input lp-input--light"> 905 </div> 906 <div class="lp-input-group m16"> 907 <label for="prod-message" class="lp-label">Message</label> 908 <textarea id="prod-message" name="message" value="" required="" class="lp-input"></textarea> 909 </div> 910 911 <div class="lp-disclaimer"> <label style='display: none;' for='-termsAccepted'>Opt In/Disclaimer Consent:</label> 912 <label class='lp-tcr-content'> 913 <span class='lp-tcr-checkbox'> 914 <input 915 type='checkbox' 916 id='-termsAccepted' 917 name='termsAccepted' 918 oninvalid="this.setCustomValidity('Please accept the terms and conditions')" 919 oninput="this.setCustomValidity('')" 920 required 921 /></span> 922 <span class='lp-tcr-message'> 923 924 I agree to be contacted by 925 The Gobin Group 926 via call, email, and text for real estate services. To opt out, you can reply 'stop' at any time or reply 'help' for assistance. 927 You can also click the unsubscribe link in the emails. Message and data rates may apply. Message frequency may vary. 928 <a href='/terms-and-conditions' target='_blank'>Privacy Policy</a>. 929 </span> 930 </label> 931 932 </div> 933 934 <input style="display: none;" type="text" name="source" value="CONTACT_INQUIRY" /> 935 936 937 <button type="submit" class="submitButton lp-btn button-style-2"> 938 <span class="label-initial">Submit</span> 939 <span class="label-loading">Submitting</span> 940 <span class="label-success">Submitted</span> 941 <span class="submit-icon lp-i lp-i--circle-notch lp-i--spin"></span> 942 </button> 943 <p class="success-message success hide"> 944 Message sent successfully! 945 </p> 946 </form> 947 948 949 </div> 950 </div> 951 </div> 952 953 </div> 954 <button class="close lp-close" type="button" aria-label="close modal"> 955 <span class="lp-close-icon" aria-hidden="true"></span> 956 </button> 957 </div> 958 <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;"> 959 <style> 960 #qualifying-questions-modal .custom-select-toggle { 961 border: 1px solid #848484; 962 border-radius: 8px; 963 padding: 12px 16px; 964 } 965 966 #qualifying-questions-modal .custom-select-toggle.is-placeholder { 967 color: #848484; 968 } 969 970 #qualifying-questions-modal #qualifying-questions-modal-phoneNumber::placeholder { 971 color: #848484; 972 opacity: 1; 973 } 974 975 #qualifying-questions-modal .disclaimer-more { 976 display: none; 977 } 978 979 #qualifying-questions-modal #qualifying-questions-modal-disclaimer-text:not(.collapsed) .disclaimer-more { 980 display: inline; 981 } 982 983 #qualifying-questions-modal #qualifying-questions-modal-disclaimer-text:not(.collapsed) .disclaimer-ellipsis { 984 display: none; 985 } 986 </style>
vendor: 119 bytes, lines 986-987
986 987 <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
987<script> 988 function toggleDisclaimerQualifyingQuestionsModal() { 989 const disclaimerText = document.getElementById('qualifying-questions-modal-disclaimer-text'); 990 const toggleButton = document.getElementById('qualifying-questions-modal-toggle-disclaimer'); 991 992 if (disclaimerText.classList.contains('collapsed')) { 993 disclaimerText.classList.remove('collapsed'); 994 toggleButton.textContent = 'Read less'; 995 toggleButton.setAttribute('aria-expanded', 'true'); 996 } else { 997 disclaimerText.classList.add('collapsed'); 998 toggleButton.textContent = 'Read more'; 999 toggleButton.setAttribute('aria-expanded', 'false'); 1000 } 1001 } 1002 </script>
1002 1003 <div style="max-width: 400px; width: 95%; margin: 0 auto;"> 1004 <div style="background: #fff; border: none; border-radius: 16px; color: black; box-shadow: none; position: relative;"> 1005 <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;"> 1006 <span aria-hidden="true">×</span> 1007 </button> 1008 <div style="padding: 40px 30px 32px;"> 1009 <div style="text-align: left; margin-bottom: 32px;"> 1010 <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;"> 1011 Thanks, please provide more information to help serve you 1012 </h2> 1013 </div> 1014 <form id="qualifying-questions-modal-form" data-type="contact-form"> 1015 <input type="hidden" name="source" value="PROFILE_UPDATE" /> 1016 <input type="hidden" name="email" value="" id="qualifying-questions-modal-email" /> 1017 <input type="hidden" name="triggerSource" id="qualifying-questions-modal-triggerSource" value="" /> 1018 <label for="qualifying-questions-modal-email" style="display:none;"> 1019 Email 1020 </label> 1021 <label for="qualifying-questions-modal-triggerSource" style="display:none;"> 1022 Trigger Source 1023 </label> 1024 1025 <div style="margin-bottom: 20px;"> 1026 <label for="qualifying-questions-modal-phoneNumber" style="display:none;"> 1027 Phone Number 1028 </label> 1029 <input 1030 type="tel" 1031 id="qualifying-questions-modal-phoneNumber" 1032 name="phoneNumber" 1033 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;" 1034 pattern="^\+?1?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}$" 1035 required 1036 placeholder="Phone" 1037 aria-label="Phone Number" 1038 inputmode="tel" 1039 autocomplete="tel" 1040 onfocus="this.style.borderColor='black';" 1041 onblur="this.style.borderColor='#848484';" 1042 /> 1043 </div> 1044 1045 <div style="margin-bottom: 20px;"> 1046 <label for="qualifying-questions-modal-interest" style="display:none;"> 1047 Interest 1048 </label> 1049 <select 1050 id="qualifying-questions-modal-interest" 1051 name="interest" 1052 required 1053 data-label="Interest" 1054 aria-label="Interest" 1055 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;" 1056 onfocus="this.style.borderColor='black'; this.style.color='black';" 1057 onblur="this.style.borderColor='#848484'; if(this.value === '') this.style.color='#848484'; else this.style.color='black';" 1058 > 1059 <option value="" style="background: #fff; color: #848484;" disabled selected>Interested in...</option> 1060 <option value="Selling & Buying" style="background: #fff; color: black;">Selling & Buying</option> 1061 <option value="Selling" style="background: #fff; color: black;">Selling</option> 1062 <option value="Buying" style="background: #fff; color: black;">Buying</option> 1063 <option value="Renting" style="background: #fff; color: black;">Renting</option> 1064 <option value="Other" style="background: #fff; color: black;">Other</option> 1065 </select> 1066 </div> 1067 1068 <div style="margin-bottom: 32px; font-size: 12px; line-height: 1.2;"> 1069 <label style='display: none;' for='qualifying-questions-modal-qualifying-questions-termsAccepted'>Opt In/Disclaimer Consent:</label> 1070 <label class='lp-tcr-content'>
1071 <span class='lp-tcr-checkbox'> 1072 <input 1073 type='checkbox' 1074 id='qualifying-questions-modal-qualifying-questions-termsAccepted' 1075 name='termsAccepted' 1076 aria-describedby='qualifying-questions-modal-disclaimer-text' 1077 oninvalid="this.setCustomValidity('Please accept the terms and conditions')" 1078 oninput="this.setCustomValidity('')" 1079 required 1080 /></span> 1081 <span class='lp-tcr-message'> 1082 <div id="qualifying-questions-modal-disclaimer-text" class="collapsed" style="color: #848484;"> 1083 1084 I agree to be contacted by 1085 <strong>The Gobin Group</strong> 1086 via call, email, and text <span class="disclaimer-more">for real estate services. 1087 To opt out, you can reply 'stop' at any time or reply 'help' for assistance. 1088 You can also click the unsubscribe link in the emails. 1089 Message and data rates may apply. Message frequency may vary.</span> 1090 <span class="disclaimer-ellipsis">...</span> 1091 <a href='/terms-and-conditions' target='_blank' rel='noopener noreferrer' style='text-decoration: underline;'>Privacy Policy</a>. 1092 </div> 1093 <button 1094 id="qualifying-questions-modal-toggle-disclaimer" 1095 type="button" 1096 style="background: none; border: none; color: #848484; font-size: inherit; font-weight: bold; padding: 0; margin-top: 4px; cursor: pointer;" 1097 aria-expanded="false" 1098 onclick="toggleDisclaimerQualifyingQuestionsModal()" 1099 > 1100 Read more 1101 </button> 1102 </span> 1103 </label> 1104 </div> 1105 1106 <div> 1107 <button 1108 type="submit" 1109 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;" 1110 onmouseover="this.style.background='transparent'; this.style.color='black';" 1111 onmouseout="this.style.background='black'; this.style.color='white';" 1112 > 1113 Submit 1114 </button> 1115 </div> 1116 </form> 1117 </div> 1118 </div> 1119 </div> 1120 </div> 1121 1122
1122<script> 1123 (function() { 1124 var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy")); 1125 1126 if ("IntersectionObserver" in window && lazyVideos.length > 0) { 1127 var lazyVideoObserver = new IntersectionObserver(function(entries, observer) { 1128 entries.forEach(function(video) { 1129 if (video.isIntersecting) { 1130 for (var source in video.target.children) { 1131 var videoSource = video.target.children[source]; 1132 if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") { 1133 videoSource.src = videoSource.dataset.src; 1134 } 1135 } 1136 1137 video.target.load(); 1138 video.target.classList.remove("lazy"); 1139 lazyVideoObserver.unobserve(video.target); 1140 } 1141 }); 1142 }); 1143 1144 lazyVideos.forEach(function(lazyVideo) { 1145 lazyVideoObserver.observe(lazyVideo); 1146 }); 1147 } 1148 })(); 1149 </script>
1149 1150 1151 <!-- Global site tag (gtag.js) - Google Analytics --> 1152
1152<script defer src="https://www.googletagmanager.com/gtag/js"></script>
1152 1153 1154 <!-- Google Tag Manager --> 1155
1155<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 1156 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 1157 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.defer=true;j.async=false;j.src= 1158 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 1159 })(window,document,'script','dataLayer','GTM-T9SFQGHZ');</script>
1159 1160 <!-- End Google Tag Manager --> 1161 1162 1163 <!-- LP Tracker (divolte.js) - LP Divolte --> 1164
1164<script>window.divolteLp=window.divolteLp||function(){(divolteLp.q=divolteLp.q||[]).push(arguments)}</script>
1164 1165 <!-- LP Tracker (eventBus) - LP EventBus --> 1166
1166<script>window.eventBusLp=window.eventBusLp||function(){(eventBusLp.q=eventBusLp.q||[]).push(arguments)}</script>
1166 1167 1168
1168<script> 1169 window.dataLayer = window.dataLayer || []; 1170 document.sendGoogleTagManagerEvent = function() { 1171 /* Honor GPC-enabled browsers and prevent GTM event if GPC is enabled. More details: https://global-privacy-control.glitch.me/ */ 1172 if (window.navigator.globalPrivacyControl) { 1173 return; 1174 } 1175 1176 dataLayer.push(arguments); 1177 } 1178 1179 document.sendGoogleTagManagerEvent('js', new Date()); 1180 document.sendGoogleTagManagerEvent('config', 'G-TZS4N64H5J', { page: location.pathname, location: location.href }); 1181 document.sendGoogleAnalyticsEvent = function(googleEvent) { 1182 document.sendGoogleTagManagerEvent('event', googleEvent.eventAction || googleEvent.hitType, { 1183 event_category: googleEvent.eventCategory, 1184 event_label: googleEvent.eventLabel, 1185 value: googleEvent.eventValue, 1186 page: googleEvent.page, 1187 location: googleEvent.location 1188 }) 1189 }; 1190 1191 document.addEventListener("DOMContentLoaded", function() { 1192 (function() { 1193 //If the page has an element with ID of auto-year-update the element will be populated with the current year. 1194 var date = new Date(); 1195 var elements = document.getElementsByClassName('auto-year-update'); 1196 var i; 1197 for (i = 0; i < elements.length; i++) { 1198 elements[i].innerText = date.getFullYear(); 1199 } 1200 })(); 1201 if (window.divolteLp) { 1202 window.divolteLp('sendLpPageView', {}); 1203 } 1204 if (window.eventBusLp) { 1205 window.eventBusLp('sendLpPageView', {}); 1206 } 1207 }); 1208 </script>
1208 1209 1210 1211
1211<script> 1212 // Function to dynamically load a script 1213 function loadScript(url, callback) { 1214 var script = document.createElement('script'); 1215 script.type = 'text/javascript'; 1216 script.src = url; 1217 script.defer = true; 1218 script.async = true; 1219 script.onload = callback; 1220 document.head.appendChild(script); 1221 } 1222 1223 // Function to dynamically load CSS file 1224 function loadCSS(url) { 1225 var link = document.createElement("link"); 1226 link.rel = "stylesheet"; 1227 link.href = url; 1228 document.head.appendChild(link); 1229 } 1230 1231 // Global methods / variables that can be accessed by element js 1232 window.luxuryPresence = { 1233 libs: { 1234 loadJs: loadScript, 1235 loadCss: loadCSS, 1236 jsLibsMap: { 1237 paroller: { 1238 jsSrc: 'https://d1e1jt2fj4r8r.cloudfront.net/javascript/jquery.paroller.min.js', 1239 isLoaded: false, 1240 }, 1241 ionRangeSlider: { 1242 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js', 1243 cssSrc: 'https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css', 1244 isLoaded: false, 1245 requires: ['jquery'], 1246 }, 1247 splide: { 1248 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/splidejs/4.1.4/js/splide.min.js', 1249 cssSrc: 'https://cdnjs.cloudflare.com/ajax/libs/splidejs/4.1.4/css/splide-core.min.css', 1250 isLoaded: false, 1251 }, 1252 wow: { 1253 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js', 1254 isLoaded: false, 1255 }, 1256 jquery: { 1257 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js', 1258 isLoaded: false, 1259 }, 1260 slick: { 1261 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js', 1262 isLoaded: false, 1263 requires: ['jquery'], 1264 }, 1265 libphonenumber: { 1266 jsSrc: 'https://cdnjs.cloudflare.com/ajax/libs/libphonenumber-js/1.11.8/libphonenumber-js.min.js', 1267 isLoaded: false, 1268 }, 1269 }, 1270 }, 1271 }; 1272 </script>
1272 1273
1273<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>
1273 1274
1274<script defer src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js"></script>
1274 1275
1275<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/handlebars-intl.min.js"></script>
1275 1276
1276<script defer src="https://cdnjs.cloudflare.com/ajax/libs/superagent/4.1.0/superagent.min.js"></script>
1276 1277
1277<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>
1277 1278
1278<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>
1278 1279
1279<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>
1279 1280 1281 <!-- GOOGLE TRANSLATE SCRIPT --> 1282
1282<script> 1283 function googleTranslateElementInit() { 1284 // list of languages can be overridden by setting window.customLanguages in the head JS. example `window.customLanguages = 'en,de,fr,ro,sk,pl'` 1285 // Language codes can be taken from here https://cloud.google.com/translate/docs/languages 1286 const DEFAULT_LANGUAGES = 'en,es,zh-CN,zh-TW,tl,vi,ar,ko,ru,de,fr,hi,pt'; 1287 document.querySelectorAll('[data-type="TRANSLATE"]').forEach(function(translate){ 1288 translate.innerText = ''; 1289 new google.translate.TranslateElement({ 1290 pageLanguage: 'en', 1291 layout: google.translate.TranslateElement.InlineLayout.SIMPLE, 1292 includedLanguages: window.customLanguages || DEFAULT_LANGUAGES, 1293 }, translate); 1294 }); 1295 } 1296 </script>
1296 1297
1297<script defer src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
1297 1298
1298<script defer src="https://accounts.google.com/gsi/intermediate"></script>
1298 1299 1300 <!-- GOOGLE TRANSLATE SCRIPT END--> 1301
1301<script> 1302 1303 // UI helpers 1304 (function () { 1305 1306 function getSideMenu () { 1307 return document.querySelector('body > div.sidemenu'); 1308 } 1309 1310 function sideMenuHide (instant) { 1311 var sideMenu = getSideMenu(); 1312 if (!sideMenu || !sideMenu.classList.contains('visible')) { 1313 return; 1314 } 1315 sideMenu.classList.remove('visible'); 1316 sideMenu.dispatchEvent(new CustomEvent('lpui-hide', { detail: { instant: !!instant } })); 1317 window.dispatchEvent(new CustomEvent('lpui-sidemenu-hide', { detail: {instant: !!instant} })); 1318 } 1319 1320 function sideMenuShow () { 1321 var sideMenu = getSideMenu(); 1322 if (!sideMenu || sideMenu.classList.contains('visible')) { 1323 return; 1324 } 1325 sideMenu.classList.add('visible'); 1326 sideMenu.dispatchEvent(new Event('lpui-show')); 1327 window.dispatchEvent(new Event('lpui-sidemenu-show')); 1328 } 1329 1330 function sideMenuToggle () { 1331 var sideMenu = getSideMenu(); 1332 if (!sideMenu) { 1333 return; 1334 } 1335 var isSideMenuVisible = sideMenu.classList.contains('visible'); 1336 if (isSideMenuVisible) { 1337 sideMenuHide(); 1338 } else { 1339 sideMenuShow(); 1340 } 1341 } 1342 1343 var scrollLockRequests = {}; 1344 window.__debug_scrollLockRequests = scrollLockRequests; 1345 var hideScrollStyles = ''+ 1346 'body {'+ 1347 'overflow: hidden;' + 1348 '}'; 1349 var hideScrollId = 'hide-body-scroll-style'; 1350 1351 function scrollLock () { 1352 var style = document.createElement('style'); 1353 style.id = hideScrollId; 1354 style.textContent = hideScrollStyles; 1355 document.head.appendChild(style); 1356 window.dispatchEvent(new Event('lpui-scroll-locked')); 1357 } 1358 1359 function scrollUnlock () { 1360 document.getElementById(hideScrollId)?.remove(); 1361 window.dispatchEvent(new Event('lpui-scroll-unlocked')); 1362 } 1363 1364 function requestScrollLock (lockId) { 1365 var wasLocked = Object.keys(scrollLockRequests).length > 0; 1366 scrollLockRequests[lockId || '__anonymous_lock'] = true; 1367 if (!wasLocked) { 1368 scrollLock(); 1369 } 1370 } 1371 1372 function releaseScrollLock (lockId) { 1373 if (lockId) { 1374 delete scrollLockRequests[lockId]; 1375 if (!Object.keys(scrollLockRequests).length) { 1376 scrollUnlock(); 1377 } 1378 } else { 1379 scrollLockRequests = {}; 1380 window.__debug_scrollLockRequests = scrollLockRequests; 1381 scrollUnlock(); 1382 } 1383 } 1384 1385 function showModal (modalId, options) { 1386 var modal = document.getElementById(modalId); 1387 if (!modal) { 1388 return; 1389 } 1390 1391 if (!modal.classList.contains('visible')) { 1392 modal.classList.add('visible'); 1393 if (options && options.scrollLock) { 1394 window.lpUI.requestScrollLock(modalId); 1395 } 1396 modal.dispatchEvent(new Event('lpui-show')); 1397 window.dispatchEvent(new CustomEvent('lpui-modal-show', { detail: { id: modalId } })); 1398 } 1399 1400 const visibleModals = document.querySelectorAll('.modal.visible'); 1401 1402 if (visibleModals.length > 1) { 1403 1404 const maxZIndex = Array.from(visibleModals).reduce((maxZIndex, modal) => { 1405 const zIndex = window.getComputedStyle(modal).zIndex; 1406 const parsedZIndex = zIndex !== 'auto' ? parseInt(zIndex) : 0; 1407 return Math.max(maxZIndex, parsedZIndex); 1408 }, 0); 1409 1410 modal.style.zIndex = maxZIndex + 1; 1411 } 1412 1413 } 1414 1415 function _hideModal (modalEl) { 1416 if (!modalEl) { 1417 return; 1418 } 1419 if (!modalEl.classList.contains('visible')) { 1420 return; 1421 } 1422 modalEl.classList.remove('visible'); 1423 modalEl.style.zIndex = '';
1424 modalEl.dispatchEvent(new Event('lpui-hide')); 1425 var modalId = modalEl.getAttribute('id'); 1426 if (modalId) { 1427 window.lpUI.releaseScrollLock(modalId); 1428 window.dispatchEvent(new CustomEvent('lpui-modal-hide', { detail: { id: modalId } })); 1429 } 1430 } 1431 1432 function hideModal (modalId) { 1433 _hideModal(document.getElementById(modalId)); 1434 } 1435 1436 function hideClosestModal (el) { 1437 const modal = el?.closest('.modal'); 1438 if (!modal) { 1439 return; 1440 } 1441 if (modal.classList) { 1442 _hideModal(modal); 1443 return; 1444 } 1445 if (modal.length && modal[0].classList) { 1446 _hideModal(modal[0]); 1447 } 1448 } 1449 1450 window.lpUI = { 1451 sideMenuHide: sideMenuHide, 1452 sideMenuShow: sideMenuShow, 1453 sideMenuToggle: sideMenuToggle, 1454 requestScrollLock: requestScrollLock, 1455 releaseScrollLock: releaseScrollLock, 1456 showModal: showModal, 1457 hideModal: hideModal, 1458 hideClosestModal: hideClosestModal 1459 } 1460 })(); 1461 1462 var stringifyPrimitive = function(v) { 1463 switch (typeof v) { 1464 case 'string': 1465 return v; 1466 1467 case 'boolean': 1468 return v ? 'true' : 'false'; 1469 1470 case 'number': 1471 return isFinite(v) ? v : ''; 1472 1473 default: 1474 return ''; 1475 } 1476 }; 1477 1478 function objectToQuerystring(obj, sep, eq, name) { 1479 // https://github.com/Gozala/querystring/blob/master/encode.js 1480 sep = sep || '&'; 1481 eq = eq || '='; 1482 if (obj === null) { 1483 obj = undefined; 1484 } 1485 1486 if (typeof obj === 'object') { 1487 return Object.keys(obj).map(function(k) { 1488 var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; 1489 if (Array.isArray(obj[k])) { 1490 return obj[k].map(function(v) { 1491 return ks + encodeURIComponent(stringifyPrimitive(v)); 1492 }).join(sep); 1493 } else { 1494 return ks + encodeURIComponent(stringifyPrimitive(obj[k])); 1495 } 1496 }).filter(Boolean).join(sep); 1497 1498 } 1499 1500 if (!name) return ''; 1501 return encodeURIComponent(stringifyPrimitive(name)) + eq + 1502 encodeURIComponent(stringifyPrimitive(obj)); 1503 } 1504 1505 function getPath(url, options) { 1506 var parser = document.createElement('a'); 1507 parser.href = url || ''; 1508 var path = parser.pathname || ''; 1509 if (path[0] !== '/') { 1510 // IE does not return path starting with a slash 1511 path = '/' + path; 1512 } 1513 1514 if (options && options.queryString) { 1515 path += parser.search; 1516 } 1517 1518 return path; 1519 } 1520 1521 function getMLSAutocomplete(keyword) { 1522 var searchURL = window.location.protocol + '//' + window.location.hostname + '/home-search/auto_complete'; 1523 var query = { 1524 kind: 'listings', 1525 query: keyword 1526 }; 1527 1528 return superagent 1529 .get(searchURL) 1530 .query(query) 1531 .then(function(res) { 1532 var data = res.body || []; 1533 /* 1534 Of the format: 1535 [{ 1536 "_index": "listing_auto_completes_production_20190723232720775", 1537 "_type": "listing_auto_complete", 1538 "_id": "235875624", 1539 "_score": 0, 1540 "status_modified_at": 1553250708, 1541 "city": "Jupiter", 1542 "price": 1335743, 1543 "display_address": "10088 Calabrese Trail Unit: 9 Jupiter FL 33478", 1544 "sold_price": null, 1545 "id": 235875624, 1546 "state": "FL", 1547 "photo_urls": [ 1548 "http://cdn.photos.sparkplatform.com/fl/20190322153144208228000000-o.jpg" 1549 ], 1550 "status": "Pending" 1551 }, ...] 1552 */ 1553 1554 return data; 1555 }); 1556 } 1557 1558 function getMLSAutocompleteWithFilters(keyword, filters = {}) { 1559 var searchURL = window.location.protocol + '//' + window.location.hostname + '/home-search/auto_complete'; 1560 1561 return superagent 1562 .get(searchURL) 1563 .query({ kind: 'listings', query: keyword, ...filters }) 1564 .then(function(res) { 1565 /* 1566 Of the format: 1567 [{ 1568 "_index": "listing_auto_completes_production_20190723232720775", 1569 "_type": "listing_auto_complete", 1570 "_id": "235875624", 1571 "_score": 0, 1572 "status_modified_at": 1553250708, 1573 "city": "Jupiter", 1574 "price": 1335743, 1575 "display_address": "10088 Calabrese Trail Unit: 9 Jupiter FL 33478", 1576 "sold_price": null, 1577 "id": 235875624, 1578 "state": "FL", 1579 "photo_urls": [ 1580 "http://cdn.photos.sparkplatform.com/fl/20190322153144208228000000-o.jpg" 1581 ], 1582 "status": "Pending" 1583 }, ...] 1584 */ 1585 return res.body || []; 1586 }); 1587 } 1588 1589 function makeMlsLink(data) { 1590 // Code Dupe from utils/googlePlace 1591 // mapping of google data type to mls data type 1592 var mapping = { 1593 neighborhood: 'neighborhood', 1594 locality: 'place', 1595 administrative_area_level_2: 'county', 1596 administrative_area_level_1: 'state', 1597 postal_code: 'postalcode', 1598 }; 1599 1600 function _filterTypes(types) { 1601 return types.filter(function(type) { return type !== 'political' }); 1602 } 1603 1604 if (!data || !Object.keys(data).length) { 1605 return '/home-search/listings'; 1606 } 1607 1608 var newData = {};
1609 _filterTypes(data.types).forEach(function(type) { 1610 if (mapping[type]) { 1611 newData.search_type = mapping[type]; 1612 } 1613 }); 1614 newData.omnibox = data.formatted_address; 1615 data.address_components.forEach(function(component) { 1616 _filterTypes(component.types).forEach(function(type) { 1617 if (mapping[type]) { 1618 newData[mapping[type]] = component.long_name; 1619 } 1620 }); 1621 }); 1622 var bounds = data.geometry.bounds; 1623 var convertedData = Object.assign(bounds, newData); 1624 1625 return '/home-search/listings?' + objectToQuerystring(convertedData); 1626 } 1627 1628 function debounce(func, wait) { 1629 let timeout; 1630 return function(...args) { 1631 const context = this; 1632 clearTimeout(timeout); 1633 timeout = setTimeout(() => func.apply(context, args), wait) 1634 } 1635 } 1636 1637 // Global methods / variables that can be accessed by element js 1638 window.luxuryPresence = { 1639 ...window.luxuryPresence, 1640 defaults: { 1641 companyId: '7638a4cd-9580-4d1f-a8a5-ac3b4943a953', 1642 apiGatewayUrl: '/api-gw', 1643 routerUrl: '/api-nv', 1644 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\
1644n }\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-
1644abb7-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
1644onId,\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}"}, 1645 propertyPlaceholderImage: {"id":"56aa76e7-3261-43a6-bcde-897a70a5572b","alt":null,"bytes":20440,"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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","authorUrl":null,"createdAt":"2025-07-08T00:11:22.878Z","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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","sourceUrl":null,"updatedAt":"2025-07-08T00:11:22.878Z","xLargeUrl":"https://media-production.lp-cdn.com/cdn-cgi/image/format=auto,quality=85/https://media-production.lp-cdn.com/media/ffe2f904-4bfe-4575-968e-cd5a25fd1194","__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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","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/ffe2f904-4bfe-4575-968e-cd5a25fd1194","originalFileName":"Property_lockup_logo","cloudinaryPublicId":"ffe2f904-4bfe-4575-968e-cd5a25fd1194"} 1646 }, 1647 objectToQuerystring: objectToQuerystring, 1648 getPath: getPath, 1649 getMLSAutocomplete: getMLSAutocomplete, 1650 getMLSAutocompleteWithFilters: getMLSAutocompleteWithFilters, 1651 makeMlsLink: makeMlsLink, 1652 debounce: debounce, 1653 }; 1654 1655 var wowOffset = 100; 1656 </script>
1656 1657
1657<script> 1658 (() => { 1659 1660function $parcel$interopDefault(a) { 1661 return a && a.__esModule ? a.default : a; 1662} 1663// Entry point for lp-sdk bundle 1664// This file exists to ensure Parcel v2 outputs the correct filename 1665/* global window */ var $53de3c160faf5a81$exports = {}; 1666/* 1667WARNING!!! This file is used both on the server and in client's web-browser 1668please don't require/import any server-side related config/functions here 1669If we need something, let's pass it as a parameter of the factory 1670*/ var $0ce6edea77f7b81a$exports = {}; 1671$0ce6edea77f7b81a$exports = { 1672 getVideoFirstFrame (videoUrl) { 1673 // 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> 1674 // https://cloudinary.com/documentation/video_manipulation_and_delivery#transformation_url_structure 1675 // The problem is that <transformations> and <version> are optional, and <transformations> can be chained separated by '/' 1676 // One more issue to be handled https://cloudinary.com/documentation/advanced_url_delivery_options#seo_friendly_media_asset_urls 1677 const CLOUDINARY_URL = 'https://res.cloudinary.com/'; 1678 const invalid = !videoUrl || !videoUrl.startsWith(CLOUDINARY_URL); 1679 if (invalid) return null; 1680 const urlComponents = videoUrl.replace(CLOUDINARY_URL, '').replace('f_auto:video', 'f_auto').split('/'); 1681 // checking if <asset_type> is not video or videos 1682 if (urlComponents[1].toLowerCase().indexOf('video') === -1) return null; 1683 // Filename is last urlComponent <public_id>.<extension> 1684 let filename = urlComponents[urlComponents.length - 1]; 1685 if (filename.lastIndexOf('.') > -1) filename = `${filename.slice(0, filename.lastIndexOf('.'))}.jpg`; 1686 else filename += '.jpg'; 1687 urlComponents[urlComponents.length - 1] = filename; 1688 // We need to add so_0,eo_0 transformation to the url to target the first frame. 1689 // we want to find the position at which we want to insert it as a chained transformation 1690 const firstFrameTransformation = 'so_0,eo_0'; 1691 let firstFrameTransformationPosition = 3; 1692 // checking cases for SEO-friendly URLs 1693 if (urlComponents[1].toLowerCase() === 'videos' && urlComponents[2] !== '') firstFrameTransformationPosition = 2; 1694 // checking the last transformation position in the url 1695 // https://cloudinary.com/documentation/transformation_reference 1696 // https://regex101.com/r/lE3W6u/1 1697 const transformationRegex = /^(?:[a-z]{1,3}|\$\w+)_\S+$/; 1698 while(firstFrameTransformationPosition < urlComponents.length - 1 && transformationRegex.test(urlComponents[firstFrameTransformationPosition]))firstFrameTransformationPosition++; 1699 urlComponents.splice(firstFrameTransformationPosition, 0, firstFrameTransformation); 1700 return CLOUDINARY_URL + urlComponents.join('/'); 1701 } 1702}; 1703 1704 1705/** 1706 * Create helpers with given Handlebars instance 1707 * 1708 * @param {Object} HandlebarsInstance 1709 * @param {Function} isEqual - we use different implementation if isEqual on server and on client 1710 * @return {Object} 1711 */ function $53de3c160faf5a81$var$handlebarsHelpersFactory(HandlebarsInstance, { isEqual: isEqual }) { 1712 // notice!: code below assumes list is ordered lowest to highest width 1713 const MEDIA_SIZES = [ 1714 { 1715 field: 'thumbnailUrl', 1716 w: 320 1717 }, 1718 { 1719 field: 'smallUrl', 1720 w: 960 1721 }, 1722 { 1723 field: 'mediumUrl', 1724 w: 1280 1725 }, 1726 { 1727 field: 'largeUrl', 1728 w: 1920 1729 }, 1730 { 1731 field: 'xLargeUrl', 1732 w: 2560 1733 }, 1734 { 1735 field: 'xxLargeUrl', 1736 w: 3456 1737 } 1738 ]; 1739 const MEDIA_SIZE_FOR_SRC = 1280; 1740 const lpFormatNumber = function(number, unit, precision) { 1741 const localization = 'en-US'; 1742 if (!number) return ''; 1743 if (typeof number === 'string') { 1744 const trimmed = number.trim(); 1745 if (/[^+\-0-9.]/.test(trimmed)) return number; // returning text 'as is' assuming it already has all formatting 1746 // eslint-disable-next-line 1747 number = parseFloat(trimmed); 1748 if (!number) return ''; 1749 } 1750 const currencyPrecision = typeof precision === 'number' ? precision : 0; 1751 const currencyFractionDigits = Number.isInteger(number) ? 0 : currencyPrecision; 1752 const currencyFractionOptions = { 1753 minimumFractionDigits: currencyFractionDigits, 1754 maximumFractionDigits: currencyFractionDigits 1755 };
1756 if (unit === 'USD') return `$${number.toLocaleString(localization, currencyFractionOptions)}`; 1757 if (unit === 'CAD') return `$${number.toLocaleString(localization, currencyFractionOptions)} CAD`; 1758 if (unit === 'EUR') return `\u{20AC}${number.toLocaleString(localization, currencyFractionOptions)}`; 1759 if (unit === 'GBP') return `\xa3${number.toLocaleString(localization, currencyFractionOptions)}`; 1760 if (unit === 'PERCENT') return `${number}%`; 1761 if (typeof precision === 'number' && precision > -1) return number.toLocaleString(localization, { 1762 maximumFractionDigits: precision 1763 }); 1764 return number.toLocaleString(localization); 1765 }; 1766 const formatFrequency = function(freqUnit) { 1767 switch(freqUnit){ 1768 case 'DAY': 1769 return 'daily'; 1770 case 'MONTH': 1771 return 'monthly'; 1772 case 'WEEK': 1773 return 'weekly'; 1774 case 'YEAR': 1775 return 'yearly'; 1776 case 'QUARTER': 1777 return 'quarterly'; 1778 case 'HALF_YEAR': 1779 return 'semi-annually'; 1780 case 'NIGHTLY': 1781 return 'nightly'; 1782 case 'SEASONAL': 1783 return 'seasonally'; 1784 default: 1785 return ''; 1786 } 1787 }; 1788 const formatFrequencyShort = function(freqUnit) { 1789 switch(freqUnit){ 1790 case 'DAY': 1791 return 'day'; 1792 case 'WEEK': 1793 return 'wk'; 1794 case 'MONTH': 1795 return 'mo'; 1796 case 'YEAR': 1797 return 'yr'; 1798 case 'QUARTER': 1799 return '3 mos'; 1800 case 'HALF_YEAR': 1801 return '6 mos'; 1802 case 'NIGHTLY': 1803 return 'night'; 1804 case 'SEASONAL': 1805 return 'season'; 1806 default: 1807 return ''; 1808 } 1809 }; 1810 const formatFrequencyStd = function(freqUnit) { 1811 switch(freqUnit){ 1812 case 'DAY': 1813 return 'day'; 1814 case 'WEEK': 1815 return 'week'; 1816 case 'MONTH': 1817 return 'month'; 1818 case 'YEAR': 1819 return 'year'; 1820 case 'QUARTER': 1821 return 'quarter'; 1822 case 'HALF_YEAR': 1823 return '6 months'; 1824 case 'NIGHTLY': 1825 return 'night'; 1826 case 'SEASONAL': 1827 return 'season'; 1828 default: 1829 return ''; 1830 } 1831 }; 1832 const formatFrequencyExt = function(unit, options) { 1833 let val; 1834 let separator; 1835 const opts = options || {}; 1836 switch(opts.mode){ 1837 case 'short': 1838 val = formatFrequencyShort(unit); 1839 separator = opts.frequencySeparator || '/'; 1840 break; 1841 case 'standard': 1842 case 'std': 1843 val = formatFrequencyStd(unit); 1844 separator = opts.frequencySeparator || '/'; 1845 break; 1846 case 'long': 1847 default: 1848 val = formatFrequency(unit); 1849 separator = opts.frequencySeparator || ' '; 1850 } 1851 if (!val) return ''; 1852 if (!opts.frequencyTag && !opts.frequencyClass) return separator + val; 1853 return `${separator}<${opts.frequencyTag || 'span'}${opts.frequencyClass ? ` class="${opts.frequencyClass}"` : ''}>${val}</${opts.frequencyTag || 'span'}>`; 1854 }; 1855 return { 1856 isEmpty (arg1, options) { 1857 const result = !arg1 || (typeof arg1 === 'string' ? !arg1.trim() : false) || !Object.keys(arg1).length; 1858 if (options.fn) return result ? options.fn(this) : options.inverse(this); 1859 return result; 1860 }, 1861 ifEquals (arg1, arg2, options) { 1862 return isEqual(arg1, arg2) ? options.fn(this) : options.inverse(this); 1863 }, 1864 'raw-helper': function(options) { 1865 return options.fn(); 1866 }, 1867 striptags (txt) { 1868 if (!txt) return ''; 1869 // Remove HTML Comments (escaping something to not make real html comment by expression) 1870 // eslint-disable-next-line no-useless-escape,no-param-reassign 1871 txt = txt.replace(/<\!--(.|[\r\n])*?-\->/g, ''); 1872 // Remove XML fragments and <style> and <svg> tags with content 1873 // eslint-disable-next-line 1874 txt = txt.replace(/<(xml|style|svg)("[^"]*"|'[^']*'|[^>])*>(.|[\r\n])*?<\/\1>/gi, ''); 1875 // Replace with space 1876 // eslint-disable-next-line no-param-reassign 1877 txt = txt.replace(/ /g, ' '); 1878 // Remove HTML Tags 1879 const regexp = /<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g; 1880 return txt.replace(regexp, ''); 1881 },
1882 striptagsLineBreaks (txt) { 1883 if (!txt) return ''; 1884 // Remove HTML Comments (escaping something to not make real html comment by expression) 1885 // eslint-disable-next-line no-useless-escape,no-param-reassign 1886 txt = txt.replace(/<\!--(.|[\r\n])*?-\->/g, ''); 1887 // Remove XML fragments and <style> and <svg> tags with content 1888 // eslint-disable-next-line no-param-reassign 1889 txt = txt.replace(/<(xml|style|svg)("[^"]*"|'[^']*'|[^>])*>(.|[\r\n])*?<\/\1>/gi, ''); 1890 // Replace <br> and </p> tags with line break char, skipping last </p> which is not followed by <br> or </p> 1891 // eslint-disable-next-line no-param-reassign 1892 txt = txt.replace(/(<br\s*\/?>)|(<\/p\s*>)(?=.*(<\/p\s*>|<br\s*\/?>))/g, ' '); 1893 // Replace with space 1894 // eslint-disable-next-line no-param-reassign 1895 txt = txt.replace(/ /g, ' '); 1896 // Remove HTML Tags 1897 const regexp = /<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g; 1898 return txt.replace(regexp, ''); 1899 }, 1900 truncate (text, limit, suffix) { 1901 if (!text) return ''; 1902 if (text.length > limit) return typeof suffix === 'string' ? text.slice(0, limit - suffix.length) + suffix : text.slice(0, limit); 1903 return text; 1904 }, 1905 // eslint-disable-next-line 1906 setSubArray (items = [], start, end, subArrayName, options) { 1907 // eslint-disable-next-line 1908 options.data.root[subArrayName] = items.slice(start, end); 1909 }, 1910 formatAreaUnit (areaUnit) { 1911 switch(areaUnit){ 1912 case 'ACRE': 1913 return 'Acres'; 1914 case 'SQUARE_METER': 1915 return 'Sq.M.'; 1916 case 'SQUARE_YARD': 1917 return 'Sq.Yd.'; 1918 default: 1919 return 'Sq.Ft.'; 1920 } 1921 }, 1922 formatFrequency: formatFrequency, 1923 formatFrequencyShort: formatFrequencyShort, 1924 lpFormatFrequency (freqUnit, options) { 1925 return formatFrequencyExt(freqUnit, options && options.hash); 1926 }, 1927 subArray (index, start, end, options) { 1928 return index >= start && index < end ? options.fn(this) : options.inverse(this); 1929 }, 1930 formatPropertyStatus (status, showSoldDate, date) { 1931 let formattedStatus = ''; 1932 switch(status){ 1933 case 'SOLD': 1934 formattedStatus = 'Sold'; 1935 break; 1936 case 'FOR_SALE': 1937 formattedStatus = 'For Sale'; 1938 break; 1939 case 'COMING_SOON': 1940 formattedStatus = 'Coming Soon'; 1941 break; 1942 case 'INACTIVE': 1943 formattedStatus = 'Inactive'; 1944 break; 1945 case 'POCKET_LISTING': 1946 formattedStatus = 'Pocket Listing'; 1947 break; 1948 case 'PENDING': 1949 formattedStatus = 'Pending'; 1950 break; 1951 case 'UNDER_CONTRACT': 1952 formattedStatus = 'Under Contract'; 1953 break; 1954 case 'ACTIVE_UNDER_CONTRACT': 1955 formattedStatus = 'Active Under Contract'; 1956 break; 1957 default: 1958 formattedStatus = status; 1959 } 1960 // `typeof date === 'string'` matters: when called as 1961 // `{{formatPropertyStatus status}}` Handlebars passes its options object 1962 // as `showSoldDate`/`date`, and this guard keeps the legacy output. 1963 if ((formattedStatus === 'Sold' || formattedStatus === 'Leased') && showSoldDate && typeof date === 'string' && date) formattedStatus += ` on ${date}`; 1964 return formattedStatus; 1965 }, 1966 formatGrade (gradeValue) { 1967 switch(gradeValue){ 1968 case 'UNDERGRADUATE_COURSES': 1969 return 'Undergrad'; 1970 case 'PRE_KINDERGARTEN': 1971 return 'PreK'; 1972 case 'KINDERGARTEN': 1973 return 'K'; 1974 case 'FIRST_GRADE': 1975 return '1st'; 1976 case 'SECOND_GRADE': 1977 return '2nd'; 1978 case 'THIRD_GRADE': 1979 return '3rd'; 1980 case 'FOURTH_GRADE': 1981 return '4th'; 1982 case 'FIFTH_GRADE': 1983 return '5th'; 1984 case 'SIXTH_GRADE': 1985 return '6th'; 1986 case 'SEVENTH_GRADE': 1987 return '7th'; 1988 case 'EIGHTH_GRADE': 1989 return '8th'; 1990 case 'NINTH_GRADE': 1991 return '9th'; 1992 case 'TENTH_GRADE': 1993 return '10th'; 1994 case 'ELEVENTH_GRADE': 1995 return '11th'; 1996 case 'TWELFTH_GRADE': 1997 return '12th'; 1998 default: 1999 return ''; 2000 } 2001 }, 2002 encodeURI (uri) { 2003 return encodeURI(uri); 2004 }, 2005 encodeURIComponent (txt) { 2006 return encodeURIComponent(txt); 2007 }, 2008 hbFormatDate (date, type) { 2009 if (!date) return ''; 2010 const newDate = date === 'current' ? new Date() : new Date(date); 2011 if (Number.isNaN(newDate.getTime())) return ''; 2012 const months = [ 2013 'January', 2014 'February', 2015 'March', 2016 'April', 2017 'May', 2018 'June', 2019 'July', 2020 'August', 2021 'September', 2022 'October',
2023 'November', 2024 'December' 2025 ]; 2026 if (type === 'YYYY' || type === 'year') return `${newDate.getFullYear()}`; 2027 if (type === 'MM/DD/YY') { 2028 let month = newDate.getMonth() + 1; 2029 if (month < 10) month = `0${month.toString()}`; 2030 return `${month}/${newDate.getDate()}/${newDate.getFullYear().toString().substr(-2)}`; 2031 } 2032 return `${months[newDate.getMonth()]} ${newDate.getDate()}, ${newDate.getFullYear()}`; 2033 }, 2034 openHousesFormat (startDate, endDate, timeZone) { 2035 if (!startDate || !endDate) return ''; 2036 /** 2037 * return formatted time. 2038 * @param {date} date 2039 * @return {time} time. 2040 */ const getTime = (date)=>{ 2041 let hours = date.getHours(); 2042 if (hours > 12) hours -= 12; 2043 const prefix = '0'; 2044 let time = `${hours}:${date.getMinutes() > 9 ? date.getMinutes() : prefix + date.getMinutes()}`; 2045 if (date.getHours() > 11) time += 'PM'; 2046 else time += 'AM'; 2047 return time; 2048 }; 2049 let tz = ''; 2050 let startFDate = startDate; 2051 let endFDate = endDate; 2052 if (timeZone) { 2053 startFDate = new Date(startDate).toLocaleString('en-US', { 2054 timeZone: timeZone 2055 }); 2056 endFDate = new Date(endDate).toLocaleString('en-US', { 2057 timeZone: timeZone 2058 }); 2059 [, , , tz] = new Date(endDate).toLocaleString('en-US', { 2060 timeZone: timeZone, 2061 timeZoneName: 'short' 2062 }).split(' '); 2063 } 2064 const date = new Date(startFDate); 2065 const openHouseDate = date.toLocaleDateString('en-US'); 2066 const time1 = getTime(date); 2067 const date2 = new Date(endFDate); 2068 const time2 = getTime(date2); 2069 return `${openHouseDate} ${time1} - ${time2} ${tz}`; 2070 }, 2071 math (lvalue, operator, rvalue) { 2072 // eslint-disable-next-line 2073 lvalue = parseFloat(lvalue); 2074 // eslint-disable-next-line 2075 rvalue = parseFloat(rvalue); 2076 return ({ 2077 '+': lvalue + rvalue, 2078 '-': lvalue - rvalue, 2079 '*': lvalue * rvalue, 2080 '/': lvalue / rvalue, 2081 '%': lvalue % rvalue 2082 })[operator]; 2083 }, 2084 findByKey (values, key, value, options) { 2085 const result = (values || []).find((entry)=>entry[key] === value); 2086 return options.fn(result); 2087 }, 2088 capitalize (string, split, options) { 2089 let capitalized; 2090 if (typeof string === 'string' && string.length) capitalized = string.toLowerCase().split(split).map((w)=>w.charAt(0).toUpperCase() + w.slice(1)).join(' ').toString(); 2091 return capitalized; 2092 }, 2093 and (...arg) { 2094 return Array.prototype.slice.call(arg).every(Boolean); 2095 }, 2096 or (...arg) { 2097 return Array.prototype.slice.call(arg, 0, -1).some(Boolean); 2098 }, 2099 not (arg) { 2100 return !arg; 2101 }, 2102 orderByIds (items, orderedIds, options) { 2103 let ret = ''; 2104 let data = null; 2105 if (options.data) data = HandlebarsInstance.createFrame(options.data); 2106 // When passed orderedIds, filter out empty items including empty strings and 2107 // only show items (and in that order) in a loop 2108 // If no orderedIds provided, show all items 2109 const filteredIds = (orderedIds || []).filter(Boolean); 2110 if (filteredIds && filteredIds.length) { 2111 let skippedItems = 0; 2112 ret = filteredIds.reduce((res, id, idx)=>{ 2113 const item = (items || []).find((item)=>item.id === id); 2114 // ID doesn't exist so ditch it 2115 if (!item) { 2116 skippedItems += 1; 2117 return res; 2118 } 2119 if (data) data.index = idx - skippedItems; 2120 return res + options.fn(item, { 2121 data: data 2122 }); 2123 }, ''); 2124 } else for(let i = 0, j = (items || []).length; i < j; i++){ 2125 if (data) data.index = i; 2126 ret += options.fn(items[i], { 2127 data: data 2128 }); 2129 } 2130 return ret; 2131 }, 2132 ifIn (elem, list, options) { 2133 if (list && list.indexOf(elem) > -1) return options.fn(this); 2134 return options.inverse(this); 2135 }, 2136 partial (name, options) { 2137 // Register a partial and output the content in a script for clientside rendering 2138 HandlebarsInstance.registerPartial(name, HandlebarsInstance.compile(options.fn())); 2139 // eslint-disable-next-line 2140 const script = `
2140<script type="text/x-handlebars-template" class="${name} pagination-script">${options.fn()}</${'script'}>`; 2141 return script; 2142 }, 2143 numCompare (l, r, operator, options) { 2144 const operators = { 2145 '==': function(l, r) { 2146 // eslint-disable-next-line 2147 return l == r; 2148 }, 2149 '===': function(l, r) { 2150 return l === r; 2151 }, 2152 '!=': function(l, r) { 2153 // eslint-disable-next-line 2154 return l != r; 2155 }, 2156 '<': function(l, r) { 2157 return l < r; 2158 }, 2159 '>': function(l, r) { 2160 return l > r; 2161 }, 2162 '<=': function(l, r) { 2163 return l <= r; 2164 }, 2165 '>=': function(l, r) { 2166 return l >= r; 2167 } 2168 }; 2169 const result = operators[operator](l, r); 2170 if (result) return options.fn ? options.fn(this) : true; 2171 return options.fn ? options.inverse(this) : false; 2172 }, 2173 lpFormatNumber: lpFormatNumber, 2174 arrayToHtmlList (arr, options) { 2175 // eslint-disable-next-line 2176 return arr.reduce((acc, current)=>{ 2177 try { 2178 if (typeof current === 'object' || current === null) return acc; 2179 // eslint-disable-next-line 2180 return acc += `<li>${current}</li>`; 2181 } catch (e) { 2182 /* empty */ } 2183 }, ''); 2184 }, 2185 join (array, separator, options) { 2186 if (!array || !array.join) return ''; 2187 return array.join(typeof separator === 'string' ? separator : ', '); 2188 }, 2189 dedupe (items, key, options) { 2190 let data = null; 2191 let skippedItems = 0; 2192 const list = new Set(); 2193 if (options.data) data = HandlebarsInstance.createFrame(options.data); 2194 return (items || []).reduce((res, item, idx)=>{ 2195 const val = key ? item[key] : item; 2196 // Item is unique if we're passed a key that is not defined 2197 const isUnique = !list.has(val) || key && val === undefined; 2198 if (isUnique) list.add(val); 2199 else { 2200 skippedItems += 1; 2201 return res; 2202 } 2203 if (data) data.index = idx - skippedItems; 2204 return res + options.fn(item, { 2205 data: data 2206 }); 2207 }, ''); 2208 }, 2209 JSONstringify (obj, options) { 2210 return JSON.stringify(obj); 2211 }, 2212 // eslint-disable-next-line sonarjs/cognitive-complexity 2213 formatPropertyPrice (...args) { 2214 const options = args[args.length - 1]; 2215 const opts = options.hash; 2216 const property = args.length > 1 ? args[0] : opts.property; 2217 const precision = opts.precision || 0; 2218 if (args.length > 2) // eslint-disable-next-line 2219 opts.mode = args[1]; 2220 if (!opts.mode) opts.mode = 'short'; 2221 let separator = args.length > 3 ? args[2] : opts.separator; 2222 if (typeof separator !== 'string') separator = ' | '; 2223 if (property.isPasswordProtected) return 'Exclusive Listing'; 2224 let priceUponRequestText = args.length > 4 ? args[3] : opts.priceUponRequestText; 2225 if (typeof priceUponRequestText !== 'string') priceUponRequestText = 'Price Upon Request'; 2226 if (property.priceUponRequest) return priceUponRequestText; 2227 let price = property.salesPrice; 2228 let reduced = null; 2229 // eslint-disable-next-line sonarjs/no-collapsible-if 2230 if (property.status !== 'SOLD' && property.status !== 'Leased') { 2231 if (property.reducedPrice) { 2232 if (!opts.reducedClass) price = property.reducedPrice; 2233 else reduced = property.reducedPrice; 2234 } 2235 } 2236 let result = ''; 2237 if (reduced) result += `<${opts.reducedTag || 'span'} class="${opts.reducedClass}">${lpFormatNumber(reduced, property.currency, precision)}</${opts.reducedTag || 'span'}>`; 2238 if (price) { 2239 price = lpFormatNumber(price, property.currency, precision); 2240 if (opts.priceTag || opts.priceClass) result += `<${opts.priceTag || 'span'}${opts.priceClass ? ` class="${opts.priceClass}"` : ''}>${price}</${opts.priceTag || 'span'}>`; 2241 else result += price; 2242 } 2243 const leasePrice = property.leasePrice && lpFormatNumber(property.leasePrice, property.currency, precision); 2244 if (leasePrice) { 2245 if (result) result += separator; 2246 const leaseText = `${leasePrice}${formatFrequencyExt(property.leasePeriod, opts)}`; 2247 if (opts.leaseTag || opts.leaseClass) result += `<${opts.leaseTag || 'span'}${opts.leaseClass ? ` class="${opts.leaseClass}"` : ''}>${leaseText}</${opts.leaseTag || 'span'}>`; 2248 else result += leaseText; 2249 } 2250 return new HandlebarsInstance.SafeString(result); 2251 }, 2252 // eslint-disable-next-line sonarjs/cognitive-complexity 2253 mediaImage (mediaSource, options = {}) { 2254 if (!mediaSource) return; 2255 const { lazy: lazy, ...attributes } = options.hash; 2256 let src = ''; 2257 let srcset = ''; 2258 if (typeof mediaSource === 'string') src = mediaSource; 2259 else { 2260 const srcMap = {}; 2261 const { height: height, width: width, altTagText: altTagText } = mediaSource; 2262 MEDIA_SIZES.forEach((src)=>{ 2263 if (mediaSource[src.field] && !srcMap[mediaSource[src.field]]) srcMap[mediaSource[src.field]] = src.w; 2264 }); 2265 const srcs = Object.keys(srcMap); 2266 if (!srcs.length) return; 2267 if (altTagText) attributes.alt = altTagText; 2268 if (height && width) { 2269 if (height >= width) { 2270 if (attributes.class) attributes.class += ' portrait'; 2271 else attributes.class = 'portrait'; 2272 } 2273 if ('setDims' in options.hash) { 2274 attributes.width = width; 2275 attributes.height = height; 2276 } 2277 } 2278 if (srcs.length > 1 && width && width < srcMap[srcs[srcs.length - 1]]) { 2279 const maxSrc = srcs.findIndex((src)=>
2279srcMap[src] >= width); 2280 srcs.splice(maxSrc + 1); 2281 srcMap[srcs[srcs.length - 1]] = width; 2282 } 2283 if (srcs.length > 1) { 2284 srcset = srcs.map((s)=>`${s} ${srcMap[s]}w`).join(', '); 2285 srcs.sort((a, b)=>Math.abs(srcMap[a] - MEDIA_SIZE_FOR_SRC) - Math.abs(srcMap[b] - MEDIA_SIZE_FOR_SRC)); 2286 } 2287 // eslint-disable-next-line 2288 src = srcs[0]; 2289 } 2290 delete attributes.setDims; 2291 if (!srcset) delete attributes.sizes; 2292 if (!('alt' in attributes)) attributes.alt = ''; 2293 if (!('loading' in attributes) && (options?.data?.root?.sectionIndex > 1 || lazy)) attributes.loading = 'lazy'; 2294 const attrs = Object.keys(attributes).map((k)=>`${HandlebarsInstance.escapeExpression(k)}="${HandlebarsInstance.escapeExpression(attributes[k])}"`).join(' '); 2295 return new HandlebarsInstance.SafeString(// eslint-disable-next-line sonarjs/no-nested-template-literals 2296 `<img src="${src}"${srcset ? ` srcset="${srcset}"` : ''}${attrs ? ` ${attrs}` : ''}>`); 2297 }, 2298 bgImage (mediaSource) { 2299 if (!mediaSource) return ''; 2300 if (typeof mediaSource === 'string') return mediaSource; 2301 return mediaSource.largeUrl || mediaSource.url || ''; 2302 }, 2303 concat (...rest) { 2304 let outStr = ''; 2305 // rest params are Array instances while arguments object is not 2306 for(const arg in rest)if (rest[arg] !== null && rest[arg] !== undefined && typeof rest[arg] !== 'object') outStr += rest[arg]; 2307 return outStr; 2308 }, 2309 setVideoExtension (uri, format) { 2310 if (!uri || !format) return ''; 2311 const decodedUri = new URL(uri); 2312 if (decodedUri.host !== 'res.cloudinary.com') { 2313 // Not a cloudinary uri, do not rewrite 2314 if (decodedUri.pathname.endsWith(`.${format}`)) return uri; 2315 return ''; 2316 } 2317 // Rewrite the cloudinary uri 2318 const lastPeriodIdx = decodedUri.pathname.lastIndexOf('.'); 2319 let pathWithoutFormat = decodedUri.pathname; 2320 if (lastPeriodIdx !== -1) pathWithoutFormat = decodedUri.pathname.substr(0, lastPeriodIdx); 2321 decodedUri.pathname = `${pathWithoutFormat}.${format}`; 2322 return decodedUri.toString(); 2323 }, 2324 addVideoSources (uri) { 2325 if (!uri) return ''; 2326 const VIDEO_VARIANTS = [ 2327 { 2328 format: 'webm', 2329 codec: 'vp9', 2330 htmlCodecs: ';codecs=vp9' 2331 }, 2332 { 2333 format: 'mp4', 2334 codec: 'h265', 2335 htmlCodecs: ';codecs=hvc1' 2336 }, 2337 { 2338 format: 'mp4', 2339 codec: 'h264', 2340 htmlCodecs: '' 2341 } 2342 ]; 2343 const VIDEO_EXT_REGEXP = /\.(?:3gp|mpeg|mp4|m4v|m4p|ogv|ogg|mov|webm)$/; 2344 if (!uri.includes('res.cloudinary.com')) // keep existing or no extension for non Cloudinary urls 2345 return `<source data-src="${uri}">`; 2346 // Cap delivery at 1080p (1920px wide) while preserving aspect ratio. Width-only: 2347 // c_limit never upscales, so portrait sources are left at their native size. 2348 // No q_auto: quality is left to Cloudinary's default rather than forced down. 2349 // Note the regex below consumes any q_auto in the source URL, so it is dropped 2350 // rather than carried through. 2351 const CONSTRAINED_DELIVERY = 'w_1920,c_limit'; 2352 const uriNoExt = uri.replace(VIDEO_EXT_REGEXP, ''); 2353 const sources = VIDEO_VARIANTS.map((type)=>{ 2354 const cloudinaryFormatUrl = `${uriNoExt.replace(/f_auto(?::video)?(?:,q_auto(?::\w+)?)?/, `f_${type.format},vc_${type.codec},${CONSTRAINED_DELIVERY}`)}.${type.format}`; 2355 return `<source data-src="${cloudinaryFormatUrl}" type="video/${type.format}${type.htmlCodecs}">`; 2356 }); 2357 return sources.join('\n'); 2358 }, 2359 cloudinaryVideoFirstFrame: $0ce6edea77f7b81a$exports.getVideoFirstFrame, 2360 initials (text, options) { 2361 if (!text) return ''; 2362 if (options?.hash?.endChar) // eslint-disable-next-line 2363 text = text.split(options.hash.endChar)[0]; 2364 // eslint-disable-next-line 2365 const maxChars = +options?.hash?.maxChars || 2; // we do not allow this to be 0 2366 let result = text.match(/\b\w/g)?.slice(0, maxChars); 2367 if (!result) return ''; 2368 if (options?.hash?.addText) result = result.map((item)=>item + options.hash.addText); 2369 return result.join(options?.hash?.joinWith || '').toUpperCase(); 2370 }, 2371 normalizePhone (phone) { 2372 if (!phone) return ''; 2373 const str = String(phone).trim(); 2374 return (str.startsWith('+') ? '+' : '') + str.replace(/\D/g, ''); 2375 } 2376 }; 2377} 2378$53de3c160faf5a81$exports = $53de3c160faf5a81$var$handlebarsHelpersFactory; 2379 2380 2381/* global window, document */ // eslint-disable-next-line import/prefer-default-export 2382class $dc851cf3939b6ef5$export$ff0712c26d5458f7 { 2383 /** 2384 * Initialize Modal Controller 2385 * @param {Object} options 2386 */ constructor(options){ 2387 this.isBuilder = false;
2388 this.companyId = null; 2389 this.websiteId = null; 2390 this.pageId = null; 2391 this.shareId = null; 2392 this.pageMeta = null; 2393 this.websiteApiGatewayUrl = null; 2394 this.buyerSellerServiceUrl = null; 2395 this.leadIngesterUrl = null; 2396 this.divolteServiceUrl = null; 2397 this.eventBus = null; 2398 this.templateId = null; 2399 this.myhomeDashboardEnabled = false; 2400 this.mlsEnabled = false; 2401 this.hstValuationRedirectEnabled = false; 2402 this.googleMapsAPIKey = null; 2403 } 2404 /** 2405 * Controllers must implement a "destroy" method to be called 2406 * after page navigation to remove event handlers / cleanup 2407 */ destroy() {} 2408 /** 2409 * Set page and supporting data 2410 * @param {string} pageId 2411 * @param {Object} options 2412 */ setPage(pageId, options = {}) { 2413 this.pageId = pageId; 2414 this.shareId = options.shareId || null; 2415 this.pageMeta = { 2416 sourceResource: options.sourceResource, 2417 pageElementId: options.pageElementId, 2418 pageQueryVariables: options.pageQueryVariables || {} 2419 }; 2420 } 2421 /** 2422 * Sets if we are in pagebuilder context or not 2423 * @param {boolean} isBuilder 2424 */ setIsBuilder(isBuilder) { 2425 this.isBuilder = isBuilder; 2426 } 2427 /** 2428 * Set Company and supporting data 2429 * @param {string} companyId 2430 * @param {Object} options 2431 */ setCompany(companyId, options = {}) { 2432 this.companyId = companyId; 2433 } 2434 /** 2435 * Set website and supporting data 2436 * @param {string} websiteId 2437 * @param {Object} options 2438 */ setWebsite(websiteId, options = {}) { 2439 this.websiteId = websiteId; 2440 if (options.myhomeDashboardEnabled) this.myhomeDashboardEnabled = options.myhomeDashboardEnabled; 2441 if (options.mlsEnabled) this.mlsEnabled = options.mlsEnabled; 2442 if (options.hstValuationRedirectEnabled) this.hstValuationRedirectEnabled = options.hstValuationRedirectEnabled; 2443 } 2444 /** 2445 * Set websiteApiGatewayUrl 2446 * @param {string} websiteApiGatewayUrl 2447 * @param {Object} options 2448 */ setWebsiteApiGatewayUrl(websiteApiGatewayUrl, options = {}) { 2449 this.websiteApiGatewayUrl = websiteApiGatewayUrl; 2450 } 2451 /** 2452 * Set buyerSellerServiceUrl 2453 * @param {string} buyerSellerServiceUrl 2454 * @param {Object} options 2455 */ setBuyerSellerServiceUrl(buyerSellerServiceUrl, options = {}) { 2456 this.buyerSellerServiceUrl = buyerSellerServiceUrl; 2457 } 2458 /** 2459 * Set divolteServiceUrl and supporting data 2460 * @param {string} divolteServiceUrl 2461 * @param {Object} options 2462 */ setDivolteServiceUrl(divolteServiceUrl, options = {}) { 2463 this.divolteServiceUrl = divolteServiceUrl; 2464 } 2465 /** 2466 * Set eventBusUrl 2467 * @param {string} eventBusUrl 2468 * @param {Object} options 2469 */ setEventBusUrl(eventBusUrl, options = {}) { 2470 this.eventBusUrl = eventBusUrl; 2471 } 2472 /** 2473 * Set templateId and supporting data 2474 * @param {string} templateId 2475 * @param {Object} options 2476 */ setTemplateId(templateId, options = {}) { 2477 this.templateId = templateId; 2478 } 2479 /** 2480 * Set leadIngesterUrl 2481 * @param {string} leadIngesterUrl 2482 * @param {Object} options 2483 */ setLeadIngesterUrl(leadIngesterUrl, options = {}) { 2484 this.leadIngesterUrl = leadIngesterUrl; 2485 } 2486 /** 2487 * Set googleMapsAPIKey 2488 * @param {string} googleMapsAPIKey 2489 * @param {Object} options 2490 */ setGoogleMapsAPIKey(googleMapsAPIKey, options = {}) { 2491 this.googleMapsAPIKey = googleMapsAPIKey; 2492 } 2493 /** 2494 * Set eventBus 2495 * @param {Object} options 2496 */ setEventBus({ enabled: enabled, apiKey: apiKey, url: url }) { 2497 this.eventBus = { 2498 enabled: enabled, 2499 apiKey: apiKey, 2500 url: url 2501 }; 2502 } 2503} 2504 2505 2506/* eslint-disable import/prefer-default-export */ // eslint-disable-next-line import/prefer-default-export 2507class $7c391e2f7931d60d$export$3b5bd9381a52554c { 2508 /** 2509 * Initialize Base Controller at build time 2510 * @param { ConfigController } config 2511 * @param {Window} window 2512 * @param {Document} document 2513 */ constructor(config, window, document){ 2514 // TODO: Listen for events from configController to update configuration 2515 this.config = config; 2516 this.window = window; 2517 this.document = document; 2518 if (!this.destroy) // With turbolinks, we want to ensure that on each page load we have the latest version of the sdk 2519 // Controllers are deconstructed and replaced (on the window object) per request 2520 // Controllers must use the destory method to remove event handlers to prevent undefined behavior 2521 throw new Error('Controllers must implement a deconstructor'); 2522 } 2523} 2524 2525 2526// eslint-disable-next-line import/prefer-default-export 2527const $a3e97e89bbc2a366$export$f037eeffb5561205 = 2000; 2528 2529 2530class $0ead03fdb95fa9ce$export$d507f25e63650365 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 2531 /** 2532 * Initialize Modal Controller at build time 2533 * @param { ConfigController } config 2534 * @param {Window} window 2535 * @param {Document} document 2536 */ constructor(config, window, document){ 2537 super(config, window, document); 2538 this.setLoginState = this.setLoginState.bind(this); 2539 this.pageId = null; 2540 this.modals = []; 2541 this.exitModalTriggered = {}; 2542 this.exitModalEventListeners = []; 2543 } 2544 /** 2545 * Initialize Modal Controller at run time 2546 * Attach handlers and events to DOM 2547 * @param {Object} options 2548 */ initialize(options) { 2549 try { 2550 const { config: config, document: document } = this; 2551 this.pageId = config.pageId; 2552 this.modals = document.querySelectorAll('body > #modals > .modal');
2553 options.modals.forEach((m)=>{ 2554 this._attachModalHandler(m); 2555 }); 2556 } catch (e) { 2557 // eslint-disable-next-line no-console 2558 console.log(e); 2559 } 2560 } 2561 /** 2562 * Controllers must implement a "destroy" method to be called 2563 * after page navigation to remove event handlers / cleanup 2564 */ destroy() { 2565 const { document: document } = this; 2566 this.exitModalEventListeners.forEach((listener)=>{ 2567 document.removeEventListener('mouseout', listener); 2568 }); 2569 this.modals = []; 2570 this.exitModalTriggered = {}; 2571 this.exitModalEventListeners = []; 2572 } 2573 /** 2574 * Set modal to local storage with expiration 2575 * @param {string} modalId 2576 */ setModalWithExpiry(modalId) { 2577 const { window: window } = this; 2578 const TTL = 86400000; // 24 hours 2579 const now = new Date(); 2580 const expiry = now.getTime() + TTL; 2581 const key = `modal-controller-${modalId}`; 2582 try { 2583 window.localStorage.setItem(key, JSON.stringify(expiry)); 2584 } catch (err) { 2585 // catch error when setting item to storage on iOS private browser 2586 } 2587 } 2588 /** 2589 * Save success login modal to local storage 2590 */ setLoginState() { 2591 const { window: window } = this; 2592 try { 2593 window.localStorage.setItem('isSignedUp', 'true'); 2594 } catch (err) { 2595 // catch error when setting item to storage on iOS private browser 2596 } 2597 } 2598 /** 2599 * Get modal and check expiration 2600 * @param {string} modalId 2601 * @return {boolean} 2602 */ getModalWithExpiry(modalId) { 2603 const { window: window } = this; 2604 const storage = window.localStorage; 2605 const expirationTime = storage.getItem(`modal-controller-${modalId}`); 2606 if (!expirationTime) return false; 2607 const expiry = JSON.parse(expirationTime); 2608 const now = new Date(); 2609 if (now.getTime() > expiry) { 2610 storage.removeItem(`modal-controller-${modalId}`); 2611 return false; 2612 } 2613 return true; 2614 } 2615 /** 2616 * Make a modal visible 2617 * @param {string} modalId 2618 * @param {Object} options 2619 */ show(modalId, options = {}) { 2620 // TODO: migrate logic from page.handlebars 2621 const { window: window } = this; 2622 const modalViewed = this.getModalWithExpiry(modalId); 2623 // Only show a modal if it has not been seen 2624 // Does not affect "show modal on button click" 2625 if (modalId && !modalViewed || options.forced === true) { 2626 window.lpUI.showModal(`modal-${modalId}`, options); 2627 this.setModalWithExpiry(modalId); 2628 } 2629 } 2630 /** 2631 * Attach events based on Modal type and page settings 2632 * @param {Modal} modal 2633 */ _attachModalHandler(modal) { 2634 const { pageId: pageId } = this; 2635 const { trigger: trigger, pageSpecific: pageSpecific } = modal; 2636 if (pageSpecific) { 2637 const pageIds = modal.pages.map((p)=>p.pageId); 2638 if (!pageIds.includes(pageId)) // Modal does not belong to this page 2639 return; 2640 } 2641 if (trigger === 'EXIT') this._exitModalHandler(modal); 2642 else if (trigger === 'TIMER') this._timerModalHandler(modal); 2643 else if (trigger === 'FORCED') this._forcedModalHandler(modal); 2644 } 2645 /** 2646 * Attach events for exit Modals 2647 * @param {Modal} modal 2648 */ _exitModalHandler(modal) { 2649 // eslint-disable-next-line 2650 const that = this; 2651 const { document: document, exitModalTriggered: exitModalTriggered } = this; 2652 const { modalId: modalId } = modal; 2653 /** 2654 * Handle the mouseout dom event 2655 * @param {Event} event 2656 */ function triggerExitModal(event) { 2657 if (exitModalTriggered[modalId]) return; 2658 if (!event.toElement && !event.relatedTarget) { 2659 that.show(modalId); 2660 exitModalTriggered[modalId] = true; 2661 } 2662 } 2663 document.addEventListener('mouseout', triggerExitModal); 2664 this.exitModalEventListeners.push(triggerExitModal); 2665 } 2666 /** 2667 * Attach events for timer Modals
2668 * @param {Modal} modal 2669 */ _timerModalHandler(modal) { 2670 const { modalId: modalId, timerDelay: timerDelay } = modal; 2671 setTimeout(()=>{ 2672 this.show(modalId); 2673 }, timerDelay); 2674 } 2675 /** 2676 * Attach events for Forced Modals 2677 * @param {Modal} modal 2678 */ _forcedModalHandler(modal) { 2679 const { modalId: modalId } = modal; 2680 const { window: window, document: document } = this; 2681 const isLoggedIn = window.localStorage.getItem('isSignedUp') === 'true'; 2682 if (!isLoggedIn) { 2683 // watch for event triggering success login 2684 const forcedModal = document.querySelector(`#modal-${modalId}`); 2685 const contactForm = forcedModal?.querySelector('form'); 2686 const MODAL_CLOSE_DELAY = contactForm?.dataset.delay || (0, $a3e97e89bbc2a366$export$f037eeffb5561205); 2687 // form submit autoclose is handled by contactForms controller 2688 contactForm.addEventListener('formsubmitted', ()=>{ 2689 this.setLoginState(); 2690 }); 2691 window.addEventListener('oauthSuccess', ()=>{ 2692 this.setLoginState(); 2693 contactForm.classList.add('success'); 2694 setTimeout(()=>{ 2695 window.lpUI.hideModal(`modal-${modalId}`); 2696 contactForm.reset(); 2697 contactForm.classList.remove('success'); 2698 }, MODAL_CLOSE_DELAY); 2699 }); 2700 this.show(modalId, { 2701 forced: true 2702 }); 2703 } 2704 } 2705} 2706 2707 2708/* eslint-disable import/prefer-default-export */ /* global window */ /* eslint-disable import/prefer-default-export */ /** 2709 * Handle navigation push 2710 * @param {string} href 2711 * @param {boolean} _blank 2712 */ const $fc0a058ae42af628$export$95e8d77caafa3e06 = (href, _blank = false)=>{ 2713 if (!href) return; 2714 if (_blank) { 2715 window.open(href); 2716 return; 2717 } 2718 window.location.assign(href); 2719}; 2720const $fc0a058ae42af628$export$267a1435fe18b8d4 = (obj, path, defValue)=>{ 2721 if (!path) return undefined; 2722 const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); 2723 const result = pathArray.reduce((prevObj, key)=>prevObj && prevObj[key], obj); 2724 return result === undefined ? defValue : result; 2725}; 2726 2727 2728 2729class $d48f9f944810f613$export$ca3218b7861b9cb0 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 2730 /** 2731 * Initialize Button Controller at build time 2732 * @param { ConfigController } config 2733 * @param {Window} window 2734 * @param {Document} document 2735 */ constructor(config, window, document){ 2736 super(config, window, document); 2737 this._boundClickHandler = this._buttonClickHandler.bind(this); 2738 } 2739 /** 2740 * Initialize Button Controller at run time 2741 * Attach handlers and events to DOM 2742 * @param {Object} options 2743 */ initialize(options = {}) { 2744 try { 2745 const { document: document } = this; 2746 document.body.removeEventListener('click', this._boundClickHandler); 2747 document.body.addEventListener('click', this._boundClickHandler); 2748 } catch (e) { 2749 // eslint-disable-next-line no-console 2750 console.error(e); 2751 } 2752 } 2753 /** 2754 * Controllers must implement a "destroy" method to be called 2755 * after page navigation to remove event handlers / cleanup 2756 */ destroy() { 2757 const { document: document } = this; 2758 document.body.removeEventListener('click', this._boundClickHandler); 2759 } 2760 /** 2761 * Buttons click handler 2762 * @param {event} e 2763 */ _buttonClickHandler(e) { 2764 this._handleButtonClick(e).catch((e)=>console.error(e)); 2765 } 2766 /** 2767 * Handle button click 2768 * We need special function to have easy way to detach listener 2769 * @param {Event} e 2770 */ async _handleButtonClick(e) { 2771 const { window: window, document: document } = this; 2772 const button = e.target.closest('button, a'); 2773 if (!button) return; 2774 const type = button.dataset.type || ''; 2775 const href = button.href || button.dataset.href || ''; 2776 const target = button.target || ''; 2777 const { submit: submit } = button.dataset; 2778 if (submit) { 2779 try { 2780 await this._handleSubmit(button); 2781 } catch (err) { 2782 // eslint-disable-next-line no-console 2783 console.error(err); 2784 } 2785 (0, $fc0a058ae42af628$export$95e8d77caafa3e06)(href, target === '_blank'); 2786 } 2787 this._trackConversion(button); 2788 if (type === 'VIDEO') { 2789 this._handleVideoButton(button); 2790 return; 2791 } 2792 if (type === 'CONTACT_US') { 2793 this._handleContactUsButton(button); 2794 return; 2795 } 2796 if (type === 'SUBSCRIBE') { 2797 // TODO: Extend for an overwritten subscribe 2798 window.lpUI.showModal('modal-global-subscribe'); 2799 return; 2800 } 2801 if (type === 'MY_ACCOUNT') { 2802 // TODO: Extend for an overwritten subscribe 2803 window.lpUI.showModal('modal-global-my-account'); 2804 return; 2805 } 2806 if (type === 'SHARE_POPUP') { 2807 // TODO: Extend for an overwritten subscribe 2808 const sharePopup = button.querySelector('.share-popup'); 2809 if (sharePopup) sharePopup.style.display = 'flex'; 2810 e.stopPropagation(); // this may not work in current 'delegate' mode 2811 return; 2812 } 2813 // Custom modals 2814 if (type.substring(0, 6) === 'MODAL_') { 2815 const modalId = type.substring(6); 2816 window.lpUI.showModal(`modal-${modalId}`); 2817 return; 2818 } 2819 // MAILTO / TEL Event 2820 if (href?.startsWith('mailto:')) { 2821 const email = href.substring(7); 2822 // TODO: Replace with SDK method 2823 document.sendGoogleAnalyticsEvent({ 2824 hitType: 'event', 2825 eventCategory: 'button', 2826 eventAction: 'click', 2827 eventLabel: 'Email', 2828 eventValue: email 2829 }); 2830 } else if (href?.startsWith('tel:')) { 2831 const phoneNumber = href.substring(4); 2832 // TODO: Replace with SDK method 2833 document.sendGoogleAnalyticsEvent({ 2834 hitType: 'event', 2835 eventCategory: 'button', 2836 eventAction: 'click', 2837 eventLabel: 'Phone', 2838 eventValue: phoneNumber 2839 }); 2840 } 2841 } 2842 /** 2843 * Handle submit 2844 * @param {HTMLButtonElement|HTMLAnchorElement} button 2845 */ async _handleSubmit(button) { 2846 const form = button.closest('form'); 2847 const { window: window } = this; 2848 if (form) return await window.luxuryPresence.contactForms.submitForm(form); 2849 return null; 2850 } 2851 _getVimeoSrc(link) { 2852 if (!link || !link.includes('vimeo.com') || link.length > 2000) return null; 2853 const matchResult = link.match(/(?:(?:www\.)?vimeo\.com\/(?:showcase\/\d+(?:\/video\/|\?video[=/])|channels\/(?:\w+\/)?|groups\/(?:[^/]*)\/videos\/|)|player\.vimeo\.com\/video\/)(\d+)(?:(?:\?.*&*h=|\/)+([\d,a-f]+))?/); 2854 if (!matchResult) return null; 2855 const [, vimeoId, vimeoHashParameter] = matchResult; 2856 let src = `https://player.vimeo.com/video/${vimeoId}?`; 2857 if (vimeoHashParameter) src += `h=${vimeoHashParameter}&`; 2858 src += 'autoplay=1'; 2859 return src; 2860 } 2861 /** 2862 * Handle type video click 2863 * @param {HTMLElement} button 2864 */ // eslint-disable-next-line sonarjs/cognitive-complexity 2865 _handleVideoButton(button) { 2866 const { document: document } = this; 2867 const section = button.closest('section'); 2868 // Embed youtube/vimeo video url 2869 let { src: src } = button.dataset; 2870 let youtubeId = ''; 2871 if (src && (src.includes('youtube.com') || src.includes('youtu.be')) && !src.includes('youtube.com/embed')) { 2872 // test link: https://regexr.com/3anm9 2873 const youtubeRegex = /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v=)
2873)|youtu.be\/)([a-zA-Z0-9_-]{6,11})/; 2874 const youtubeResult = src.match(youtubeRegex); 2875 // eslint-disable-next-line 2876 if (youtubeResult) youtubeId = youtubeResult[1]; 2877 } 2878 const vimeoSrc = this._getVimeoSrc(src); 2879 if (youtubeId) src = `https://youtube.com/embed/${youtubeId}?autoplay=1&controls=0`; 2880 else if (vimeoSrc) src = vimeoSrc; 2881 if (!src || !section) return; 2882 const isVideoFile = src.endsWith('.mp4') || src.endsWith('.webm') || src.includes('cloudinary.com'); 2883 const modalHtml = ` 2884 <div id="modal-${section.id}" class="modal visible"> 2885 <div class="modal-content"> 2886 <div class="lightbox-video"> 2887 <div class="video-player"> 2888 <div class="embed-container"> 2889 ${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>`} 2890 </div> 2891 </div> 2892 </div> 2893 </div> 2894 <button class="close lp-close" type="button" aria-label="close modal"><span class="lp-close-icon" aria-hidden="true"></span></button> 2895 </div> 2896 `; 2897 document.body.insertAdjacentHTML('beforeend', modalHtml); 2898 const modal = document.getElementById(`modal-${section.id}`); 2899 const closeModal = modal.querySelector('.close'); 2900 closeModal.addEventListener('click', ()=>{ 2901 modal.remove(); 2902 }); 2903 } 2904 /** 2905 * Handle type contact us click 2906 * @param {HTMLElement} button 2907 */ _handleContactUsButton(button) { 2908 const { window: window, document: document } = this; 2909 // TODO: Extend for an overwritten contact us 2910 document.sendGoogleAnalyticsEvent({ 2911 hitType: 'event', 2912 eventCategory: 'button', 2913 eventAction: 'click', 2914 eventLabel: 'contact' 2915 }); 2916 window.lpUI.showModal('modal-global-contact-us', { 2917 scrollLock: true 2918 }); 2919 } 2920 /** 2921 * Track conversion 2922 * @param {HTMLElement} button 2923 */ _trackConversion(button) { 2924 const { window: window, document: document } = this; 2925 // Conversion Tracking Options 2926 const { gtagConversionId: gtagConversionId, gtagConversionLabel: gtagConversionLabel, fbEventName: fbEventName } = button.dataset; 2927 if (gtagConversionId && gtagConversionLabel) { 2928 if (window.dataLayer && window.dataLayer.length) { 2929 const configured = window.dataLayer.some((layer)=>layer.length && layer[0] === 'config' && layer[1] === gtagConversionId); 2930 if (!configured) document.sendGoogleTagManagerEvent('config', gtagConversionId); 2931 } 2932 const sentTo = `${gtagConversionId}/${gtagConversionLabel}`; 2933 document.sendGoogleTagManagerEvent('event', 'conversion', { 2934 send_to: sentTo 2935 }); 2936 } 2937 if (window.fbq && fbEventName) window.fbq('track', fbEventName, {}); 2938 } 2939} 2940 2941 2942/* eslint-disable import/prefer-default-export */ 2943class $68a2d4aa500c7a05$export$61ec8f2b6291ec31 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 2944 /** 2945 * Initialize Validation Controller at build time 2946 * @param { ConfigController } config 2947 * @param {Window} window 2948 * @param {Document} document 2949 */ constructor(config, window, document){ 2950 super(config, window, document); 2951 this.validatedForms = []; 2952 } 2953 /** 2954 * Initialize Contact Form Controller at run time 2955 * Attach handlers and events to DOM 2956 * @param {Object} options 2957 */ initialize(options = {}) { 2958 try { 2959 const { window: window, document: document } = this; 2960 const { selector: selector } = options; 2961 let validatedForms = []; 2962 if (selector) validatedForms = document.querySelectorAll(`${selector} form[data-type="contact-form"]`); 2963 else validatedForms = document.querySelectorAll('form[data-type="contact-form"]'); 2964 const isPhoneValidationLibRequired = !!document.querySelectorAll('input[type="tel"]').length; 2965 // we are loading the phone validation lib from the globally defined list of libs 2966 if (isPhoneValidationLibRequired && !window.libphonenumber && window?.luxuryPresence?.libs) { 2967 const { loadJs: loadJs, jsLibsMap: jsLibsMap } = window.luxuryPresence.libs; 2968 const { libphonenumber: libphonenumber } = jsLibsMap; 2969 loadJs(libphonenumber.jsSrc, this.attachValidation.bind(this, validatedForms)); 2970 }
2970 else this.attachValidation(validatedForms); 2971 this.validatedForms = this.validatedForms.concat(validatedForms); 2972 } catch (e) { 2973 // eslint-disable-next-line no-console 2974 console.log(e); 2975 } 2976 } 2977 /** 2978 * Controllers must implement a "destroy" method to be called 2979 * after page navigation to remove event handlers / cleanup 2980 */ destroy() { 2981 this.validatedForms = []; 2982 } 2983 /** 2984 * Validate all forms in the document 2985 * @param {NodeListOf<HTMLFormElement>} forms 2986 */ attachValidation(forms) { 2987 forms.forEach((form)=>{ 2988 const inputs = form.querySelectorAll('input, select, textarea'); 2989 inputs.forEach((input)=>{ 2990 this.applyFieldValidation(input); 2991 }); 2992 }); 2993 } 2994 /** 2995 * Field Validation Handler from global context 2996 * @param {HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement} inputField 2997 */ applyFieldValidation(inputField) { 2998 const fieldType = inputField.getAttribute('type'); 2999 if (fieldType === 'tel') this._applyPhoneValidation(inputField); 3000 } 3001 /** 3002 * Phone Field Validation Handler 3003 * @param {HTMLInputElement} inputField 3004 */ _applyPhoneValidation(inputField) { 3005 const { window: window } = this; 3006 if (window.libphonenumber) { 3007 // https://codepen.io/coinscope/pen/BaXBvBp?editors=1010 3008 const phoneUtil = window.libphonenumber.isValidPhoneNumber; 3009 inputField.addEventListener('keyup', function() { 3010 if (this.hasAttribute('required') || this.value.replace(/\s/g, '').length) try { 3011 const phoneNumber = this.value; 3012 const region = 'US'; 3013 const isValidNumber = phoneUtil(phoneNumber, region); 3014 if (!isValidNumber) this.setCustomValidity('Please enter a valid phone number.'); 3015 else this.setCustomValidity(''); 3016 } catch (e) { 3017 this.setCustomValidity('Please enter a valid phone number.'); 3018 } 3019 else this.setCustomValidity(''); 3020 }); 3021 } 3022 } 3023} 3024 3025 3026 3027 3028/** 3029 * Fires the `generate_lead` Google Ads conversion on any marketing-site lead 3030 * event â lead-form submits (all routed through ContactFormController) and 3031 * social sign-in (oauth.js) â at most once per session. 3032 * 3033 * Reuses the same `generate_lead` event the Home Search Tool fires; the page 3034 * template already configures the LP Google tags, so no new Google Ads setup is 3035 * needed. Cross-tab/visitor dedupe is left to the conversion action's 3036 * Count="One" â localStorage is intentionally avoided as it would suppress a 3037 * returning visitor's later lead. 3038 */ const $3ec2bf3965f87ecc$export$78b64890ea40f4e4 = 'generate_lead'; 3039const $3ec2bf3965f87ecc$export$568da12be2433b06 = 'lp_lead_form_conversion_fired'; 3040function $3ec2bf3965f87ecc$var$alreadyFired(window) { 3041 try { 3042 return window.sessionStorage.getItem($3ec2bf3965f87ecc$export$568da12be2433b06) === 'true'; 3043 } catch { 3044 // sessionStorage can throw in private browsing; fail open so we still fire. 3045 return false; 3046 } 3047} 3048function $3ec2bf3965f87ecc$var$markFired(window) { 3049 try { 3050 window.sessionStorage.setItem($3ec2bf3965f87ecc$export$568da12be2433b06, 'true'); 3051 } catch { 3052 // Ignore â see alreadyFired(). 3053 } 3054} 3055function $3ec2bf3965f87ecc$export$e70565180c0e6950(window, document) { 3056 if (!window || !document) return; 3057 // GA bootstrap may not have run yet (or no pixel on this page); don't throw, 3058 // and don't burn the once-per-session flag if we can't actually fire. 3059 if (typeof document.sendGoogleTagManagerEvent !== 'function') return; 3060 if ($3ec2bf3965f87ecc$var$alreadyFired(window)) return; 3061 try { 3062 // Mark fired only AFTER a successful send, so a thrown GTM call doesn't 3063 // permanently suppress the conversion for the rest of the session â and 3064 // never let an analytics failure break the caller's success flow. 3065 document.sendGoogleTagManagerEvent('event', $3ec2bf3965f87ecc$export$78b64890ea40f4e4); 3066 $3ec2bf3965f87ecc$var$markFired(window); 3067 } catch { 3068 // Swallow â analytics must not break form submit / sign-in. 3069 } 3070} 3071 3072 3073 3074const $2aefad83322125c9$var$homeValuationRoute = '/api/v1/home-valuation'; 3075class $2aefad83322125c9$export$2e2bcd8739ae039 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 3076 destroy() { 3077 // 3078 } 3079 /** 3080 * Clean address string by removing call time frame suffix and extra whitespace 3081 * 3082 * Handles 17 templates that append ", call time frame: [value]" to the address: 3083 * - TheTrailblazerSir_2, TheMasterpiece (2x), TheInspirationSir_1, TheIconSir_3
3084 * - Influencer, GlobalCollective, Evolution, CorcoranAgent_1 3085 * - CompassSE (2x), CompassPrestige (2x), CompassNavigator 3086 * - ColdwellBanker (2x), Classic 3087 * 3088 * @param {string} address - Raw address string that may contain time frame info 3089 * @return {string} - Cleaned address string 3090 */ _cleanAddressString(address) { 3091 if (!address || typeof address !== 'string') return ''; 3092 let cleaned = address.trim(); 3093 // Fix 1: Handle "User entered address:\n..." pattern from TheProducer templates 3094 // Extract only the user entered address, ignore geocoded part 3095 if (cleaned.includes('User entered address:')) { 3096 const match = cleaned.match(/User entered address:\s*\n?\s*([^\n]+)/); 3097 if (match && match[1]) cleaned = match[1].trim(); 3098 } 3099 // Fix 2: Remove ", call time frame: ..." suffix if present (affects 17 templates) 3100 const timeFrameIndex = cleaned.indexOf(', call time frame:'); 3101 if (timeFrameIndex !== -1) cleaned = cleaned.substring(0, timeFrameIndex).trim(); 3102 return cleaned; 3103 } 3104 /** 3105 * Transform Google Maps address components to structured format 3106 * @param {Array} addressComponents - Google Maps address components 3107 * @return {Object} - Structured address object 3108 */ _transformAddressComponents(addressComponents) { 3109 const get = (t)=>(addressComponents.find((c)=>c.componentType === t) || {}).componentName?.text; 3110 const structuredAddress = {}; 3111 const streetNumber = get('street_number'); 3112 const streetName = get('route'); 3113 const state = get('administrative_area_level_1'); 3114 const zipcode = get('postal_code'); 3115 const addressLine2 = get('subpremise'); 3116 // explicit precedence for city 3117 const city = get('locality') || get('sublocality_level_1') || get('neighborhood'); 3118 if (streetNumber) structuredAddress.streetNumber = streetNumber; 3119 if (streetName) structuredAddress.streetName = streetName; 3120 if (city) structuredAddress.city = city; 3121 if (state) structuredAddress.state = state; 3122 if (zipcode) structuredAddress.zipcode = zipcode; 3123 if (addressLine2) structuredAddress.addressLine2 = addressLine2; 3124 return structuredAddress; 3125 } 3126 /** 3127 * Extract address and coordinates from Google Maps validation data 3128 * @param {Object} validatedAddressData - Google Maps validation result 3129 * @return {Object} - Object containing structuredAddress and coordinates 3130 */ _extractAddressAndCoordinates(validatedAddressData) { 3131 let structuredAddress = null; 3132 let coordinates = null; 3133 if (validatedAddressData?.result) { 3134 const { result: result } = validatedAddressData; 3135 // Extract structured address components 3136 if (result.address?.addressComponents) structuredAddress = this._transformAddressComponents(result.address.addressComponents); 3137 // Extract coordinates 3138 if (result.geocode?.location) coordinates = { 3139 latitude: result.geocode.location.latitude, 3140 longitude: result.geocode.location.longitude 3141 }; 3142 } 3143 return { 3144 structuredAddress: structuredAddress, 3145 coordinates: coordinates 3146 }; 3147 } 3148 /** 3149 * Filter out empty string values from an object, keeping only non-empty values 3150 * @param {Object} obj - Object to filter 3151 * @return {Object} - Filtered object without empty strings 3152 */ _filterEmptyStrings(obj) { 3153 const filtered = {}; 3154 for (const [key, value] of Object.entries(obj))if (value !== '' && value !== null && value !== undefined) filtered[key] = value; 3155 return filtered; 3156 } 3157 /** 3158 * Extract raw address from form data with priority fallback chain. 3159 * Order is critical to handle 38 home valuation templates with different field naming: 3160 * 3161 * IMPORTANT: contactForms.js (line 189) stores name="message" in comments_attributes[0].text 3162 * because 'message' is in DEFAULT_LEAD_FIELDS. Fields NOT in DEFAULT_LEAD_FIELDS go to content. 3163 * 3164 * Priority (most specific â most generic): 3165 * 1. address - Pattern 1: 9 templates (explicit address, stored in content) 3166 * 2. property-address - Pattern 3: 4 templates (dash variant with JS, stored in content) 3167 * 3. property_address - Pattern 4: 3 templates (underscore, stored in content - handles VanguardProperties!) 3168 * 4. Property_Address - Pattern 5: 1 template (capital P - TheProducer/HomeValuationRansomHouse, stored in content)
3169 * 5. comments_attributes[0].text - Pattern 2: ALL 17 templates with name="message" store HERE! 3170 * (e.g., Evolution/HomeValuation, TheProducer/HomeValuation, etc.) 3171 * 6. message - Pattern 6: 4 templates with JS-populated message (rare, checked last) 3172 * 7-8. homeValuationAddress, propertyAddress - Legacy/unknown formats 3173 * 3174 * Critical: Each field is cleaned BEFORE checking, so dropdown values are skipped and we try next field 3175 * 3176 * @param {Object} data - Form data 3177 * @return {string} - Raw address string (may contain trailing text like ", call time frame: ...") 3178 */ _getRawAddress(data) { 3179 const content = data.activity.content || {}; 3180 const comments = data.activity.comments_attributes?.[0]?.text; 3181 const possibleFields = [ 3182 content.address, 3183 content['property-address'], 3184 content.property_address, 3185 content.Property_Address, 3186 comments, 3187 content.message, 3188 content.homeValuationAddress, 3189 content.propertyAddress 3190 ]; 3191 return possibleFields.map((field)=>field && this._cleanAddressString(field)).find(Boolean) || ''; 3192 } 3193 /** 3194 * Logs lead-related events for monitoring 3195 * @param {string} eventType - Type of event 3196 * @param {Object} data - Form data 3197 * @param {Error} error - Optional error object 3198 */ _logLeadEvent(eventType, data, error = null) { 3199 const eventPayload = { 3200 event: eventType, 3201 companyId: this.config.companyId, 3202 websiteId: this.config.websiteId, 3203 timestamp: new Date().toISOString(), 3204 hasEmail: !!data.activity?.author_email, 3205 hasAddress: !!this._getRawAddress(data) 3206 }; 3207 if (error) { 3208 // Use userMessage (sanitized) instead of raw message to prevent PII exposure 3209 // userMessage is set by _getUserFriendlyErrorMessage() which provides safe messages 3210 eventPayload.errorMessage = error.userMessage || (error.status ? `Request failed with status ${error.status}` : 'An error occurred'); 3211 eventPayload.errorName = error.name; 3212 eventPayload.errorStatus = error.status; 3213 } 3214 // Log to console with structured format for log aggregation 3215 // eslint-disable-next-line no-console 3216 console.error(`[HomeValuation] ${eventType}`, JSON.stringify(eventPayload)); 3217 // If PostHog is available, send event for analytics 3218 // Wrap in try/catch to prevent SDK failures from blocking submissions 3219 if (this.window.posthog) try { 3220 this.window.posthog.capture(eventType, eventPayload); 3221 } catch (posthogError) { 3222 // eslint-disable-next-line no-console 3223 console.error('[HomeValuation] PostHog capture failed:', posthogError); 3224 } 3225 } 3226 /** 3227 * Maps error types to user-friendly messages 3228 * @param {Error} error - The error object 3229 * @returns {string} - User-friendly message 3230 */ _getUserFriendlyErrorMessage(error) { 3231 if (error.name === 'AbortError' || error.message?.includes('timeout')) return 'Connection timed out. Please try again.'; 3232 if (error.name === 'TypeError' && error.message?.includes('fetch')) return 'Unable to connect. Please check your internet connection and try again.'; 3233 if (error.status === 503 || error.status === 502 || error.status === 504) return 'Service temporarily unavailable. Please try again in a moment.'; 3234 if (error.status === 400) return 'Please check your information and try again.'; 3235 return 'Something went wrong. Please try again or contact us directly.'; 3236 } 3237 /** 3238 * Build formatted address string from structured address components 3239 * @param {Object} structuredAddress - Structured address object 3240 * @return {string} - Formatted address string 3241 */ _formatStructuredAddress(structuredAddress) { 3242 if (!structuredAddress || Object.keys(structuredAddress).length === 0) return ''; 3243 const parts = []; 3244 // Line 1: streetNumber streetName addressLine2 3245 const line1 = [ 3246 structuredAddress.streetNumber, 3247 structuredAddress.streetName, 3248 structuredAddress.addressLine2
3249 ].filter(Boolean).join(' '); 3250 parts.push(line1); 3251 // Line 2: city, state zipcode 3252 const cityState = [ 3253 structuredAddress.city, 3254 structuredAddress.state 3255 ].filter(Boolean).join(', '); 3256 const line2 = [ 3257 cityState, 3258 structuredAddress.zipcode 3259 ].filter(Boolean).join(' '); 3260 parts.push(line2); 3261 return parts.filter(Boolean).join(', '); 3262 } 3263 /** 3264 * Build home valuation data object 3265 * @param {Object} data - Form data 3266 * @param {string} homeValuationEstimate - Home valuation estimate 3267 * @param {Object} structuredAddress - Structured address object 3268 * @param {Object} coordinates - Coordinates object 3269 * @return {Object} - Home valuation data object 3270 */ _buildHomeValuationData(data, homeValuationEstimate, structuredAddress, coordinates) { 3271 // Build homeValuationAddress from structured address (validated by Google) if available 3272 // Format: streetNumber streetName, city, state zipcode, addressLine2 3273 const homeValuationAddress = this._formatStructuredAddress(structuredAddress) || this._getRawAddress(data); 3274 // Validate that we have an address before proceeding 3275 if (!homeValuationAddress) throw new Error('Unable to extract home valuation address from form data'); 3276 // Required fields that must always be included 3277 const requiredFields = { 3278 companyId: data.companyId, 3279 homeValuationAddress: homeValuationAddress, 3280 homeValuationEstimate: homeValuationEstimate ? new Intl.NumberFormat('en-US', { 3281 style: 'currency', 3282 currency: 'USD', 3283 maximumFractionDigits: 0, 3284 minimumFractionDigits: 0 3285 }).format(homeValuationEstimate) : null, 3286 websiteId: data.page.websiteId, 3287 sourceUrl: data.activity.source_url 3288 }; 3289 // Optional fields that will be filtered if empty 3290 const optionalFields = { 3291 leadEmailAddress: data.activity.author_email, 3292 leadFullName: data.activity.author_name, 3293 leadPhoneNumber: data.activity.author_phone, 3294 parcelId: data.activity.content?.parcelId, 3295 resourceId: data.page.pageMeta?.resourceId, 3296 pageId: data.page.pageId,
3297 sourceResource: data.page.pageMeta?.sourceResource, 3298 pageElementId: data.page.pageMeta?.pageElementId, 3299 formId: data.page.pageMeta?.formId, 3300 utmSource: data.activity.content?.utm_source, 3301 utmMedium: data.activity.content?.utm_medium, 3302 utmCampaign: data.activity.content?.utm_campaign, 3303 utmTerm: data.activity.content?.utm_term, 3304 utmContent: data.activity.content?.utm_content, 3305 utmId: data.activity.content?.utm_id, 3306 timeToSell: data.activity.content?.timeToSell, 3307 lookingToBuy: data.activity.content?.lookingToBuy, 3308 referrer: data.referrer, 3309 content: data.activity.content || {}, 3310 fields: data.fields || {} 3311 }; 3312 // Filter out empty strings from optional fields 3313 const filteredOptionalFields = this._filterEmptyStrings(optionalFields); 3314 return { 3315 ...requiredFields, 3316 ...filteredOptionalFields, 3317 // Add structured address and coordinates if they exist 3318 ...structuredAddress && { 3319 address: structuredAddress 3320 }, 3321 ...coordinates && { 3322 coordinates: coordinates 3323 } 3324 }; 3325 } 3326 /** 3327 * Validate address with Google Maps 3328 * @param {string} rawAddress - Raw address string 3329 * @returns {Promise<Object|null>} - Validated address data or null 3330 * @throws {Error} - If validation fails, error is thrown with userMessage 3331 */ async _validateAddressSafely(rawAddress) { 3332 if (!rawAddress) { 3333 // eslint-disable-next-line no-console 3334 console.error('Home valuation: No address found in form data'); 3335 return null; 3336 } 3337 try { 3338 return await this._validateAddressWithGoogleMaps(rawAddress); 3339 } catch (error) { 3340 // eslint-disable-next-line no-console 3341 console.error('Error validating address with Google Maps:', error); 3342 // Attach user-friendly message and throw so user sees the error 3343 error.userMessage = this._getUserFriendlyErrorMessage(error); 3344 throw error; 3345 } 3346 } 3347 /** 3348 * Get home valuation estimate 3349 * @param {Object} validatedAddressData - Validated address data 3350 * @returns {Promise<number|null>} - Home valuation estimate or null 3351 * @throws {Error} - If estimate fetch fails, error is thrown with userMessage 3352 */ async _getHomeValuationEstimateSafely(validatedAddressData) { 3353 try { 3354 return await this._getHomeValuationEstimate(validatedAddressData); 3355 } catch (error) { 3356 // eslint-disable-next-line no-console 3357 console.error('Error getting home valuation estimate:', error); 3358 // Attach user-friendly message and throw so user sees the error 3359 error.userMessage = this._getUserFriendlyErrorMessage(error); 3360 throw error; 3361 } 3362 } 3363 /** 3364 * Parse response text into payload object 3365 * @param {string} text - Response text 3366 * @returns {Object} - Parsed payload 3367 */ _parseResponsePayload(text) { 3368 try { 3369 return text ? JSON.parse(text) : {}; 3370 } catch { 3371 return { 3372 raw: text 3373 }; 3374 } 3375 } 3376 /** 3377 * Create error from failed response 3378 * @param {Object} payload - Response payload 3379 * @param {number} status - HTTP status code 3380 * @returns {Error} - Error object with status and payload 3381 */ _createResponseError(payload, status) { 3382 const errorMessage = payload && typeof payload === 'object' && Object.keys(payload).length ? payload.message || JSON.stringify(payload) : 'Request failed'; 3383 const error = new Error(errorMessage); 3384 // Preserve payload properties if it's an object 3385 if (payload && typeof payload === 'object' && Object.keys(payload).length) Object.assign(error, payload); 3386 // Preserve numeric HTTP status - must be set after Object.assign 3387 // to ensure it takes precedence over any status in payload 3388 error.status = status; 3389 return error; 3390 } 3391 /** 3392 * Submit lead to API endpoint 3393 * @param {string} leadRoute - API endpoint URL 3394 * @param {Object} homeValuationData - Data to submit 3395 * @returns {Promise<Object>} - Submission result 3396 */ async _submitLead(leadRoute, homeValuationData) { 3397 const controller = new AbortController(); 3398 const timeoutId = setTimeout(()=>controller.abort(), 10000); 3399 try { 3400 const response = await fetch(leadRoute, { 3401 method: 'POST', 3402 headers: { 3403 'Content-Type': 'application/json' 3404 }, 3405 body: JSON.stringify(homeValuationData), 3406 signal: controller.signal 3407 }); 3408 clearTimeout(timeoutId); 3409 const text = await response.text(); 3410 const payload = this._parseResponsePayload(text); 3411 if (!response.ok) throw this._createResponseError(payload, response.status); 3412 if (payload && payload.status === 'success' && payload.redirectUrl) { 3413 this.window.location.href = payload.redirectUrl; 3414 return { 3415 redirected: true, 3416 url: payload.redirectUrl 3417 }; 3418 } 3419 return payload; 3420 } catch (error) { 3421 clearTimeout(timeoutId); 3422 throw error; 3423 } 3424 } 3425 /** 3426 * Submit home valuation request with Google Maps validation 3427 * @param {Object} data 3428 * @return {Promise<Object>} 3429 */ async _submitHomeValuationRequest(data) { 3430 const { config: config } = this; 3431 // Use websiteApiGatewayUrl from config 3432 if (!config.websiteApiGatewayUrl) throw new Error('websiteApiGatewayUrl not configured for home valuation'); 3433 // Log submission started 3434 this._logLeadEvent('home_valuation_submission_started', data); 3435 try { 3436 // Validate address with Google Maps 3437 const rawAddress = this._getRawAddress(data); 3438 let validatedAddressData = null; 3439 try {
3440 validatedAddressData = await this._validateAddressSafely(rawAddress); 3441 } catch (error) { 3442 // Error already has userMessage from _validateAddressSafely 3443 this._logLeadEvent('home_valuation_address_validation_failed', data, error); 3444 throw error; 3445 } 3446 // Get home valuation estimate. 3447 // The estimate is best-effort: many valid properties (e.g. commercial 3448 // parcels or addresses without AVM coverage) have no estimate and the 3449 // estimate endpoint returns a non-OK status for them. A missing estimate 3450 // must never block lead capture, so we log the failure and continue with 3451 // a null estimate rather than aborting the whole submission. 3452 let homeValuationEstimate = null; 3453 try { 3454 homeValuationEstimate = await this._getHomeValuationEstimateSafely(validatedAddressData); 3455 } catch (error) { 3456 // Error already has userMessage from _getHomeValuationEstimateSafely 3457 this._logLeadEvent('home_valuation_estimate_failed', data, error); 3458 homeValuationEstimate = null; 3459 } 3460 // Extract structured address and coordinates from Google Maps validation 3461 const { structuredAddress: structuredAddress, coordinates: coordinates } = this._extractAddressAndCoordinates(validatedAddressData); 3462 const leadRoute = `${config.websiteApiGatewayUrl}${$2aefad83322125c9$var$homeValuationRoute}`; 3463 const homeValuationData = this._buildHomeValuationData(data, homeValuationEstimate, structuredAddress, coordinates); 3464 const result = await this._submitLead(leadRoute, homeValuationData); 3465 // Log success 3466 this._logLeadEvent('home_valuation_submission_success', data); 3467 return result; 3468 } catch (error) { 3469 // Ensure error has user-friendly message (may already be set by helper methods) 3470 if (!error.userMessage) error.userMessage = this._getUserFriendlyErrorMessage(error); 3471 this._logLeadEvent('home_valuation_submission_failed', data, error); 3472 throw error; 3473 } 3474 } 3475 /** 3476 * Validate address using Google Maps Address Validation API 3477 * @param {string} addressStr - The address string to validate 3478 * @returns {Promise<Object|null>} - Validated address data or null if validation fails 3479 */ async _validateAddressWithGoogleMaps(addressStr) { 3480 const { config: config, window: window } = this; 3481 // Ensure Google Maps API key is loaded 3482 let apiKey = config.googleMapsAPIKey; 3483 if (!apiKey && window.luxuryPresence?.mapApiLoader) apiKey = await window.luxuryPresence.mapApiLoader.getMapApiKey(); 3484 if (!apiKey) throw new Error('Google Maps API key not configured'); 3485 const controller = new AbortController(); 3486 const timeoutId = setTimeout(()=>controller.abort(), 10000); 3487 try { 3488 const response = await fetch(`https://addressvalidation.googleapis.com/v1:validateAddress?key=${apiKey}`, { 3489 method: 'POST', 3490 headers: { 3491 'Content-Type': 'application/json' 3492 }, 3493 body: JSON.stringify({ 3494 address: { 3495 addressLines: [ 3496 addressStr 3497 ] 3498 }, 3499 enableUspsCass: false 3500 }), 3501 signal: controller.signal 3502 }); 3503 clearTimeout(timeoutId); 3504 if (!response.ok) { 3505 const error = new Error(`Address validation failed: ${response.status}`); 3506 error.status = response.status; 3507 throw error; 3508 } 3509 return response.json(); 3510 } catch (error) { 3511 clearTimeout(timeoutId); 3512 throw error; 3513 } 3514 } 3515 /** 3516 * Check if structured address has all mandatory fields 3517 * @param {Object} structuredAddress - Structured address object 3518 * @return {boolean} 3519 */ _hasMandatoryAddressFields(structuredAddress) { 3520 return !!(structuredAddress.streetNumber && structuredAddress.streetName && structuredAddress.city && structuredAddress.state && structuredAddress.zipcode); 3521 } 3522 /** 3523 * Log missing mandatory address fields 3524 * @param {Object} structuredAddress - Structured address object 3525 */ _logMissingAddressFields(structuredAddress) { 3526 const missingFields = [];
3527 if (!structuredAddress.streetNumber) missingFields.push('streetNumber'); 3528 if (!structuredAddress.streetName) missingFields.push('streetName'); 3529 if (!structuredAddress.city) missingFields.push('city'); 3530 if (!structuredAddress.state) missingFields.push('state'); 3531 if (!structuredAddress.zipcode) missingFields.push('zipcode'); 3532 // eslint-disable-next-line no-console 3533 console.log('Home valuation estimate skipped - missing required fields:', missingFields.join(', '), 'Available fields:', Object.keys(structuredAddress).join(', ')); 3534 } 3535 /** 3536 * Build query string from structured address 3537 * @param {Object} structuredAddress - Structured address object 3538 * @return {string} 3539 */ _buildAddressQueryString(structuredAddress) { 3540 return Object.entries(structuredAddress).map(([key, value])=>`${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&'); 3541 } 3542 /** 3543 * GET home valuation estimate 3544 * @param {string} address 3545 * @param {Object} validatedAddressData - Google Maps validated address data 3546 * @return {Promise<number|null>} 3547 */ async _getHomeValuationEstimate(validatedAddressData = null) { 3548 const { config: config } = this; 3549 if (!config.websiteApiGatewayUrl) throw new Error('websiteApiGatewayUrl not configured'); 3550 const base = `${config.websiteApiGatewayUrl}${$2aefad83322125c9$var$homeValuationRoute}`; 3551 // Check if we have validated address data 3552 if (!validatedAddressData?.result?.address?.addressComponents) return null; 3553 const structuredAddress = this._transformAddressComponents(validatedAddressData.result.address.addressComponents); 3554 // Check if all mandatory fields exist 3555 if (!this._hasMandatoryAddressFields(structuredAddress)) { 3556 this._logMissingAddressFields(structuredAddress); 3557 return null; 3558 } 3559 // Build URL with query string 3560 const qs = this._buildAddressQueryString(structuredAddress); 3561 const homeValURL = `${base}?${qs}`; 3562 const controller = new AbortController(); 3563 const timeoutId = setTimeout(()=>controller.abort(), 10000); 3564 try { 3565 const response = await fetch(homeValURL, { 3566 headers: { 3567 Accept: 'application/json' 3568 }, 3569 signal: controller.signal 3570 }); 3571 clearTimeout(timeoutId); 3572 if (!response.ok) { 3573 const error = new Error(`Home valuation estimate failed: ${response.status}`); 3574 error.status = response.status; 3575 throw error; 3576 } 3577 const data = await response.json(); 3578 return data?.valueDollars ?? null; 3579 } catch (error) { 3580 clearTimeout(timeoutId); 3581 // Re-throw to allow retry logic to handle it 3582 throw error; 3583 } 3584 } 3585} 3586 3587 3588const $e10bd00497be8876$export$97de66002300ed70 = 'middleName'; 3589// Default lead fields 3590const $e10bd00497be8876$var$DEFAULT_LEAD_FIELDS = [ 3591 'name', 3592 'firstName', 3593 'lastName', 3594 $e10bd00497be8876$export$97de66002300ed70, 3595 'email', 3596 'phone', 3597 'phoneNumber', 3598 'source', 3599 'message', 3600 'mlsId', 3601 'sourceUrl' 3602]; 3603class $e10bd00497be8876$export$3c5380623cf51249 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 3604 /** 3605 * Initialize Contact Form Controller at build time 3606 * @param { ConfigController } config 3607 * @param {Window} window 3608 * @param {Document} document 3609 */ constructor(config, window, document){ 3610 super(config, window, document); 3611 this.forms = []; 3612 this.homeValuationService = new (0, $2aefad83322125c9$export$2e2bcd8739ae039)(config, window, document); 3613 } 3614 /** 3615 * Initialize Contact Form Controller at run time 3616 * Attach handlers and events to DOM 3617 * @param {Object} options 3618 */ initialize(options = {}) { 3619 try { 3620 const { document: document } = this; 3621 const { selector: selector } = options; 3622 let forms = []; 3623 if (selector) forms = document.querySelectorAll(`${selector} form[data-type="contact-form"]`); 3624 else forms = document.querySelectorAll('form[data-type="contact-form"]');
3625 forms.forEach((form)=>{ 3626 this._attachSubmitHandler(form); 3627 // this._attachValidation(form); 3628 }); 3629 this.forms = this.forms.concat(forms); 3630 } catch (e) { 3631 // eslint-disable-next-line no-console 3632 console.log(e); 3633 } 3634 } 3635 /** 3636 * Controllers must implement a "destroy" method to be called 3637 * after page navigation to remove event handlers / cleanup 3638 */ destroy() { 3639 this.forms = []; 3640 } 3641 /** 3642 * Handle submit from global context 3643 * @param {HTMLFormElement} form 3644 */ submitForm(form) { 3645 this._handleSubmit(null, form).catch((e)=>console.error(e)); 3646 } 3647 /** 3648 * Attach submit event for form 3649 * @param {HTMLFormElement} contactForm 3650 */ _attachValidation(contactForm) { 3651 const { window: window } = this; 3652 const inputs = contactForm.querySelectorAll('input, select, textarea'); 3653 inputs.forEach((input)=>{ 3654 window.luxuryPresence.validation.applyFieldValidation(input); 3655 }); 3656 } 3657 /** 3658 * Attach submit event for form 3659 * @param {HTMLFormElement} contactForm 3660 */ _attachSubmitHandler(contactForm) { 3661 contactForm.addEventListener('submit', (e)=>this._handleSubmit(e, contactForm)); 3662 } 3663 /** 3664 * Extract and process form values 3665 * @param {HTMLFormElement} contactForm 3666 * @return {Object} - Processed form values 3667 */ _extractFormValues(contactForm) { 3668 const formData = new FormData(contactForm); 3669 const values = {}; 3670 const nameParts = []; 3671 const nameKeyRegex = /^name(?:-\d+)?$/; 3672 formData.forEach((value, key)=>{ 3673 if (typeof value === 'string') { 3674 const curr = value.trim(); 3675 if (nameKeyRegex.test(key) && curr) nameParts.push(curr); 3676 const prev = values[key]; 3677 values[key] = prev ? `${prev} ${curr}` : curr; 3678 } else values[key] = value; 3679 }); 3680 if (nameParts.length) values.name = nameParts.join(' ').trim(); 3681 else if (!values.name && values.firstName) { 3682 values.name = values.firstName; 3683 if (values.lastName) values.name += ` ${values.lastName}`; 3684 } 3685 return values; 3686 } 3687 /** 3688 * Build submission data object 3689 * @param {Object} values - Form values 3690 * @param {Object} fields - Form fields 3691 * @param {HTMLFormElement} contactForm - Form element 3692 * @return {Object} - Submission data 3693 */ _buildSubmissionData(values, fields, contactForm) { 3694 const { window: window, config: config } = this; 3695 const content = Object.keys(values).filter((key)=>!$e10bd00497be8876$var$DEFAULT_LEAD_FIELDS.includes(key)).reduce((result, key)=>{ 3696 // eslint-disable-next-line 3697 result[key] = values[key]; 3698 return result; 3699 }, {}); 3700 const { pageId: pageId, companyId: companyId, websiteId: websiteId, pageMeta: pageMeta } = config; 3701 const utm = window.localStorage.getItem('utm_vars') || '{}'; 3702 const referrer = window.localStorage.getItem('referrer') || ''; 3703 const formId = this._getFormId(contactForm); 3704 return { 3705 activity: { 3706 author_email: values.email, 3707 author_name: values.name, 3708 author_phone: values.phone || values.phoneNumber, 3709 activity_source: values.source || 'CONTACT_INQUIRY', 3710 comments_attributes: [ 3711 { 3712 text: values.message || undefined 3713 } 3714 ], 3715 source_url: window.location.href, 3716 content: { 3717 ...content, 3718 ...JSON.parse(utm) 3719 } 3720 }, 3721 page: { 3722 pageId: pageId, 3723 companyId: companyId, 3724 websiteId: websiteId, 3725 pageMeta: { 3726 ...pageMeta, 3727 formId: formId 3728 } 3729 }, 3730 companyId: companyId, 3731 referrer: referrer, 3732 fields: fields 3733 }; 3734 } 3735 /** 3736 * Handle successful form submission 3737 * @param {HTMLFormElement} contactForm - Form element 3738 */ _handleSubmissionSuccess(contactForm) { 3739 const { window: window } = this; 3740 const closeDelay = contactForm.dataset.delay || (0, $a3e97e89bbc2a366$export$f037eeffb5561205); 3741 contactForm.classList.remove('loading'); 3742 contactForm.classList.remove('error'); 3743 contactForm.classList.add('success'); 3744 // TODO: Review producer and classic to deprecate "hide" 3745 contactForm.querySelectorAll('.success').forEach((el)=>el.classList.remove('hide')); 3746 contactForm.dispatchEvent(new Event('formsubmitted')); 3747 // Any successful lead submit credits the Google Ads lead conversion 3748 // (reuses the existing `generate_lead` action), once per session. 3749 (0, $3ec2bf3965f87ecc$export$e70565180c0e6950)(this.window, this.document); 3750 setTimeout(()=>{ 3751 window.lpUI.hideClosestModal(contactForm); 3752 contactForm.reset(); 3753 window.lpUI.sideMenuHide(); 3754 contactForm.querySelectorAll('.success').forEach((el)=>el.classList.add('hide')); 3755 contactForm.classList.remove('success'); 3756 }, closeDelay); 3757 } 3758 /** 3759 * Submit Contact Form Handler 3760 * @param {Event} e 3761 * @param {HTMLFormElement} contactForm 3762 * @return {Promise<Object>} 3763 */ async _handleSubmit(e, contactForm) { 3764 if (e) e.preventDefault(); 3765 if (contactForm.classList.contains('loading')) // Form already submitting 3766 return; 3767 // Hide any previous error message and clear error state 3768 this._hideSubmissionError(contactForm); 3769 contactForm.classList.remove('error'); 3770 contactForm.classList.add('loading'); 3771 try { 3772 // Extract form values first (before async operations) 3773 const values = this._extractFormValues(contactForm); 3774 // TODO: HoneyPot should still send request 3775 if (values.middleName) { 3776 contactForm.classList.remove('loading'); 3777 return; 3778 } 3779 const fields = this._getFields(contactForm); 3780 const data = this._buildSubmissionData(values, fields, contactForm); 3781 await this._submitLeadRequest(data); 3782 this._sendGAEvent(data); 3783 this._handleSubmissionSuccess(contactForm); 3784 } catch (err) { 3785 // eslint-disable-next-line no-console 3786 console.error('Form submission failed:', err); 3787 contactForm.dispatchEvent(new Event('formsubmiterror')); 3788 contactForm.classList.remove('loading'); 3789 contactForm.classList.add('error'); 3790 // Show user-friendly error message if available (from home valuation service)
3791 if (err.userMessage) this._showSubmissionError(contactForm, err.userMessage); 3792 else this._showSubmissionError(contactForm, 'Something went wrong. Please try again.'); 3793 } 3794 } 3795 /** 3796 * Alias anonymous user with canonical ID using event bus 3797 * Links the user's anonymous browsing session to their canonical identity 3798 * @param {Object} data - Form submission data 3799 * @private 3800 */ _aliasUserWithEventBus(data) { 3801 try { 3802 // Check if event bus library and required methods are available 3803 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 3804 // Skip if user is already identified 3805 if (this.window.eventBusProvider.isIdentified()) { 3806 console.log('[EventBus] User already identified, skipping alias'); 3807 return; 3808 } 3809 const email = data.activity?.author_email; 3810 const { companyId: companyId } = this.config; 3811 if (!email || !companyId) { 3812 console.warn('[EventBus] Missing required data for user alias'); 3813 return; 3814 } 3815 // Get the anonymous distinct ID from PostHog 3816 const anonId = this.window.eventBusProvider.getDistinctId(); 3817 if (!anonId) { 3818 console.warn('[EventBus] No anonymous ID available for alias'); 3819 return; 3820 } 3821 // Generate deterministic canonical ID from company + email 3822 const canonicalId = this.window.LuxuryPresenceEventBus.generateUUIDv5FromCompanyEmail(companyId, email); 3823 // Create alias linking anonymous ID to canonical ID 3824 this.window.eventBusProvider.alias({ 3825 anonId: anonId, 3826 canonicalId: canonicalId 3827 }); 3828 console.log('[EventBus] User aliased with canonical ID'); 3829 } catch (error) { 3830 // Never block form submission due to analytics errors 3831 console.error('[EventBus] User alias failed:', error); 3832 } 3833 } 3834 /** 3835 * Send Lead Request 3836 * @param {Object} data 3837 * @return {Promise<Object>} 3838 */ async _submitLeadRequest(data) { 3839 const { config: config } = this; 3840 // Alias user with event bus before submitting the lead 3841 this._aliasUserWithEventBus(data); 3842 if (config.myhomeDashboardEnabled && (data.activity?.activity_source === 'HOME_VALUATION' || data.activity?.activity_source === 'HOME_VALUE')) return this.homeValuationService._submitHomeValuationRequest(data); 3843 const leadRoute = `${config.leadIngesterUrl}/api/v1/leads`; 3844 return fetch(leadRoute, { 3845 method: 'POST', 3846 headers: { 3847 'Content-Type': 'application/json' 3848 }, 3849 body: JSON.stringify(data) 3850 }).then((response)=>{ 3851 if (!response.ok) return response.json().then((error)=>{ 3852 throw error; 3853 }); 3854 return response.json(); 3855 }); 3856 } 3857 /** 3858 * Send GA event 3859 * @param {Object} data 3860 */ _sendGAEvent(data) { 3861 const { document: document } = this; 3862 let event = { 3863 hitType: 'event', 3864 eventCategory: 'button', 3865 eventAction: 'click' 3866 }; 3867 switch(data.activity.activity_source){ 3868 case 'NEWSLETTER_SIGNUP': 3869 event.eventLabel = 'Newsletter'; 3870 document.sendGoogleTagManagerEvent('event', 'newsletter_signup'); 3871 break; 3872 case 'HOME_SEARCH': 3873 event.eventLabel = 'HomeSearch'; 3874 document.sendGoogleTagManagerEvent('event', 'home_search'); 3875 break; 3876 case 'HOME_VALUE': 3877 case 'HOME_VALUATION': 3878 event.eventLabel = 'HomeValue'; 3879 document.sendGoogleTagManagerEvent('event', 'home_valuation'); 3880 break; 3881 case 'EBOOK': 3882 event.eventLabel = 'Ebook'; 3883 document.sendGoogleTagManagerEvent('event', 'ebook_download'); 3884 break; 3885 case 'CONTACT_INQUIRY': 3886 default: 3887 // for contact forms, Marketing has requested that they see a page-view of 'thank-you' as indication of success 3888 // Note that this will break if we have actual page with url of /thank-you 3889 event = { 3890 hitType: 'pageview', 3891 page: '/thank-you' 3892 }; 3893 document.sendGoogleTagManagerEvent('event', 'contact_inquiry'); 3894 break; 3895 } 3896 document.sendGoogleAnalyticsEvent(event); 3897 } 3898 /** 3899 * Gather fields / schema for form, used for display in CRM 3900 * @param {HTMLFormElement} form 3901 * @return {Object} 3902 */ _getFields(form) { 3903 const inputs = form.querySelectorAll('input, select, textarea'); 3904 const fields = {};
3905 inputs.forEach((input)=>{ 3906 const { id: id, name: name, type: inputType } = input; 3907 if (name === $e10bd00497be8876$export$97de66002300ed70) // Honeypot continue 3908 return true; 3909 let label = ''; 3910 if (id) { 3911 const labelNode = form.querySelector(`label[for='${id}']`); 3912 if (labelNode) label = labelNode.textContent.trim(); 3913 else if (input.placeholder) label = input.placeholder.trim(); 3914 } 3915 fields[name] = { 3916 label: label, 3917 type: input.tagName, 3918 inputType: input.tagName === 'INPUT' ? inputType : 'text' 3919 }; 3920 }); 3921 return fields; 3922 } 3923 /** 3924 * Figure out relevant section or div ID for form 3925 * @param {HTMLFormElement} form 3926 * @return {string} 3927 */ _getFormId(form) { 3928 const SELECTORS = "section[id^='section-'], footer[id], .modal[id^='modal-']"; 3929 const parent = form.closest(SELECTORS); 3930 return parent?.id ? this._cleanFormId(parent.id) : ''; 3931 } 3932 /** 3933 * Remove prefix from formID 3934 * @param {string} formId 3935 * @return {string} 3936 */ _cleanFormId(formId) { 3937 const PREFIXES = [ 3938 'section-', 3939 'modal-' 3940 ]; 3941 for (const prefix of PREFIXES){ 3942 if (formId.startsWith(prefix)) return formId.substring(prefix.length); 3943 } 3944 return formId; 3945 } 3946 /** 3947 * Show submission error message on form 3948 * @param {HTMLFormElement} form 3949 * @param {string} message 3950 */ _showSubmissionError(form, message) { 3951 const errorEl = form.querySelector('.submission-error-message'); 3952 if (errorEl) { 3953 errorEl.textContent = message || 'Something went wrong. Please try again.'; 3954 errorEl.style.display = 'block'; 3955 } 3956 } 3957 /** 3958 * Hide submission error message on form 3959 * @param {HTMLFormElement} form 3960 */ _hideSubmissionError(form) { 3961 const errorEl = form.querySelector('.submission-error-message'); 3962 if (errorEl) errorEl.style.display = 'none'; 3963 } 3964} 3965 3966 3967 3968const $ea6901fdf47e0ec1$var$CALLBACK = '__googleMapsCallback'; 3969const $ea6901fdf47e0ec1$var$GOOGLE_MAPS_URL = 'https://maps.googleapis.com/maps/api/js'; 3970const $ea6901fdf47e0ec1$export$76299006759be400 = 1024; 3971const $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS = 3; 3972const $ea6901fdf47e0ec1$var$KEY_RETRY_BASE_DELAY_MS = 300; 3973const $ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG = 'lp_map_key_failed'; 3974class $ea6901fdf47e0ec1$export$3c19195edca3fa5c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 3975 /** 3976 * Initialize Button Controller at build time 3977 * @param { ConfigController } config 3978 * @param {Window} window 3979 * @param {Document} document 3980 */ constructor(config, window, document){ 3981 super(config, window, document); 3982 this.retries = 3; 3983 this.callbacks = []; 3984 this.id = `__googleMapsScriptId${Date.now()}`; 3985 this._apiKey = ''; 3986 this.reset(); 3987 } 3988 /** 3989 * Set the Google Maps api key 3990 * @param {string} apiKey 3991 */ set apiKey(apiKey) { 3992 this._apiKey = apiKey; 3993 this.config.setGoogleMapsAPIKey(apiKey); 3994 } 3995 /** 3996 * Get the Google Maps api key 3997 * @return {string} 3998 */ get apiKey() { 3999 return this._apiKey; 4000 } 4001 /** 4002 * Reset the loader state. 4003 */ reset() { 4004 this.deleteScript(); 4005 this.done = false; 4006 this.loading = false; 4007 this.failed = false; 4008 this.errors = []; 4009 this.onerrorEvent = null; 4010 } 4011 /** 4012 * Destroy 4013 */ destroy() { 4014 this.reset(); 4015 } 4016 /** 4017 * get map api Key 4018 * @return {Promise<string>} 4019 */ async getMapApiKey() { 4020 if (this.apiKey) return this.apiKey; 4021 const hadPreviousFailure = this._hadPreviousFailure(); 4022 let recoveryReported = false; 4023 for(let attempt = 1; attempt <= $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS; attempt += 1){ 4024 const reportRecovery = hadPreviousFailure && !recoveryReported; 4025 try { 4026 // eslint-disable-next-line no-await-in-loop 4027 const response = await fetch(this._getMapKeyUrl(attempt, reportRecovery));
4028 // The request reached the server, so a recovery marker on it was 4029 // delivered and must not be repeated on later attempts or pages. A 4030 // rejected fetch never arrived, so the marker moves to the next 4031 // attempt. 4032 recoveryReported = recoveryReported || reportRecovery; 4033 this._setFailureFlag(false); 4034 if (!response.ok) throw new Error(`Failed to fetch API key: ${response.status}`); 4035 // eslint-disable-next-line no-await-in-loop 4036 const code = await response.text(); 4037 if (!code) return ''; 4038 this.apiKey = code; 4039 return this.apiKey; 4040 } catch (e) { 4041 // eslint-disable-next-line no-console 4042 console.error(e); 4043 if (attempt < $ea6901fdf47e0ec1$var$KEY_FETCH_ATTEMPTS) // eslint-disable-next-line no-await-in-loop 4044 await this._delay($ea6901fdf47e0ec1$var$KEY_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1)); 4045 } 4046 } 4047 this._setFailureFlag(true); 4048 return ''; 4049 } 4050 /** 4051 * Build the map key request url. Retries carry their attempt number, and a 4052 * single request per session carries the recovery marker, so both are 4053 * countable in existing request logs without new infrastructure. 4054 * @param {number} attempt 1-based attempt number 4055 * @param {boolean} reportRecovery tag this request as following a session 4056 * in which every attempt failed 4057 * @return {string} 4058 */ _getMapKeyUrl(attempt, reportRecovery) { 4059 const params = []; 4060 if (attempt > 1) params.push(`attempt=${attempt}`); 4061 if (reportRecovery) params.push('recovered_after_failure=1'); 4062 const query = params.length ? `?${params.join('&')}` : ''; 4063 return `${this._getBaseUrl()}/api/v1/map${query}`; 4064 } 4065 /** 4066 * Whether an earlier attempt in this session exhausted all retries. 4067 * @return {boolean} 4068 */ _hadPreviousFailure() { 4069 try { 4070 return this.window.sessionStorage.getItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG) === '1'; 4071 } catch (e) { 4072 // Storage can throw when disabled (private browsing); absence of the 4073 // flag is the safe default. 4074 return false; 4075 } 4076 } 4077 /** 4078 * Record or clear the session-level key fetch failure flag. 4079 * @param {boolean} failed 4080 */ _setFailureFlag(failed) { 4081 try { 4082 if (failed) this.window.sessionStorage.setItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG, '1'); 4083 else this.window.sessionStorage.removeItem($ea6901fdf47e0ec1$var$KEY_FAILURE_FLAG); 4084 } catch (e) { 4085 // Storage unavailable - reporting is best effort, never fatal. 4086 } 4087 } 4088 /** 4089 * @param {number} ms 4090 * @return {Promise} 4091 */ _delay(ms) { 4092 return new Promise((resolve)=>{ 4093 this.window.setTimeout(resolve, ms); 4094 }); 4095 } 4096 /** 4097 * CreateUrl returns the Google Maps JavaScript API script url ]. 4098 * @return {string} 4099 */ async createUrl() { 4100 const apiKey = await this.getMapApiKey(); 4101 // Google Maps loads successfully without a key and then fails at call time 4102 // with NoApiKeys, which produces a broken map and no load error. Refuse 4103 // instead, so the failure surfaces to the caller. 4104 if (!apiKey) throw new Error('Refusing to load Google Maps without an API key'); 4105 let url = $ea6901fdf47e0ec1$var$GOOGLE_MAPS_URL; 4106 url += `?callback=${$ea6901fdf47e0ec1$var$CALLBACK}`; 4107 url += `&key=${apiKey}`; 4108 url += `&libraries=places`; 4109 return url; 4110 } 4111 /** 4112 * Set the script on document. 4113 */ async setScript() { 4114 if (this.document.getElementById(this.id)) { 4115 this.callback(); 4116 return; 4117 } 4118 let url; 4119 try { 4120 url = await this.createUrl(); 4121 } catch (e) { 4122 // eslint-disable-next-line no-console 4123 console.error(e); 4124 this.failed = true; 4125 this.loading = false; 4126 this.onerrorEvent = e; 4127 this.callback(); 4128 return; 4129 } 4130 const script = this.document.createElement('script'); 4131 script.id = this.id; 4132 script.type = 'text/javascript'; 4133 script.src = url; 4134 script.onerror = this.loadErrorCallback.bind(this); 4135 script.defer = true; 4136 script.async = true; 4137 this.document.head.appendChild(script); 4138 } 4139 /** 4140 * Function to be called if script tag fails 4141 * @param {Error} e 4142 */ loadErrorCallback(e) { 4143 this.errors.push(e); 4144 if (this.errors.length <= this.retries) {
4145 const delay = this.errors.length * 2 ** this.errors.length; 4146 // eslint-disable-next-line no-console 4147 console.log(`Failed to load Google Maps script, retrying in ${delay} ms.`); 4148 setTimeout(()=>{ 4149 this.deleteScript(); 4150 this.setScript().catch((e)=>console.error(e)); 4151 }, delay); 4152 } else { 4153 this.failed = true; 4154 this.onerrorEvent = e; 4155 this.callback(); 4156 } 4157 } 4158 /** 4159 * Delete the script tag 4160 */ deleteScript() { 4161 const script = this.document.getElementById(this.id); 4162 if (script) script.remove(); 4163 } 4164 /** 4165 * Load the Google Maps JavaScript API script and return a Promise. 4166 * @return {Promise} 4167 */ load() { 4168 return this.loadPromise(); 4169 } 4170 /** 4171 * Load the Google Maps JavaScript API script and return a Promise. 4172 * @return {Promise} 4173 */ loadPromise() { 4174 return new Promise((resolve, reject)=>{ 4175 this.loadCallback((err)=>{ 4176 if (!err) resolve(); 4177 else reject(err); 4178 }); 4179 }); 4180 } 4181 /** 4182 * Load the Google Maps JavaScript API script with a callback. 4183 * @param {Function<Event>} fn 4184 */ loadCallback(fn) { 4185 this.callbacks.push(fn); 4186 this.execute(); 4187 } 4188 /** 4189 * Sets the callback function that will be sent as part of the script URL. 4190 */ setCallback() { 4191 this.window.__googleMapsCallback = this.callback.bind(this); 4192 } 4193 /** 4194 * Reset if failed 4195 */ resetIfRetryingFailed() { 4196 if (this.failed) this.reset(); 4197 } 4198 /** 4199 * This is the function that we set the callback parameter to. 4200 */ callback() { 4201 this.done = true; 4202 this.loading = false; 4203 this.callbacks.forEach((cb)=>{ 4204 cb(this.onerrorEvent); 4205 }); 4206 this.callbacks = []; 4207 } 4208 /** 4209 * Set the script a if needed; set the callback 4210 */ execute() { 4211 if (this.window.google && this.window.google.maps && this.window.google.maps.version) // Google Maps already loaded 4212 this.callback(); 4213 this.resetIfRetryingFailed(); 4214 if (this.done) this.callback(); 4215 else if (this.loading) ; 4216 else { 4217 this.loading = true; 4218 this.setCallback(); 4219 this.setScript().catch((e)=>console.error(e)); 4220 } 4221 } 4222 /** 4223 * get base url based on current config 4224 * @return {string} 4225 */ _getBaseUrl() { 4226 // Special handling for page builder since no wag available 4227 const { isBuilder: isBuilder, websiteApiGatewayUrl: websiteApiGatewayUrl } = this.config; 4228 return isBuilder ? websiteApiGatewayUrl : ''; 4229 } 4230 /** 4231 * Resize static map requests to the max 1024px while preserving aspect ratio 4232 * @param {number} width 4233 * @param {number} height 4234 * @return {{width, height}} 4235 */ resizeStaticMapDimensions(width, height) { 4236 if (width <= $ea6901fdf47e0ec1$export$76299006759be400 && height <= $ea6901fdf47e0ec1$export$76299006759be400) return { 4237 width: width, 4238 height: height 4239 }; 4240 // Size param ignored if dimensions exceed STATIC_MAP_MAX_DIM 4241 const ratio = Math.min($ea6901fdf47e0ec1$export$76299006759be400 / width, $ea6901fdf47e0ec1$export$76299006759be400 / height); 4242 return { 4243 width: parseInt(width * ratio), 4244 height: parseInt(height * ratio) 4245 }; 4246 } 4247 /** 4248 * Convert theme to static api param object 4249 * @param {Object} theme 4250 * @return {Object} 4251 */ convertThemeToStaticApiUrl(theme) { 4252 // https://developers.google.com/maps/documentation/maps-static/style-reference 4253 // Google Maps Static API uses a special syntax for it's urls based on the interactive map styles 4254 return theme.map((t)=>{ 4255 const styles = t.stylers.reduce((acc, s)=>{ 4256 const visibility = s.visibility ? `visibility:${s.visibility}` : ''; 4257 const color = s.color ? `color:${s.color.replace('#', '0x')}` : ''; 4258 const lightness = s.lightness ? `lightness:${s.lightness}` : ''; 4259 return `${acc}|${visibility}${color}${lightness}`; 4260 }, ''); 4261 const element = t.elementType ? `|element:${t.elementType}` : ''; 4262 return `feature:${t.featureType}${element}${styles}`; 4263 }); 4264 } 4265 /** 4266 * generate digital signature for url 4267 * @param {string} queryString to sign 4268 * @return {Promise<string>} digitally signed url 4269 */ async getMapApiSignedUrl(queryString) { 4270 try { 4271 const response = await fetch(`${this._getBaseUrl()}/api/v1/map/signature?${queryString}`); 4272 if (!response.ok) throw new Error('Failed to fetch signed URL'); 4273 const { url: url } = await response.json(); 4274 return url; 4275 } catch (e) { 4276 // eslint-disable-next-line no-console 4277 console.error(e); 4278 return ''; 4279 } 4280 } 4281 /** 4282 * Generate static map url 4283 * @param {number} lat 4284 * @param {number} lng 4285 * @param {number} zoom 4286 * @param {Object} theme 4287 * @param {number} srcWidth 4288 * @param {number} srcHeight 4289 * @return {string} 4290 */ generateStaticMapUrl(lat, lng, zoom, theme, srcWidth, srcHeight) {
4291 const baseUrl = 'https://maps.googleapis.com/maps/api/staticmap'; 4292 const { width: width, height: height } = this.resizeStaticMapDimensions(srcWidth, srcHeight); 4293 const query = { 4294 center: `${lat},${lng}`, 4295 zoom: zoom, 4296 scale: 2, 4297 size: `${width}x${height}`, 4298 key: this.apiKey 4299 }; 4300 if (theme) query.style = this.convertThemeToStaticApiUrl(theme); 4301 const params = new URLSearchParams(); 4302 Object.entries(query).forEach(([key, value])=>{ 4303 if (Array.isArray(value)) value.forEach((v)=>params.append(key, v.toString())); 4304 else params.append(key, value.toString()); 4305 }); 4306 return `${baseUrl}?${params.toString()}`; 4307 } 4308 /** 4309 * Generate static map url with digital signature 4310 * @param {Object} { 4311 * srcWidth {number}, required 4312 * srcHeight {number}, required 4313 * theme {array}, 4314 * center: `${lat},${lng}`, required 4315 * zoom: number, required 4316 * markers: `${lat},${lng}`, 4317 * scale: number, 4318 * otherQueryParams... (these must match what is compatible with google maps static api query params) 4319 * } 4320 * @return {Promise<string>} digitally signed url 4321 */ async generateDigitallySignedStaticMapUrl({ srcWidth: srcWidth, srcHeight: srcHeight, theme: theme, ...query }) { 4322 const { width: width, height: height } = this.resizeStaticMapDimensions(srcWidth, srcHeight); 4323 const queryParams = { 4324 ...query, 4325 size: `${width}x${height}` 4326 }; 4327 if (theme) queryParams.style = this.convertThemeToStaticApiUrl(theme); 4328 const params = new URLSearchParams(); 4329 Object.entries(queryParams).forEach(([key, value])=>{ 4330 if (Array.isArray(value)) value.forEach((v)=>params.append(key, v.toString())); 4331 else params.append(key, value.toString()); 4332 }); 4333 const queryString = params.toString(); 4334 try { 4335 // fetch digitally signed url 4336 return await this.getMapApiSignedUrl(queryString); 4337 } catch (e) { 4338 console.error(e); 4339 return ''; 4340 } 4341 } 4342} 4343 4344 4345/* eslint-disable import/prefer-default-export */ 4346 4347class $0a0ad49f13c0b8fd$export$ba9afeb75f20f616 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 4348 // constructor is not needed as it is inherited from BaseController 4349 /** 4350 * Controllers must implement a "destroy" method to be called 4351 * after page navigation to remove event handlers / cleanup 4352 */ destroy() {} 4353 /** 4354 * Places (re-places) a value into the query string under specified key 4355 * or removes it if new value is null or undefined 4356 * @param {string} key 4357 * @param {string|null|undefined|object|array} value 4358 * @param {string} url - defaults to window.location.href 4359 * @return {string} 4360 */ // eslint-disable-next-line sonarjs/cognitive-complexity 4361 updateQueryString(key, value, url) { 4362 // https://stackoverflow.com/questions/5999118/how-can-i-add-or-update-a-query-string-parameter 4363 if (!url) // eslint-disable-next-line 4364 url = this.window.location.href; 4365 let re = new RegExp(`([?&])${key}=.*?(&|#|$)`, 'i'); 4366 let replacement = ''; 4367 if (typeof value !== 'undefined' && value !== null) { 4368 if (Array.isArray(value)) { 4369 if (value.length) replacement = this.serializeArray(key, value); 4370 } else if (typeof value === 'object') { 4371 re = new RegExp(`([?&])${key}\\[[^=]*\\]=.*?(&|#|$)`, 'i'); 4372 replacement = this.serializeObj(value, '', key); 4373 } else replacement = `${key}=${encodeURIComponent(value)}`; 4374 } 4375 const hash = url.split('#'); 4376 let result = hash[0]; 4377 if (re.test(url)) { 4378 let clean = result; 4379 replacement = replacement ? `$1${replacement}$2` : '$1'; 4380 while(re.test(clean)){ 4381 result = clean.replace(re, replacement); 4382 clean = clean.replace(re, '$1'); 4383 } 4384 result = result.replace(/(&|\?)$/, ''); 4385 } else if (replacement) { 4386 const separator = result.indexOf('?') !== -1 ? '&' : '?'; 4387 result += `${separator}${replacement}`; 4388 } 4389 if (typeof hash[1] !== 'undefined' && hash[1] !== null) result += `#${hash[1]}`; 4390 return result; 4391 } 4392 /** 4393 * Returns variable from query string specified by parameter name 4394 * @param {string} name 4395 * @param {string} url defaults to window.location.href 4396 * @return {string|null} 4397 */ getParameterByName(name, url) { 4398 if (!url) // eslint-disable-next-line 4399 url = this.window.location.href; 4400 // eslint-disable-next-line 4401 name = name.replace(/[[\]]/g, '\\$&'); 4402 const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`); 4403 let results = Array.from(RegExp.prototype[Symbol.matchAll].call(regex, url)).flat(); 4404 // check for object like syntax where the last value can be an array eg. advancedFilters[query][statusIds][in][0] or advancedFilters[query][city] 4405 if (!results.length) { 4406 const objRegex = new RegExp(`[?&]${name}(\\[.*?\\])=(.*?)(?=&|#|$)`, 'g'); 4407 results = Array.from(RegExp.prototype[Symbol.matchAll].call(objRegex, url)).flat(); 4408 return this._parseParamToObject(results, name === 'advancedFilters'); 4409 } 4410 // For multiple param values, eg arrays 4411 /* Results from regex match all come in this form: 4412 [ '&advancedFilters[query][statusIds][in]=uuid-segundo-123', '[query][statusIds][in]', 'uuid-segundo-123' ] 4413 So using every third value will be the actual value and the second value will be the path 4414 */ if (results.length > 3) return results.reduce((acc, value, index)=>{ 4415 if ((index + 1) % 3 === 0) acc.push(decodeURIComponent(value.replace(/\+/g, ' '))); 4416 return acc; 4417 }, []); 4418 if (!results[2]) return ''; 4419 return decodeURIComponent(results[2].replace(/\+/g, ' ')); 4420 } 4421 /** 4422 * Generates section specific key to store page number in the URL 4423 * @param {string} sectionDomId 4424 * @return {string} 4425 */ makePageKey(sectionDomId) { 4426 return sectionDomId.replace('section-', '').replace(/-/g, ''); 4427 } 4428 /** 4429 * Generates specific key to store parameter in the URL 4430 * uses prevsiouly calculated baseKey for section specific parameters 4431 * @param {Object} formParam 4432 * @param {string} baseKey pre-calculated base for section specific parameters 4433 * @return {string} 4434 */ makeParamKey(formParam, baseKey) { 4435 return formParam.global ? formParam.urlKey : `${baseKey}-${formParam.urlKey}`; 4436 } 4437 /** 4438 * Gets a set of parameters from window query string 4439 * always returns value of "page" parameter if present 4440 * @param {Object[]} formConfig 4441 * @param {string} sectionDomId 4442 * @return {Object} 4443 */ deserializeParams(formConfig, sectionDomId) { 4444 const params = {}; 4445 const urlPageKey = this.makePageKey(sectionDomId); 4446 const page = this.getParameterByName(urlPageKey); 4447 if (page) params.page = parseInt(page); 4448 if (Array.isArray(formConfig)) formConfig.forEach((formParam)=>{
4449 const key = this.makeParamKey(formParam, urlPageKey); 4450 let urlValue = this.getParameterByName(key); 4451 if (formParam.type === 'int') { 4452 urlValue = parseInt(urlValue); 4453 // eslint-disable-next-line 4454 if (!isFinite(urlValue)) urlValue = null; 4455 } else if (formParam.type === 'bool' || formParam.type === 'boolean') urlValue = // eslint-disable-next-line 4456 urlValue === 'true' ? true : urlValue === 'false' ? false : null; 4457 else if (formParam.type === 'json') try { 4458 urlValue = JSON.parse(urlValue); 4459 } catch (e) { 4460 // no need to do anything 4461 } 4462 params[formParam.formKey || formParam.param] = urlValue; 4463 }); 4464 return params; 4465 } 4466 /** 4467 * Serializes set of parameters defined by formConfig into the URL 4468 * adding or replacing or removing required parameters 4469 * @param {Object[]} formConfig 4470 * @param {string} sectionDomId 4471 * @param {Object} params 4472 * @return {string} 4473 */ serializeParams(formConfig, sectionDomId, params) { 4474 let result = this.window.location.href; 4475 const urlPageKey = this.makePageKey(sectionDomId); 4476 result = this.updateQueryString(urlPageKey, params.page, result); 4477 if (Array.isArray(formConfig)) formConfig.forEach((formParam)=>{ 4478 const key = this.makeParamKey(formParam, urlPageKey); 4479 let value = params[formParam.formKey || formParam.param]; 4480 if (formParam.type === 'json' && value !== null && typeof value !== 'undefined') value = JSON.stringify(value); 4481 result = this.updateQueryString(key, value, result); 4482 }); 4483 return result; 4484 } 4485 /** 4486 * Formats small number for slider values 4487 * @param {number} value 4488 * @param {string} currency 4489 * @return {string} 4490 */ formatSliderAtom(value, currency = '') { 4491 const formattedValue = Number.isInteger(value) ? value : value.toFixed(2); 4492 return currency + formattedValue; 4493 } 4494 /** 4495 * Formats a number for slider values 4496 * @param {number} value 4497 * @param {string} currency 4498 * @param {string} delimiter 4499 * @return {string} 4500 */ formatSliderValue(value, currency = '', delimiter = '') { 4501 if (value < 1000) return this.formatSliderAtom(value, currency); 4502 if (value < 1000000) return `${this.formatSliderAtom(value / 1000, currency)}${delimiter}K`; 4503 return `${this.formatSliderAtom(value / 1000000, currency)}${delimiter}M`; 4504 } 4505 /** 4506 * Format price slider range 4507 * @param {number} value 4508 * @param {Object} range 4509 * @param {string} currency 4510 * @param {Object} options 4511 * @return {string} 4512 */ formatSliderPriceRange(value, range, currency, options) { 4513 if (range.min === value && value !== 0) return `${options.lowPrefix}${this.formatSliderValue(value, currency, ' ')}`; 4514 if (range.max === value) return `${this.formatSliderValue(value, currency, ' ')}${options.highSuffix}`; 4515 return `${this.formatSliderValue(value, currency, ' ')}`; 4516 } 4517 /** 4518 * Format area slider range 4519 * @param {number} value 4520 * @param {Object} range 4521 * @param {string} suffix 4522 * @param {Object} options 4523 * @return {string} 4524 */ formatSliderAreaRange(value, range, suffix, options) { 4525 if (range.min === value && value !== 0) return `${options.lowPrefix}${this.formatSliderValue(value)} ${suffix}`; 4526 if (range.max === value) return `${this.formatSliderValue(value)}${options.highSuffix} ${suffix}`; 4527 return `${this.formatSliderValue(value)} ${suffix}`; 4528 } 4529 /** 4530 * Utility function to get properties search parameters from a set of jQuery objects 4531 * @param {Object} options 4532 * @param {jQuery|HTMLElement} [options.queryElement] 4533 * @param {jQuery|HTMLElement} [options.priceSliderElement] 4534 * @param {jQuery|HTMLElement} [options.areaSliderElement] 4535 * @param {jQuery|HTMLElement} [options.neighborhoodSelect] 4536 * @return {Object} 4537 */ // eslint-disable-next-line sonarjs/cognitive-complexity 4538 getSearchFormValues(options) { 4539 const { queryElement: queryElement, priceSliderElement: priceSliderElement, areaSli
4539derElement: areaSliderElement, neighborhoodSelect: neighborhoodSelect } = options; 4540 const result = {}; 4541 if (queryElement) result.search = queryElement.value || null; 4542 if (priceSliderElement) { 4543 const priceValues = priceSliderElement.value.split(';'); 4544 const priceMinLimit = parseInt(priceSliderElement.dataset.min); 4545 const priceMaxLimit = parseInt(priceSliderElement.dataset.max); 4546 const priceMin = parseInt(priceValues[0]); 4547 const priceMax = parseInt(priceValues[1]); 4548 result.priceMin = priceMin !== priceMinLimit ? priceMin : null; 4549 result.priceMax = priceMax !== priceMaxLimit ? priceMax : null; 4550 } 4551 if (areaSliderElement) { 4552 const areaValues = areaSliderElement.value.split(';'); 4553 const areaMinLimit = parseInt(areaSliderElement.dataset.min); 4554 const areaMaxLimit = parseInt(areaSliderElement.dataset.max); 4555 const areaMin = parseInt(areaValues[0]); 4556 const areaMax = parseInt(areaValues[1]); 4557 result.areaMin = areaMin !== areaMinLimit ? areaMin : null; 4558 result.areaMax = areaMax !== areaMaxLimit ? areaMax : null; 4559 } 4560 if (neighborhoodSelect) result.neighborhoodId = neighborhoodSelect.value || null; 4561 return result; 4562 } 4563 /** 4564 * Add supports for object typeof values to be encoded on URL 4565 * Ref: https://stackoverflow.com/questions/1714786/query-string-encoding-of-a-javascript-object 4566 * @param {*} obj 4567 * @param {string} prefix 4568 * @param {string} baseParam used for grouping in case of nested objects 4569 * @returns 4570 */ // eslint-disable-next-line sonarjs/cognitive-complexity 4571 serializeObj(obj, prefix = '', baseParam = '') { 4572 const result = []; 4573 for(const prop in obj)if (obj.hasOwnProperty(prop)) { 4574 const value = obj[prop]; 4575 let k; 4576 if (baseParam) { 4577 const newPrefix = prefix ? `[${prefix}][${prop}]` : `[${prop}]`; 4578 k = `${baseParam}${newPrefix}`; 4579 } else k = prefix ? `${prefix}[${prop}]` : prop; 4580 if (value !== null && Array.isArray(value)) { 4581 if (value.length) result.push(this.serializeArray(k, value)); 4582 } else if (value !== null && typeof value === 'object') result.push(this.serializeObj(value, k)); 4583 else result.push(`${k}=${encodeURIComponent(value)}`); 4584 } 4585 return result.join('&'); 4586 } 4587 /** 4588 * Adds support for array values to be encoded on URL 4589 * @param {string} key 4590 * @param {Array} value 4591 * @param {string} baseParam 4592 */ serializeArray(key, value, baseParam = '') { 4593 const result = []; 4594 value.forEach((val)=>{ 4595 const paramName = baseParam ? `${baseParam}${key}` : key; 4596 result.push(`${paramName}=${encodeURIComponent(val)}`); 4597 }); 4598 return result.join('&'); 4599 } 4600 /** 4601 * Private method to process string search values. 4602 * @param {Array} results comes from regex matchAll. 4603 * @param {Boolean} isAdvancedFilters flag to determine if the search is for advanced filters. 4604 * @returns 4605 */ _parseParamToObject(results, isAdvancedFilters = false) { 4606 if (!results.length) return null; 4607 const obj = {}; 4608 for(let i = 0; i < results.length; i++)/* Results from regex match all come in this form: 4609 [ '&advancedFilters[query][statusIds][in]=uuid-segundo-123', '[query][statusIds][in]', 'uuid-segundo-123' ] 4610 So using every third value will be the actual value and the second value will be the path 4611 */ if ((i + 1) % 3 === 0) { 4612 const value = decodeURIComponent(results[i].replace(/\+/g, ' ')); 4613 const path = results[i - 1]; 4614 Object.assign(obj, this._setObjectPath(path, value, obj, isAdvancedFilters)); 4615 } 4616 return obj; 4617 } 4618 /** * 4619 * Private method to set object value given a path 4620 * @param {String} path 4621 * @param {*} value 4622 * @param {Object} baseObj 4623 * @param {Boolean} isAdvancedFilters flag to determine if the search is for advanced filters. 4624 */ _setObjectPath(path, value, baseObj, isAdvancedFilters = false) { 4625 // eslint-disable-next-line
4626 const keys = path.split(/[\[\]]/).filter(Boolean); 4627 const afArrayKeys = [ 4628 'in', 4629 'nin', 4630 'btw', 4631 'ciin', 4632 'cinin' 4633 ]; 4634 const obj = {}; 4635 let ref = obj; 4636 const valueExists = (0, $fc0a058ae42af628$export$267a1435fe18b8d4)(baseObj, keys.join('.')); 4637 keys.forEach((key, index)=>{ 4638 if (index === keys.length - 1) { 4639 if (valueExists) ref[key] = Array.isArray(valueExists) ? [ 4640 ...valueExists, 4641 value 4642 ] : [ 4643 valueExists, 4644 value 4645 ]; 4646 else ref[key] = isAdvancedFilters && afArrayKeys.includes(key) ? [ 4647 value 4648 ] : value; 4649 } else { 4650 ref[key] = baseObj[key] ? baseObj[key] : {}; 4651 ref = ref[key]; 4652 } 4653 }); 4654 return obj; 4655 } 4656} 4657 4658 4659/* eslint-disable import/prefer-default-export */ 4660class $2b1790aa32f109d1$export$43e435c053a109f6 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 4661 /** 4662 * Initialize Expand Slider Controller at build time 4663 * @param { ConfigController } config 4664 * @param {Window} window 4665 * @param {Document} document 4666 */ constructor(config, window, document){ 4667 super(config, window, document); 4668 this._createLightbox = this._createLightbox.bind(this); 4669 this.expandSliders = []; 4670 } 4671 /** 4672 * Initialize Expand Slider Controller at run time 4673 * Attach handlers and events to DOM 4674 * @param {Object} options 4675 */ initialize(options = {}) { 4676 try { 4677 const { document: document } = this; 4678 const expandSliders = document.querySelectorAll('.has-mobile-expand'); 4679 expandSliders.forEach((block)=>{ 4680 this._addExpandButton(block); 4681 }); 4682 this.expandSliders = this.expandSliders.concat(expandSliders); 4683 } catch (e) { 4684 // eslint-disable-next-line no-console 4685 console.log(e); 4686 } 4687 } 4688 /** 4689 * Controllers must implement a "destroy" method to be called 4690 * after page navigation to remove event handlers / cleanup 4691 */ destroy() { 4692 const { document: document } = this; 4693 document.querySelectorAll('.lp-expand-btn, .lp-expand-btn-wrapper').forEach((element)=>element.remove()); 4694 this.expandSliders = []; 4695 } 4696 /** 4697 * Create expand button for sliders 4698 * @param {HTMLElement} slider 4699 */ _addExpandButton(slider) { 4700 const { document: document } = this; 4701 const section = slider.closest('section[id]'); 4702 const appendTargetSelector = slider.dataset.append; 4703 let expandBtn = section.querySelector('.lp-expand-btn'); 4704 if (!expandBtn) { 4705 expandBtn = document.createElement('button'); 4706 expandBtn.className = 'lp-expand-btn'; 4707 expandBtn.setAttribute('aria-label', 'Open a lightbox'); 4708 expandBtn.innerHTML = `<span class="lp-i lp-i--expand-alt" aria-hidden="true"></span>`; 4709 if (appendTargetSelector) { 4710 const appendTarget = section.querySelector(appendTargetSelector); 4711 if (appendTarget) appendTarget.appendChild(expandBtn); 4712 } else { 4713 const wrapper = document.createElement('div'); 4714 wrapper.className = 'lp-expand-btn-wrapper'; 4715 wrapper.style.position = 'relative'; 4716 wrapper.appendChild(expandBtn); 4717 slider.parentNode.insertBefore(wrapper, slider.nextSibling); 4718 } 4719 } 4720 expandBtn.addEventListener('click', ()=>{ 4721 this._createLightbox({ 4722 slider: slider, 4723 section: section 4724 }); 4725 }); 4726 } 4727 /** 4728 * Creates a lightbox modal for displaying slider images in a larger view. 4729 * 4730 * @param {Object} params - The parameters for the function. 4731 * @param {HTMLElement} params.slider - The slider element containing images. 4732 * @param {HTMLElement} params.section - The section element related to the slider. 4733 * @param {number} [params.initialIndex] - Optional index of the image to show initially. 4734 */ _createLightbox({ slider: slider, section: section, initialIndex: initialIndex }) { 4735 const { window: window, document: document } = this; 4736 const modalId = `lightbox-for-${section?.id}`; 4737 const isSlickAvailable = window.$ && window.$.fn.slick; 4738 const isSectionSlickInitialized = isSlickAvailable && slider.slick; 4739 const isSplideAvailable = typeof window.Splide === 'function'; 4740 const isSectionSplideInitialized = slider.classList.contains('is-initialized') && slider.classList.contains('splide'); 4741 if (typeof window.lpUI.requestScrollLock === 'function') window.lpUI.requestScrollLock(modalId); 4742 else document.body.style.overflow = 'hidden'; 4743 function createSlickLightbox() { 4744 const slickOverlayOptions = { 4745 arrows: true, 4746 dots: false, 4747 infinite: true, 4748 draggable: true, 4749 prevArrow: '<button type="button" class="lp-lightbox-arrow--prev lp-lightbox-arrow" aria-label="Previous"></button>', 4750 nextArrow: '<button type="button" class="lp-lightbox-arrow--next lp-lightbox-arrow" aria-label="Next"></button>' 4751 }; 4752 const modal = document.createElement('div'); 4753 modal.id = modalId; 4754 modal.className = 'lp-lightbox'; 4755 modal.setAttribute('tabindex', '-1'); 4756 modal.setAttribute('role', 'dialog'); 4757 modal.setAttribute('aria-modal', 'true'); 4758 modal.innerHTML = ` 4759 <button class="lp-lightbox__close" aria-label="close modal"></button> 4760 <div class="lp-lightbox__content"> 4761 <div class="lp-lightbox__carousel"></div> 4762 </div> 4763 `; 4764 document.body.appendChild(modal); 4765 const overlaySlider = modal.querySelector('.lp-lightbox__carousel'); 4766 modal.classList.add('show'); 4767 let sourceImages; 4768 if (isSectionSlickInitialized) { 4769 sourceImages = slider.slick.$slides.find('img'); 4770 slickOverlayOptions.initialSlide = slider.slick?.currentSlide || 0; 4771 sourceImages.each(function() { 4772 window.$('.lp-lightbox__carousel').append(window.$(this).clone(false).removeAttr('style').wrap('<div class="lp-lightbox__slide"></div>').parent()); 4773 }); 4774 } else { 4775 sourceImages = slider.querySelectorAll('img');
4776 sourceImages.forEach((img)=>{ 4777 const imgClone = img.cloneNode(true); 4778 imgClone.removeAttribute('style'); 4779 const slide = document.createElement('div'); 4780 slide.className = 'lp-lightbox__slide'; 4781 slide.appendChild(imgClone); 4782 overlaySlider.appendChild(slide); 4783 }); 4784 } 4785 window.$(overlaySlider).slick(slickOverlayOptions); 4786 // Focus modal after it's created 4787 setTimeout(()=>{ 4788 modal.focus(); 4789 }, 100); 4790 // Keyboard navigation handler 4791 const handleKeydown = (e)=>{ 4792 if (!modal.classList.contains('show')) return; 4793 const prevArrow = modal.querySelector('.lp-lightbox-arrow--prev'); 4794 const nextArrow = modal.querySelector('.lp-lightbox-arrow--next'); 4795 const closeBtn = modal.querySelector('.lp-lightbox__close'); 4796 if (e.key === 'ArrowLeft' && prevArrow) { 4797 e.preventDefault(); 4798 prevArrow.click(); 4799 } else if (e.key === 'ArrowRight' && nextArrow) { 4800 e.preventDefault(); 4801 nextArrow.click(); 4802 } else if (e.key === 'Escape' && closeBtn) { 4803 e.preventDefault(); 4804 closeBtn.click(); 4805 } 4806 }; 4807 document.addEventListener('keydown', handleKeydown); 4808 modal.querySelector('.lp-lightbox__close').addEventListener('click', ()=>{ 4809 document.removeEventListener('keydown', handleKeydown); 4810 modal.classList.remove('show'); 4811 const currentSlide = overlaySlider?.slick ? window.$(overlaySlider).slick('slickCurrentSlide') : 0; 4812 if (overlaySlider?.slick) window.$(overlaySlider).slick('unslick'); 4813 if (isSectionSlickInitialized) window.$(slider).slick('slickGoTo', currentSlide); 4814 if (typeof window.lpUI.releaseScrollLock === 'function') window.lpUI.releaseScrollLock(modalId); 4815 else document.body.style.overflow = ''; 4816 modal.remove(); 4817 }); 4818 } 4819 function createSplideLightbox() { 4820 const splideOptions = { 4821 rewind: true, 4822 arrows: true, 4823 arrowPath: '', 4824 type: 'loop', 4825 clones: 1, 4826 pagination: false, 4827 perPage: 1, 4828 perMove: 1 4829 }; 4830 const modal = document.createElement('div'); 4831 modal.id = modalId; 4832 modal.className = 'lp-lightbox'; 4833 modal.setAttribute('tabindex', '-1'); 4834 modal.setAttribute('role', 'dialog'); 4835 modal.setAttribute('aria-modal', 'true'); 4836 modal.innerHTML = ` 4837 <button class="lp-lightbox__close" aria-label="close modal"></button> 4838 <div class="lp-lightbox__content"> 4839 <div class="lp-lightbox__carousel splide" role="group" aria-label="Image Gallery"> 4840 <div class="splide__arrows"> 4841 <button class="splide__arrow splide__arrow--prev lp-lightbox-arrow lp-lightbox-arrow--prev"></button> 4842 <button class="splide__arrow splide__arrow--next lp-lightbox-arrow lp-lightbox-arrow--next"></button> 4843 </div> 4844 <div class="splide__track"> 4845 <ul class="splide__list"></ul> 4846 </div> 4847 </div> 4848 </div> 4849 `; 4850 if (typeof window.lpUI.requestScrollLock === 'function') window.lpUI.requestScrollLock(modalId); 4851 else document.body.style.overflow = 'hidden'; 4852 document.body.appendChild(modal); 4853 const overlaySlider = modal.querySelector('.lp-lightbox__carousel'); 4854 const overlaySliderList = overlaySlider.querySelector('.splide__list'); 4855 modal.classList.add('show'); 4856 let sourceImages; 4857 if (isSectionSplideInitialized) sourceImages = slider.querySelectorAll('.splide__slide:not(.splide__slide--clone) img'); 4858 else sourceImages = slider.querySelectorAll('img');
4859 sourceImages.forEach((img)=>{ 4860 const imgClone = img.cloneNode(true); 4861 imgClone.removeAttribute('style'); 4862 const slide = document.createElement('li'); 4863 slide.className = 'lp-lightbox__slide splide__slide'; 4864 slide.appendChild(imgClone); 4865 overlaySliderList.appendChild(slide); 4866 }); 4867 const overlaySplide = new window.Splide(overlaySlider, splideOptions); 4868 overlaySplide.mount(); 4869 // Navigate to initial index if provided 4870 if (typeof initialIndex !== 'undefined' && initialIndex >= 0) overlaySplide.go(initialIndex); 4871 // Focus modal after it's created and mounted 4872 setTimeout(()=>{ 4873 modal.focus(); 4874 }, 100); 4875 // Keyboard navigation handler 4876 const handleKeydown = (e)=>{ 4877 if (!modal.classList.contains('show')) return; 4878 const prevArrow = modal.querySelector('.splide__arrow--prev'); 4879 const nextArrow = modal.querySelector('.splide__arrow--next'); 4880 const closeBtn = modal.querySelector('.lp-lightbox__close'); 4881 if (e.key === 'ArrowLeft' && prevArrow) { 4882 e.preventDefault(); 4883 prevArrow.click(); 4884 } else if (e.key === 'ArrowRight' && nextArrow) { 4885 e.preventDefault(); 4886 nextArrow.click(); 4887 } else if (e.key === 'Escape' && closeBtn) { 4888 e.preventDefault(); 4889 closeBtn.click(); 4890 } 4891 }; 4892 document.addEventListener('keydown', handleKeydown); 4893 modal.querySelector('.lp-lightbox__close').addEventListener('click', ()=>{ 4894 document.removeEventListener('keydown', handleKeydown); 4895 modal.classList.remove('show'); 4896 if (overlaySplide) overlaySplide.destroy(); 4897 if (typeof window.lpUI.releaseScrollLock === 'function') window.lpUI.releaseScrollLock(modalId); 4898 else document.body.style.overflow = ''; 4899 modal.remove(); 4900 }); 4901 } 4902 if (isSlickAvailable && !isSectionSplideInitialized) createSlickLightbox(); 4903 else if (isSplideAvailable) createSplideLightbox(); 4904 else { 4905 window.luxuryPresence.libs.loadCss(window.luxuryPresence.libs.jsLibsMap.splide.cssSrc); 4906 window.luxuryPresence.libs.loadJs(window.luxuryPresence.libs.jsLibsMap.splide.jsSrc, ()=>{ 4907 createSplideLightbox(); 4908 window.luxuryPresence.libs.jsLibsMap.splide.isLoaded = true; 4909 }); 4910 } 4911 } 4912} 4913 4914 4915/* eslint-disable import/prefer-default-export */ 4916class $4f184d9bd3037f15$export$7a6215890afba974 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 4917 // constructor is not needed as it is inherited from BaseController 4918 /** 4919 * Destroy 4920 */ destroy() { 4921 if (!this.window.divolte) this.window.divolteLp = function() { 4922 (this.window.divolteLp.q = this.window.divolteLp.q || []).push(// eslint-disable-next-line prefer-rest-params 4923 arguments); 4924 }; 4925 } 4926 /** 4927 * Initialize divolte controller 4928 * @param {Object} options 4929 */ initialize(options = {}) { 4930 const { divolteServiceUrl: divolteServiceUrl } = this.config; 4931 if (!divolteServiceUrl || this.window.divolte) return; 4932 this.loadScript(); 4933 } 4934 /** 4935 * loads divolte 4936 */ loadScript() { 4937 const { divolteServiceUrl: divolteServiceUrl } = this.config; 4938 const script = this.document.createElement('script'); 4939 script.id = 'divolte-script'; 4940 script.type = 'text/javascript'; 4941 script.defer = true; 4942 script.async = true; 4943 script.src = `${divolteServiceUrl}/divolte.js`; 4944 this.document.head.appendChild(script); 4945 script.addEventListener('load', this.executeQueue.bind(this)); 4946 } 4947 /** 4948 * executeQueue 4949 */ executeQueue() { 4950 (this.window.divolteLp.q || []).forEach(([methodName, params])=>{ 4951 this[methodName](params); 4952 }); 4953 this.window.divolteLp = this.divolteLp.bind(this); 4954 } 4955 /** 4956 * divolteLp 4957 * @param {string} name 4958 * @param {Object} params 4959 */ divolteLp(name, params) { 4960 try { 4961 this[name](params); 4962 } catch (error) { 4963 // eslint-disable-next-line no-console 4964 console.log(error); 4965 } 4966 } 4967 /** 4968 * sendLpEvent 4969 * @param {string} name 4970 * @param {Object} params 4971 */ sendLpEvent(name, params) { 4972 // Events must be defined in divolte schema! To ensure correct usage, event names are validated here. 4973 if (!name.includes('pageView')) { 4974 // Event not defined 4975 // eslint-disable-next-line no-console 4976 console.log(`${name} IS NOT SUPPORTED`); 4977 return; 4978 } 4979 const { companyId: companyId, templateId: templateId, websiteId: websiteId, pageId: pageId, shareId: shareId, pageMeta: pageMeta } = this.config; 4980 const baseParams = { 4981 companyId: companyId, 4982 templateId: templateId, 4983 websiteId: websiteId, 4984 pageId: pageId, 4985 shareId: shareId, 4986 pageMeta: pageMeta 4987 }; 4988 this.window.divolte.signal(name, Object.assign(baseParams, params)); 4989 } 4990 /** 4991 * sendLpPageView 4992 */ sendLpPageView() { 4993 this.sendLpEvent('pageView', {}); 4994 } 4995} 4996 4997 4998/* eslint-disable import/prefer-default-export */ 4999const $102039871668a1df$var$EVENT_BUS_SCRIPT = 'event-bus-js.js'; 5000const $102039871668a1df$var$EVENT_BUS_VERSION = 'v2.8.0'; 5001const $102039871668a1df$var$EVENT_BUS_DEFAULT_SOURCE = 'frontend://website-render-engine'; 5002class $102039871668a1df$export$e22e4b1be0bb6c61 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 5003 // eslint-disable-next-line @typescript-eslint/no-useless-constructor 5004 constructor(config, window, document){ 5005 super(config, window, document); 5006 } 5007 /** 5008 * Initialize EventBus controller 5009 * @param {Object} options 5010 */ initialize(options = {}) { 5011 const enabled = options.enabled !== undefined ? options.enabled : this.config.eventBus?.enabled; 5012 if (enabled && this.config.eventBus?.apiKey && this.config.eventBus?.url) this.loadScript(); 5013 } 5014 /** 5015 * loads eventBus script 5016 */ loadScript() { 5017 const { eventBusUrl: eventBusUrl } = this.config; 5018 const script = this.document.createElement('script'); 5019 script.id = 'posthog-script'; 5020 script.type = 'text/javascript'; 5021 script.defer = true; 5022 script.async = true; 5023 script.src = `${eventBusUrl}/${$102039871668a1df$var$EVENT_BUS_VERSION}/${$102039871668a1df$var$EVENT_BUS_SCRIPT}`; 5024 this.document.head.appendChild(script); 5025 script.addEventListener('load', this.executeQueue.bind(this)); 5026 } 5027 /** 5028 * executeQueue - Process queued eventBusLp calls 5029 */ executeQueue() { 5030 // Initialize the event bus provider using the global EventBusJS 5031 if (this.window.LuxuryPresenceEventBus) this.window.eventBusProvider = this.window.LuxuryPresenceEventBus.createEventBusProvider({ 5032 apiKey: this.config.eventBus.apiKey, 5033 host: this.config.eventBus.url, 5034 defaultSource: $102039871668a1df$var$EVENT_BUS_DEFAULT_SOURCE 5035 });
5036 (this.window.eventBusLp.q || []).forEach(([methodName, params])=>{ 5037 this[methodName](params); 5038 }); 5039 // Replace queue function with real function 5040 this.window.eventBusLp = this.eventBusLp.bind(this); 5041 } 5042 /** 5043 * Destroy 5044 */ destroy() { 5045 if (!this.window.eventBusProvider) { 5046 // Reset to queue function if no provider exists 5047 this.window.eventBusLp = function() { 5048 (this.window.eventBusLp.q = this.window.eventBusLp.q || []).push(// eslint-disable-next-line prefer-rest-params 5049 arguments); 5050 }; 5051 return; 5052 } 5053 this.window.eventBusProvider.shutdown(); 5054 } 5055 /** 5056 * sendLpEvent 5057 * @param {string} eventType 5058 * @param {Object} data 5059 */ sendLpEvent(eventType, data) { 5060 // Events must be defined in event-bus schema! To ensure correct usage, event types are validated here. 5061 if (eventType !== 'user.activity.page.viewed') { 5062 // Event type not defined 5063 // eslint-disable-next-line no-console 5064 console.log(`${eventType} IS NOT SUPPORTED`); 5065 return; 5066 } 5067 if (!this.window.eventBusProvider) return; 5068 const { companyId: companyId } = this.config; 5069 const eventData = { 5070 company: companyId, 5071 data: {} 5072 }; 5073 try { 5074 this.window.eventBusProvider.capture(eventType, eventData); 5075 } catch (error) { 5076 // eslint-disable-next-line no-console 5077 console.log('EventBus capture error:', error); 5078 } 5079 } 5080 /** 5081 * eventBusLp 5082 * @param {string} name 5083 * @param {Object} params 5084 */ eventBusLp(name, params) { 5085 try { 5086 this[name](params); 5087 } catch (error) { 5088 // eslint-disable-next-line no-console 5089 console.log(error); 5090 } 5091 } 5092 /** 5093 * sendLpPageView 5094 */ sendLpPageView() { 5095 this.sendLpEvent('user.activity.page.viewed', {}); 5096 } 5097} 5098 5099 5100/* eslint-disable import/prefer-default-export */ 5101 5102const $0d25a3fa2e0f4f92$var$EVENT_NAME = 'oauthSuccess'; 5103class $0d25a3fa2e0f4f92$export$b718a981691eae5c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 5104 /** 5105 * Initialize Button Controller at build time 5106 * @param { ConfigController } config 5107 * @param {Window} window 5108 * @param {Document} document 5109 */ constructor(config, window, document){ 5110 super(config, window, document); 5111 this.successListeners = []; 5112 this._listenToMessages = this._listenToMessages.bind(this); 5113 this._listenToOneTapMessage = this._listenToOneTapMessage.bind(this); 5114 } 5115 /** 5116 * Initialize OAuth Controller at run time 5117 * Swap out special buttons for the iframe 5118 * @param {Object} options 5119 */ initialize(options = {}) { 5120 try { 5121 // handle google one tap 5122 if (options.googleSignOnEnabled && !options.iframe) this._renderGoogleOneTap(); 5123 // handle google sign in buttons 5124 this.document.querySelectorAll('div[data-signin-type="google-sign-in"]').forEach((el)=>this._convertGoogleSignIn(el)); 5125 // handle facebook sign in buttons 5126 this.document.querySelectorAll('div[data-signin-type="facebook-sign-in"]').forEach((el)=>this._convertFacebookSignIn(el)); 5127 } catch (e) { 5128 // eslint-disable-next-line no-console 5129 console.log(e); 5130 } 5131 } 5132 /** 5133 * Controllers must implement a "destroy" method to be called 5134 * after page navigation to remove event handlers / cleanup 5135 */ destroy() { 5136 this.successListeners.forEach((callback)=>{ 5137 this.window.removeEventListener('message', this._listenToMessages); 5138 this.window.removeEventListener('message', this._listenToOneTapMessage); 5139 this.window.removeEventListener($0d25a3fa2e0f4f92$var$EVENT_NAME, this.window[callback]); 5140 }); 5141 } 5142 /** 5143 * Convert google one tap 5144 */ _renderGoogleOneTap() { 5145 if (!this._isGoogleOneTapOnCooldown()) { 5146 const dummyEl = this.document.createElement('div'); 5147 // eslint-disable-next-line no-undef 5148 google.accounts.id.initializeIntermediate({ 5149 src: this._buildUrlAndCopyAttributes(dummyEl, dummyEl, 'googleOneTap') 5150 }); 5151 this.window.localStorage.removeItem('googleOneTapExpiration'); 5152 this.window.addEventListener('message', this._listenToOneTapMessage); 5153 } 5154 } 5155 /** 5156 * Listening for messages from BSS one tap iframes 5157 * @param {MessageEvent} e 5158 */ _listenToOneTapMessage(e) { 5159 const messageTypes = { 5160 SHOW_INTERMEDIATE_IFRAME: 'show_intermediate_iframe', 5161 HIDE_INTERMEDIATE_IFRAME: 'hide_intermediate_iframe' 5162 };
5163 const iframeId = 'onetap_google_intermediate_iframe'; 5164 const { buyerSellerServiceUrl: buyerSellerServiceUrl } = this.config; 5165 const { data: data, origin: origin } = e; 5166 const { type: type, height: height, event: event, source: source, token: token } = data; 5167 if (type === messageTypes.SHOW_INTERMEDIATE_IFRAME || type === messageTypes.HIDE_INTERMEDIATE_IFRAME) { 5168 const bssIframe = this.document.getElementById(iframeId); 5169 if (bssIframe) { 5170 bssIframe.style.height = height; 5171 bssIframe.style.display = type === messageTypes.SHOW_INTERMEDIATE_IFRAME ? 'unset' : 'none'; 5172 } 5173 } 5174 // these events are generated by our code in the bss iframe 5175 if (origin === buyerSellerServiceUrl && source === 'GOOGLE_SIGN_ON') { 5176 if (event === 'success') { 5177 this._setExpirationLsItem(86400000); // 24 hours 5178 this._handleQualifyingQuestionsModal(token); 5179 } else if (event === 'cancel') this._setExpirationLsItem(7200000); // 2 hours 5180 } 5181 } 5182 /** 5183 * Set expiration local storage item for google one tap 5184 * @param {number} ms 5185 */ _setExpirationLsItem(ms) { 5186 const expiration = new Date().getTime() + ms; 5187 this.window.localStorage.setItem('googleOneTapExpiration', expiration); 5188 } 5189 /** 5190 * Check if google one tap is expired 5191 * @return {boolean} 5192 */ _isGoogleOneTapOnCooldown() { 5193 const expirationTime = this.window.localStorage.getItem('googleOneTapExpiration'); 5194 return Number(expirationTime) > new Date().getTime(); 5195 } 5196 /** 5197 * Convert google sign in buttons 5198 * @param {HTMLElement} el 5199 */ _convertGoogleSignIn(el) { 5200 this._replaceWithIframe('googleSignIn', el); 5201 } 5202 /** 5203 * Convert google sign in buttons 5204 * @param {HTMLElement} el 5205 */ _convertFacebookSignIn(el) { 5206 this._replaceWithIframe('facebookSignIn', el); 5207 } 5208 /** 5209 * Convert google sign in buttons 5210 * @param {'googleSignIn' | 'facebookSignIn'} provider 5211 * @param {HTMLElement} el 5212 */ _replaceWithIframe(provider, el) { 5213 this._attachSuccessCallback(el); 5214 const iframe = this.document.createElement('iframe'); 5215 iframe.src = this._buildUrlAndCopyAttributes(el, iframe, provider); 5216 iframe.dataset.isSocialOauthButton = true; 5217 el.replaceWith(iframe); 5218 } 5219 /** 5220 * Listening for messages from BSS iframes 5221 * @param {Event} e 5222 */ _listenToMessages(e) { 5223 const { buyerSellerServiceUrl: buyerSellerServiceUrl } = this.config; 5224 // eslint-disable-next-line sonarjs/no-collapsible-if 5225 if (e.origin === buyerSellerServiceUrl) { 5226 if (e.data.event === 'success') { 5227 const event = new Event($0d25a3fa2e0f4f92$var$EVENT_NAME); 5228 this.window.dispatchEvent(event); 5229 // Registration / social sign-in is a lead event â credit the conversion. 5230 (0, $3ec2bf3965f87ecc$export$e70565180c0e6950)(this.window, this.document); 5231 this.successListeners.forEach((callback)=>{ 5232 if (this.window[callback]) this.window[callback](event); 5233 else // eslint-disable-next-line no-console 5234 console.error(`Callback function ${callback} not found on window object`); 5235 }); 5236 this.document.documentElement.classList.add('is-login-success'); 5237 } 5238 } 5239 } 5240 /** 5241 * Attach callback to iframe 5242 * @param {HTMLElement} el 5243 */ _attachSuccessCallback(el) { 5244 this.window.addEventListener('message', this._listenToMessages); 5245 const callbackFunction = el.dataset.onSuccessFunctionName; 5246 if (callbackFunction) this.successListeners.push(callbackFunction); 5247 } 5248 /** 5249 * Build Iframe URL 5250 * @param {HTMLElement} source 5251 * @param {HTMLElement} target 5252 * @param {string} provider 5253 * @return {string} 5254 */ _buildUrlAndCopyAttributes(source, target, provider) { 5255 const { buyerSellerServiceUrl: buyerSellerServiceUrl, companyId: companyId, websiteId: websiteId, pageId: pageId, pageMeta: pageMeta } = this.config; 5256 const { location: location } = this.window; 5257 const sourceUrl = location.origin + location.pathname; 5258 const destination = new URL(`${buyerSellerServiceUrl}/buttons/${provider}`); 5259 const utm = this.window.localStorage.getItem('utm_vars'); 5260 const referrer = this.window.localStorage.getItem('referrer'); 5261 destination.searchParams.append('companyId', companyId); 5262 destination.searchParams.append('websiteId', websiteId); 5263 destination.searchParams.append('pageId', pageId); 5264 destination.searchParams.append('sourceUrl', sourceUrl); 5265 destination.searchParams.append('pageMeta', JSON.stringify(pageMeta)); 5266 if (utm) destination.searchParams.append('utm', utm); 5267 if (referrer) destination.searchParams.append('referrer', referrer); 5268 // Google and Facebook Attributes used to style the social button 5269 const RESERVED_ATTRIBUTES = [ 5270 'data-size', 5271 'data-width', 5272 'data-text', 5273 'data-button-type', 5274 'data-shape', 5275 'data-layout', 5276 'data-max-rows', 5277 'data-use-continue-as', 5278 'data-type', 5279 'data-theme', 5280 'data-logo_alignment', 5281 'data-locale' 5282 ];
5283 Array.from(source.attributes).forEach((attribute)=>{ 5284 if (RESERVED_ATTRIBUTES.includes(attribute.nodeName)) destination.searchParams.append(attribute.nodeName, attribute.nodeValue); 5285 else target.setAttribute(attribute.nodeName === 'id' ? 'data-id' : attribute.nodeName, attribute.nodeValue); 5286 }); 5287 return destination.toString(); 5288 } 5289 /** 5290 * Decode a JWT token to extract payload information 5291 * @param {string} token - The JWT token to decode 5292 * @return {Object|null} The decoded payload object or null if decoding fails 5293 */ _decodeToken(token) { 5294 try { 5295 const parts = token.split('.'); 5296 const payload = parts[1]; 5297 const base64 = payload.replace(/-/g, '+').replace(/_/g, '/'); 5298 const padding = 4 - base64.length % 4; 5299 const padded = padding === 4 ? base64 : base64 + '='.repeat(padding); 5300 return JSON.parse(atob(padded)); 5301 } catch (error) { 5302 return null; 5303 } 5304 } 5305 /** 5306 * Handle qualifying questions modal showing for Google Sign On 5307 * Decodes the JWT token to extract user email and shows the modal if available 5308 * @param {string} token - The JWT token containing user information 5309 */ _handleQualifyingQuestionsModal(token) { 5310 if (token && this.window.luxuryPresence && this.window.luxuryPresence.qualifyingQuestionsModal) { 5311 // Decoding only for lead attribution, fine to skip signature verification 5312 const decoded = this._decodeToken(token); 5313 if (decoded && decoded.email) this.window.luxuryPresence.qualifyingQuestionsModal.showModal(decoded.email, 'Google Sign On'); 5314 } 5315 } 5316} 5317 5318 5319/* eslint-disable import/prefer-default-export */ 5320class $dcf72769f009ff26$export$b900d6fe921fd49c extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 5321 /** 5322 * Initialize Qualifying Questions Modal Controller at build time 5323 * @param { ConfigController } config 5324 * @param {Window} window 5325 * @param {Document} document 5326 */ constructor(config, window, document){ 5327 super(config, window, document); 5328 this.showModal = this.showModal.bind(this); 5329 this.hasModalBeenSubmitted = this.hasModalBeenSubmitted.bind(this); 5330 this.modalId = 'qualifying-questions-modal'; 5331 this.cookieKey = 'qualifyingQuestionsModalSubmitted'; 5332 this.qualifyingQuestionsModalEnabled = true; 5333 // Store references for cleanup 5334 this.eventListeners = []; 5335 this.timeouts = []; 5336 } 5337 initialize(options = {}) { 5338 this.qualifyingQuestionsModalEnabled = options.qualifyingQuestionsModalEnabled ?? this.qualifyingQuestionsModalEnabled; 5339 if (!this.qualifyingQuestionsModalEnabled) return; 5340 this.attachModalCloseListeners(); 5341 } 5342 destroy() { 5343 // Remove all stored event listeners 5344 this.eventListeners.forEach(({ element: element, event: event, handler: handler })=>{ 5345 if (element && element.removeEventListener) element.removeEventListener(event, handler); 5346 }); 5347 this.timeouts.forEach((timeoutId)=>{ 5348 clearTimeout(timeoutId); 5349 }); 5350 this.restoreBodyScroll(); 5351 this.eventListeners = []; 5352 this.timeouts = []; 5353 } 5354 /** 5355 * Check if modal has been submitted using cookie-based deduplication 5356 * @return {boolean} 5357 */ hasModalBeenSubmitted() { 5358 const cookieValue = this.getCookie(this.cookieKey); 5359 return cookieValue === 'true'; 5360 } 5361 /** 5362 * Set cookie to prevent modal from showing again 5363 */ setModalSubmittedCookie() { 5364 this.setCookie(this.cookieKey, 'true', 365); // 1 year 5365 } 5366 showModal(email, triggerSource) { 5367 if (!this.qualifyingQuestionsModalEnabled || this.hasModalBeenSubmitted()) return; 5368 this.updateEmailValue(email); 5369 this.updateTriggerSourceValue(triggerSource); 5370 this.showModalElement(); 5371 } 5372 /** 5373 * Get modal element with error handling 5374 * @return {Element|null} 5375 */ getModalElement() { 5376 const modal = this.document.getElementById(this.modalId); 5377 if (!modal) console.error('Modal element not found:', this.modalId); 5378 return modal; 5379 } 5380 updateEmailValue(email) { 5381 const modal = this.getModalElement(); 5382 if (!modal) return; 5383 const emailInput = modal.querySelector('input[name="email"]'); 5384 if (emailInput && typeof email === 'string') emailInput.value = email; 5385 } 5386 updateTriggerSourceValue(triggerSource) { 5387 const modal = this.getModalElement(); 5388 if (!modal) return;
5389 const triggerSourceInput = modal.querySelector(`#${this.modalId}-triggerSource`); 5390 if (triggerSourceInput && typeof triggerSource === 'string') triggerSourceInput.value = triggerSource; 5391 } 5392 showModalElement() { 5393 const modal = this.getModalElement(); 5394 if (!modal) return; 5395 modal.style.display = 'flex'; 5396 this.blockBodyScroll(); 5397 } 5398 /** 5399 * Helper method to get cookie value 5400 * @param {string} name 5401 * @return {string|null} 5402 */ getCookie(name) { 5403 const value = `; ${this.document.cookie}`; 5404 const parts = value.split(`; ${name}=`); 5405 if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift()); 5406 return null; 5407 } 5408 /** 5409 * Helper method to set cookie 5410 * @param {string} name 5411 * @param {string} value 5412 * @param {number} days 5413 */ setCookie(name, value, days) { 5414 let expires = ''; 5415 if (days) { 5416 const date = new Date(); 5417 date.setTime(date.getTime() + days * 86400000); 5418 expires = `; expires=${date.toUTCString()}`; 5419 } 5420 let attrs = '; path=/; SameSite=Lax'; 5421 if (this.window && this.window.location && this.window.location.protocol === 'https:') attrs += '; Secure'; 5422 this.document.cookie = `${name}=${encodeURIComponent(value || '')}${expires}${attrs}`; 5423 } 5424 blockBodyScroll() { 5425 this._prevOverflow = this.document.body.style.overflow; 5426 this.document.body.style.overflow = 'hidden'; 5427 } 5428 restoreBodyScroll() { 5429 this.document.body.style.overflow = this._prevOverflow || ''; 5430 this._prevOverflow = null; 5431 } 5432 attachModalCloseListeners() { 5433 const modal = this.getModalElement(); 5434 if (!modal) return; 5435 // Listen for form submission success (when modal closes automatically) 5436 const form = this.document.getElementById(`${this.modalId}-form`); 5437 if (form) { 5438 const formSubmittedHandler = ()=>{ 5439 // Set cookie to prevent showing again and hide modal 5440 this.setModalSubmittedCookie(); 5441 const timeoutId = setTimeout(()=>{ 5442 modal.style.display = 'none'; 5443 this.restoreBodyScroll(); 5444 }, 100); 5445 this.timeouts.push(timeoutId); 5446 }; 5447 form.addEventListener('formsubmitted', formSubmittedHandler); 5448 this.eventListeners.push({ 5449 element: form, 5450 event: 'formsubmitted', 5451 handler: formSubmittedHandler 5452 }); 5453 } 5454 // Listen for close button clicks 5455 const closeButton = modal.querySelector('[data-dismiss="modal"]'); 5456 if (closeButton) { 5457 const closeButtonHandler = ()=>{ 5458 modal.style.display = 'none'; 5459 this.restoreBodyScroll(); 5460 }; 5461 closeButton.addEventListener('click', closeButtonHandler); 5462 this.eventListeners.push({ 5463 element: closeButton, 5464 event: 'click', 5465 handler: closeButtonHandler 5466 }); 5467 } 5468 // Listen for backdrop clicks 5469 const backdropClickHandler = (e)=>{ 5470 // Check if click is on the modal backdrop (not on the modal content) 5471 if (e.target === modal || e.target.id === this.modalId) { 5472 modal.style.display = 'none'; 5473 this.restoreBodyScroll(); 5474 } 5475 }; 5476 modal.addEventListener('click', backdropClickHandler); 5477 this.eventListeners.push({ 5478 element: modal, 5479 event: 'click', 5480 handler: backdropClickHandler 5481 }); 5482 } 5483} 5484 5485 5486/* eslint-disable import/prefer-default-export */ 5487class $50eefeef8d1f2372$export$8a2bf06fbae4dde extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 5488 constructor(configController, window, document){ 5489 super(configController, window, document); 5490 this.isValidating = false; 5491 this.lastValidationResult = null; 5492 this.lastValidationTime = null; 5493 this.validationCacheDuration = 300000; // 5 minutes 5494 } 5495 /** 5496 * Destroy 5497 */ destroy() { 5498 this.isValidating = false;
5499 this.lastValidationResult = null; 5500 this.lastValidationTime = null; 5501 } 5502 /** 5503 * Validate user session using GraphQL validSession query 5504 * @param {Object} options - Options for session validation 5505 * @param {boolean} options.useCache - Whether to use cached validation result 5506 * @returns {Promise<boolean>} - true if session is valid, false otherwise 5507 */ async validateSession(options = {}) { 5508 const { useCache: useCache = true } = options; 5509 if (useCache && this.lastValidationResult !== null && this.lastValidationTime) { 5510 const timeSinceLastValidation = Date.now() - this.lastValidationTime; 5511 if (timeSinceLastValidation < this.validationCacheDuration) return this.lastValidationResult; 5512 } 5513 if (this.isValidating) return this.lastValidationResult !== null ? this.lastValidationResult : false; 5514 this.isValidating = true; 5515 const query = ` 5516 query { 5517 validSession { 5518 success 5519 } 5520 } 5521 `; 5522 try { 5523 // query from same domain as the website 5524 const response = await this.window.fetch(`/graphql`, { 5525 method: 'POST', 5526 headers: { 5527 'Content-Type': 'application/json' 5528 }, 5529 credentials: 'include', 5530 body: JSON.stringify({ 5531 query: query 5532 }) 5533 }); 5534 if (!response.ok) { 5535 // eslint-disable-next-line no-console 5536 console.error('SessionController: HTTP error during session validation', response.status); 5537 this.lastValidationResult = false;
5538 this.lastValidationTime = Date.now(); 5539 return false; 5540 } 5541 const data = await response.json(); 5542 if (data.errors) { 5543 this.lastValidationResult = false; 5544 this.lastValidationTime = Date.now(); 5545 return false; 5546 } 5547 const isValid = data.data?.validSession?.success === true; 5548 this.lastValidationResult = isValid; 5549 this.lastValidationTime = Date.now(); 5550 return isValid; 5551 } catch (error) { 5552 // eslint-disable-next-line no-console 5553 console.error('SessionController: Error validating session', error); 5554 this.lastValidationResult = false; 5555 this.lastValidationTime = Date.now(); 5556 return false; 5557 } finally{ 5558 this.isValidating = false; 5559 } 5560 } 5561 /** 5562 * Clear validation cache 5563 */ clearCache() { 5564 this.lastValidationResult = null; 5565 this.lastValidationTime = null; 5566 } 5567} 5568 5569 5570/* eslint-disable import/prefer-default-export */ 5571function $396d9f0ca7465335$export$48d5542b9e3ba39(document) { 5572 const match = document.cookie.match(/cookieyes-consent=([^;]+)/); 5573 if (!match) return false; 5574 try { 5575 const cookieValue = decodeURIComponent(match[1]); 5576 if (cookieValue.includes(',')) { 5577 const segments = cookieValue.split(',').map((c)=>c.trim()); 5578 if (segments.some((s)=>s.includes(':'))) return segments.some((s)=>s === 'analytics:yes'); 5579 return segments.includes('analytics'); 5580 } 5581 return cookieValue.includes('analytics'); 5582 } catch (error) { 5583 return false; 5584 } 5585} 5586/** 5587 * Consent providers. Each entry isolates the only things that differ between 5588 * integrations: the change-event name, how to read the *initial* analytics 5589 * consent, and how to interpret a change event's detail. Everything else 5590 * (loading/removing trackers, lifecycle) is shared by the controller. 5591 */ const $396d9f0ca7465335$var$PROVIDERS = { 5592 // Third-party CookieYes banner. 5593 cookieyes: { 5594 eventName: 'cookieyes_consent_update', 5595 hasAnalyticsConsent: (document)=>$396d9f0ca7465335$export$48d5542b9e3ba39(document), 5596 isAnalyticsAccepted: (detail)=>Array.isArray(detail?.accepted) && detail.accepted.includes('analytics') 5597 }, 5598 // LP in-house consent widget (lp-consent-widget). It exposes resolved state on 5599 // window.__lpConsent and emits `lp_consent_update` with detail.choices. 5600 'lp-consent': { 5601 eventName: 'lp_consent_update', 5602 hasAnalyticsConsent: (_document, window)=>!!window.__lpConsent?.state?.c?.analytics, 5603 isAnalyticsAccepted: (detail)=>!!detail?.choices?.analytics 5604 } 5605}; 5606class $396d9f0ca7465335$export$bb018224876724b9 extends (0, $7c391e2f7931d60d$export$3b5bd9381a52554c) { 5607 constructor(config, window, document){ 5608 super(config, window, document); 5609 this.consentListener = null; 5610 this.eventName = null; 5611 } 5612 /** 5613 * Destroy and cleanup event listeners 5614 */ destroy() { 5615 if (this.consentListener && this.eventName) { 5616 this.document.removeEventListener(this.eventName, this.consentListener); 5617 this.consentListener = null; 5618 } 5619 } 5620 /** 5621 * Load PostHog and Divolte scripts (idempotent â guarded by element id). 5622 */ loadScript() { 5623 if (!this.document.getElementById('posthog-script')) this.window.luxuryPresence.eventBus.initialize({ 5624 enabled: this.config.eventBus?.enabled 5625 }); 5626 if (!this.document.getElementById('divolte-script')) this.window.luxuryPresence.divolte.initialize({}); 5627 } 5628 /** 5629 * Remove PostHog and Divolte scripts (used on consent withdrawal). 5630 */ removeScripts() { 5631 this.window.luxuryPresence?.eventBus?.destroy?.(); 5632 this.window.luxuryPresence?.divolte?.destroy?.(); 5633 this.document.getElementById('posthog-script')?.remove(); 5634 this.document.getElementById('divolte-script')?.remove(); 5635 } 5636 /** 5637 * Initialize the consent controller for a given provider. 5638 * @param {{ provider: 'cookieyes' | 'lp-consent' }} options 5639 */ async initialize(options = {}) { 5640 const provider = $396d9f0ca7465335$var$PROVIDERS[options.provider]; 5641 if (!provider) return; 5642 this.eventName = provider.eventName; 5643 const isAuthenticated = await this.window.luxuryPresence.session.validateSession(); 5644 if (provider.hasAnalyticsConsent(this.document, this.window) || isAuthenticated) this.loadScript(); 5645 if (!this.consentListener) { 5646 this.consentListener = (eventData)=>{ 5647 if (provider.isAnalyticsAccepted(eventData.detail)) this.loadScript(); 5648 else this.removeScripts(); 5649 }; 5650 this.document.addEventListener(provider.eventName, this.consentListener); 5651 } 5652 } 5653} 5654 5655 5656/* global window */ /* eslint-disable import/prefer-default-export */ /** 5657 * Checks if the current site should redirect homeowner valuation submissions to HST. 5658 * Returns true and performs the redirect if all three gate conditions are met. 5659 * Returns false if the redirect did not fire (caller should continue with existing flow). 5660 * 5661 * @param {string} address - The human-readable address string from the form 5662 * @returns {boolean} 5663 */ function $0ae243a777665fd3$var$checkHstRedirect(address) { 5664 const { config: config } = window.luxuryPresence; 5665 if (config.hstValuationRedirectEnabled && config.mlsEnabled && config.myhomeDashboardEnabled) { 5666 window.location.href = `/home-search/home-valuation?address=${encodeURIComponent(address)}`; 5667 return true; 5668 } 5669 return false;
5670} 5671const $0ae243a777665fd3$export$4225ff17959c7313 = { 5672 checkHstRedirect: $0ae243a777665fd3$var$checkHstRedirect, 5673 destroy () {} 5674}; 5675 5676 5677const $fa0280e505379701$export$1fd2b467a3644d37 = new (0, $dc851cf3939b6ef5$export$ff0712c26d5458f7)({}); 5678const $fa0280e505379701$export$e12694e911a05f40 = new (0, $0ead03fdb95fa9ce$export$d507f25e63650365)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5679const $fa0280e505379701$export$3de614e59a842917 = new (0, $d48f9f944810f613$export$ca3218b7861b9cb0)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5680const $fa0280e505379701$export$fb9b298fdbf31455 = new (0, $68a2d4aa500c7a05$export$61ec8f2b6291ec31)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5681const $fa0280e505379701$export$178cc3119b453c2a = new (0, $e10bd00497be8876$export$3c5380623cf51249)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5682const $fa0280e505379701$export$9376af1a01686f2 = new (0, $ea6901fdf47e0ec1$export$3c19195edca3fa5c)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5683const $fa0280e505379701$export$94d36f806562393e = new (0, $0a0ad49f13c0b8fd$export$ba9afeb75f20f616)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5684const $fa0280e505379701$export$89e66d1faf94651e = new (0, $2b1790aa32f109d1$export$43e435c053a109f6)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5685const $fa0280e505379701$export$7743b07270cd6d6c = new (0, $4f184d9bd3037f15$export$7a6215890afba974)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5686const $fa0280e505379701$export$40a7039551318c37 = new (0, $102039871668a1df$export$e22e4b1be0bb6c61)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5687const $fa0280e505379701$export$8a0bbf7e7652fcfc = new (0, $0d25a3fa2e0f4f92$export$b718a981691eae5c)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5688const $fa0280e505379701$export$b313b3f6544c97a3 = new (0, $dcf72769f009ff26$export$b900d6fe921fd49c)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5689const $fa0280e505379701$export$b526bc4ac03268ef = new (0, $50eefeef8d1f2372$export$8a2bf06fbae4dde)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5690const $fa0280e505379701$export$c0affdb0a7a2ef6 = new (0, $396d9f0ca7465335$export$bb018224876724b9)($fa0280e505379701$export$1fd2b467a3644d37, window, document); 5691 5692 5693/** 5694 * Attach controller to window for usage 5695 * @param {string} key 5696 * @param {any} controller 5697 */ function $89a8a84b77163415$var$attachController(key, controller) { 5698 if (window.luxuryPresence[key]) try { 5699 // New version of sdk, destroy previous 5700 window.luxuryPresence[key].destroy(); 5701 } catch (e) { 5702 // eslint-disable-next-line no-console 5703 console.log(e); 5704 } 5705 window.luxuryPresence[key] = controller; 5706} 5707$89a8a84b77163415$var$attachController('config', (0, $fa0280e505379701$export$1fd2b467a3644d37)); 5708$89a8a84b77163415$var$attachController('modals', (0, $fa0280e505379701$export$e12694e911a05f40)); 5709$89a8a84b77163415$var$attachController('buttons', (0, $fa0280e505379701$export$3de614e59a842917)); 5710$89a8a84b77163415$var$attachController('validation', (0, $fa0280e505379701$export$fb9b298fdbf31455)); 5711$89a8a84b77163415$var$attachController('contactForms', (0, $fa0280e505379701$export$178cc3119b453c2a)); 5712$89a8a84b77163415$var$attachController('mapApiLoader', (0, $fa0280e505379701$export$9376af1a01686f2)); 5713$89a8a84b77163415$var$attachController('pagination', (0, $fa0280e505379701$export$94d36f806562393e)); 5714$89a8a84b77163415$var$attachController('expandSliders', (0, $fa0280e505379701$export$89e66d1faf94651e)); 5715$89a8a84b77163415$var$attachController('divolte', (0, $fa0280e505379701$export$7743b07270cd6d6c)); 5716$89a8a84b77163415$var$attachController('eventBus', (0, $fa0280e505379701$export$40a7039551318c37)); 5717$89a8a84b77163415$var$attachController('oauth', (0, $fa0280e505379701$export$8a0bbf7e7652fcfc)); 5718$89a8a84b77163415$var$attachController('qualifyingQuestionsModal', (0, $fa0280e505379701$export$b313b3f6544c97a3)); 5719$89a8a84b77163415$var$attachController('session', (0, $fa0280e505379701$export$b526bc4ac03268ef)); 5720$89a8a84b77163415$var$attachController('consent', (0, $fa0280e505379701$export$c0affdb0a7a2ef6)); 5721$89a8a84b77163415$var$attachController('redirects', (0, $0ae243a777665fd3$export$4225ff17959c7313)); 5722// methods for existing elements (can be removed later after elements updated) 5723window.luxuryPresence.formatSliderPriceRange = (0, $fa0280e505379701$export$94d36f806562393e).formatSliderPriceRange.bind((0, $fa0280e505379701$export$94d36f806562393e)); 5724window.luxuryPresence.formatSliderAreaRange = (0, $fa0280e505379701$export$94d36f806562393e).formatSliderAreaRange.bind((0, $fa0280e505379701$export$94d36f806562393e)); 5725// method below doesn't use 'this', but just to be safe in case of further method updates 5726window.luxuryPresence.getSearchFormValues = (0, $fa0280e505379701$export$94d36f806562393e).getSearchFormValues.bind((0, $fa0280e505379701$export$94d36f806562393e)); 5727window.luxuryPresence.handlebarsHelpersFactory = function(handlebarsInstance) { 5728 return (0, (/*@__PURE__*/$parcel$interopDefault($53de3c160faf5a81$exports
5728)))(handlebarsInstance, { 5729 isEqual (a, b) { 5730 // eslint-disable-next-line 5731 return a == b; 5732 } 5733 }); 5734}; 5735 5736 5737 5738})(); 5739//# sourceMappingURL=lp-sdk.js.map 5740 5741 </script>
5741 5742 5743
5743<script> 5744 var lpGlobalInitialized = false; 5745 5746 function lpGlobalInit () { 5747 if (lpGlobalInitialized) { 5748 return; 5749 } 5750 lpGlobalInitialized = true; 5751 // Initialize wow animation plugin only according to turbolinks 5752 var wow; 5753 if (window.WOW) { 5754 wow = new WOW({ 5755 animateClass: 'animated', 5756 offset: wowOffset, 5757 live: false, 5758 callback: function(box) {} 5759 }); 5760 } 5761 // Initialize handlebar helpers only once 5762 function handlebarsInit() { 5763 if (!window.Handlebars) { 5764 return; 5765 } 5766 HandlebarsIntl.registerWith(Handlebars); 5767 Handlebars.registerHelper(window.luxuryPresence.handlebarsHelpersFactory(Handlebars)); 5768 } 5769 5770 handlebarsInit(); 5771 5772 var modalContentUrl = "/modals.html"; 5773 const modalsContainer = document.getElementById('modals'); 5774 if (modalsContainer) { 5775 fetch(modalContentUrl).then(function(res) { 5776 if (!res.ok) { 5777 throw new Error(`HTTP error! Status: ${res.status}`); 5778 } 5779 return res.text(); 5780 }).then(function(resultText) { 5781 modalsContainer.innerHTML = resultText; 5782 5783 // now we need to execute all script elements 5784 Array.from(modalsContainer.getElementsByTagName('script')).forEach(function (s) { 5785 const script = document.createElement("script"); 5786 script.text = s.innerHTML; 5787 Array.from(s.attributes).forEach(function (a) { 5788 script.setAttribute(a.name, a.value); 5789 }) 5790 s.parentNode.replaceChild(script, s); 5791 }); 5792 5793 try { 5794 window.luxuryPresence.modals.initialize(window.luxuryPresence._modalIncludes); 5795 window.luxuryPresence.contactForms.initialize({ selector: '#modals' }); 5796 window.luxuryPresence.validation.initialize({ selector: '#modals' }); 5797 window.luxuryPresence.oauth.initialize({ 5798 googleSignOnEnabled: true, 5799 iframe: false }); 5800 } catch (e) { 5801 console.log(e); 5802 } 5803 document.querySelectorAll('.modals > .modal .close').forEach(closeModalBtn => { 5804 closeModalBtn.addEventListener('click', function() { 5805 window.lpUI.hideClosestModal(closeModalBtn); 5806 }); 5807 }); 5808 }).catch((e) => console.log(e)); 5809 } 5810 /* Initialize Luxury Presence SDK */ 5811 try { 5812 window.luxuryPresence.config.setCompany("7638a4cd-9580-4d1f-a8a5-ac3b4943a953", {}); 5813 window.luxuryPresence.config.setWebsite("6dd48137-4176-40e9-8267-8bd0f0be23f4", { 5814 myhomeDashboardEnabled: true, 5815 mlsEnabled: true, 5816 hstValuationRedirectEnabled: true 5817 }); 5818 const url = new URL(window.location.href); 5819 const shareId = url.searchParams.get('shareId'); 5820 window.luxuryPresence.config.setPage("c78da963-7d87-4284-b5c6-6a98bc449d9f", { 5821 sourceResource: "", 5822 pageElementId: "", 5823 pageQueryVariables: {}, 5824 shareId: "", 5825 }); 5826 window.luxuryPresence.config.setWebsiteApiGatewayUrl("https://wgw.luxurypresence.com", {}); 5827 window.luxuryPresence.config.setBuyerSellerServiceUrl("https://bss.luxurypresence.com", {}); 5828 window.luxuryPresence.config.setDivolteServiceUrl("https://t.luxurypresence.com", {}); 5829 window.luxuryPresence.config.setEventBusUrl("https://cdn.luxurypresence.com/scripts/event-bus-js", {}); 5830 window.luxuryPresence.config.setEventBus({ 5831 enabled: true, 5832 apiKey: "phc_PMYT31xlmXBaTCwpIRx1v6RrpLVZIuP47N3mOT6KLnr", 5833 url: "https://p.luxurypresence.com", 5834 }); 5835 window.luxuryPresence.config.setTemplateId("0c2b9641-6f2a-40f2-a2e0-dabc022eb278", {}); 5836 window.luxuryPresence.config.setLeadIngesterUrl("https://leads.luxurypresence.com", {}); 5837 window.luxuryPresence.buttons.initialize({}); 5838 window.luxuryPresence.eventBus.initialize({}); 5839 window.luxuryPresence.contactForms.initialize({}); 5840 window.luxuryPresence.validation.initialize({}); 5841 window.luxuryPresence.expandSliders.initialize({}); 5842 window.luxuryPresence.oauth.initialize({ googleSignOnEnabled: true, iframe: false }); 5843 window.luxuryPresence.qualifyingQuestionsModal.initialize({ qualifyingQuestionsModalEnabled: true }); 5844 window.luxuryPresence.divolte.initialize({}); 5845 } catch (e) { 5846 console.log(e); 5847 } 5848 5849 /* Inject Section Specific Javascript */ 5850 try { 5851(function init(sectionDomId) { 5852 const disclaimerLabel = document.querySelector('#' + sectionDomId + ' .lp-tcr-content'); 5853 if (disclaimerLabel) { 5854 const input = disclaimerLabel.querySelector('input'); 5855 if (input) { 5856 input.setAttribute('id', `${sectionDomId}-termsAccepted`); 5857 input.value = 'true'; 5858 const label = document.createElement('label'); 5859 label.setAttribute('for', `${sectionDomId}-termsAccepted`); 5860 label.classList.add('lp-visually-hidden'); 5861 label.textContent = 'Opt in/Disclaimer Consent:'; 5862 disclaimerLabel.prepend(label); 5863 } 5864 } 5865 function setHttp(link) { 5866 if (link.search(/^http[s]?\:\/\/|\//) == -1) { 5867 link = 'https://' + link; 5868 } 5869 return link; 5870 } 5871 const socialLinks = document.querySelectorAll('#' + sectionDomId + ' .socials__link, #' + sectionDomId + ' .lp-socials__link'); 5872 socialLinks.forEach(linkElement => { 5873 const href = linkElement.getAttribute('href'); 5874 if (href) { 5875 linkElement.setAttribute('href', setHttp(href)); 5876 } 5877 }); 5878 const redirectLink = $('#' + sectionDomId + ' .redirect-link'); 5879 if (redirectLink.length) { 5880 const rawHref = setHttp(redirectLink.attr('href')); 5881 let formEvent; 5882 if (rawHref) { 5883 formEvent = redirectLink.data('redirect') ? 'formsubmitted' : 'reset'; 5884 $('#' + sectionDomId + ' .contact-form').find('form').on(formEvent, function () { 5885 redirectLink.attr('href', rawHref); 5886 redirectLink[0].click(); 5887 }); 5888 } 5889 } 5890})('modal-global-contact-us'); 5891} catch(e) { 5892console.log(e); 5893} 5894 5895 try { 5896(function init(sectionDomId) { 5897 const $section = $('#' + sectionDomId); 5898 const $hamburger = $section.find('.hamburger-component'); 5899 function onSideMenuShow() { 5900 if (!$hamburger.hasClass('active')) { 5901 $hamburger.addClass('active'); 5902 } 5903 } 5904 function onSideMenuHide() { 5905 $hamburger.removeClass('active'); 5906 } 5907 const $window = $(window); 5908 $window.on('lpui-sidemenu-show.lpui-auto-clean', onSideMenuShow); 5909 $window.on('lpui-sidemenu-hide.lpui-auto-clean', onSideMenuHide); 5910 const $subContainers = $section.find('.navigation__item.sub-nav-container'); 5911 $subContainers.hover(function () { 5912 $(this).find('.sub-nav').addClass('visible'); 5913 }, function () { 5914 $(this).find('.sub-nav').removeClass('visible'); 5915 }); 5916 $window.on('click.lpui-auto-clean', function () { 5917 $('.sub-nav-container.visible-dropdown').removeClass('visible-dropdown'); 5918 }); 5919 let fixedWidth = 0; 5920 const rightPad = 20; 5921 function fixSubsPosition() { 5922 const wWidth = window.innerWidth; 5923 if (innerWidth === fixedWidth) { 5924 return; 5925 } 5926 fixedWidth = wWidth; 5927 $subContainers.each(function () { 5928 const $sub = $(this).find('.sub-nav'); 5929 $sub[0].style.right = '';
5930 const sRect = $sub[0].getBoundingClientRect(); 5931 const sRight = sRect.left + sRect.width; 5932 if (sRight > wWidth - rightPad) { 5933 const parentRect = $sub[0].offsetParent.getBoundingClientRect(); 5934 const parentRight = parentRect.left + parentRect.width; 5935 $sub[0].style.right = `${parentRight - wWidth + rightPad}px`; 5936 } 5937 }); 5938 } 5939 var debouncer; 5940 $window.on('resize.lpui-auto-clean', function () { 5941 clearTimeout(debouncer); 5942 debouncer = setTimeout(fixSubsPosition, 500); 5943 }); 5944 fixSubsPosition(); 5945 if ($('.property-intro').length || $('.property-intro-2').length) { 5946 $('nav').addClass('dark-opening'); 5947 $("#global-navbar").css({ 5948 "background-color": "rgb(26, 26, 26)", 5949 "color": "rgb(255, 255, 255)" 5950 }); 5951 } 5952 function initAutoTruncateMenu() { 5953 const $navbar = $section.find('.navbar'); 5954 const $navList = $section.find('.navigation > ul'); 5955 if (!$navbar.length || !$navList.length) { 5956 return; 5957 } 5958 const $logo = $section.find('.logo'); 5959 const $buttonsWrapper = $section.find('.buttons-wrapper'); 5960 const $allItems = $navList.children('.navigation__item'); 5961 const $phoneItem = $allItems.filter(function () { 5962 return $(this).find('a[href^="tel:"]').length > 0; 5963 }); 5964 const $menuItems = $allItems.not($phoneItem); 5965 if (!$menuItems.length) { 5966 return; 5967 } 5968 const buffer = 8; 5969 function measureFixedWidth() { 5970 let width = buffer; 5971 if ($logo.length) { 5972 width += $logo.outerWidth(true) || 0; 5973 } 5974 if ($buttonsWrapper.length) { 5975 width += $buttonsWrapper.outerWidth(true) || 0; 5976 } 5977 if ($phoneItem.length) { 5978 width += $phoneItem.outerWidth(true) || 0; 5979 } 5980 return width; 5981 } 5982 function truncateMenu() { 5983 if (!$navList.is(':visible')) { 5984 return; 5985 } 5986 $menuItems.css('display', ''); 5987 const availableWidth = $navbar[0].getBoundingClientRect().width - measureFixedWidth(); 5988 let widthSoFar = 0; 5989 let overflowed = false; 5990 $menuItems.each(function () { 5991 const $item = $(this); 5992 if (overflowed) { 5993 $item.css('display', 'none'); 5994 return; 5995 } 5996 widthSoFar += $item.outerWidth(true); 5997 if (widthSoFar > availableWidth) { 5998 $item.css('display', 'none'); 5999 overflowed = true; 6000 } 6001 }); 6002 } 6003 let truncateFrame; 6004 function scheduleTruncate() { 6005 if (truncateFrame) { 6006 return; 6007 } 6008 truncateFrame = window.requestAnimationFrame(function () { 6009 truncateFrame = null; 6010 truncateMenu(); 6011 }); 6012 } 6013 scheduleTruncate(); 6014 if (window.ResizeObserver) { 6015 const resizeObserver = new ResizeObserver(scheduleTruncate); 6016 resizeObserver.observe($navbar[0]); 6017 } else { 6018 $(window).on('resize.lpui-auto-truncate', scheduleTruncate); 6019 } 6020 $section.find('img').on('load.lpui-auto-truncate', scheduleTruncate); 6021 $(window).on('load.lpui-auto-truncate', scheduleTruncate); 6022 if (document.fonts && document.fonts.ready) { 6023 document.fonts.ready.then(scheduleTruncate); 6024 } 6025 } 6026 initAutoTruncateMenu(); 6027})('global-navbar'); 6028} catch(e) { 6029console.log(e); 6030} 6031 try { 6032(function init(sectionDomId, options) { 6033 var elementSelector = options.elementSelector || 'nav'; 6034 var element = document.querySelector(elementSelector); 6035 var sections = document.querySelectorAll('body > section'); 6036 var subNavContainers = element.querySelectorAll('.sub-nav'); 6037 var initialBackgroundColor = options.initialBackgroundColor || element.style.backgroundColor; 6038 var backgroundColorScroll = options.backgroundColorScroll || '#191919'; 6039 var fontColor = options.fontColor || '#fff'; 6040 var fontColorScroll = options.fontColorScroll || '#000'; 6041 var didScroll = false; 6042 var lastScrollTop = 0; 6043 var delta = 5; 6044 6045 // eslint-disable-next-line sonarjs/no-collapsible-if 6046 if (wow) { 6047 // Wowjs might not trigger for position fixed elements 6048 if (window.scrollY > 0) { 6049 element.querySelectorAll('.wow').forEach(el => wow.show(el)); 6050 } 6051 } 6052 function adjustNavPinState() { 6053 // Remove 'visible' class from all subNavContainers 6054 for (let i = 0; i < subNavContainers.length; i++) { 6055 subNavContainers[i].classList.remove('visible'); 6056 } 6057 if (window.scrollY > 0) { 6058 element.style.backgroundColor = backgroundColorScroll; 6059 element.style.color = fontColorScroll; 6060 element.classList.add('scroll'); 6061 } else {
6062 element.style.backgroundColor = initialBackgroundColor; 6063 element.style.color = fontColor; 6064 element.classList.remove('scroll'); 6065 } 6066 } 6067 adjustNavPinState(); 6068 function onScroll() { 6069 didScroll = true; 6070 } 6071 window.addEventListener('scroll', onScroll); 6072 6073 // eslint-disable-next-line 6074 var debounceInterval = setInterval(() => { 6075 if (didScroll) { 6076 // eslint-disable-next-line 6077 hasScrolled(); 6078 didScroll = false; 6079 } 6080 }, 250); 6081 function hasScrolled() { 6082 adjustNavPinState(); 6083 // eslint-disable-next-line 6084 var navbarHeight = element.offsetHeight; 6085 // eslint-disable-next-line 6086 var st = window.scrollY; 6087 6088 // Make sure they scroll more than delta 6089 if (Math.abs(lastScrollTop - st) <= delta) { 6090 return; 6091 } 6092 if (st > lastScrollTop && st > navbarHeight) { 6093 // Scroll Down 6094 element.style.transform = `translateY(-${navbarHeight}px) scaleY(0)`; 6095 document.documentElement.style.setProperty('--global-header-height', '0px'); 6096 6097 // Some sections "follow" the navbar with class sticky (i.e. Producer search) 6098 sections.forEach(section => { 6099 if (section.classList.contains('sticky')) { 6100 section.style.top = '0px'; 6101 } 6102 }); 6103 } else { 6104 // Scroll Up 6105 // eslint-disable-next-line 6106 if (st + window.innerHeight < document.documentElement.scrollHeight) { 6107 element.style.transform = `translateY(0) scaleY(1)`; 6108 document.documentElement.style.setProperty('--global-header-height', `${navbarHeight}px`); 6109 sections.forEach(section => { 6110 if (section.classList.contains('sticky')) { 6111 section.style.top = `${navbarHeight}px`; 6112 } 6113 }); 6114 } 6115 } 6116 lastScrollTop = st; 6117 } 6118})('NAVBAR', JSON.parse("{\"fontColor\":\"#fff\",\"elementSelector\":\"nav\",\"fontColorScroll\":\"#fff\",\"initialFontColor\":\"#fff\",\"backgroundColorScroll\":\"#1a1a1a\",\"initialBackgroundColor\":\"rgba(0,0,0,0)\"}")); 6119} catch(e) { 6120console.log(e); 6121} 6122 try { 6123(function init(sectionDomId) { 6124 var sidemenu = $('#' + sectionDomId); 6125 sidemenu.on('lpui-sidemenu-show.lpui-auto-clean', function () { 6126 window.lpUI.requestScrollLock(sectionDomId); 6127 }); 6128 $(window).on('lpui-sidemenu-hide.lpui-auto-clean', function () { 6129 window.lpUI.releaseScrollLock(sectionDomId); 6130 }); 6131 $(window).click(function (e) { 6132 let targetContactForm = $(e.target).closest('#modal-global-contact-us').length; 6133 let targetSideMenu = $(e.target).closest('.sidemenu').length; 6134 let targetContactItem = $(e.target).closest('[data-type="CONTACT_US"]').length; 6135 let targetHamburger = $(e.target).closest('.hamburger-component').length; 6136 if (!(targetContactForm || targetSideMenu || targetContactItem || targetHamburger)) { 6137 $('body').removeClass('locked'); 6138 $('.hamburger').removeClass('active'); 6139 $('.sidemenu').removeClass('visible'); 6140 $('#modal-global-contact-us').removeClass('visible'); 6141 } 6142 }); 6143})('global-sidemenu'); 6144} catch(e) { 6145console.log(e); 6146} 6147 6148 try { 6149(function init(footerId) { 6150 var textContent = $(".text_content_wrap p").text().trim().length; 6151 const socialLinks = $(`#${footerId} .lp-socials__link`); 6152 if (textContent < 1) { 6153 $(".text_content_wrap").remove(); 6154 $(".second_text_footer").css({ 6155 'margin-bottom': 0 6156 }); 6157 } 6158 if (socialLinks.length > 0) { 6159 socialLinks.attr('data-wow-offset', '10'); 6160 } 6161 if ($(window).width() > 1280) { 6162 let footer = document.querySelector("#" + footerId); 6163 let copyrightElem = footer.querySelector(".copy_zone"); 6164 if (copyrightElem) { 6165 copyrightElem.style.whiteSpace = "nowrap"; 6166 let nowrapElemWidth = copyrightElem.clientWidth; 6167 copyrightElem.style.whiteSpace = ""; 6168 let normalElemWidth = copyrightElem.clientWidth; 6169 if (nowrapElemWidth > normalElemWidth) { 6170 footer.querySelector(".form-col--socials").classList.add("form-col--xl-auto"); 6171 } 6172 } 6173 } 6174 const form = $("#" + footerId).find("form"); 6175 const redirectLink = $('#' + footerId + ' .redirect-link'); 6176 form.on("reset", function () { 6177 redirectPage(redirectLink); 6178 }); 6179 function redirectPage(link) { 6180 if (link.length) { 6181 const rawHref = link.attr('href'); 6182 link.attr('href', setHttp(rawHref)); 6183 link[0].click(); 6184 } 6185 } 6186 function setHttp(link) { 6187 if (link.search(/^http[s]?\:\/\/|\//) == -1) { 6188 link = 'http://' + link; 6189 } 6190 return link; 6191 } 6192})('global-footer'); 6193} catch(e) { 6194console.log(e); 6195} 6196 6197 try { 6198(function init(sectionDomId) { 6199 var _section = $('#' + sectionDomId); 6200 var _footer = document.getElementById('global-footer'); 6201 const redirectLink = _section.find('.js-redirect-link'); 6202 function setHttp(link) { 6203 if (link.search(/^(http[s]?\:\/\/|\/)/) == -1) { 6204 link = 'https://' + link; 6205 } 6206 return link; 6207 } 6208 function redirectPage(link) { 6209 if (link.length) { 6210 window.location.href = setHttp(link.attr('href')); 6211 } 6212 } 6213 const emailInput = _section.find('.js-email-input'); 6214 const emailRegex = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~\-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+/; 6215 emailInput.on('input', function () { 6216 if (emailRegex.test(this.value)) { 6217 this.setCustomValidity(''); 6218 } else { 6219 this.setCustomValidity('Please enter a valid email address.'); 6220 } 6221 this.reportValidity(); 6222 }); 6223 _section.find('input[name="name"]').on("keyup", function () { 6224 if (this.value.replaceAll(/\d/g, "").trim().split(" ").length < 2 || this.value.replaceAll(/\d/g, "").trim() === "") { 6225 this.setCustomValidity("Please input your first name and last name."); 6226 } else { 6227 this.setCustomValidity(""); 6228 } 6229 }); 6230 _section.find('form').on("reset", function () { 6231 $(this).addClass("show-success"); 6232 redirectPage(redirectLink); 6233 }); 6234 $(window).scroll(function () { 6235 if ($(this).scrollTop() >= 150) _section.find('.btn-holder').addClass('visible');else _section.find('.btn-holder').removeClass('visible'); 6236 }); 6237 _section.find('.close-btn, .connect-btn').click(function () { 6238 _section.find('.pop-up').toggle(); 6239 _section.find('.btn-holder').toggle(); 6240 }); 6241 if (!_footer) return; 6242 const observer = new IntersectionObserver(entries => {
6243 entries.forEach(entry => { 6244 if (entry.isIntersecting) _section.hide();else _section.show(); 6245 }); 6246 }, { 6247 threshold: 0.1 6248 }); 6249 observer.observe(_footer); 6250 function selectToDropdown(selectItem) { 6251 let customDropdown = ` 6252 <div class="custom-select" role="presentation"> 6253 <button class="custom-select-toggle is-placeholder" type="button" aria-haspopup="true" aria-expanded="false"></button> 6254 <div class="custom-select-menu" style="display: none;max-height: none;"> 6255 <div class="custom-select-content"> 6256 </div> 6257 </div> 6258 </div>`; 6259 $(customDropdown).insertAfter(selectItem); 6260 let $dropdown = $($(selectItem).next()); 6261 let $dropdownToggle = $dropdown.find(".custom-select-toggle"); 6262 let $dropdownMenu = $dropdown.find(".custom-select-menu"); 6263 let $dropdownContent = $dropdown.find(".custom-select-content"); 6264 $dropdownToggle.addClass($(selectItem).attr("class")).removeClass("dropdown-select"); 6265 $dropdownToggle.attr("id", $(selectItem).attr("id") + "custom"); 6266 $dropdownMenu.attr("aria-labelledby", $dropdownToggle.attr("id")); 6267 appendOptionButtons(selectItem, $dropdownContent); 6268 $(selectItem).removeClass().addClass("sr-only"); 6269 var toggleText = $(selectItem).find(":selected").first().text() || $(selectItem).children().first().text(); 6270 $dropdownToggle.html(toggleText); 6271 $dropdown.on("click", ".custom-select-item", function (e) { 6272 if ($(this).hasClass("is-disabled")) return; 6273 let elementNumber = $(this).index(); 6274 let $originalSelect = $(this).closest(".custom-select").siblings("select"); 6275 let $linkedOption = $originalSelect.find("option").eq(elementNumber); 6276 if (!$linkedOption.prop("selected")) { 6277 $linkedOption.prop("selected", true); 6278 $originalSelect.change(); 6279 $(this).addClass("is-selected").siblings(".custom-select-item").removeClass("is-selected"); 6280 $dropdownToggle.html($(this).html()); 6281 closeSelectMenu($(this).closest(".custom-select-menu")); 6282 } 6283 $dropdownToggle.removeClass("is-placeholder"); 6284 }); 6285 function convertOptionToButton(option) { 6286 var optionText = $(option).text(); 6287 var optionValue = $(option).attr("value") || $(option).text(); 6288 var optionIsDisabled = $(option).prop("disabled"); 6289 var outputButton = `<button value="${optionValue}" class="custom-select-item" type="button" ${optionIsDisabled ? "disabled" : ""}>${optionText}</button>`; 6290 return outputButton; 6291 } 6292 function appendOptionButtons(selectItem, appendTarget) { 6293 $(selectItem).find("option").each(function () { 6294 let currentButton = convertOptionToButton(this); 6295 $(appendTarget).append(currentButton); 6296 }); 6297 } 6298 function showSelectMenu(selectMenu) { 6299 var customSelect = $(selectMenu).closest(".custom-select")[0]; 6300 $(customSelect).addClass("open"); 6301 $(selectMenu).slideDown(); 6302 } 6303 function closeSelectMenu(selectMenu) { 6304 var customSelect = $(selectMenu).closest(".custom-select")[0]; 6305 $(customSelect).removeClass("open"); 6306 $(selectMenu).slideUp(); 6307 } 6308 $dropdown.on("click", ".custom-select-toggle", function (e) { 6309 var $customSelect = $(this).closest(".custom-select"); 6310 var selectMenu = $customSelect.find(".custom-select-menu")[0]; 6311 if ($customSelect.hasClass("open")) { 6312 closeSelectMenu(selectMenu); 6313 } else { 6314 showSelectMenu(selectMenu); 6315 } 6316 }); 6317 $(document).on("click", function (e) { 6318 if ($(e.target).closest(".custom-select").length < 1 && $(".custom-select").hasClass("open")) { 6319 $(".custom-select.open").each(function () { 6320 var selectMenu = $(this).find(".custom-select-menu")[0]; 6321 closeSelectMenu(selectMenu); 6322 }); 6323 } 6324 }); 6325 } 6326 $(".pop-up select[name='interest']").each(function () { 6327 selectToDropdown(this); 6328 }); 6329})('global-mobile-contact'); 6330} catch(e) { 6331console.log(e); 6332} 6333 6334 try { 6335(function init(sectionDomId) { 6336 const $section = $('#' + sectionDomId); 6337 const $form = $section.find('.custom-form__download-form'); 6338 const redirectLink = $section.find('.js-redirect-link'); 6339 function redirectPage(link) { 6340 if (link.length) { 6341 const rawHref = link.attr('href'); 6342 link.attr('href', setHttp(rawHref)); 6343 link[0].click(); 6344 } 6345 } 6346 function setHttp(link) { 6347 if (link.search(/^http[s]?\:\/\/|\//) == -1) { 6348 link = 'https://' + link; 6349 } 6350 return link; 6351 } 6352 $form.on('reset', function () { 6353 redirectPage(redirectLink); 6354 }); 6355 var backupEmailField = $section.find('.js-backup-email'); 6356 if (backupEmailField) { 6357 var dynEmailField = $section.find('input.js-form-element[name="email"]:not(.js-backup-field)'); 6358 if (dynEmailField.length === 0) { 6359 backupEmailField.removeClass('js-backup-email'); 6360 } else { 6361 backupEmailField.remove(); 6362 } 6363 } 6364 var $allElements = $section.find('.js-form-element'); 6365 const putAllInMessage = false;
6366 var hasCustomFields = false; 6367 const standardFields = { 6368 'name': true, 6369 'email': true, 6370 'phone': true, 6371 'message': true, 6372 'interest': true 6373 }; 6374 const busyFormNames = { 6375 'address': true, 6376 'city': true, 6377 'state': true, 6378 'postalCode': true, 6379 'mlsId': true, 6380 'sourceUrl': true 6381 }; 6382 $allElements.each(function () { 6383 var $el = $(this); 6384 var name = this.hasAttribute('data-name') ? $el.attr('data-name') : $el.attr('name'); 6385 if (!name) { 6386 return; 6387 } 6388 if (!standardFields[name]) { 6389 hasCustomFields = true; 6390 } 6391 let newName = /[^a-z\d-_]/.test(name) ? name.trim().toLowerCase().replace(/[^a-z\d-_]/g, '-') : name; 6392 if (!/^[a-z]/.test(newName)) { 6393 newName = 'fld-' + newName; 6394 } 6395 if (busyFormNames[newName]) { 6396 let idx = 1; 6397 while (busyFormNames[`${newName}-${idx}`] && idx < 100) { 6398 idx++; 6399 } 6400 newName = `${newName}-${idx}`; 6401 } 6402 busyFormNames[newName] = $el; 6403 if (name !== newName) { 6404 $el.attr('name', newName); 6405 } 6406 }); 6407 let $customFields = []; 6408 if (putAllInMessage && hasCustomFields) { 6409 $allElements.each(function () { 6410 var name = this.getAttribute('name'); 6411 if (name && (!standardFields[name] || name === 'message' && !$(this).hasClass('js-composed-message'))) { 6412 this.setAttribute('data-name', name); 6413 this.removeAttribute('name'); 6414 } 6415 if (this.hasAttribute('data-name')) { 6416 $customFields.push($(this)); 6417 } 6418 }); 6419 if (!$form[0].elements['message']) { 6420 $('<input type="hidden" name="message" class="js-composed-message" value="">').appendTo($form); 6421 } 6422 } 6423 $selects = $section.find('select.js-select'); 6424 var $checkboxGroups = $section.find('.js-checkboxes-group'); 6425 if ($checkboxGroups.length) { 6426 $checkboxGroups.each(function () { 6427 var $group = $(this); 6428 if (!$group.data('required')) return; 6429 var $checkboxes = $group.find('.js-multi-checkbox'); 6430 function updateValidity() { 6431 var anyChecked = $group.find('.js-multi-checkbox:checked').length > 0; 6432 $checkboxes.each(function () { 6433 this.setCustomValidity(anyChecked ? '' : 'Please select at least one option.'); 6434 }); 6435 } 6436 updateValidity(); 6437 $checkboxes.on('change', updateValidity); 6438 }); 6439 $form.on('submit', function () { 6440 $checkboxGroups.each(function () { 6441 var $group = $(this); 6442 var name = $group.data('name'); 6443 if (!name) return; 6444 var checked = $group.find('.js-multi-checkbox:checked').map(function () { 6445 return this.value; 6446 }).get().join(', '); 6447 $form.find('input[type="hidden"][data-checkbox-group="' + name + '"]').remove(); 6448 $('<input type="hidden">').attr('name', name).val(checked).attr('data-checkbox-group', name).appendTo($form); 6449 var $groupCheckboxes = $group.find('.js-multi-checkbox'); 6450 $groupCheckboxes.prop('disabled', true); 6451 setTimeout(function () { 6452 $groupCheckboxes.prop('disabled', false); 6453 }, 0); 6454 }); 6455 }); 6456 } 6457 let selectsInitialized = false; 6458 function initializeSelects() { 6459 if (selectsInitialized) { 6460 return; 6461 } 6462 selectsInitialized = true; 6463 $selects.each(function () { 6464 if (this.id) { 6465 $label = $section.find('[for="' + this.id + '"]'); 6466 if ($label.length) { 6467 var rect = $label[0].getBoundingClientRect(); 6468 if (rect && rect.width < 30) { 6469 var firstOption = $(this).find('option').first(); 6470 firstOption.attr('label', firstOption.data('label')); 6471 } 6472 } 6473 $gr = $(this).closest('.lp-input-group'); 6474 var b = $gr.css('border-left-width'); 6475 if (b && b !== '0px') { 6476 $gr[0].style.setProperty('--uf-border-left', b); 6477 } 6478 b = $gr.css('border-right-width'); 6479 if (b && b !== '0px') { 6480 $gr[0].style.setProperty('--uf-border-right', b); 6481 } 6482 } 6483 }); 6484 var csPrefix = 'uf-cus-sel'; 6485 function convertSelectToDropdown(selectItem) { 6486 const $selectItem = $(selectItem); 6487 const selectId = $selectItem.attr('id'); 6488 const id = $selectItem.attr('id') + '-custom-select'; 6489 let $dropdown = $selectItem.next(); 6490 let initialized = true; 6491 if ($dropdown.attr('id') !== id) { 6492 $selectItem.addClass("sr-only"); 6493 initialized = false;
6494 let customDropdown = ` 6495 <div class="${csPrefix}" role="presentation"> 6496 <button class="${csPrefix}-toggle" type="button" aria-haspopup="true" aria-expanded="false"></button> 6497 <div class="${csPrefix}-menu"> 6498 <div class="${csPrefix}-content"> 6499 </div> 6500 </div> 6501 </div>`; 6502 $(customDropdown).insertAfter(selectItem); 6503 $dropdown = $selectItem.next(); 6504 $dropdown.attr('id', id); 6505 } 6506 let $dropdownToggle = $dropdown.find('.' + csPrefix + '-toggle'); 6507 let $dropdownMenu = $dropdown.find('.' + csPrefix + '-menu'); 6508 let $dropdownContent = $dropdown.find('.' + csPrefix + '-content'); 6509 if (!initialized) { 6510 $dropdownToggle.addClass($selectItem.attr("class")).removeClass(['dropdown-select', 'js-select', 'js-form-element', 'sr-only']); 6511 $dropdownToggle.attr("id", id + '-toggle'); 6512 $dropdownMenu.attr("aria-labelledby", $dropdownToggle.attr("id")); 6513 appendOptionButtons(selectItem, $dropdownContent); 6514 } 6515 $selectItem.on("focus", function () { 6516 showSelectMenu($dropdownMenu[0]); 6517 $dropdownToggle.focus(); 6518 }); 6519 function setInitialValue() { 6520 $dropdownMenu.find('.' + csPrefix + '-item').removeClass('is-selected'); 6521 var $selectedOption = $selectItem.find(':selected').first(); 6522 if (!$selectedOption.length) { 6523 $selectedOption = $selectItem.children().first(); 6524 } 6525 var defaultText = ' '; 6526 var isPlaceholder = true; 6527 if ($selectedOption.length) { 6528 defaultText = ($selectedOption[0].hasAttribute('label') ? $selectedOption.attr('label') : $selectedOption.text()) || ' '; 6529 isPlaceholder = !!$selectedOption.prop("disabled"); 6530 } 6531 $dropdownToggle.html(defaultText); 6532 if (isPlaceholder) { 6533 $dropdownToggle.addClass('is-placeholder'); 6534 } 6535 } 6536 setInitialValue(); 6537 $dropdown.on("click", '.' + csPrefix + '-item', function (e) { 6538 const $button = $(this); 6539 if ($button.hasClass("is-disabled")) return; 6540 let elementNumber = $button.index(); 6541 let $linkedOption = $selectItem.find("option").eq(elementNumber); 6542 if (!$linkedOption.prop("selected")) { 6543 $linkedOption.prop("selected", true); 6544 $selectItem.change(); 6545 $button.addClass("is-selected").siblings('.' + csPrefix + '-item').removeClass("is-selected"); 6546 $dropdownToggle.removeClass("is-placeholder").html($button.html()); 6547 closeSelectMenu($button.closest('.' + csPrefix + '-menu')); 6548 } 6549 }); 6550 $(selectItem.form).on('reset', function () { 6551 setTimeout(function () { 6552 setInitialValue(); 6553 }); 6554 }); 6555 function convertOptionToButton(option) { 6556 const $option = $(option); 6557 var optionText = $option.text(); 6558 var optionValue = $option.attr("value"); 6559 var optionIsDisabled = $option.prop("disabled"); 6560 var outputButton = `<button value="${optionValue}" class="${csPrefix}-item" type="button" ${optionIsDisabled ? "disabled" : ""}>${optionText}</button>`; 6561 return outputButton; 6562 } 6563 function appendOptionButtons(selectItem, appendTarget) { 6564 const $appendTarget = $(appendTarget); 6565 $(selectItem).find("option").each(function () { 6566 let currentButton = convertOptionToButton(this); 6567 $appendTarget.append(currentButton); 6568 }); 6569 } 6570 function showSelectMenu(selectMenu) { 6571 var $customSelect = $(selectMenu).closest('.' + csPrefix); 6572 $customSelect.addClass("open"); 6573 $(selectMenu).slideDown(); 6574 } 6575 function closeSelectMenu(selectMenu) { 6576 var $customSelect = $(selectMenu).closest('.' + csPrefix); 6577 $customSelect.removeClass("open"); 6578 $(selectMenu).slideUp(); 6579 } 6580 $dropdown.on("click", '.' + csPrefix + '-toggle', function (e) { 6581 var $customSelect = $(this).closest('.' + csPrefix); 6582 var selectMenu = $customSelect.find('.' + csPrefix + '-menu')[0]; 6583 if ($customSelect.hasClass("open")) { 6584 closeSelectMenu(selectMenu); 6585 } else { 6586 showSelectMenu(selectMenu); 6587 } 6588 }); 6589 $(document.body).on("click", function (e) { 6590 var $closestCustomSelect = $(e.target).closest('.lp-input-group').find('.' + csPrefix); 6591 $section.find('.' + csPrefix + '.open').not($closestCustomSelect).each(function () { 6592 closeSelectMenu($(this).find('.' + csPrefix + '-menu')[0]); 6593 }); 6594 }); 6595 } 6596 $selects.each(function () { 6597 convertSelectToDropdown(this); 6598 }); 6599 if (putAllInMessage && hasCustomFields) { 6600 $allElements.on('change', function () { 6601 if (!this.hasAttribute('data-name')) { 6602 return; 6603 } 6604 var message = ''; 6605 var customMessages = []; 6606 $customFields.forEach(function ($el) { 6607 var value = $el.val(); 6608 if (!value) { 6609 return; 6610 } 6611 if ($el.attr('data-name') === 'message') { 6612 message = value; 6613 return; 6614 } 6615 var label = $section.find(`label[for='${$el[0].id}']`).text(); 6616 customMessages.push(label + ': ' + ($el[0].tagName === 'TEXTAREA' ? '\n' : '') + value); 6617 }); 6618 if (customMessages.length) { 6619 if (message) { 6620 customMessages.push('Message: \n' + message); 6621 } 6622 $form[0].elements['message'].value = customMessages.join('\n'); 6623 } else { 6624 $form[0].elements['message'].value = message; 6625 } 6626 }); 6627 } 6628 } 6629 function initModalColors() { 6630 try { 6631 if (!$section.css('--bgColor')) { 6632 var colorStr = $section.css('background-color'); 6633 var bgColor = makeColor(colorStr); 6634 var isDark = (bgColor.rgba.r * 299 + bgColor.rgba.g * 587 + bgColor.rgba.b * 114) / 1000 < 128; 6635 $section[0].style.setProperty('--bgColor', colorStr); 6636 $section[0].style.setProperty('--bgColor_H', bgColor.hsla.h + 'deg'); 6637 $section[0].style.setProperty('--bgColor_S', bgColor.hsla.s + '%'); 6638 $section[0].style.setProperty('--bgColor_L', bgColor.hsla.l + '%'); 6639 $section[0].style.setProperty('--bgColor_A', bgColor.hsla.a); 6640 $section[0].style.setProperty('--bgColor_darkenDir', isDark ? 1 : -1); 6641 $section.addClass('is-background-color-' + (isDark ? 'dark' : 'light')); 6642 } 6643 } catch (e) {} 6644 } 6645 function makeColor(str) { 6646 var color = { 6647 rgba: { 6648 r: 0, 6649 g: 0, 6650 b: 0, 6651 a: 0 6652 } 6653 }; 6654 if (str && str.match) { 6655 var m = str.match(/rgba?\s*\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\.0-9]+))?\)/); 6656 if (m) { 6657 color.rgba.r = parseInt(m[1]); 6658 color.rgba.g = parseInt(m[2]); 6659 color.rgba.b = parseInt(m[3]); 6660 color.rgba.a = parseFloat(m[4]); 6661 if (isNaN(color.rgba.a)) { 6662 color.rgba.a = 1; 6663 } 6664 } 6665 } 6666 color.hsla = makeHSLA(color.rgba); 6667 return color; 6668 } 6669 function makeHSLA(rgba) { 6670 var r = rgba.r / 255, 6671 g = rgba.g / 255, 6672 b = rgba.b / 255, 6673 a = rgba.a; 6674 var min = Math.min(r, g, b), 6675 max = Math.max(r, g, b), 6676 l = (max + min) / 2, 6677 d = max - min, 6678 h, 6679 s; 6680 switch (max) { 6681 case min: 6682 h = 0; 6683 break; 6684 case r: 6685 h = 60 * (g - b) / d; 6686 break; 6687 case g: 6688 h = 60 * (b - r) / d + 120; 6689 break; 6690 case b: 6691 h = 60 * (r - g) / d + 240; 6692 break; 6693 } 6694 if (max == min) { 6695 s = 0; 6696 } else if (l < .5) { 6697 s = d / (2 * l); 6698 } else { 6699 s = d / (2 - 2 * l); 6700 } 6701 s *= 100; 6702 l *= 100; 6703 return { 6704 h: h, 6705 s: s, 6706 l: l, 6707 a: a 6708 }; 6709 } 6710 if ($section.is('.modal')) { 6711 initModalColors(); 6712 $section.on('lpui-show', function () { 6713 window.lpUI.requestScrollLock(sectionDomId); 6714 }); 6715 $section.on('lpui-hide', function () { 6716 window.lpUI.releaseScrollLock(sectionDomId); 6717 }); 6718 } 6719 initializeSelects(); 6720 var $addressInputs = $section.find('.js-address-autocomplete'); 6721 if ($addressInputs.length && window.luxuryPresence && window.luxuryPresence.mapApiLoader) { 6722 window.luxuryPresence.mapApiLoader.load().then(function () { 6723 var autocompleteOptions = { 6724 types: ['geocode'], 6725 fields: ['formatted_address'] 6726 }; 6727 $addressInputs.each(function () { 6728 var input = this; 6729 var autocomplete = new google.maps.places.Autocomplete(input, autocompleteOptions); 6730 autocomplete.addListener('place_changed', function () { 6731 var place = autocomplete.getPlace(); 6732 if (place && place.formatted_address) { 6733 input.value = place.formatted_address; 6734 } 6735 }); 6736 }); 6737 }); 6738 } 6739})('section-a6ae58a0-a07f-4664-a9fd-fe7d60274725', 'undefined'); 6740} catch(e) { 6741console.log(e); 6742} 6743 try { 6744(function init(sectionDomId) {})('section-b433caf7-4caa-4aa7-a1cc-7e5212905ad8', 'undefined'); 6745} catch(e) { 6746console.log(e); 6747} 6748 try { 6749(function init(sectionDomId, options) { 6750 let section = null; 6751 switch (sectionDomId) { 6752 case 'NAVBAR': 6753 section = document.querySelector('body > nav, #global-navbar'); 6754 break; 6755 case 'FOOTER': 6756 section = document.querySelector('body > footer, #global-footer'); 6757 break; 6758 case 'SIDEMENU': 6759 section = document.querySelector('body > div.sidemenu, #global-sidemenu'); 6760 break; 6761 case 'CONTACT':
6762 section = document.querySelector('#modal-global-contact-us'); 6763 break; 6764 case 'MOBILE_CONTACT': 6765 section = document.querySelector('body > div.mobile-contact-wrapper, #global-mobile-contact'); 6766 break; 6767 case 'SUBSCRIBE': 6768 // Subscribe Not Implemented 6769 section = null; 6770 break; 6771 case 'ACCOUNT': 6772 // Account Not Implemented 6773 section = null; 6774 break; 6775 default: 6776 section = document.querySelector('#' + sectionDomId); 6777 } 6778 if (!section) { 6779 return; 6780 } 6781 var url = window.luxuryPresence.defaults.routerUrl; 6782 var companyId = window.luxuryPresence.defaults.companyId; 6783 var limit = options.limit || 8; 6784 if (typeof limit === 'string') { 6785 limit = parseInt(limit, 10) || 8; // this NaN protection also filters out 0 - this is expected 6786 } 6787 var templateSelector = options.templateSelector || '.jsIGTemplate'; 6788 var containerSelector = options.containerSelector || '.jsIGContainer'; 6789 var hasDataClass = options.hasDataClass || 'has-data'; 6790 var hideActivateMessage = options.hasDataClass || false; 6791 var payload = { 6792 companyId: companyId, 6793 limit: limit 6794 }; 6795 if (options.resourceId && typeof options.resourceId === 'string' && !options.resourceId.match(/^{{.*}}$/)) { 6796 payload.resourceId = options.resourceId; 6797 // Federated enum values are uppercase (AGENT/TEAM); element configs carry lowercase 6798 payload.resource = String(options.resource || 'agent').toUpperCase(); 6799 payload.fallbackToNoResource = options.fallbackToNoResource === 'true' || options.fallbackToNoResource === true; 6800 } 6801 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'; 6802 var templateHTML = section.querySelector(templateSelector)?.innerHTML || ''; 6803 var template = Handlebars.compile(templateHTML); 6804 var container = section.querySelector(containerSelector); 6805 if (options.variables) { 6806 Object.keys(options.variables).forEach(function (key) { 6807 if (options.variables.hasOwnProperty(key) && (typeof options.variables[key] !== 'string' || !options.variables[key].match(/^{{.*}}$/))) { 6808 payload[key] = options.variables[key]; 6809 } 6810 }); 6811 } 6812 function getData() { 6813 var feed = { 6814 error: true 6815 }; 6816 if (payload.companyId == null || payload.companyId === '') { 6817 // instagramContentFeed requires companyId (ID!) â nothing to fetch without it. 6818 // Checked after the options.variables merge, which may override the default. 6819 // Deferred so element listeners (attached after this template runs) still receive it. 6820 setTimeout(function () { 6821 section.dispatchEvent(new CustomEvent('ig-data', { 6822 detail: feed 6823 })); 6824 }, 0); 6825 return; 6826 } 6827 superagent.post(url + '/graphql').send({ 6828 query: query, 6829 variables: payload 6830 }).then(res => { 6831 try { 6832 if (!res.body.errors) { 6833 feed = res.body.data.instagramContentFeed; 6834 if (!feed.active) { 6835 if (!hideActivateMessage && sectionDomId === 'section-temp' && container) { 6836 if (payload.resourceId) { 6837 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>'; 6838 } else { 6839 container.innerHTML = '<div style="text-align: center">Instagram account is not connected.<br /> Connect it on <a href="/profile">Profile page</a></div>'; 6840 } 6841 } 6842 } else { 6843 if (feed.items.length) { 6844 if (hasDataClass) { 6845 section.classList.add(hasDataClass); 6846 } 6847 const feedName = feed.username; 6848 section.querySelectorAll('.jsIGLink').forEach(link => link.setAttribute('href', feed.feedUrl)); 6849 section.querySelectorAll('.jsIGName').forEach(name => { 6850 name.textContent = '@' + feedName; 6851 name.setAttribute('title', '@' + feedName); 6852 }); 6853 if (container && template) { 6854 container.innerHTML = template(feed); 6855 } 6856 } 6857 } 6858 } 6859 } catch (e) {} 6860 section.dispatchEvent(new CustomEvent('ig-data', { 6861 detail: feed 6862 })); 6863 }).catch(e => { 6864 console.log('err', e); 6865 section.dispatchEvent(new CustomEvent('ig-data', { 6866 detail: feed 6867 })); 6868 }); 6869 } 6870 getData(); 6871})('section-56d00219-b3d8-459e-8dda-281976e80716', JSON.parse("{\"limit\":33,\"resource\":\"agent\",\"resourceId\":\"\",\"fallbackToNoResource\":\"true\",\"companyId\":\"7638a4cd-9580-4d1f-a8a5-ac3b4943a953\",\"usePageResource\":false,\"sectionIndex\":4}")); 6872} catch(e) { 6873console.log(e); 6874} 6875 try { 6876(function init(sectionDomId) { 6877 const $section = $('#' + sectionDomId); 6878 var templateHTML = $section.find('.jsIGItem').html(); 6879 var itemTemplate = templateHTML && Handlebars.compile(templateHTML); 6880 const $container = $section.find('.ig-feed-feed'); 6881 const $topPrev = $section.find('.top-nav-prev'); 6882 const $topNext = $section.find('.top-nav-next'); 6883 const $bottomPrev = $section.find('.bottom-nav-prev'); 6884 const $bottomNext = $section.find('.bottom-nav-next'); 6885 let limit = 33; 6886 try { 6887 limit = parseInt($container[0].dataset['limit']); 6888 } catch (e) {} 6889 if (!limit) { 6890 limit = 33; 6891 } 6892 let igFeed = {}; 6893 let usedWidth = 0; 6894 let slider = null; 6895 $section.on('ig-data', function (ev, feed) { 6896 feed = ev.detail || feed; 6897 igFeed = feed; 6898 if (feed.active && feed.items.length) { 6899 buildSlider(); 6900 } 6901 }); 6902 $(window).on('resize.lpui-auto-clean', onResize); 6903 let timer = null; 6904 function onResize() { 6905 clearTimeout(timer); 6906 timer = window.setTimeout(buildSlider, 50); 6907 } 6908 function getLayout(w, n) { 6909 if (w > 1100) { 6910 if (n > 7) { 6911 return { 6912 type: 'type1', 6913 single: 1, 6914 multi: n, 6915 slides: 3, 6916 slider: n > 9 6917 }; 6918 } 6919 if (n > 5) { 6920 return { 6921 type: 'type1', 6922 single: 2, 6923 multi: n, 6924 slides: 3, 6925 slider: false 6926 }; 6927 } 6928 return { 6929 type: 'type1', 6930 single: n, 6931 multi: n, 6932 slides: 3, 6933 slider: n > 3 6934 }; 6935 } else if (w > 880) { 6936 if (n > 4) { 6937 return { 6938 type: 'type2', 6939 single: 1, 6940 multi: n, 6941 slides: 2.5, 6942 slider: n > 7 6943 }; 6944 } 6945 return { 6946 type: 'type1', 6947 single: n, 6948 multi: n, 6949 slides: 3, 6950 slider: n > 3 6951 }; 6952 } else if (w > 767) { 6953 if (n > 4) { 6954 return { 6955 type: 'type3', 6956 single: 1, 6957 multi: n, 6958 slides: 2, 6959 slider: n > 5 6960 }; 6961 } 6962 return { 6963 type: 'type4', 6964 single: n, 6965 multi: n, 6966 slides: 2, 6967 slider: n > 2 6968 }; 6969 } else if (w > 460) { 6970 return { 6971 type: 'type4', 6972 single: n, 6973 multi: n, 6974 slides: 2, 6975 slider: n > 2 6976 }; 6977 } 6978 return { 6979 type: 'type5', 6980 single: n, 6981 multi: n, 6982 slides: 1, 6983 slider: n > 1 6984 }; 6985 } 6986 function ensureClass($el, className) { 6987 if ($el.hasClass(className)) { 6988 return; 6989 } 6990 $el.addClass(className); 6991 } 6992 function makeSquare($el) { 6993 const el = $el[0]; 6994 el.style.width = ''; 6995 el.style.height = ''; 6996 const rect = el.getBoundingClientRect(); 6997 if (rect.width !== rect.height) { 6998 el.style.width = rect.height + 'px'; 6999 } 7000 } 7001 function buildSlider() { 7002 const cWidth = $container[0].getBoundingClientRect().width; 7003 if (cWidth === usedWidth) { 7004 return; 7005 } 7006 $container.empty();
7007 slider = $('<div class="ig-feed-slider"></div>'); 7008 const items = igFeed.items.slice(0, limit); 7009 const layout = getLayout(cWidth, items.length); 7010 let i = 0; 7011 let slide = null; 7012 while (i < layout.single) { 7013 slide = $(`<div class="slide-single ${layout.type}"></div>`).append(itemTemplate(items[i])).appendTo(slider); 7014 i++; 7015 } 7016 while (i < layout.multi) { 7017 slide = $(`<div class="slide-multi ${layout.type}"></div>`).appendTo(slider); 7018 let slideContent = $('<div class="slide-multi-content"></div>').appendTo(slide); 7019 const lim = i + 4; 7020 while (i < lim && i < layout.multi) { 7021 slideContent.append(itemTemplate(items[i])); 7022 i++; 7023 } 7024 } 7025 $container.append(slider); 7026 if (layout.slider) { 7027 $topPrev.removeClass('hidden-control'); 7028 $topNext.removeClass('hidden-control'); 7029 $bottomPrev.removeClass('hidden-control'); 7030 $bottomNext.removeClass('hidden-control'); 7031 let prev, next; 7032 if ($bottomPrev.parent()[0].getBoundingClientRect().width) { 7033 prev = $bottomPrev; 7034 next = $bottomNext; 7035 } else { 7036 prev = $topPrev; 7037 next = $topNext; 7038 makeSquare($topPrev); 7039 makeSquare($topNext); 7040 } 7041 slider.children().each(function () { 7042 this.style.width = this.getBoundingClientRect().width + 'px'; 7043 }); 7044 slider.slick({ 7045 dots: false, 7046 prevArrow: prev, 7047 nextArrow: next, 7048 slidesToScroll: 1, 7049 infinite: false, 7050 slidesToShow: layout.slides 7051 }); 7052 } else { 7053 ensureClass($topPrev, 'hidden-control'); 7054 ensureClass($topNext, 'hidden-control'); 7055 ensureClass($bottomPrev, 'hidden-control'); 7056 ensureClass($bottomNext, 'hidden-control'); 7057 } 7058 } 7059})('section-56d00219-b3d8-459e-8dda-281976e80716', 'undefined'); 7060} catch(e) { 7061console.log(e); 7062} 7063 7064 var { body } = document; 7065 var globalNav = body.querySelector(':scope > nav'); 7066 var globalSideMenu = body.querySelector(':scope > div.sidemenu'); 7067 7068 document.querySelectorAll('body > .modal .close').forEach(modalCloseBtn => { 7069 modalCloseBtn.addEventListener('click', function() { 7070 window.lpUI.hideClosestModal(modalCloseBtn); 7071 }); 7072 }); 7073 7074 window.addEventListener('click', function() { 7075 document.querySelectorAll('.share-popup').forEach(sharedPopup => { 7076 sharedPopup.style.display = 'none' ; 7077 }); 7078 }); 7079 7080 /* Misc Partials / Addons */ 7081 function initWOW() { 7082 if (wow) { 7083 wow.init(); 7084 wow.scrollHandler(); 7085 setTimeout(function () { 7086 const wowHideStyle = document.getElementById('wow-hide-elements'); 7087 if(wowHideStyle) { 7088 wowHideStyle.disabled = true; 7089 } 7090 }, 1); 7091 } 7092 } 7093 7094 const wowHideElements = document.getElementById('wow-hide-elements'); 7095 if (wowHideElements) { 7096 wowHideElements.disabled = false; 7097 } 7098 7099 var globalLoader = document.getElementById('global-loader'); 7100 if (globalLoader) { 7101 setTimeout(function() { 7102 globalLoader.style.height = "0px"; 7103 window.sessionStorage.setItem('global_loading_displayed', 'yes'); 7104 7105 // Remove global-loader to prevent caching issues with turbolinks 7106 globalLoader.addEventListener('transitionend', 7107 function(e) { 7108 globalLoader.remove(); 7109 initWOW(); 7110 }); 7111 }, 1000); 7112 } else { 7113 initWOW(); 7114 } 7115 7116 /* Generic Navbar Handling */ 7117 globalNav?.querySelectorAll('.hamburger-component').forEach(hamburgerComponent => { 7118 hamburgerComponent.addEventListener('click', function() { 7119 window.lpUI.sideMenuToggle(); 7120 }); 7121 }); 7122 globalSideMenu?.querySelectorAll('.toggle').forEach(toggleEl => { 7123 toggleEl.addEventListener('click', function() { 7124 window.lpUI.sideMenuToggle(); 7125 }); 7126 }); 7127 7128 document.querySelectorAll('body > nav .sub-nav-container > a, body > div.sidemenu .sub-nav-container > a').forEach(linkEl => { 7129 linkEl.addEventListener('click', function(e) { 7130 e.preventDefault(); 7131 e.stopPropagation();
7132 var subNav = linkEl.parentElement.querySelector(':scope > .sub-nav'); 7133 if (subNav && subNav.classList.contains('visible')){ 7134 subNav.classList.remove('visible'); 7135 } else { 7136 globalNav?.querySelectorAll('.sub-nav-container .sub-nav').forEach(globalSubNav => { 7137 globalSubNav.classList.remove('visible'); 7138 }); 7139 globalSideMenu?.querySelectorAll('.sub-nav').forEach(sideMenuSubNav => { 7140 sideMenuSubNav.classList.remove('visible'); 7141 }); 7142 subNav?.classList.add('visible'); 7143 } 7144 }); 7145 }); 7146 window.addEventListener('click', function() { 7147 document.querySelectorAll('nav .sub-nav.visible, .sidemenu .sub-nav.visible').forEach(subNavEl => { 7148 subNavEl.classList.remove('visible'); 7149 }); 7150 }); 7151 7152 } 7153 7154 document.addEventListener('DOMContentLoaded', lpGlobalInit); 7155 7156 </script>
7156 7157 7158
7158<script type="module"> 7159 function selectorExists(selector) { 7160 return document.querySelector(selector) !== null; 7161 } 7162 7163 // Function to initialize the third-party library 7164 function initParoller(selector = '.my-paroller') { 7165 var $parollerElements = $(selector); 7166 if ($parollerElements.length > 0 && typeof $parollerElements.paroller === 'function') { 7167 $parollerElements.paroller(); 7168 } 7169 } 7170 7171 const parollerSelector = '.my-paroller'; 7172 7173 if (selectorExists(parollerSelector)) { 7174 window.luxuryPresence.libs.loadJs(window.luxuryPresence.libs.jsLibsMap.paroller.jsSrc, function() { 7175 initParoller(parollerSelector); 7176 window.luxuryPresence.libs.jsLibsMap.paroller.isLoaded = true; 7177 }); 7178 } 7179 </script>
7179 7180 7181 <!-- Google Tag Manager (noscript) -->
vendor: 80 bytes, lines 7181-7182
7181 7182 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
7182GTM-T9SFQGHZ
vendor: 107 bytes, lines 7182-7184
7182" 7183 height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 7184
7184<!-- End Google Tag Manager --> 7185 7186
7186<script 7187 src="https://cdn.luxurypresence.com/scripts/a11y-widget/latest/widget.js" 7188 data-website-id="6dd48137-4176-40e9-8267-8bd0f0be23f4" 7189 7190 defer></script>
vendor: 1 bytes, line 7190
7190
7191<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:'a479d4920fb5ffc4',t:'MTc5MTUxMTYzMQ=='};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>
7191<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v4bc70e2c01a94c73b74392e4234840661791215815920" integrity="sha512-L0ha0OXavK/8okipN9F8BtP84dg9DUhPERbBXzwI6dgTA55d2+yweo3pn5CSFYs45/r8md2+xvUPtTdvTNRfjA==" data-cf-beacon='{"version":"2024.11.0","token":"d2a8f4b3d65944edb8fcd6ffce49ee5e","spa":2}' crossorigin="anonymous"></script>
7191 7192</body> 7193</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.