PageSourceSearch

https://maryscleaningcare.com/

html maryscleaningcare.com collected 2026-09-29 14:56:12 UTC 140,837 bytes, 3,034 lines download raw bytes

1
2<!DOCTYPE html>
3<html>
4<head>
5    <meta charset="utf-8" />
6    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1.0" />
7    <meta name="format-detection" content="telephone=no" />
8    <meta property="og:locale" content="en_US" />
9    <meta property="og:type" content="website" />
10        <meta property="og:title" content="Mary’s Cleaning Care Inc - Urbandale, IA" />
11            <meta property="og:url" content="https://maryscleaningcare.com/" />
12                <meta property="og:image" content="https://du9m0k402rjmo.cloudfront.net/images/P_40420/24df8162-12a8-4f18-b575-057abacf3c0f.jpg" />
13            <meta property="og:description" content="Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in routine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit." />
14        <meta name="description" content="Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in routine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit." />
15            <meta name="title" content="Mary’s Cleaning Care Inc - Urbandale IA" />
16            <meta name="keywords" content="Carpet Cleaning,Cleaning,Cleaning and Maid Service,Cleaning Houses and Windows,Cleaning Service,Cleaning Service Near Me,Deep Clean,House Cleaning,Residential Cleaning,Salon Cleaning,Floor Waxing" />
17    <title>Mary’s Cleaning Care Inc - Urbandale, IA</title>
18    
18<script src="/Scripts/Profile/googleAnalytics.js" type="text/javascript"></script>
vendor: 112 bytes, lines 18-21
18
19    <script type="text/javascript" src="https://www.google.com/recaptcha/api.js" async defer></script>
20
21    
21<script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
21
22    
23    
23<script>window.jQuery || document.write('
23<script src="/scripts/templates/jquery-3.5.0.min.js"><\/script>')</script>
23
24
25    
25<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
25
26    
27    
27<script>if (typeof (Popper) === 'undefined') { document.write('
27<script src="/scripts/templates/popper.min.js"><\/script>') }</script>
27
28
29    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
30
31    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
32
33    
33<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-mrcBkRTg0HmTfecoh1I+48Ptm7cAe18uN+3GsS5SXXGSwzpjIhJZkxEJ5jYaZmE" crossorigin="anonymous"></script>
33
34    
35    
35<script>if (typeof ($.fn.modal) === 'undefined') { document.write('
35<script src="/scripts/templates/bootstrap.min.js"><\/script>') }</script>
35
36
37    
37<script src="/Scripts/Templates/googleMaps.js" type="text/javascript"></script>
37
38    <link href="/Content/Templates/custom-bootstrap.css" type="text/css" rel="stylesheet" />
39    
39<script src="/Scripts/bootbox.min.js" type="text/javascript"></script>
39
40    
40<script src="/Scripts/Profile/jquery.barrating.1.1.4.js" type="text/javascript"></script>
40
41    
41<script src="/Scripts/Templates/cleave.min.js" type="text/javascript"></script>
41
42    
42<script src="/Scripts/Templates/cleave-phone.us.js" type="text/javascript"></script>
42
43    
43<script src="/Scripts/Templates/slick.min.js" type="text/javascript"></script>
43
44    <link href="/Content/Templates/slick.css" type="text/css" rel="stylesheet" />
45    <link href="/Content/Templates/slick-theme.css" type="text/css" rel="stylesheet" />
46    
46<script src="/Scripts/Templates/googleMapsMultiLocation.js" type="text/javascript"></script>
vendor: 66 bytes, lines 46-47
46
47    <script src="https://www.google.com/recaptcha/api.js?render=
476LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH
vendor: 40 bytes, lines 47-48
47" type="text/javascript"></script>
48    
48<script src="https://player.vimeo.com/api/player.js" type="text/javascript"></script>
48
49
50    <link href="/Content/Templates/chatbot.css" type="text/css" rel="stylesheet" />
51
52    <meta name="viewport" content="width=device-width, user-scalable=yes,initial-scale=1, maximum-scale=2" />
53    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
54    
55    
56    <link href="/Content/Templates/platinum_fonts.css" type="text/css" rel="stylesheet" />
57    
58    <style>
59        :root {
60            --body_font: Open Sans;
61            --header_font: Roboto Slab;
62            --text_color: 0, 0, 0, 0.7;
63            --text_color_rgba: rgba(var(--text_color));
64            --customer_color: #4DCCAA;
65            --slogan_font_size: 2.5rem;
66            --slogan_text_color: ;
67            --faq_question_text_color: #000000;
68            --post_text_color: 0, 0, 0, 0.7;
69            --post_text_color_rgba: rgba(var(--post_text_color));
70            --text-transform: capitalize;
71            --scroll-padding-top: 0px; /* Initial value */
72        }
73    </style>
74    <link href="/Content/Templates/platinum_1.css" type="text/css" rel="stylesheet" />
75
76        <link rel="canonical" href="https://maryscleaningcare.com/">
77
78
79<script type="application/ld+json">
80{
81  "@context": "https://schema.org",
82  "@graph": [
83    {
84      "@type": "LocalBusiness",
85      "@id": "https://maryscleaningcare.com/#localbusiness",
86      "name": "Mary’s Cleaning Care Inc",
87      "url": "https://maryscleaningcare.com/",
88      "description": "Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in routine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit.",
89      "image": "https://du9m0k402rjmo.cloudfront.net/images/P_40420/24df8162-12a8-4f18-b575-057abacf3c0f.jpg",
90      "logo": "https://du9m0k402rjmo.cloudfront.net/images/P_40420/24df8162-12a8-4f18-b575-057abacf3c0f.jpg",
91      "address": {
92        "@type": "PostalAddress",
93        "streetAddress": "7921 Douglas Ave",
94        "addressLocality": "Urbandale",
95        "addressRegion": "IA",
96        "postalCode": "50322",
97        "addressCountry": "US"
98      },
99      "telephone": "(515) 270-1612",
100      "email": "[email protected]",
101      "geo": {
102        "@type": "GeoCoordinates",
103        "latitude": 41.62968,
104        "longitude": -93.727642
105      },
106      "openingHoursSpecification": [
107        {
108          "@type": "OpeningHoursSpecification",
109          "dayOfWeek": "Monday",
110          "opens": "09:00",
111          "closes": "16:00"
112        },
113        {
114          "@type": "OpeningHoursSpecification",
115          "dayOfWeek": "Tuesday",
116          "opens": "09:00",
117          "closes": "16:00"
118        },
119        {
120          "@type": "OpeningHoursSpecification",
121          "dayOfWeek": "Wednesday",
122          "opens": "09:00",
123          "closes": "16:00"
124        },
125        {
126          "@type": "OpeningHoursSpecification",
127          "dayOfWeek": "Thursday",
128          "opens": "09:00",
129          "closes": "16:00"
130        },
131        {
132          "@type": "OpeningHoursSpecification",
133          "dayOfWeek": "Friday",
134          "opens": "09:00",
135          "closes": "16:00"
136        }
137      ],
138      "paymentAccepted": "American Express, Personal Checks, Debit Cards, Discover, MasterCard, Visa",
139      "sameAs": [
140        "https://www.facebook.com/MarysCleaningCare/",
141        "https://www.instagram.com/maryscleaningcare/"
142      ]
143    },
144    {
145      "@type": "WebSite",
146      "@id": "https://maryscleaningcare.com/#website",
147      "url": "https://maryscleaningcare.com/",
148      "name": "Mary’s Cleaning Care Inc",
149      "description": "Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in routine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit.",
150      "potentialAction": {
151        "@type": "SearchAction",
152        "target": "https://maryscleaningcare.com/?s={search_term_string}",
153        "query-input": "required name=search_term_string"
154      }
155    },
156    {
157      "@type": "WebPage",
158      "@id": "https://maryscleaningcare.com/#webpage",
159      "url": "https://maryscleaningcare.com/",
160      "name": "Mary’s Cleaning Care Inc - Urbandale, IA",
161      "description": "Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in rout
161ine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit.",
162      "isPartOf": {
163        "@id": "https://maryscleaningcare.com/#website"
164      },
165      "about": {
166        "@id": "https://maryscleaningcare.com/#localbusiness"
167      },
168      "primaryImageOfPage": {
169        "@type": "ImageObject",
170        "url": "https://du9m0k402rjmo.cloudfront.net/images/P_40420/24df8162-12a8-4f18-b575-057abacf3c0f.jpg"
171      },
172      "breadcrumb": {
173        "@type": "BreadcrumbList",
174        "itemListElement": [
175          {
176            "@type": "ListItem",
177            "position": 1,
178            "name": "Home",
179            "item": "https://maryscleaningcare.com/"
180          }
181        ]
182      }
183    },
184    {
185      "@type": "Service",
186      "@id": "https://maryscleaningcare.com/#service",
187      "name": "Our Services",
188      "provider": {
189        "@id": "https://maryscleaningcare.com/#localbusiness"
190      },
191      "serviceType": [
192        "Commercial Cleaning",
193        "Janitorial Services",
194        "Residential Cleaning",
195        "Office Cleaning",
196        "Business Cleaning",
197        "Church Cleaning",
198        "Car Dealership Cleaning",
199        "Automotive Space Cleaning",
200        "Salon Cleaning",
201        "Carpet Cleaning",
202        "Tile Grout Cleaning",
203        "Floor Stripping",
204        "Floor Waxing",
205        "Deep Clean Service"
206      ],
207      "description": "Professional services offered by Mary’s Cleaning Care Inc"
208    },
209    {
210      "@type": "Service",
211      "@id": "https://maryscleaningcare.com/#service1",
212      "name": "Residential Cleaning",
213      "provider": {
214        "@id": "https://maryscleaningcare.com/#localbusiness"
215      },
216      "serviceType": "Residential Cleaning",
217      "description": "Your home deserves the best, and Mary’s Cleaning Care Inc delivers just that. We provide thorough and dependable residential cleaning services, from regular upkeep to detailed deep cleans. Our team tackles dust, grime, and clutter, leaving your home spotless and refreshed. Whether it’s a weekly clean or a one-time service for a special occasion, we use safe, eco-friendly products to protect your family and pets. Our attention to detail means every corner is cared for—so you can relax and enjoy your clean, comfortable space. We’re here to make your home shine, inside and out."
218    },
219    {
220      "@type": "Service",
221      "@id": "https://maryscleaningcare.com/#service2",
222      "name": "Commercial & Office Cleaning",
223      "provider": {
224        "@id": "https://maryscleaningcare.com/#localbusiness"
225      },
226      "serviceType": "Commercial & Office Cleaning",
227      "description": "Mary’s Cleaning Care Inc helps businesses look their best with our reliable and professional commercial cleaning services. We service offices, churches, salons, dealerships, and more, offering flexible cleaning schedules and customized plans. Whether you need daily janitorial services or periodic deep cleaning, we ensure your space stays sanitized, organized, and inviting. From restrooms to break rooms and everything in between, we use high-quality products and pay close attention to detail. A clean work environment boosts morale and leaves a great impression—let us handle the cleaning so you can focus on running your business."
228    },
229    {
230      "@type": "Service",
231      "@id": "https://maryscleaningcare.com/#service3",
232      "name": "Carpet & Floor Care",
233      "provider": {
234        "@id": "https://maryscleaningcare.com/#localbusiness"
235      },
236      "serviceType": "Carpet & Floor Care",
237      "description": "Clean floors make a powerful difference in the look and feel of any space. That’s why Mary’s Cleaning Care Inc offers professional carpet cleaning, tile and grout care, and expert floor str
237ipping and waxing. Our team removes deep-down dirt, allergens, and stains from carpets while restoring shine to hard surfaces. We use commercial-grade equipment and safe solutions to bring your flooring back to life. Whether it’s your home’s living room carpet or a high-traffic commercial lobby, our floor care services leave lasting results. Trust us to protect and enhance one of the most important parts of your space—your floors."
238    },
239    {
240      "@type": "FAQPage",
241      "@id": "https://maryscleaningcare.com/#faqpage",
242      "url": "https://maryscleaningcare.com/#faq",
243      "name": "Frequently Asked Questions",
244      "description": "Frequently asked questions about Mary’s Cleaning Care Inc",
245      "mainEntity": [
246        {
247          "@type": "Question",
248          "name": "Where is Mary’s Cleaning Care located and how can I contact you?",
249          "acceptedAnswer": {
250            "@type": "Answer",
251            "text": "Mary’s Cleaning Care is based in Urbandale, IA, and surrounding communities with trusted, high-quality cleaning services. You can reach us at (515) 270-1612 or email [email protected] to schedule your cleaning service. We tailor our services to meet the needs of your business, whether it’s daily office cleaning, deep-cleaning high-traffic areas, or maintaining your floors with expert stripping and waxing"
252          }
253        },
254        {
255          "@type": "Question",
256          "name": "What types of cleaning services do you offer?",
257          "acceptedAnswer": {
258            "@type": "Answer",
259            "text": "We specialize in a wide range of cleaning services, including residential cleaning, commercial cleaning, carpet cleaning, tile and grout care, and floor maintenance."
260          }
261        },
262        {
263          "@type": "Question",
264          "name": "How do I book a cleaning appointment?",
265          "acceptedAnswer": {
266            "@type": "Answer",
267            "text": "Booking is simple! You can call us directly, email, or use our online booking system. We recommend scheduling at least 24 hours in advance to guarantee availability."
268          }
269        },
270        {
271          "@type": "Question",
272          "name": "What is your cancellation policy?",
273          "acceptedAnswer": {
274            "@type": "Answer",
275            "text": "If you need to cancel or reschedule, please notify us at least 24 hours in advance to avoid any fees and help us adjust our schedule."
276          }
277        },
278        {
279          "@type": "Question",
280          "name": "Do you use environmentally friendly cleaning products?",
281          "acceptedAnswer": {
282            "@type": "Answer",
283            "text": "Yes!  Our team of trained and experienced professionals works with great attention to detail, using effective methods and environmentally friendly products to ensure every space we touch is left spotless and refreshed."
284          }
285        },
286        {
287          "@type": "Question",
288          "name": "What areas does Mary’s Cleaning Care serve around Urbandale, IA?",
289          "acceptedAnswer": {
290            "@type": "Answer",
291            "text": "Mary’s Cleaning Care proudly serves Urbandale and surrounding communities including West Des Moines, Clive, Waukee, Johnston, Grimes, Ankeny, and the greater Des Moines metro. We provide both residential and commercial cleaning services across these areas with flexible scheduling."
292          }
293        },
294        {
295          "@type": "Question",
296          "name": "Do you offer weekly or biweekly residential cleaning services?",
297          "acceptedAnswer": {
298            "@type": "Answer",
299            "text": "Yes! We specialize in recurring weekly and biweekly home cleanings. This includes dusting, vacuuming, mopping, kitchen cleaning, bathroom sanitizing, and general home upkeep—perfect for busy families or anyone looking to maintain a consistently clean home."
300          }
301        },
302        {
303          "@type": "Question",
304          "name": "What types of commercial cleaning services do you provide?",
305          "acceptedAnswer": {
306            "@type": "Answer",
307            "text": "We offer customized commercial cleaning for offices, small businesses, retail spaces, and professional buildings. Services include disinfecting high‑touch areas, breakroom and restroom cleaning, floor care, trash removal, and after‑hours cleanings to minimize disruption."
308          }
309        },
310        {
311          "@type": "Question",
312          "name": "Can you customize a cleaning plan for my home or business?",
313          "acceptedAnswer": {
314            "@type": "Answer",
315            "text": "Absolutely. Whether you need a detailed deep clean, routine residential cleanings, or a commercial cleaning plan tailored to your business hours, budget, and space type, we create customized solutions to fit your exact needs."
316          }
317        },
318        {
319          "@type": "Question",
320          "name": "How do I get a quote for residential or commercial cleaning in the Urbandale area?",
321          "acceptedAnswer": {
322            "@type": "Answer",
323            "text": "You can request a free quote online or by phone. We’ll gather a few details about your home or business, your preferred cleaning frequency, and your location in or around Urbandale. Quotes are fast, transparent, and include no hidden fees."
324          }
325        }
326      ]
327    }
328  ]
329}
330</script>
330</head>
331<body>
332    <div id="bootstrapCssTest" class="d-none"></div>
333    
333<script>
334        $(function () {
335            
336            if ($('#bootstrapCssTest').is(':visible')) {
337                $("head").prepend('<link rel="stylesheet" href="/content/templates/bootstrap.min.css">');
338            }
339        });
340    </script>
340
341
342    
343
344
345<input type="hidden" id="areaMarkers" />
346<input type="hidden" id="selectedServiceId" value="" />
347
348<!-- NAVBAR -->
349<div class="container-fullwidth fixed-top">
350    
351
352
353
354
355<header id="headernav" class="content-header custom-background-color d-flex flex-wrap align-items-center justify-content-between py-0 px-2">
356
357    
358    <div class="nav-phone-social pb-1 d-flex flex-wrap justify-content-center">
359        <div class="my-1 header-address d-flex flex-wrap justify-content-center">
360                <div class="nav-phone text-center nav-header-item-no-spacing mx-1"><a id="PhoneNav" class="text-font-color phone-nav-mobile" href="tel:5152701612"><i class="fas fa-phone fa-inverse fa-xs fa-rotate-90 mr-1"></i>(515) 270-1612</a></div>
361                            <div class="nav-phone text-center nav-header-item-no-spacing mx-1 px-1"><a id="eMailNav" class="text-font-color phone-nav-mobile text-lowercase" href="mailto:[email protected]" target="_blank"><i class="fas fa-envelope fa-inverse fa-sm mr-1"></i>[email protected]</a></div>
362        </div>
363    </div>
364
365    
366    <div class="nav-phone-social pb-1 d-flex flex-wrap justify-content-center">
367        <div class="nav-social mx-1 px-1">
368                <div class="mx-auto text-center d-flex flex-wrap justify-content-center">
369                                            <div class="mt-1 mb-1 ml-2 mr-2">
370                            <a class="text-font-color social-link-footer" href="https://www.facebook.com/MarysCleaningCare/" target="_blank" id="facebook-social-footer" title="Facebook">
371                                <i class="fab fa-facebook-f fa-lg"></i>
372                            </a>
373                        </div>
374                                                                                    <div class="mt-1 mb-1 ml-2 mr-2">
375                            <a class="text-font-color social-link-footer" href="https://www.instagram.com/maryscleaningcare/" target="_blank" id="instagram-social-footer" title="Instagram">
376                                <i class="fab fa-instagram fa-lg"></i>
377                            </a>
378                        </div>
379                                                        </div>
380        </div>
381    </div>
382</header>
383
384
385<nav class="bg-default-color bg-light navbar navbar-light navbar-expand-xl pt-1">
386
387    <div class="nav-image bg-default-color bg-light flex-column text-center nav-image-desktop">
388            <a href="#home-section" class="navbar-brand ml-3" id="HomeNav" onclick="DisplayPage('#homePage')">
389                <img src="https://du9m0k402rjmo.cloudfront.net/images/P_40420/24df8162-12a8-4f18-b575-057abacf3c0f.jpg" alt="navbar logo" class="d-line-block align-top nav-logo-medium" />
390            </a>
391    </div>
392
393    <button class="navbar-toggler nav-menu collapsed" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation">
394        <span class="navbar-toggler-icon"></span>
395        <span class="my-1 mx-2 close">X</span>
396    </button>
397
398    <div class="collapse navbar-collapse flex-column mx-auto" id="navbarToggler">
399        
400        <div class="d-none d-xl-block nav-section">
401            <div class="navbar-nav d-flex flex-wrap align-items-center">
402
403
404<div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="HomePageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#homePage')">Home</a>
405</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="AboutPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#aboutPage')">About</a>
406</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="PhotosNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#imageryPage')">Gallery</a>
407</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="ServicesPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#servicesPage')">Services</a>
408</div>
408<div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="testimonialsPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a>
409</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="ContactPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#contactPage')">Contact</a>
410</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="PostsPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#postsPage')">News</a>
411</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a target="_blank" href="https://maryscleaningcare.com/optimamedia/products/P_40420/3bfc95da-7812-47f4-a8f6-4e2bb179a37b.jpg" id="DocumentPageNavigationLink" class="nav-link header-font p-3">More</a>
412</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap">            <a href="#" id="FaqPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#faqPage')">FAQ</a>
413</div>            </div>
414        </div>
415        
416        <div class="d-xs-block d-xl-none">
417            <ul class="navbar-nav mx-auto mr-auto mt-2 mt-xl-0 mb-2">
418
419
420<li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="HomePageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#homePage')">Home</a>
421</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="AboutPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#aboutPage')">About</a>
422</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="PhotosNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#imageryPage')">Gallery</a>
423</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="ServicesPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#servicesPage')">Services</a>
424</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="testimonialsPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a>
425</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="ContactPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#contactPage')">Contact</a>
426</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="PostsPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#postsPage')">News</a>
427</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a target="_blank" href="https://maryscleaningcare.com/optimamedia/products/P_40420/3bfc95da-7812-47f4-a8f6-4e2bb179a37b.jpg" id="DocumentPageNavigationLink" class="nav-link header-font pl-3">More</a>
428</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap">            <a href="#" id="FaqPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#faqPage')">FAQ</a>
429</li>            </ul>
430        </div>
431    </div>
432</nav>
433</div>
434
435<div id="pages" class="pages-left-medium">
436    <!--Home Page Information-->
437    <div class="content collapse show bg-alt-color" id="homePage">
438
439<div class="d-flex flex-wrap">
440
441        <div class="w-100 mx-auto home-banner">
442            <div id="homepagebanner" class="parallax w-100 aspect-ratio-16x9">
443                    <div class="img-fluid banner-image"><object data="https://fast.wistia.com/embed/medias/s679kpxzdx?fitStrategy=cover&endVideoBehavior=loop&controlsVisibleOnLoad=false&autoPlay=true&volumeControl=false&muted=true&playbar=false&smallPlayButton=false&settingsControl=false&control-bar-right=false" style="width: 100%; height: 100%;" onload="jQuery('.w-css-reset').hide(); jQuery('.w-bottom-bar').hide(); jQuery('.w-ui-container').remove();  "></object></div>
444
445                <div class="home-content">
446                    <div class="d-flex flex-wrap justify-content-center align-items-center px-2"></div>
447                </div>
448            </div>
449        </div>
450    
451        <div class="w-100 w-lg-80 w-sm-90 w-md-90 mx-auto p-2">
452            <div class="d-flex flex-row flex-wrap justify-content-center text-left py-2">
453                    <div class="col-md mx-auto text-center pt-2">
454                        <img alt="Image" src="https://du9m0k402rjmo.
454cloudfront.net/images/P_40420/225b441b-0005-46c6-aaec-7c9bb8981f5f.png" class="img-fluid mx-auto text-center" />
455                    </div>
456                                    <div class="col-md pt-2">
457                        <div class="mx-auto mb-2 section-information">
458                            <div class="strike">
459                                <span class="text-center header-item">About Us</span>
460                            </div>
461                        </div>
462                        <div class="mx-auto mb-2 description-speakable" style="white-space: pre-line">Mary’s Cleaning Care Inc has proudly served Urbandale, IA, and surrounding areas since 2009, providing dependable, high-quality residential cleaning services. We specialize in routine maintenance cleaning and one-time deep cleanings, tailored to meet the unique needs of each home. Our experienced team is committed to delivering thorough, consistent results that leave your home clean, comfortable, and inviting. We use eco-friendly cleaning products to support a healthy living environment for you and your family. When you choose Mary’s Cleaning Care Inc, you can count on reliable service and attention to detail every visit.</div>
463                    </div>
464            </div>
465        </div>
466
467        <div class="w-100 w-lg-80 w-sm-90 w-md-90 mx-auto p-2" id="photos-content">
468            <div class="mx-auto mb-2 section-information">
469                <div class="strike">
470                    <span class="text-center header-item">Highlights</span>
471                </div>
472            </div>
473            <div class="d-flex flex-row flex-wrap justify-content-center py-2">
474                    <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto">
475                        <div class="d-flex flex-wrap">
476                            <div class="col p-2">
477<a href="#" id="photos-image-element1" class="thumbnail mx-auto d-block">                                <img src="https://du9m0k402rjmo.cloudfront.net/images/P_40420/49d8a9ce-2aa1-402c-ab18-83e9a667ebc7.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" />
478                                    <div class="text-center pt-2" style="color:black">Residential Cleaning</div>
479                                </a>                            </div>
480                        </div>
481                    </div>
482                                    <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto">
483                        <div class="d-flex flex-wrap">
484                            <div class="col p-2">
485<a href="#" id="photos-image-element2" class="thumbnail mx-auto d-block">                                <img src="https://du9m0k402rjmo.cloudfront.net/images/P_40420/3798b090-4728-4854-8a77-af72064675ad.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" />
486                                    <div class="text-center pt-2" style="color:black">Commercial &amp; Office Cleaning</div>
487                                </a>                            </div>
488                        </div>
489                    </div>
490                                    <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto">
491                        <div class="d-flex flex-wrap">
492                            <div class="col p-2">
493<a href="#" id="photos-image-element3" class="thumbnail mx-auto d-block">                                <img src="https://du9m0k402rjmo.cloudfront.net/images/P_40420/205df6ce-4756-4d76-b513-427bedfddefc.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" />
494                                    <div class="text-center pt-2" style="color:black">Carpet &amp; Floor Care</div>
495                                </a>                            </div>
496                        </div>
497                    </div>
498            </div>
499        </div>
500
501</div>
502
503    </div>
504
505    <!--About Page Information-->
506    <div class="content collapse bg-alt-color" id="aboutPage"></div>
507
508    <!--Services Page Information-->
509    <div class="content collapse bg-alt-color" id="servicesPage"></div>
510
511    <!--Testimonial Page Information-->
512        <div class="content collapse bg-alt-color" id="testimonialsPage"></div>
513
514    <!-- REVIEW MODAL -->
515    <div id="reviewFormParentContainer"></div>
516
517    <!--Contact Page Information-->
518    <div class="content collapse bg-alt-color" id="contactPage"></div>
519
520    <!--Imagery Page Information-->
521    <div class="content collapse bg-alt-color" id="imageryPage"></div>
522
523    <!--Posts Page Information-->
524        <div class="content collapse bg-alt-color" id="postsPage">
525
526<div class="d-flex flex-wrap">
527
528    
529        <div class="w-100 mx-auto banner">
530            <div class="parallax w-100">
531                    <div class="img-fluid banner-image " style="background-image: url(https://du9m0k402rjmo.cloudfront.net/images/P_40420/532f1553-3ab2-4bdf-8a87-be3ee400bcee.jpg)"></div>
532            </div>
533        </div>
534    <div class="w-100 w-lg-80 w-sm-90 w-md-90 mx-auto p-2">
535        <div class="d-flex flex-row flex-wrap justify-content-center text-center">
536            <div class="posts-partial-content w-100">
537                <div class="mx-auto mb-2 section-information pt-3">
538                    <div class="strike">
539                        <span class="text-center header-item">News</span>
540                    </div>
541                </div>
542                
543                <div class="postsInfo" id="testimonialPostsInfo"></div>
544                <div class="text-center m-3">
545                    <button type="button" id="prevPosts" class="btn btn-light btn-md" disabled><i class="fas fa-angle-left"></i> Previous</button>
546                    <button type="button" id="nextPosts" class="btn btn-light btn-md">Next <i class="fas fa-angle-right"></i></button>
547                </div>
548            </div>
549        </div>
550    </div>
551</div>
552        </div>
553
554    <!--Locations Page Information-->
555    <div class="content collapse bg-alt-color" id="locationsPage"></div>
556
557    <!--FAQ Page Information-->
558    <div class="content collapse bg-alt-color" id="faqPage"></div>
559
560    <!--Additional Content Page Information-->
561    <div class="content collapse bg-alt-color" id="contentPage"></div>
562
563</div> 
564
565<!--FOOTER Information-->
566<footer id="footer-container" class="footer custom-background-color">
567
568
569<div class="container-fluid pt-1">
570    <div class="row pl-3 pr-3">
571            <div id="footer-address" class="col-sm-3 col-md-4 col-lg-3 mx-auto d-flex flex-wrap footer-content">
572                <div class="justify-content-left text-font-color">
573                    <div class="footer-header mb-2 mt-2 text-left text-nowrap">Contact Information</div>
574                        <div class="content-large">Mary’s Cleaning Care Inc</div>
575                                            <div class="mt-1 content-medium">
5767921 Douglas Ave                        </div>
577                                            <div class="content-medium">Urbandale, IA 50322</div>
578                    <div class="mt-2 mb-2">
579                            <div class="mx-auto content-medium">
580                                <strong>Phone:</strong> <a id="footer_phoneLink" href="tel:5152701612" class="text-font-color footer-link">(515) 270-1612</a>
581                            </div>
582                                                                            <div class="mx-auto content-medium">
583                                <strong>Mobile:</strong> <a id="footer_MobilePhoneLink" href="tel:5157241962" class="text-font-color contact-phone">(515) 724-1962</a>
584                            </div>
585                                                    <div class="mx-auto content-medium">
586                                <strong>Email:</strong> <a id="footer_ContactEmail" title="[email protected]" class="text-font-color break-word-hyphen" href="mailto:[email protected]">scheduling<wbr>@maryscleaningcare<wbr>.com</a>
587                            </div>
588                    </div>
589                </div>
590            </div>
591        <div id="footer-hours" class='col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap justify-content-center'>
592            <div class="justify-content-left text-font-color">
593                    <div class="footer-hours-detail business-info-footer">
594                        <div class="row">
595                            <div class="col-12 footer-header mt-2 mb-2 text-nowrap">Our Hours</div>
596                        </div>
597                                                    <div class="row">
598                                <div class="col-12 content-medium pt-1 pb-1">Holiday Hours May Vary. Please Call For Details.</div>
599                            </div>
600                                                        <div class="row content-medium pt-1 pb-1">
601                                    <div class="col-6">
602                                        <div class="mr-3 font-weight-bold">
603                                            Monday
604                                        </div>
605                                    </div>
606                                    <div class="col-6">
607                                                    <div class="contact-hours ml-1 text-nowrap">
608                                                        9:00 AM - 4:00 PM
609                                                    </div>
610                                    </div>
611                                </div>
612                        
613                                <div class="row content-medium pt-1 pb-1">
614                                    <div class="col-6">
615                                        <div class="mr-3 font-weight-bold">
616                                            Tuesday
617                                        </div>
618                                    </div>
619                                    <div class="col-6">
620                                                    <div class="contact-hours ml-1 text-nowrap">
621                                                        9:00 AM - 4:00 PM
622                                                    </div>
623                                    </div>
624                                </div>
625                        
626                                <div class="row content-medium pt-1 pb-1">
627                                    <div class="col-6">
628                                        <div class="mr-3 font-weight-bold">
629                                            Wednesday
630                                        </div>
631                                    </div>
632                                    <div class="col-6">
633                                                    <div class="contact-hours ml-1 text-nowrap">
634                                                        9:00 AM - 4:00 PM
635                                                    </div>
636                                    </div>
637                                </div>
638                        
639                                <div class="row content-medium pt-1 pb-1">
640                                    <div class="col-6">
641                                        <div class="mr-3 font-weight-bold">
642                                            Thursday
643                                        </div>
644                                    </div>
645                                    <div class="col-6">
646                                                    <div class="contact-hours ml-1 text-nowrap">
647                                                        9:00 AM - 4:00 PM
648                                                    </div>
649                                    </div>
650                                </div>
651                        
652                                <div class="row content-medium pt-1 pb-1">
653                                    <div class="col-6">
654                                        <div class="mr-3 font-weight-bold">
655                                            Friday
656                                        </div>
657                                    </div>
658                                    <div class="col-6">
659                                                    <div class="contact-hours ml-1 text-nowrap">
660                                                        9:00 AM - 4:00 PM
661                                                    </div>
662                                    </div>
663                                </div>
664                        
665                        
666                    </div>
667            </div>
668        </div>
669            <div id="footer-certificationandassociation" class="col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap">
670                <div class="justify-content-left text-font-color">
671                        <div id="associationsHeader" class="footer-header text-left mb-2 mt-2 text-nowrap">Associations</div>
672                            <div id="associations">Urbandale Chamber of Commerce</div>
673                            <div id="associations">Better Business Bureau (BBB)</div>
674                </div>
675            </div>
676        <div id="footer-sitenav" class='col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap justify-content-center'>
677            <div class="justify-content-left text-font-color">
678                <div class="footer-header text-left mb-2 mt-2 text-nowrap">Site Navigation</div>
679
680
681<div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="HomePageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#homePage')">Home</a>
682</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="AboutPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#aboutPage')">About</a>
683</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="PhotosNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#imageryPage')">Gallery</a>
684</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="ServicesPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#servicesPage')">Services</a>
685</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="testimonialsPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#testimonialsPage')">Testimonials</a>
686</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="ContactPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#contactPage')">Contact</a>
687</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="PostsPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#postsPage')">News</a>
688</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a target="_blank" href="https://maryscleaningcare.com/optimamedia/products/P_40420/3bfc95da-7812-47f4-a8f6-4e2bb179a37b.jpg" id="DocumentPageNavigationLink" class="text-font-color footer-link">More</a>
689</div><div class="text-left content-medium mx-auto text-nowrap pb-1">            <a href="#" id="FaqPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#faqPage')">FAQ</a>
690</div>                                    <div class="text-left content-medium mx-auto text-nowrap">
691                        <a href="/Accessibility?domain=maryscleaningcare" target="_blank" class="text-font-color footer-link">
692                            Text-Only Site Version
693                        </a>
694                    </div>
695            </div>
696        </div>
697    </div>
698</div>
699
700<div class="d-flex flex-wrap text-center justify-content-center pb-3 pl-3 pr-3">
701        <div class="d-flex text-center text-nowrap tos pt-1 w-100 justify-content-center">
702            <a class="text-font-color" href="/Home/TermsOfUse" id="tosLink" target="_blank">Terms of Use</a><div id="footerdash">&nbsp;|&nbsp;</div><a class="text-font-color" href="/Home/PrivacyPolicy" id="ppLink" target="_blank">Privacy Policy</a>
703        </div>
704        <div class="d-flex text-center pt-2 w-100 justify-content-center" style="font-size: 0.75rem; color: #999;">
705            &copy; 2026 American Marketing & Publishing, L.L.C. All rights reserved. Names, logos, and other marks displayed are the property of their respective owners.
706        </div>
707    </div>
708</footer>
709
710    <div class="accessibility-img py-2 px-2">
711        <div class="d-flex flex-wrap justify-content-center align-items-center text-center">
712            <a href="/Accessibility?domain=maryscleaningcare" target="_blank" class="dark">
713                <img src="/Content/Templates/images/accessibility_icon.png" height="60" width="42" />
714            </a>
715        </div>
716    </div>
717
718
719
720
721<div class="chatbot-toggle-container">
722  <button id="chatbot-toggle">
723    <img src="/Content/Templates/images/chat_icon.png" height="60" width="60" />
724  </button>
725</div>
726
727<!-- Chat Window -->
728<div id="chat-window">
729  <!-- Chat Header -->
730  <div class="chat-header">
731    <div class="chat-header-content">
732      <h3 class="chat-header-title">Mary’s Cleaning Care Inc Assistant</h3>
733    </div>
734    <button id="close-chat" class="chat-close-btn" aria-label="Close chat">
735      <i class="fas fa-times"></i>
736    </button>
737  </div>
738
739  <!-- Chat Messages -->
740  <div id="chat-messages">
741    <div class="chat-message-container">
742      <div class="chat-message">
743        Hi there! How can we help you today?
744      </div>
745    </div>
746  </div>
747
748  <div id="disclaimer-info">
749    <div class="disclaimer-content">
750      <div class="disclaimer-text">
751        AI Responses not guaranteed; verify before reliance
752      </div>
753    </div>
754  </div>
755
756  <!-- Cost Display -->
757  <div id="cost-info">
758    <div class="cost-info-row">
759      <div class="cost-info-left">
760        <i class="fas fa-dollar-sign fa-xs cost-icon"></i>
761        <span id="cost-display">Cost: $0.00000</span>
762      </div>
763      <span id="percentage-display">0.0% of $0.02</span>
764    </div>
765    <div class="cost-progress-bar">
766      <div id="cost-progress"></div>
767    </div>
768  </div>
769
770  <!-- Chat Input -->
771  <div class="chat-input-container">
772    <form id="chat-form">
773      <input type="text" id="chat-input" placeholder="Type your message..." />
774      <button type="submit" id="send-message">
775        <i class="fas fa-paper-plane"></i>
776      </button>
777    </form>
778    <div id="character-count">0/250</div>
779    <div id="character-limit-message" style="display: none; color: #dc2626; font-size: 12px; margin-top: 4px;">
780      Your message is too long. Please limit your question to 250 characters or less.
781    </div>
782  </div>
783</div>
784
785<!-- Contact Form Window -->
786<div id="contact-form-window">
787  <div class="contact-form-header">
788    <h3 class="contact-form-title">Contact Form</h3>
789    <button id="close-contact-form" class="contact-form-close-btn" aria-label="Close contact form">
790      <i class="fas fa-times"></i>
791    </button>
792  </div>
793
794  <div class="contact-form-content">
795    <form id="chatbot-contact-form">
796      <input type="hidden" id="chat_captcha_alt" name="chat_captcha_alt" value="F+uBSrMkrMsywsG3uIUzMi3u3fzINcFLlQ3YsycLG9bLVe80ollQTXhDRFtbH0Ba" />
797      <input type="hidden" id="chat_g-Recaptcha-Response-Contact" name="chat_g-Recaptcha-Response-Contact" value="" />
798      <input type="hidden" name="chat_aid" value="9a2815c2-398a-428e-be85-33d4b7ef02da" />
799      <input type="hidden" name="chat_contactSubject" value="FrontDesk&#8482; Contact Form" />
800      <input type="hidden" name="chat_contactAddress" value="" />
801      <input type="hidden" name="chat_contactZip" value="" />
802      <input type="hidden" name="chat_contactCity" value="" />
803      <input type="hidden" name="chat_contactState" value="" />
804
805      <div class="ai-liability mt-1 mb-1">(Messages sent through this site are subject to third party moderation and are not encrypted or secure. We always try to respond as soon as possible, but off-hours inquiries may take us a little longer to reply.)</div>
806
807      <div class="form-group">
808        <label for="chat_contactName" class="form-label">Name *</label>
809        <input type="text" id="chat_contactName" name="chat_contactName" class="form-input" required />
810      </div>
811
812      <div class="form-group">
813        <label for="chat_contactEmail" class="form-label">Email *</label>
814        <input type="email" id="chat_contactEmail" name="chat_contactEmail" class="form-input" required />
815      </div>
816
817      <div class="form-group">
818        <label for="chat_contactPhone" class="form-label">Phone</label>
819        <input type="tel" id="chat_contactPhone" name="chat_contactPhone" class="form-input" />
820      </div>
821
822      <div class="form-group">
823        <label for="chat_contactMessage" class="form-label">Message *</label>
824        <textarea id="chat_contactMessage" name="chat_contactMessage" rows="4" class="form-textarea" required></textarea>
825      </div>
826
827      <div id="classicCaptcha" class="d-flex flex-column">
828        <div class="g-recaptcha ml-auto mb-3 captcha-responsive" data-sitekey="6LeprWcUAAAAAF533Xd5p6kCrnRs0z4ceJieYgeO"></div>
829      </div>
830
831      <!-- Sticky footer section with reCAPTCHA disclaimer and submit button -->
832      <div class="form-sticky-footer">
833        <div class="grecaptcha-info">
834          This site is protected by reCAPTCHA and the Google
835          <a href="https://policies.google.com/privacy">Privacy Policy</a> and
836          <a href="https://policies.google.com/terms">Terms of Service</a> apply.
837        </div>
838        <button type="submit" id="contact-submit-btn" class="form-submit-btn">Submit</button>
839      </div>
840    </form>
841  </div>
842</div>
843
844<script>
845    // Wrap entire chatbot functionality in a namespace to prevent conflicts
846    window.ChatbotModule = (function() {
847        'use strict';
848
849        // Private variables
850        let isOpen = false;
851        let contactFormOpen = false;
852        let messages = [
853            { role: 'assistant', content: 'Hi there! How can we help you today?' }
854        ];
855        let isLoading = false;
856        let showContactForm = false;
857        let limitReached = false;
858        let apiCost = 0;
859        const maxCost = 0.5;
860        const maxQuestionLength = 250;
861
862        // Private element references
863        let $chatbotToggle;
864        let $chatWindow;
865        let $contactFormWindow;
866        let $closeChat;
867        let $closeContactForm;
868        let $chatMessages;
869        let $chatForm;
870        let $chatInput;
871        let $sendMessage;
872        let $characterCount;
873        let $costDisplay;
874        let $percentageDisplay;
875        let $costProgress;
876        let $contactForm;
877
878        // Initialize element references
879        function initializeElements() {
880            $chatbotToggle = $('#chatbot-toggle');
881            $chatWindow = $('#chat-window');
882            $contactFormWindow = $('#contact-form-window');
883            $closeChat = $('#close-chat');
884            $closeContactForm = $('#close-contact-form');
885            $chatMessages = $('#chat-messages');
886            $chatForm = $('#chat-form');
887            $chatInput = $('#chat-input');
888            $sendMessage = $('#send-message');
889            $characterCount = $('#character-count');
890            $costDisplay = $('#cost-display');
891            $percentageDisplay = $('#percentage-display');
892            $costProgress = $('#cost-progress');
893            $contactForm = $('#chatbot-contact-form');
894        }
895
896        // Initialize
897        function init() {
898            // Initialize element references
899            initializeElements();
900
901            // Load cost from localStorage
902            const savedCost = localStorage.getItem('api_cost');
903            if (savedCost) {
904                apiCost = parseFloat(savedCost);
905
906                // Check if cost limit is reached
907                if (apiCost >= maxCost) {
908                    limitReached = true;
909                    updateChatInputState();
910                }
911            }
912
913            // Initialize character count display
914            updateCharacterCount();
915
916            document.documentElement.style.setProperty('--adaptive-text-color', '#374151');
917            document.documentElement.style.setProperty('--image-invert', 'none');
918
919            setTimeout(updateTextColors, 100);
920
921            // Ensure chatbot stays on top even when modals are opened
922            $(document).on('shown.bs.modal', function (e) {
923              // Temporarily boost chatbot z-index when modals are shown
924              $('.chatbot-toggle-container').css('z-index', '2147483647');
925              $('#chat-window').css('z-index', '2147483646');
926              $('#contact-form-window').css('z-index', '2147483645');
927            });
928
929            // Set up event listeners
930            setupEventListeners();
931        }
932
933        // Event Listeners with namespacing
934        function setupEventListeners() {
935            // Remove any existing chatbot event listeners to prevent duplicates
936            $chatbotToggle.off('.chatbot');
937            $closeChat.off('.chatbot');
938            $closeContactForm.off('.chatbot');
939            $chatForm.off('.chatbot');
940            $chatInput.off('.chatbot');
941            $contactForm.off('.chatbot');
942
943            // Toggle chat window
944            $chatbotToggle.on('click.chatbot', function(e) {
945                e.preventDefault();
946                e.stopPropagation();
947                toggleChat();
948            });
949
950            $closeChat.on('click.chatbot', function(e) {
951                e.preventDefault();
952                e.stopPropagation();
953                closeChat();
954            });
955
956            $closeContactForm.on('click.chatbot', function(e) {
957                e.preventDefault();
958                e.stopPropagation();
959                hideContactForm();
960            });
961
962            // Send message
963            $chatForm.on('submit.chatbot', function (e) {
964                e.preventDefault();
965                e.stopPropagation();
966
967                // Check if submit button is disabled
968                if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) {
969                    return false;
970                }
971
972                sendMessage();
973            });
974
975            // Character count - update on every keystroke
976            $chatInput.on('input.chatbot', function(e) {
977                // Only handle if this is specifically the chatbot input
978                if ($(this).attr('id') === 'chat-input') {
979                    updateCharacterCount();
980                }
981            });
982
983            // Also check on keyup to catch paste events
984            $chatInput.on('keyup.chatbot paste.chatbot', function(e) {
985                // Only handle if this is specifically the chatbot input
986                if ($(this).attr('id') === 'chat-input') {
987                    setTimeout(updateCharacterCount, 10);
988                }
989            });
990
991            // Handle "Enter" key for sending messages
992            $chatInput.on('keydown.chatbot', function (e) {
993                // Only handle if this is specifically the chatbot input
994                if ($(this).attr('id') !== 'chat-input') {
995                    return;
996                }
997
998                if (e.key === 'Enter' && !e.shiftKey && !limitReached) {
999                    e.preventDefault();
1000                    e.stopImmediatePropagation();
1001
1002                    // Check if submit button is disabled
1003                    if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) {
1004                        return false;
1005                    }
1006
1007                    sendMessage();
1008                    return;
1009                }
1010            });
1011
1012            // Contact form submission
1013            $contactForm.on('submit.chatbot', function (e) {
1014                e.preventDefault();
1015                e.stopPropagation();
1016                submitContactForm();
1017            });
1018        }
1019
1020        // Toggle chat window
1021      function toggleChat() {
1022        if (!isOpen) {
1023          // Opening the chat
1024          isOpen = true;
1025
1026          // Hide toggle button on both mobile and desktop
1027          $('.chatbot-toggle-container').addClass('hide-toggle');
1028
1029          // First show the window (still off-screen)
1030          $chatWindow.show();
1031
1032          // Force a reflow to ensure the transition will work
1033          $chatWindow[0].offsetHeight;
1034
1035          // Then add the class that triggers the slide-in animation
1036          setTimeout(function () {
1037            $chatWindow.addClass('show');
1038            scrollToBottom();
1039          }, 10);
1040        } else {
1041          // Closing the chat
1042          isOpen = false;
1043
1044          // Show toggle button again
1045          $('.chatbot-toggle-container').removeClass('hide-toggle');
1046
1047          // Remove the show class to trigger slide-out animation
1048          $chatWindow.removeClass('show');
1049
1050          // Hide the window after the animation completes
1051          setTimeout(function () {
1052            $chatWindow.hide();
1053          }, 300); // Match the CSS transition duration
1054
1055          // Also hide contact form if open
1056          if (contactFormOpen) {
1057            hideContactForm();
1058          }
1059        }
1060      }
1061
1062        // Close chat window
1063      function closeChat() {
1064        if (isOpen) {
1065          isOpen = false;
1066
1067          // Show toggle button again
1068          $('.chatbot-toggle-container').removeClass('hide-toggle');
1069
1070          // Trigger slide-out animation
1071          $chatWindow.removeClass('show');
1072
1073          // Hide after animation
1074          setTimeout(function () {
1075            $chatWindow.hide();
1076          }, 300);
1077
1078          if (contactFormOpen) {
1079            hideContactForm();
1080          }
1081        }
1082      }
1083
1084        // Update character count and submit button state
1085        function updateCharacterCount() {
1086            const count = $chatInput.val().length;
1087            const remaining = maxQuestionLength - count;
1088            const $limitMessage = $('#character-limit-message');
1089
1090            if (count > maxQuestionLength) {
1091                // Over limit - disable submit button and show message
1092                $characterCount.text(`${count}/${maxQuestionLength} (${Math.abs(remaining)} over limit)`).css('color', '#dc2626');
1093                $limitMessage.text(`Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${count} characters.`).show();
1094                $chatInput.addClass('over-limit');
1095
1096                // Disable submit button with proper styling
1097                $sendMessage.prop('disabled', true).addClass('disabled');
1098                $sendMessage.css({
1099                    'background-color': '#9ca3af',
1100                    'color': '#6b7280',
1101                    'cursor': 'not-allowed',
1102                    'opacity': '0.5',
1103                    'pointer-events': 'none'
1104                });
1105
1106            } else if (remaining <= 20) {
1107                // Close to limit - show warning but allow submit
1108                $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#f59e0b');
1109                $limitMessage.hide();
1110                $chatInput.removeClass('over-limit');
1111
1112                // Enable submit button and reset styling
1113                $sendMessage.prop('disabled', false).removeClass('disabled');
1114                $sendMessage.css({
1115                    'background-color': '',
1116                    'color': '',
1117                    'cursor': '',
1118                    'opacity': '',
1119                    'pointer-events': ''
1120                });
1121
1122            } else {
1123                // Within limit - normal state
1124                $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#6b7280');
1125                $limitMessage.hide();
1126                $chatInput.removeClass('over-limit');
1127
1128                // Enable submit button and reset styling
1129                $sendMessage.prop('disabled', false).removeClass('disabled');
1130                $sendMessage.css({
1131                    'background-color': '',
1132                    'color': '',
1133                    'cursor': '',
1134                    'opacity': '',
1135                    'pointer-events': ''
1136                });
1137            }
1138        }
1139
1140        // Send message
1141        function sendMessage() {
1142            const message = $chatInput.val().trim();
1143            if (!message || isLoading || limitReached) return;
1144
1145            // Double check character limit including whitespace
1146            if (message.length > maxQuestionLength) {
1147                appendMessage('assistant', `Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${message.length} characters.`);
1148                return;
1149            }
1150
1151            // Add user message to chat
1152            messages.push({ role: 'user', content: message });
1153            appendMessage('user', message);
1154
1155            // Clear input
1156            $chatInput.val('');
1157            updateCharacterCount();
1158
1159            // Send to API
1160            fetchChatResponse(messages);
1161        }
1162
1163        // Fetch chat response from API
1164        function fetchChatResponse(messages) {
1165            isLoading = true;
1166            showLoadingIndicator();
1167
1168            $.ajax({
1169                url: '/Home/Chat',
1170                type: 'POST',
1171                contentType: 'application/json',
1172                data: JSON.stringify({
1173                    Messages: messages,
1174                    ProfileId: '40420'
1175                }),
1176                headers: {
1177                    'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val()
1178                },
1179                success: function (response) {
1180                    hideLoadingIndicator();
1181
1182                    if (response.error) {
1183                        appendMessage('assistant', `Error: ${response.error}`);
1184                        console.error('API Error:', response.error);
1185                        isLoading = false;
1186                        return;
1187                    }
1188
1189                    // Update cost
1190                    apiCost = response.Cost;
1191                    localStorage.setItem('api_cost', apiCost.toString());
1192
1193                    // Check if limit reached
1194                    if (response.LimitReached) {
1195                        limitReached = true;
1196                        showContactFormWindow();
1197                        appendMessage('assistant', 'Our AI chat has reached its capacity. Please use the contact form to get in touch directly with us.');
1198                    } else {
1199                        // Check if response contains contact form trigger
1200                        if (response.Message.includes('<start_contact_form>')) {
1201                            const cleanResponse = response.Message.replace('<start_contact_form>', '');
1202                            appendMessage('assistant', cleanResponse);
1203                            showContactFormWindow();
1204                        } else {
1205                            appendMessage('assistant', response.Message);
1206                        }
1207
1208                        // Add response to messages array
1209                        messages.push({ role: 'assistant', content: response.Message });
1210                    }
1211
1212                    isLoading = false;
1213                    updateChatInputState();
1214                },
1215                error: function (xhr, status, error) {
1216                    hideLoadingIndicator();
1217                    appendMessage('assistant', 'Sorry, I encountered an error. Please try again later.');
1218                    console.error('AJAX Error:', error);
1219                    isLoading = false;
1220                }
1221            });
1222        }
1223
1224        // Append message to chat
1225        function appendMessage(role, content) {
1226            content = convertMarkdownLinksToHTML(content);
1227            const rootStyles = getComputedStyle(document.documentElement);
1228            const customerColor = rootStyles.getPropertyValue('--customer_color').trim();
1229            const adaptivefontColor = rootStyles.getPropertyValue('--adaptive-text-color').trim();
1230
1231            const messageClass = role === 'user' ? 'flex-end' : 'flex-start';
1232            const bgColor = role === 'user' ? customerColor : 'white';
1233            const textColor = role === 'user' ? adaptivefontColor : '#374151';
1234            const borderRadius = role === 'user' ? 'border-bottom-right-radius: 0;' : 'border-bottom-left-radius: 0;';
1235            const border = role === 'user' ? '' : 'border: 1px solid #e5e7eb;';
1236
1237            const messageHtml = `
1238                <div style="display: flex; justify-content: ${messageClass}; margin-bottom: 16px;">
1239                    <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: ${bgColor}; ${border} ${borderRadius} color: ${textColor}; word-wrap: break-word; overflow-wrap: break-word;">
1240                        ${content}
1241                    </div>
1242                </div>
1243            `;
1244
1245            $chatMessages.append(messageHtml);
1246            scrollToBottom();
1247        }
1248
1249        // Show loading indicator
1250        function showLoadingIndicator() {
1251            const loadingHtml = `
1252                <div id="loading-indicator" style="display: flex; justify-content: flex-start; margin-bottom: 16px;">
1253                    <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: white; border: 1px solid #e5e7eb; color: #374151; display: flex; gap: 4px;">
1254                        <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div>
1255                        <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div>
1256                        <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div>
1257                    </div>
1258                </div>
1259            `;
1260
1261            $chatMessages.append(loadingHtml);
1262            animateLoadingDots();
1263            scrollToBottom();
1264
1265            // Disable input while loading
1266            $chatInput.prop('disabled', true);
1267            $sendMessage.prop('disabled', true);
1268        }
1269
1270        // Animate loading dots
1271        function animateLoadingDots() {
1272            if (!$("#loading-indicator").length) return;
1273
1274            $(".loading-dot").each(function (index) {
1275                var $dot = $(this);
1276                setTimeout(function () {
1277                    $dot.animate({ opacity: 0.3 }, 300)
1278                        .animate({ opacity: 1 }, 300);
1279                }, index * 200);
1280            });
1281
1282            setTimeout(function () {
1283                animateLoadingDots();
1284            }, 900);
1285        }
1286
1287        // Hide loading indicator
1288        function hideLoadingIndicator() {
1289            $('#loading-indicator').remove();
1290
1291            // Enable input after loading (unless limit reached)
1292            if (!limitReached) {
1293                $chatInput.prop('disabled', false);
1294                updateCharacterCount(); // This will set the correct submit button state
1295            }
1296        }
1297
1298        // Scroll to bottom of chat
1299        function scrollToBottom() {
1300            $chatMessages.scrollTop($chatMessages[0].scrollHeight);
1301        }
1302
1303        // Update cost display
1304        function updateCostDisplay() {
1305            $("#cost-info").show();
1306            $costDisplay.text(`Cost: $${apiCost.toFixed(5)}`);
1307
1308            const percentage = (apiCost / maxCost) * 100;
1309            $percentageDisplay.text(`${percentage.toFixed(1)}% of $${maxCost.toFixed(2)}`);
1310
1311            $costProgress.css('width', `${percentage}%`);
1312
1313            // Change progress bar color if near limit
1314            if (percentage > 80) {
1315                $costProgress.css("background-color", "#dc2626");
1316            } else {
1317                $costProgress.css("background-color", "#4f46e5");
1318            }
1319
1320            // Update chat input state
1321            updateChatInputState();
1322        }
1323
1324        // Update chat input state based on limit
1325        function updateChatInputState() {
1326            if (limitReached) {
1327                $chatInput.prop('disabled', true);
1328                $sendMessage.prop('disabled', true);
1329                $chatInput.attr('placeholder', 'Chat Unavailable.');
1330            } else {
1331                $chatInput.prop('disabled', false);
1332                updateCharacterCount(); // This will set the correct submit button state
1333                $chatInput.attr('placeholder', 'Type your message...');
1334            }
1335        }
1336
1337        // Show contact form
1338      function showContactFormWindow() {
1339        if (!contactFormOpen) {
1340          contactFormOpen = true;
1341
1342          // Hide toggle button when contact form opens
1343          $('.chatbot-toggle-container').addClass('hide-toggle');
1344
1345          if (isMobile()) {
1346            // On mobile, slide out chat and slide in contact form
1347            $chatWindow.removeClass('show');
1348            setTimeout(function () {
1349              $chatWindow.hide();
1350              $contactFormWindow.show();
1351              // Force reflow
1352              $contactFormWindow[0].offsetHeight;
1353              // Add show class for slide animation
1354              setTimeout(function () {
1355                $contactFormWindow.addClass('show');
1356                $('.contact-form-content').scrollTop(0);
1357              }, 10);
1358            }, 300);
1359          } else {
1360            // Desktop - slide chat to left and slide in contact form
1361            $chatWindow.animate({ right: '390px' }, 300);
1362            $contactFormWindow.show();
1363            setTimeout(function () {
1364              $contactFormWindow.animate({ right: '20px' }, 300);
1365            }, 50);
1366          }
1367        }
1368      }
1369
1370      // Hide contact form - slides out and chat returns to original position
1371      function hideContactForm() {
1372        if (contactFormOpen) {
1373          contactFormOpen = false;
1374
1375          if (isMobile()) {
1376            // Slide out contact form
1377            $contactFormWindow.removeClass('show');
1378
1379            setTimeout(function () {
1380              $contactFormWindow.hide();
1381              // Show chat window again if it was open
1382              if (isOpen) {
1383                $chatWindow.show();
1384                // Force reflow
1385                $chatWindow[0].offsetHeight;
1386                setTimeout(function () {
1387                  $chatWindow.addClass('show');
1388                }, 10);
1389              } else {
1390                // If chat is not open, show toggle button
1391                $('.chatbot-toggle-container').removeClass('hide-toggle');
1392              }
1393            }, 300);
1394          } else {
1395            // Desktop - animate back
1396            $contactFormWindow.animate({ right: '-370px' }, 300, function () {
1397              $contactFormWindow.hide();
1398            });
1399            $chatWindow.animate({ right: '20px' }, 300);
1400
1401            // Only show toggle if both windows are closed
1402            if (!isOpen) {
1403              $('.chatbot-toggle-container').removeClass('hide-toggle');
1404            }
1405          }
1406        }
1407      }
1408
1409      // Submit contact form
1410        function submitContactForm() {
1411            const name = $('#chat_contactName').val();
1412            const email = $('#chat_contactEmail').val();
1413            const phone = $('#chat_contactPhone').val();
1414            const message = $('#chat_contactMessage').val();
1415
1416            // Basic validation
1417            if (!name || !email || !message) {
1418                alert('Please fill out all required fields.');
1419                return;
1420            }
1421
1422            // Email validation
1423            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1424            if (!emailRegex.test(email)) {
1425                alert('Please enter a valid email address.');
1426                return;
1427            }
1428
1429            // Message length validation
1430            if (message.length < 10) {
1431                alert('Your message must be at least 10 characters long.');
1432                return;
1433            }
1434
1435            // Disable form during submission
1436            $('#contact-submit-btn').prop('disabled', true).text('Sending...');
1437
1438            var form = $("#chatbot-contact-form");
1439
1440            // Execute reCAPTCHA before submitting
1441            grecaptcha.ready(function() {
1442                grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) {
1443                    // Set the reCAPTCHA token
1444                    $("#chat_g-Recaptcha-Response-Contact").val(token);
1445
1446                    // Submit the form with reCAPTCHA token
1447                    $.ajax({
1448                        url: "/Home/ChatContactPost",
1449                        type: 'POST',
1450                        data: form.serialize(),
1451                        success: function (response) {
1452                            if (typeof response === 'string' && response.indexOf('{"message":') != -1) {
1453                                var jsonData = JSON.parse(response);
1454                                if (jsonData.success) {
1455                                    appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.');
1456                                    hideContactForm();
1457
1458                                    // Reset the form
1459                                    $('#chat_contactName').val('');
1460                                    $('#chat_contactEmail').val('');
1461                                    $('#chat_contactPhone').val('');
1462                                    $('#chat_contactMessage').val('');
1463                                } else {
1464                                    alert(jsonData.message || 'There was an error processing your request.');
1465                                }
1466                            } else if (response.success) {
1467                                appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.');
1468                                hideContactForm();
1469
1470                                // Reset the form
1471                                $('#chat_contactName').val('');
1472                                $('#chat_contactEmail').val('');
1473                                $('#chat_contactPhone').val('');
1474                                $('#chat_contactMessage').val('');
1475
1476                            } else {
1477                                alert(response.message || 'There was an error processing your request.');
1478                            }
1479
1480                            $('#contact-submit-btn').prop('disabled', false).text('Submit');
1481                        },
1482                        error: function (xhr, status, error) {
1483                            alert('Failed to submit your information. Please try again.');
1484                            console.error('AJAX Error:', error);
1485                            $('#contact-submit-btn').prop('disabled', false).text('Submit');
1486                        }
1487                    });
1488                });
1489            });
1490        }
1491
1492        function convertMarkdownLinksToHTML(text) {
1493            return text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => {
1494                // Add target="_blank" for http/https links
1495                if (url.startsWith('http://') || url.startsWith('https://')) {
1496                    return `<a href="${url}" target="_blank" rel="noopener noreferrer">${linkText}</a>`;
1497                }
1498                // Keep tel: and mailto: links as-is
1499                return `<a href="${url}">${linkText}</a>`;
1500            });
1501        }
1502
1503        function getLuminance(hex) {
1504            // Remove # if present
1505            hex = hex.replace('#', '');
1506
1507            // Convert hex to RGB
1508            const r = parseInt(hex.substr(0, 2), 16) / 255;
1509            const g = parseInt(hex.substr(2, 2), 16) / 255;
1510            const b = parseInt(hex.substr(4, 2), 16) / 255;
1511
1512            // Calculate relative luminance
1513            const rLum = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
1514            const gLum = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
1515            const bLum = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
1516
1517            return 0.2126 * rLum + 0.7152 * gLum + 0.0722 * bLum;
1518        }
1519
1520        function isLightColor(hex) {
1521            const luminance = getLuminance(hex);
1522            return luminance > 0.5; // Threshold for light vs dark
1523        }
1524
1525        function updateTextColors() {
1526            const rootStyles = getComputedStyle(document.documentElement);
1527            let customerColor = rootStyles.getPropertyValue('--customer_color').trim();
1528
1529            // Check if customer color is not set or is empty
1530            if (!customerColor || customerColor === '') {
1531                const defaultColor = '#f3f3f3';
1532
1533                // Set the default customer color
1534                document.documentElement.style.setProperty('--customer_color', defaultColor);
1535                customerColor = defaultColor;
1536            }
1537
1538            const isLight = isLightColor(customerColor);
1539            const textColor = isLight ? '#000000b3' : '#ffffff';
1540
1541            const $chatbotToggle = $('#chatbot-toggle');
1542            if (isLight) {
1543                $chatbotToggle.removeClass('dark-background').addClass('light-background');
1544            } else {
1545                $chatbotToggle.removeClass('light-background').addClass('dark-background');
1546            }
1547
1548            // Update the CSS custom property
1549            document.documentElement.style.setProperty('--adaptive-text-color', textColor);
1550        }
1551
1552        function isMobile() {
1553            return window.innerWidth <= 768;
1554        }
1555
1556        // Public interface
1557        return {
1558            init: init
1559        };
1560    })();
1561
1562    // Initialize the chatbot module when document is ready
1563    $(document).ready(function () {
1564        if (window.ChatbotModule) {
1565            window.ChatbotModule.init();
1566        }
1567    });
1568</script>
1568
1569<div id="loadingImg" class="loader" style="display:none !important">
1570    <i class="fas fa-circle"></i>
1571    <i class="fas fa-circle"></i>
1572    <i class="fas fa-circle"></i>
1573</div>
1574
1575<script type="text/javascript">
1576    var isMobile = false;
1577    var isTablet = false;
1578    var itemsVisible = false; // false indicates that items are initially hidden
1579    var pageSize = 5;
1580    var pageIndex = 0;
1581    var hasbanner = false;
1582    var keepPostUp = false;
1583    var listOfSites = "";
1584    var testimonialPageBackgroundColor = '#4DCCAA';
1585    var numOfPosts = 25;
1586    var postsPageIndex = 0;
1587    var geocode = null;
1588    var selectedServiceId = null;
1589    var servicesRendered = false;
1590    var aboutRendered = false;
1591    var testimonialsRendered = false;
1592    var contactRendered = false;
1593    var photosRendered = false;
1594    var faqRendered = false;
1595    var locationsRendered = false;
1596    var additionalContentRendered = false;
1597    var isSubmittingReview = false; //global flag to track submission
1598
1599    $(document).ready(function () {
1600         if ($("#contact_us_phone").length > 0) {
1601            var cleave = new Cleave('#contact_us_phone', {
1602                phone: true,
1603                phoneRegionCode: 'US'
1604            });
1605        }
1606
1607        checkMobile();
1608        checkTablet();
1609        checkHashRoute();
1610        PauseVideoPlayer();
1611
1612         if(hasbanner){
1613            GetPostsBanner();
1614        }
1615
1616        $(window).on('hashchange', function(){
1617            checkHashRoute();
1618        });
1619
1620        var navMain = $("#navbarToggler");
1621        navMain.on("click", "a", null, function () {
1622            navMain.collapse('hide');
1623        });
1624
1625        document.addEventListener("visibilitychange", function () {
1626            if (document["hidden"]) {
1627                PauseVideoPlayer();
1628            }
1629        });
1630
1631        $(window).scroll(function () {
1632            var scroll = $(window).scrollTop();
1633            if (('False' == 'False') || ('False' == 'True' && window.outerWidth > 767.98)) {
1634                if (scroll > 150){
1635                    $(".content").addClass("page-section-adjust");
1636                    $(".nav-logo").addClass("nav-logo-adjust");
1637                    $(".nav-location").addClass("nav-item-adjust");
1638                }
1639                else if(scroll <= 150){
1640                    $(".content").removeClass("page-section-adjust");
1641                    $(".nav-logo").removeClass("nav-logo-adjust");
1642                    $(".nav-location").removeClass("nav-item-adjust");
1643                }
1644            }
1645        });
1646
1647        $(document).on("click", "#btnContactPost", function (e) {
1648            $("#btnContactPost").prop('disabled', true);
1649            $("#btnContactPost").css('font-weight', 'normal');
1650            contactUsPost(e);
1651        });
1652
1653        var analyticsCategory = "Desktop";
1654        if (isMobile == true) {
1655            analyticsCategory = "Mobile";
1656            if ($(window).width() < 576) {
1657                if ($("#headernav").hasClass('justify-content-between')) {
1658                    $("#headernav").removeClass('justify-content-between');
1659                }
1660                if (!$("#headernav").hasClass('justify-content-center')) {
1661                    $("#headernav").addClass('justify-content-center');
1662                }
1663                if ($("#footer-address").hasClass('justify-content-center')) {
1664                    $("#footer-address").removeClass('justify-content-center');
1665                }
1666                if ($("#footer-hours").hasClass('justify-content-center')) {
1667                    $("#footer-hours").removeClass('justify-content-center');
1668                }
1669                if ($("#footer-sitenav").hasClass('justify-content-center')) {
1670                    $("#footer-sitenav").removeClass('justify-content-center');
1671                }
1672            }
1673        }
1674
1675        if (testimonialPageBackgroundColor != null && testimonialPageBackgroundColor != '' && testimonialPageBackgroundColor != "#F5F5F5") {
1676            //set footer background color
1677            $('.custom-background-color').css('background-color', testimonialPageBackgroundColor);
1678        }
1679        else {
1680            //set footer background color to white
1681            var white = "#FFFFFF";
1682            $('.custom-background-color').css('background-color', white);
1683        }
1684
1685        $("#HomePageNavigationLink").click(function(e){
1686            $('html, body').animate({ scrollTop: 0 }, 'fast');
1687        });
1688
1689        $(".business-name").click(function(e){
1690            $('html, body').animate({ scrollTop: 0 }, 'fast');
1691        });
1692
1693        if(numOfPosts > 0){
1694            GetPostsData(0);
1695        }
1696
1697        $(document).on('click', "#nextPosts", function (e) {
1698            ScrollForPosts(e);
1699            GetPostsData(1);
1700        });
1701
1702        $(document).on('click', "#prevPosts", function (e) {
1703            ScrollForPosts(e);
1704            GetPostsData(-1);
1705        });
1706
1707        $(document).on('click', "#postReview", function (e) {
1708            e.preventDefault();
1709            e.stopPropagation();
1710
1711            if (isSubmittingReview) {
1712                console.log('Review submission already in progress - blocking duplicate submission');
1713                return false;
1714            }
1715
1716            var $button = $(this);
1717            var $form = $("#postReviewForm");
1718            var $modal = $("#reviewFormSection");
1719
1720            isSubmittingReview = true;
1721            console.log('Starting review submission');
1722
1723            setProcessingState($button, $form, true);
1724
1725            var alertType = "success";
1726
1727            if(validateReview("#postReview")) {
1728                console.log('Review validation passed');
1729                ShowLoading();
1730
1731                grecaptcha.ready(function() {
1732                    grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'testimonial_review'}).then(function(token) {
1733                        $("#g-Recaptcha-Response-Review").attr("value", token);
1734
1735                        var rating = null;
1736                        var selectElement = document.getElementById('starRating');
1737                        var selectRating = selectElement ? selectElement.value : null;
1738                        var selectedOption = $('#starRating option:selected').val();
1739                        var barRating = null;
1740                        var reviewerAlias = $('#review_alias').val() || '';
1741                        var reviewHeading = $('#review_heading').val() || '';
1742                        var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
1743                        var recaptchaToken = $('#g-Recaptcha-Response-Review').val();
1744                        var timeToPost = $('#phoneNumber_alternative').val();
1745
1746                        var reviewText = $('#review').val() || '';
1747                        var profileId = 40420;
1748
1749                        console.log('Trying to get rating value...');
1750
1751                        var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null;
1752                        console.log('Select element direct value:', selectRating);
1753
1754                        var jqueryRating = $('#starRating').val();
1755                        console.log('jQuery val() result:', jqueryRating, typeof jqueryRating);
1756
1757                        if (typeof $('#starRating').barrating === 'function') {
1758                            try {
1759                                var barResult = $('#starRating').barrating('show');
1760
1761                                if (barResult && typeof barResult === 'string') {
1762                                    barRating = barResult;
1763                                } else if (barResult && typeof barResult === 'number') {
1764                                    barRating = barResult.toString();
1765                                }
1766                            } catch (e) {
1767                                console.log('Error getting barrating value:', e);
1768                            }
1769                        }
1770
1771                        var selectedOption = $('#starRating option:selected').val();
1772                        console.log('Selected option value:', selectedOption);
1773
1774                        var jqueryResult = $('#starRating').val();
1775                        var jqueryRating = null;
1776
1777                        if (jqueryResult && typeof jqueryResult === 'string') {
1778                            jqueryRating = jqueryResult;
1779                        } else if (jqueryResult && typeof jqueryResult === 'number') {
1780                            jqueryRating = jqueryResult.toString();
1781                        }
1782
1783                        if (barRating && barRating !== "" && barRating !== "0") {
1784                            rating = barRating;
1785                        } else if (selectRating && selectRating !== "" && selectRating !== "0") {
1786                            rating = selectRating;
1787                        } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") {
1788                            rating = selectedOption;
1789                        } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") {
1790                            rating = jqueryRating;
1791                        }
1792
1793                        if (rating && typeof rating !== 'string') {
1794                            console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
1795                            rating = String(rating);
1796                        }
1797
1798                        if (rating && typeof rating === 'object') {
1799                            console.error('CRITICAL ERROR: Rating is still an object!', rating);
1800                            rating = null;
1801                        }
1802
1803                        console.log('Validation check - rating found:', rating, typeof rating);
1804                        console.log('Final rating value:', rating, typeof rating);
1805
1806                        console.log('Form values before sending:');
1807                        console.log('- Review text:', reviewText);
1808                        console.log('- Rating:', rating);
1809                        console.log('- Profile ID:', profileId);
1810                        console.log('- Reviewer alias:', reviewerAlias);
1811                        console.log('- Review heading:', reviewHeading);
1812                        console.log('- Anti-forgery token:', antiForgeryToken ? 'Present' : 'Missing');
1813
1814                        // Build form data
1815                        var formDataArray = [
1816                            { name: 'profile_id', value: profileId },
1817                            { name: 'review', value: reviewText },
1818                            { name: 'review_rating', value: rating },
1819                            { name: 'reviewer_alias', value: reviewerAlias },
1820                            { name: 'review_heading', value: reviewHeading },
1821                            { name: '__RequestVerificationToken', value: antiForgeryToken },
1822                            { name: 'g-Recaptcha-Response-Review', value: recaptchaToken },
1823                            { name: 'phoneNumber_alternative', value: timeToPost },
1824                            { name: '_t', value: new Date().getTime() }
1825                        ];
1826
1827                        var formData = formDataArray
1828                            .filter(item => item.value !== undefined && item.value !== null && item.value !== '')
1829                            .map(item => encodeURIComponent(item.name) + '=' + encodeURIComponent(item.value))
1830                            .join('&');
1831
1832                        console.log('Manual form data built:', formData);
1833
1834                        $.ajax({
1835                            url: "/Home/ReviewPost",
1836                            type: "POST",
1837                            data: formData,
1838                            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
1839                            dataType: "json",
1840                            success: function(data) {
1841                                console.log('Review submission response:', data);
1842
1843                                if (!data.message || data.message.trim() === '') {
1844                                    data.message = data.success ?
1845                                        'Thank you for your review! It has been submitted successfully.' :
1846                                        'There was an issue submitting your review. Please check all fields and try again.';
1847                                }
1848
1849                                alertType = data.success ? "success" : "warning";
1850
1851                                if (!data.success) {
1852                                    recaptchaReviewIncomplete();
1853                                    showClassicCaptcha("review");
1854                                }
1855
1856                                $form.find('.alert').remove();
1857
1858                                var alertHtml = '<div class="alert alert-' + alertType + ' alert-dismissible" role="alert">' +
1859                                                '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
1860                                                '<span aria-hidden="true">&times;</span></button>' +
1861                                                data.message + '</div>';
1862
1863                                $form.prepend(alertHtml);
1864
1865                                $modal.find('.modal-body').scrollTop(0);
1866
1867                                if(alertType === "success") {
1868                                    // Auto-hide modal after showing success message
1869                                    setTimeout(function () {
1870                                        $modal.modal('hide');
1871                                        ClearReviewFields();
1872                                    }, 3000);
1873                                }
1874
1875                                // Fade out alert after delay
1876                                setTimeout(function() {
1877                                    $form.find('.alert').fadeOut(500, function() {
1878                                        $(this).remove();
1879                                    });
1880                                }, 6000);
1881                            },
1882                            error: function(xhr, status, error) {
1883                                console.error('AJAX Error:', status, error);
1884                                console.error('Response Text:', xhr.responseText);
1885
1886                                $form.find('.alert').remove();
1887                                var errorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">' +
1888                                                '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
1889                                                '<span aria-hidden="true">&times;</span></button>' +
1890                                                'An error occurred while submitting your review. Please try again.</div>';
1891                                $form.prepend(errorHtml);
1892
1893                                $modal.find('.modal-body').scrollTop(0);
1894                            },
1895                            complete: function() {
1896                                // Reset states
1897                                console.log('Resetting processing state');
1898                                setProcessingState($button, $form, false);
1899                                HideLoading();
1900                                isSubmittingReview = false;
1901                                console.log('Review submission completed');
1902                            }
1903                        });
1904
1905                    }).catch(function(error) {
1906                        console.error('reCAPTCHA Error:', error);
1907
1908                        $form.find('.alert').remove();
1909                        var captchaErrorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">
1909' +
1910                                                '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
1911                                                '<span aria-hidden="true">&times;</span></button>' +
1912                                                'Security verification failed. Please refresh the page and try again.</div>';
1913                        $form.prepend(captchaErrorHtml);
1914
1915                        $modal.find('.modal-body').scrollTop(0);
1916                        setProcessingState($button, $form, false);
1917                        HideLoading();
1918                        isSubmittingReview = false;
1919                    });
1920                });
1921            } else {
1922                console.log('Review validation failed');
1923
1924                var missingFields = [];
1925                if (!$('#review').val() || $('#review').val().trim() === '') {
1926                    missingFields.push('review text');
1927                }
1928
1929                var rating = null;
1930                var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null;
1931                var jqueryRating = $('#starRating').val();
1932                var selectedOption = $('#starRating option:selected').val();
1933                var barRating = null;
1934
1935                if (typeof $('#starRating').barrating === 'function') {
1936                    try {
1937                        barRating = $('#starRating').barrating('show');
1938                    } catch (e) {
1939                        // Ignore error
1940                    }
1941                }
1942
1943                if (barRating && barRating !== "" && barRating !== "0") {
1944                    rating = barRating;
1945                } else if (selectRating && selectRating !== "" && selectRating !== "0") {
1946                    rating = selectRating;
1947                } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") {
1948                    rating = selectedOption;
1949                } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") {
1950                    rating = jqueryRating;
1951                }
1952
1953                console.log('Validation check - rating found:', rating);
1954
1955                if (!rating || rating === "" || rating === "0") {
1956                    missingFields.push('rating');
1957                }
1958
1959                var validationMessage = 'Please fill out the following required fields: ' + missingFields.join(' and ') + '.';
1960                console.log('Validation message:', validationMessage);
1961
1962                $form.find('.alert').remove();
1963                var validationHtml = '<div class="alert alert-warning alert-dismissible" role="alert">' +
1964                                    '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
1965                                    '<span aria-hidden="true">&times;</span></button>' +
1966                                    validationMessage + '</div>';
1967                $form.prepend(validationHtml);
1968
1969                $modal.find('.modal-body').scrollTop(0);
1970                setProcessingState($button, $form, false);
1971                isSubmittingReview = false;
1972
1973                return false;
1974            }
1975        });
1976
1977        $('#reviewFormSection').on('hidden.bs.modal', function () {
1978            console.log('Modal hidden - resetting submission state');
1979            isSubmittingReview = false;
1980            setProcessingState($("#postReview"), $("#postReviewForm"), false);
1981            $(this).find('.alert').remove();
1982        });
1983
1984        $('#reviewFormSection').on('show.bs.modal', function () {
1985            console.log('Modal shown - ensuring clean state');
1986            isSubmittingReview = false;
1987            setProcessingState($("#postReview"), $("#postReviewForm"), false);
1988
1989            $("#postReview").prop('disabled', false);
1990            $("#postReview").css('font-weight', 'bold');
1991
1992            setTimeout(function () {
1993                console.log('=== STAR RATING DEBUG ===');
1994                console.log('Star rating element:', $('#starRating')[0]);
1995                console.log('Star rating jQuery object:', $('#starRating'));
1996                console.log('Star rating direct value:', $('#starRating')[0] ? $('#starRating')[0].value : 'N/A');
1997                console.log('Star rating jQuery val():', $('#starRating').val());
1998                console.log('Star rating selected option:', $('#starRating option:selected').val());
1999                console.log('Barrating plugin available:', typeof $('#starRating').barrating === 'function');
2000                if (typeof $('#starRating').barrating === 'function') {
2001                    try {
2002                        console.log('Barrating current value:', $('#starRating').barrating('show'));
2003                    } catch (e) {
2004                        console.log('Error getting barrating value:', e);
2005                    }
2006                }
2007                console.log('=== END STAR RATING DEBUG ===');
2008            }, 100);
2009        });
2010
2011        // Prevent modal from closing during submission
2012        $('#reviewFormSection').on('hide.bs.modal', function (e) {
2013            if (isSubmittingReview) {
2014                console.log('Preventing modal close during submission');
2015                e.preventDefault();
2016                return false;
2017            }
2018        });
2019
2020        $('a').on('click', function () {
2021            if (this.id !== "undefined" && this.id !== "") {
2022                gtag('event', 'Link Click', {
2023                    'event_category': analyticsCategory,
2024                    'event_label': this.id
2025                });
2026            }
2027        });
2028
2029        $('#PhoneNav').on('click', function () {
2030            gtag('event', 'Link Click', {
2031                'event_category': analyticsCategory,
2032                'event_label': "CustomerBusinessPhoneLinkPlatinum1"
2033            });
2034        });
2035        $('.phoneLinkInput').on('click', function () {
2036            gtag('event', 'Link Click', {
2037                'event_category': analyticsCategory,
2038                'event_label': "CustomerBusinessPhoneLinkPlatinum1-1"
2039            });
2040        });
2041        $('#contactPhoneLink').on('click', function () {
2042            gtag('event', 'Link Click', {
2043                'event_category': analyticsCategory,
2044                'event_label': "CustomerBusinessPhoneLinkPlatinum1-2"
2045            });
2046        });
2047        $('#contactPrimaryPhoneLink').on('click', function () {
2048            gtag('event', 'Link Click', {
2049                'event_category': analyticsCategory,
2050                'event_label': "CustomerBusinessPhoneLinkPlatinum1-3"
2051            });
2052        });
2053        $('#contactSecondaryPhoneLink').on('click', function () {
2054            gtag('event', 'Link Click', {
2055                'event_category': analyticsCategory,
2056                'event_label': "CustomerBusinessPhoneLinkPlatinum1-4"
2057            });
2058        });
2059        $('#contactMobilePhoneLink').on('click', function () {
2060            gtag('event', 'Link Click', {
2061                'event_category': analyticsCategory,
2062                'event_label': "CustomerBusinessPhoneLinkPlatinum1-5"
2063            });
2064        });
2065        $('#contactFaxPhoneLink').on('click', function () {
2066            gtag('event', 'Link Click', {
2067                'event_category': analyticsCategory,
2068                'event_label': "CustomerBusinessPhoneLinkPlatinum1-6"
2069            });
2070        });
2071        $('#contactTollfreePhoneLink').on('click', function () {
2072            gtag('event', 'Link Click', {
2073                'event_category': analyticsCategory,
2074                'event_label': "CustomerBusinessPhoneLinkPlatinum1-7"
2075            });
2076        });
2077        $('#contactPhoneC1').on('click', function () {
2078            gtag('event', 'Link Click', {
2079                'event_category': analyticsCategory,
2080                'event_label': "CustomerContactPhoneLinkPlatinum1-8"
2081            });
2082        });
2083        $('#contactPhoneC2').on('click', function () {
2084            gtag('event', 'Link Click', {
2085                'event_category': analyticsCategory,
2086                'event_label': "CustomerContactPhoneLinkPlatinum1-9"
2087            });
2088        });
2089        $('#contactPhoneC3').on('click', function () {
2090            gtag('event', 'Link Click', {
2091                'event_category': analyticsCategory,
2092                'event_label': "CustomerContactPhoneLinkPlatinum1-10"
2093            });
2094        });
2095        $('#contactPhoneC4').on('click', function () {
2096            gtag('event', 'Link Click', {
2097                'event_category': analyticsCategory,
2098                'event_label': "CustomerContactPhoneLinkPlatinum1-11"
2099            });
2100        });
2101        $('#contactPhoneC5').on('click', function () {
2102            gtag('event', 'Link Click', {
2103                'event_category': analyticsCategory,
2104                'event_label': "CustomerContactPhoneLinkPlatinum1-12"
2105            });
2106        });
2107        $('#contactEmail').on('click', function () {
2108            gtag('event', 'Link Click', {
2109                'event_category': analyticsCategory,
2110                'event_label': "CustomerBusinessEmailLinkPlatinum1"
2111            });
2112        });
2113        $('#writeReviewBt').on('click', function () {
2114            gtag('event', 'Button Click', {
2115                'event_category': analyticsCategory,
2116                'event_label': "WriteReviewButtonPlatinum1"
2117            });
2118        });
2119        $(document).on('click', '#postReview', function () {
2120            gtag('event', 'Button Click', {
2121                'event_category': analyticsCategory,
2122                'event_label': "PostReviewButtonPlatinum1"
2123            });
2124        });
2125        $('#nextReview').on('click', function () {
2126            gtag('event', 'Button Click', {
2127                'event_category': analyticsCategory,
2128                'event_label': "ShowNextReviewsButtonPlatinum1"
2129            });
2130        });
2131        $('#prevReview').on('click', function () {
2132            gtag('event', 'Button Click', {
2133                'event_category': analyticsCategory,
2134                'event_label': "ShowPreviousReviewsButtonPlatinum1"
2135            });
2136        });
2137        $('#google-social').on('click', function () {
2138            gtag('event', 'Link Click', {
2139                'event_category': analyticsCategory,
2140                'event_label': "CustomerGoogleSocialLinkPlatinum1-1"
2141            });
2142        });
2143        $('#facebook-social').on('click', function () {
2144            gtag('event', 'Link Click', {
2145                'event_category': analyticsCategory,
2146                'event_label': "CustomerFacebookSocialLinkPlatinum1-1"
2147            });
2148        });
2149        $('#yelp-social').on('click', function () {
2150            gtag('event', 'Link Click', {
2151                'event_category': analyticsCategory,
2152                'event_label': "CustomerYelpSocialLinkPlatinum1-1"
2153            });
2154        });
2155        $('#twitter-social').on('click', function () {
2156            gtag('event', 'Link Click', {
2157                'event_category': analyticsCategory,
2158                'event_label': "CustomerTwitterSocialLinkPlatinum1-1"
2159            });
2160        });
2161        $('#linkedin-social').on('click', function () {
2162            gtag('event', 'Link Click', {
2163                'event_category': analyticsCategory,
2164                'event_label': "CustomerLinkedinSocialLinkPlatinum1-1"
2165            });
2166        });
2167        $('#instagram-social').on('click', function () {
2168            gtag('event', 'Link Click', {
2169                'event_category': analyticsCategory,
2170                'event_label': "CustomerInstagramSocialLinkPlatinum1-1"
2171            });
2172        });
2173        $('#google-social-footer').on('click', function () {
2174            gtag('event', 'Link Click', {
2175                'event_category': analyticsCategory,
2176                'event_label': "CustomerGoogleSocialLinkPlatinum1-2"
2177            });
2178        });
2179        $('#facebook-social-footer').on('click', function () {
2180            gtag('event', 'Link Click', {
2181                'event_category': analyticsCategory,
2182                'event_label': "CustomerFacebookSocialLinkPlatinum1-2"
2183            });
2184        });
2185        $('#yelp-social-footer').on('click', function () {
2186            gtag('event', 'Link Click', {
2187                'event_category': analyticsCategory,
2188                'event_label': "CustomerYelpSocialLinkPlatinum1-2"
2189            });
2190        });
2191        $('#twitter-social-footer').on('click', function () {
2192            gtag('event', 'Link Click', {
2193                'event_category': analyticsCategory,
2194                'event_label': "CustomerTwitterSocialLinkPlatinum1-2"
2195            });
2196        });
2197        $('#linkedin-social-footer').on('click', function () {
2198            gtag('event', 'Link Click', {
2199                'event_category': analyticsCategory,
2200                'event_label': "CustomerLinkedinSocialLinkPlatinum1-2"
2201            });
2202        });
2203        $('#instagram-social-footer').on('click', function () {
2204            gtag('event', 'Link Click', {
2205                'event_category': analyticsCategory,
2206                'event_label': "CustomerInstagramSocialLinkPlatinum1-2"
2207            });
2208        });
2209        $('#contactEmailFooter').on('click', function () {
2210            gtag('event', 'Link Click', {
2211                'event_category': analyticsCategory,
2212                'event_label': "CustomerBusinessEmailLinkPlatinum1-2"
2213            });
2214        });
2215        $('#btnContactPost').on('click', function () {
2216            gtag('event', 'Link Click', {
2217                'event_category': analyticsCategory,
2218                'event_label': "CustomerContactLeadPostPlatinum1"
2219            });
2220        });
2221        $("#external-review-link").on('click', function () {
2222            gtag('event', 'Link Click', {
2223                'event_category': analyticsCategory,
2224                'event_label': "CustomerExternalReviewLinkPlatinum1"
2225            });
2226        });
2227        $('#video').on('click', function () {
2228            gtag('event', 'Video Click', {
2229                'event_category': analyticsCategory,
2230                'event_label': "CustomerVideoPlatinum1"
2231            });
2232        });
2233        $('#website-social').on('click', function () {
2234            gtag('event', 'Link Click', {
2235                'event_category': analyticsCategory,
2236                'event_label': "CustomerWebsiteSocialLinkPlatinum1-1"
2237            });
2238        });
2239        $('#website-social-footer').on('click', function () {
2240            gtag('event', 'Link Click', {
2241                'event_category': analyticsCategory,
2242                'event_label': "CustomerWebsiteSocialLinkPlatinum1-2"
2243            });
2244        });
2245        $('#accessibility-social-footer').on('click', function () {
2246            gtag('event', 'Link Click', {
2247                'event_category': analyticsCategory,
2248                'event_label': "CustomerWebsiteAccessibilityLinkPlatinum1"
2249            });
2250        });
2251        $('#photos-image-element').on('click', function () {
2252            gtag('event', 'Link Click', {
2253                'event_category': analyticsCategory,
2254                'event_label': "CustomerWebsiteImageryPhotoPlatinum1"
2255            });
2256        });
2257        $('#HomePageNavigationLink').on('click', function () {
2258            gtag('event', 'Link Click', {
2259                'event_category': analyticsCategory,
2260                'event_label': "CustomerHomePageNavLinkPlatinum1"
2261            });
2262        });
2263        $('#AccessibilityPageNavigationLink').on('click', function () {
2264            gtag('event', 'Link Click', {
2265                'event_category': analyticsCategory,
2266                'event_label': "CustomerAccessibilityPageNavLinkPlatinum1"
2267            });
2268        });
2269        $('#ContactPageNavigationLink').on('click', function () {
2270            gtag('event', 'Link Click', {
2271                'event_category': analyticsCategory,
2272                'event_label': "CustomerContactPageNavLinkPlatinum1"
2273            });
2274        });
2275        $('#PhotosNavigationLink').on('click', function () {
2276            gtag('event', 'Link Click', {
2277                'event_category': analyticsCategory,
2278                'event_label': "CustomerPhotosPageNavLinkPlatinum1"
2279            });
2280        });
2281        $('#testimoinalsPageNavigationLink').on('click', function () {
2282            gtag('event', 'Link Click', {
2283                'event_category': analyticsCategory,
2284                'event_label': "CustomerTestimonialsPageNavLinkPlatinum1"
2285            });
2286        });
2287        $('#ServicesPageNavigationLink').on('click', function () {
2288            gtag('event', 'Link Click', {
2289                'event_category': analyticsCategory,
2290                'event_label': "CustomerServicesPageNavLinkPlatinum1"
2291            });
2292        });
2293        $('#AboutPageNavigationLink').on('click', function () {
2294            gtag('event', 'Link Click', {
2295                'event_category': analyticsCategory,
2296                'event_label': "CustomerAboutPageNavLinkPlatinum1"
2297            });
2298        });
2299
2300         $(document).on('click', '.btn-link', function() {
2301             // Find the closest parent that includes both the button and the items to be toggled
2302             var $parentNav = $(this).closest('.navbar-attribute');
2303
2304             // Toggle the visibility of hidden items within this specific parent
2305             var $hiddenItems = $parentNav.find('.hidden-item');
2306             $hiddenItems.toggle();
2307
2308             // Find the arrow within the clicked button
2309             var $arrow = $(this).find('.arrow');
2310
2311             // Toggle arrow direction by switching classes
2312             if ($arrow.hasClass('arrow-down')) {
2313                 $arrow.removeClass('arrow-down').addClass('arrow-up');
2314             } else {
2315                 $arrow.removeClass('arrow-up').addClass('arrow-down');
2316             }
2317         });
2318
2319        $(document).on('click', '#photos-image-element1', function () {
2320            $('#selectedServiceId').val('service1');
2321            DisplayPage('#servicesPage');
2322        });
2323        $(document).on('click', '#photos-image-element2', function () {
2324            $('#selectedServiceId').val('service2');
2325            DisplayPage('#servicesPage');
2326        });
2327        $(document).on('click', '#photos-image-element3', function () {
2328            $('#selectedServiceId').val('service3');
2329            DisplayPage('#servicesPage');
2330        });
2331
2332        //unable to directly track cross domain iFrame clicks. Track only first click on the iFrame itself
2333        var monitor = setInterval(function () {
2334            var elem = document.activeElement;
2335            if (elem && elem.tagName == "IFRAME" && elem.id == "googleMapEmbed") {
2336                gtag('event', 'iFrame Click', {
2337                    'event_category': analyticsCategory,
2338                    'event_label': "GoogleDirectionsPlatinum1"
2339                });
2340                clearInterval(monitor);
2341            }
2342        }, 1000);
2343
2344        var navbarHeight = $('#headernav').outerHeight();  // Make sure this matches your navbar class
2345        document.documentElement.style.setProperty('--scroll-padding-top', navbarHeight + 'px');
2346    });
2347
2348    function scrollToService(serviceId) {
2349        var targetElement = document.getElementById(serviceId);
2350        if (targetElement) {
2351            var headerHeight = document.querySelector('#headernav').offsetHeight;
2352            var descriptionOffset = 165; // Adjust this value as needed
2353            var scrollPosition = targetElement.offsetTop - headerHeight - descriptionOffset;
2354
2355            window.scrollTo({
2356                top: scrollPosition,
2357                behavior: 'smooth'
2358            });
2359        } else {
2360            console.log('Service section element not found');
2361        }
2362    }
2363
2364    function DisplayPage(page, serviceId) {
2365        PauseVideoPlayer();
2366
2367        if (!$(page).hasClass("show")) {
2368            $("#pages div.collapse.show").collapse("hide");
2369        }
2370        $(page).collapse("show");
2371
2372        if(page == "#homePage")
2373        {
2374            var carousel = $(".slick-slider");
2375            if(carousel != null)
2376            {
2377                carousel.slick('refresh');
2378            }
2379        }
2380
2381        if (page == "#testimonialsPage") {
2382             // Load Testimonials via Ajax if not already loaded
2383            if (!testimonialsRendered) {
2384                ShowLoading();
2385                $.get('/Home/GetTestimonialsContent', { id: 40420, template: "Platinum_1"}, function (data) {
2386                    if (data != "")
2387                    {
2388                        $("#testimonialsPage").append(data);
2389                    }
2390                }).always(function() {
2391                    HideLoading();
2392                    testimonialsRendered = true;
2393                });
2394            }
2395
2396            $("html, body").animate({ scrollTop: 0 }, "fast");
2397        }
2398
2399        if (page == "#aboutPage") {
2400            // Load About via Ajax if not already loaded
2401            if (!aboutRendered) {
2402                ShowLoading();
2403                $.get('/Home/GetAboutContent', { id: 40420, template: "Platinum_1"}, function (data) {
2404                    if (data != "")
2405                    {
2406                        $("#aboutPage").append(data);
2407                        $.getScript("https://maps.googleapis.com/maps/api/js?key=AIzaSyB2UoPWVWPR8WrIFK_zqJ5nTN1NvGm9dqY&callback=initMap");
2408
2409                    }
2410                }).always(function() {
2411                    HideLoading();
2412                    aboutRendered = true;
2413                });
2414            }
2415        }
2416
2417        if (page === "#servicesPage")
2418        {
2419            // Load Services via Ajax if not already loaded
2420            if (!servicesRendered) {
2421                ShowLoading();
2422                $.get('/Home/GetServicesContent', { id: 40420, template: "Platinum_1" })
2423                    .done(function (data) {
2424                        if (data !== "") {
2425                            $("#servicesPage").append(data);
2426                            servicesRendered = true;
2427                            // Trigger the scroll after a short delay
2428                            setTimeout(function() {
2429                                var selectedServiceId = $('#selectedServiceId').val();
2430                                if (selectedServiceId) {
2431                                    scrollToService(selectedServiceId);
2432                                    $('#selectedServiceId').val('');
2433                                }
2434                            }, 300); // Adjust the delay as needed
2435                        }
2436                    })
2437                    .always(function () {
2438                        HideLoading();
2439                    });
2440            } else {
2441                // If the services are already rendered, trigger the scroll after a short delay
2442                setTimeout(function() {
2443                    var selectedServiceId = $('#selectedServiceId').val();
2444                    if (selectedServiceId) {
2445                        scrollToService(selectedServiceId);
2446                        $('#selectedServiceId').val('');
2447                    }
2448                }, 100); // Adjust the delay as needed
2449            }
2450        } else {
2451            window.scrollTo(0, 0);
2452        }
2453
2454        if (page == "#imageryPage") {
2455            // Load photos via Ajax if not already loaded
2456            if (!photosRendered) {
2457                ShowLoading();
2458                $.get('/Home/GetPhotosContent', { id: 40420, template: "Platinum_1"}, function (data) {
2459                    if (data != "")
2460                    {
2461                        $("#imageryPage").append(data);
2462                    }
2463                }).always(function() {
2464                    HideLoading();
2465                    photosRendered = true;
2466                });
2467            }
2468        }
2469
2470        if (page == "#contactPage") {
2471            // Load Contact via Ajax if not already loaded
2472            if (!contactRendered) {
2473                ShowLoading();
2474                $.get('/Home/GetContactContent', { id: 40420, template: "Platinum_1"}, function (data) {
2475                    if (data != "")
2476                    {
2477                        $("#contactPage").append(data);
2478                    }
2479                }).always(function() {
2480                    HideLoading();
2481                    contactRendered = true;
2482                });
2483            }
2484        }
2485
2486         if (page == "#locationsPage") {
2487            // Load Locations via Ajax if not already loaded
2488             if (!locationsRendered) {
2489                 ShowLoading();
2490
2491                 $.get('/Home/GetLocationsContent', { id: 40420, template: "Platinum_1" }, function (data) {
2492                     if (data != "")
2493                     {
2494                        $("#locationsPage").append(data);
2495                     }
2496                 }).always(function() {
2497                    HideLoading();
2498                    locationsRendered = true;
2499                 });
2500             }
2501        }
2502
2503        if (page == "#faqPage") {
2504            // Load Faqs via Ajax if not already loaded
2505            if (!faqRendered) {
2506                ShowLoading();
2507
2508                $.get('/Home/GetFAQContent', { id: 40420, template: "Platinum_1" }, function (data) {
2509                    if (data != "") {
2510                        $("#faqPage").append(data);
2511                    }
2512                }).always(function () {
2513                    HideLoading();
2514                    faqRendered = true;
2515                });
2516            }
2517        }
2518
2519        if (page == "#contentPage") {
2520            // Load Additional Content via Ajax if not already loaded
2521            if (!additionalContentRendered) {
2522                ShowLoading();
2523
2524                $.get('/Home/GetAdditionalContentContent', { id: 40420, template: "Platinum_1" }, function (data) {
2525                    if (data != "") {
2526                        $("#contentPage").append(data);
2527                    }
2528                }).always(function () {
2529                    HideLoading();
2530                    additionalContentRendered = true;
2531                });
2532            }
2533        }
2534    }
2535
2536    function PauseVideoPlayer() {
2537
2538        var videos = document.querySelectorAll('video');
2539        var iframes = document.querySelectorAll('iframe');
2540
2541        //mp4
2542        Array.prototype.forEach.call(videos, video => {
2543            video.pause();
2544        });
2545
2546        //youtube
2547        Array.prototype.forEach.call(iframes, iframe => {
2548            iframe.contentWindow.postMessage(JSON.stringify({
2549                event: 'command',
2550                func: 'pauseVideo'
2551            }), '*');
2552        });
2553
2554        //wistia + vimeo
2555        Array.prototype.forEach.call(iframes, iframe => {
2556            iframe.contentWindow.postMessage(JSON.stringify({
2557                "method": "pause",
2558                "value": "true"
2559            }), '*');
2560        });
2561    }
2562
2563    function GetPostsData(i)
2564    {
2565        if(i != 0){
2566            ShowLoading();
2567        }
2568        postsPageIndex = postsPageIndex + i;
2569        $.get('/Home/GetTestimonialPostsInfo', {id: 40420, program_id: 18, profileDomain: 'https://maryscleaningc
2569are.com/', subdomain: 'maryscleaningcare', testimonialSSL : 'False', domainSSL : 'True', pageIndex: postsPageIndex, pageSize: pageSize, file: '_TestimonialPostsContent'}, function (data) {
2570            if (data != "")
2571            {
2572                $(".postsInfo").html(data);
2573            }
2574        }).always(function() {
2575            HideLoading();
2576        });
2577        SetPostsPaginationButtons();
2578    }
2579
2580    function GetPostsBanner()
2581    {
2582        ShowLoading();
2583        var bannerObj = null;
2584        $.ajax({
2585            method: "POST",
2586            url: "/Home/GetPostBanner",
2587            data:JSON.stringify(
2588            {
2589                banner: bannerObj,
2590                testimonialPageColor: (false) ? 'transparent' :'',
2591                postsColor: '#ffffff'
2592            }),
2593            contentType: 'application/json',
2594            success: function (data) {
2595                var holdaspect = "";
2596                if ($("#homepagebanner").hasClass('aspect-ratio-16x9')) {
2597                    $('#homepagebanner').removeClass('aspect-ratio-16x9');
2598                    holdaspect = "aspect-ratio-16x9";
2599                }
2600
2601                if(isMobile || isTablet){
2602                    setTimeout(function(){
2603                        $(".home-content").prepend(data);
2604                    }, 5000);
2605                }
2606                else{
2607                    $(".home-content").prepend(data);
2608                }
2609
2610                $('#bannerclose').click(function() {
2611                    if (holdaspect != "") {
2612                        $('#homepagebanner').addClass('aspect-ratio-16x9');
2613                    }
2614                });
2615
2616                /*remove banner after 30 seconds regardless of mobile/tablet/desktop*/
2617                if (!keepPostUp) {
2618                    setTimeout(function () {
2619                        $("#posts-banner-alert").remove();
2620                        if (holdaspect != "" && !(isMobile || isTablet)) {
2621                            $('#homepagebanner').addClass('aspect-ratio-16x9');
2622                        }
2623                    }, 30000);
2624                }
2625            }
2626        }).always(function() {
2627            HideLoading();
2628            if (holdaspect != "" && !(isMobile || isTablet)) {
2629                $('#homepagebanner').addClass('aspect-ratio-16x9');
2630            }
2631        });
2632    }
2633
2634    function SetPostsPaginationButtons()
2635    {
2636        //look ahead by one
2637        if (((postsPageIndex + 1) * pageSize) >= numOfPosts) {
2638            $("#nextPosts").hide();
2639        }
2640        else {
2641            $("#nextPosts").show();
2642            $("#nextPosts").prop('disabled', false);
2643        }
2644
2645        if (postsPageIndex <= 0) {
2646            postsPageIndex = 0;
2647            $("#prevPosts").hide();
2648        }
2649        else if (postsPageIndex > 0) {
2650            $("#prevPosts").show();
2651            $("#prevPosts").prop('disabled', false);
2652        }
2653    }
2654
2655    function ShowLoading()
2656    {
2657        $("#loadingImg").show();
2658    }
2659
2660    function HideLoading()
2661    {
2662        $("#loadingImg").hide();
2663    }
2664
2665    function checkMobile() {
2666        var windowsize = $(window).width();
2667        switch (true) {
2668        case /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent):
2669            isMobile = true;
2670            break;
2671        case windowsize < 800:
2672            isMobile = true;
2673            break;
2674        default:
2675            isMobile = false;
2676      }
2677    }
2678
2679    function checkTablet() {
2680        var windowsize = $(window).width();
2681        switch (true) {
2682        case (windowsize >= 800) && (windowsize < 1200):
2683            isTablet = true;
2684            break;
2685        default:
2686            isTablet = false;
2687      }
2688    }
2689
2690    function checkHashRoute() {
2691        if ((location.hash != null) && (location.hash != "") && (location.hash == '#homePage' || location.hash == '#aboutPage' || location.hash == '#servicesPage' || location.hash == '#testimonialsPage' || location.hash == '#contactPage' || location.hash == '#locationsPage' || location.hash == '#faqPage' || location.hash == '#contentPage')) {
2692            DisplayPage(location.hash);
2693        }
2694    }
2695
2696  function contactUsPost(event) {
2697    var _contactForm = $("#ContactPostForm");
2698
2699    // Clear previous validation states
2700    $('.validation-error-message').remove();
2701    _contactForm.find('.validation-error').removeClass('validation-error');
2702    $("#contactResponseMessage").empty();
2703
2704    if (_contactForm[0].checkValidity()) {
2705      contactUsSubmit(event);
2706    } else {
2707      var firstInvalidField = null;
2708
2709      _contactForm.find('input[required], textarea[required], select[required]').each(function () {
2710        var $field = $(this);
2711
2712        if (!this.checkValidity()) {
2713          var fieldId = $field.attr('id') || $field.attr('name');
2714          var fieldLabel = getFieldLabel(fieldId);
2715
2716          $field.addClass('validation-error');
2717
2718          var errorMessage = getCustomErrorMessage($field, fieldLabel);
2719          $field.after(`<div class="validation-error-message">${errorMessage}</div>`);
2720
2721          if (!firstInvalidField) {
2722            firstInvalidField = $field;
2723          }
2724        }
2725      });
2726
2727      // Focus first invalid field
2728      if (firstInvalidField) {
2729        firstInvalidField.focus();
2730      }
2731
2732      // Re-enable submit button
2733      $("#btnContactPost").prop('disabled', false);
2734      $("#btnContactPost").css('font-weight', 'bold');
2735    }
2736  }
2737
2738  function getFieldLabel(fieldId) {
2739    var labels = {
2740      'contact_us_phone': 'Phone Number',
2741      'contact_us_address': 'Address',
2742      'contact_us_city': 'City',
2743      'contact_us_state': 'State',
2744      'contact_us_zip': 'ZIP Code',
2745      'contact_us_subject': 'Subject',
2746      'contact_us_name': 'Name',
2747      'contact_us_email': 'Email',
2748      'contact_us_message': 'Message'
2749    };
2750    return labels[fieldId] || 'This field';
2751  }
2752
2753  function getCustomErrorMessage($field, fieldLabel) {
2754    if ($field.prop('required') && !$field.val().trim()) {
2755      return `${fieldLabel} required`;
2756    }
2757
2758    if ($field.attr('type') === 'email' && $field.val()) {
2759      return `Please enter a valid email address.`;
2760    }
2761
2762    return `Please enter a valid ${fieldLabel.toLowerCase()}.`;
2763  }
2764
2765    function contactUsSubmit(event) {
2766        event.preventDefault();
2767
2768        var form = $("#ContactPostForm");
2769        grecaptcha.ready(function() {
2770            grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) {
2771                $("#g-Recaptcha-Response-Contact").attr("value", token); //add token for server side validation
2772                $.ajax({
2773                    type: "POST",
2774                    url: "/Home/ContactPost",
2775                    data: form.serialize(),
2776                    success: function(data){
2777                        if (data.indexOf('{"message":') != -1) {
2778                            var jsonData = JSON.parse(data);
2779                            if (!jsonData.success) {
2780                                $("#contactResponseMessage").html('<div class="alert alert-warning alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' + jsonData.message + '</div>');
2781                                recaptchaContactUsInComplete();
2782                                showClassicCaptcha("contact");
2783                            }
2784                            else{
2785                                $("#contactResponseMessage").html('<div class="alert alert-success alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' + jsonData.message + '</div>');
2786                                recaptchaContactUsComplete();
2787                            }
2788                        }
2789                    }
2790                });
2791            });
2792        });
2793    }
2794
2795    function ScrollForPosts(e){
2796        // target element
2797        var $id = $(".posts-partial-content");
2798        if ($id.length === 0) {
2799            return;
2800        }
2801
2802        // prevent standard hash navigation (avoid blinking in IE)
2803        e.preventDefault();
2804
2805        // top position relative to the document
2806        var pos = $id.offset().top - $('.navbar').height();
2807
2808        // animated top scrolling
2809        // .stop() keeps from scrolling to top then to element
2810        $('body, html').stop().animate({ scrollTop: pos }, 500);
2811    }
2812
2813    function recaptchaContactUsInComplete(){
2814        $("#btnContactPost").prop('disabled', false);
2815        $("#btnContactPost").css('font-weight', 'bold');
2816    }
2817
2818  function recaptchaContactUsComplete() {
2819    $("#btnContactPost").prop('disabled', false);
2820    $("#btnContactPost").css('font-weight', 'normal');
2821    $("#ContactPostForm").trigger("reset");
2822  }
2823
2824    function recaptchaReviewIncomplete(){
2825        $("#postReview").prop('disabled', false);
2826        $("#postReview").css('font-weight', 'bold');
2827    }
2828
2829    function recaptchaReviewComplete(){
2830        $("#postReview").css('font-weight', 'normal');
2831        $("#postReviewForm").trigger("reset");
2832        $("#postReview").prop('disabled', false);
2833    }
2834
2835    function ClearReviewFields() {
2836        $('#starRating').barrating('clear');
2837        $("#review").val("");
2838        $("#review_alias").val("");
2839        $("#review_heading").val("");
2840        $("#reviewCaptcha").val("");
2841    }
2842
2843    function resetReviewButton($button) {
2844        var $buttonText = $button.find('.button-text');
2845        var $spinner = $button.find('.spinner');
2846
2847        $button.prop('disabled', false);
2848
2849        if ($buttonText.length && $spinner.length) {
2850            $buttonText.show();
2851            $spinner.hide();
2852        } else {
2853            var originalText = $button.data('original-text');
2854            if (originalText) {
2855                $button.html(originalText);
2856            }
2857        }
2858    }
2859
2860    function setProcessingState($button, $form, isProcessing) {
2861        var $buttonText = $button.find('.button-text');
2862        var $spinner = $button.find('.spinner');
2863
2864        if (isProcessing) {
2865            $button.prop('disabled', true);
2866            $form.addClass('review-form-processing');
2867            $form.find('input, textarea, select').not('#profile_id, #g-Recaptcha-Response-Review, [type="hidden"]').prop('disabled', true);
2868
2869            if ($buttonText.length && $spinner.length) {
2870                $buttonText.hide();
2871                $spinner.show();
2872            } else {
2873                $button.data('original-text', $button.html());
2874                $button.html('<i class="fas fa-spinner fa-spin"></i> Processing...');
2875            }
2876        } else {
2877            $button.prop('disabled', false);
2878            $form.removeClass('review-form-processing');
2879            $form.find('input, textarea, select').prop('disabled', false);
2880
2881            if ($buttonText.length && $spinner.length) {
2882                $buttonText.show();
2883                $spinner.hide();
2884            } else {
2885                var originalText = $button.data('original-text');
2886                if (originalText) {
2887                    $button.html(originalText);
2888                }
2889            }
2890        }
2891    }
2892
2893    function ClearReviewFields() {
2894        console.log('Clearing review fields');
2895        $('#starRating').barrating('clear');
2896        $("#review").val("");
2897        $("#review_alias").val("");
2898        $("#review_heading").val("");
2899        $("#reviewCaptcha").val("");
2900
2901        $("#postReviewForm input, #postReviewForm textarea").removeClass('error');
2902        $("#postReviewForm .br-widget").removeClass('error');
2903    }
2904
2905    function validateReview(btn) {
2906        var $form = $("#postReviewForm");
2907        var isValid = true;
2908
2909        console.log('Starting validation...');
2910
2911        $form.find('input, textarea').removeClass('error');
2912        $form.find('.br-widget').removeClass('error');
2913
2914        var reviewText = $('#review').val();
2915        console.log('Review text length:', reviewText ? reviewText.trim().length : 0);
2916
2917        if (!reviewText || reviewText.trim().length === 0) {
2918            console.log('Review text validation failed - empty or whitespace only');
2919            $('#review').addClass('error');
2920            $('#review').focus();
2921            isValid = false;
2922        } else {
2923            console.log('Review text validation passed');
2924        }
2925
2926        var rating = null;
2927        var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null;
2928        var jqueryRating = $('#starRating').val();
2929        var selectedOption = $('#starRating option:selected').val();
2930        var barRating = null;
2931
2932        if (typeof $('#starRating').barrating === 'function') {
2933            try {
2934                var barResult = $('#starRating').barrating('show');
2935                if (barResult && typeof barResult === 'string') {
2936                    barRating = barResult;
2937                } else if (barResult && typeof barResult === 'number') {
2938                    barRating = barResult.toString();
2939                }
2940            } catch (e) {
2941                console.log('Error getting barrating value:', e);
2942            }
2943        }
2944
2945        if (jqueryRating && typeof jqueryRating === 'string') {
2946        } else if (jqueryRating && typeof jqueryRating === 'number') {
2947            jqueryRating = jqueryRating.toString();
2948        } else {
2949            jqueryRating = null;
2950        }
2951
2952        if (barRating && barRating !== "" && barRating !== "0") {
2953            rating = barRating;
2954        } else if (selectRating && selectRating !== "" && selectRating !== "0") {
2955            rating = selectRating;
2956        } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") {
2957            rating = selectedOption;
2958        } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") {
2959            rating = jqueryRating;
2960        }
2961
2962        if (rating && typeof rating !== 'string') {
2963            console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
2964            rating = String(rating);
2965        }
2966
2967        if (rating && typeof rating === 'object') {
2968            console.error('CRITICAL ERROR: Rating is still an object!', rating);
2969            rating = null;
2970        }
2971
2972        console.log('Validation - Final rating value:', rating, typeof rating);
2973
2974        if (!rating || rating === "" || rating === "0") {
2975            console.log('Rating validation failed');
2976            $('.br-widget').addClass('error');
2977            isValid = false;
2978        } else {
2979            console.log('Rating validation passed with value:', rating);
2980        }
2981
2982        console.log('Validation result:', isValid);
2983        return isValid;
2984    }
2985
2986    function validateReviewLength() {
2987        var text = $('#review').val();
2988        var success = true;
2989
2990        if (text.trim().length == 0) {
2991            $('#review').addClass('error');
2992            success = false;
2993        }
2994        return success;
2995    }
2996
2997    function validateRating() {
2998        var rating = null;
2999
3000        // Use the same rating detection logic
3001        var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null;
3002        var jqueryRating = $('#starRating').val();
3003        var selectedOption = $('#starRating option:selected').val();
3004        var barRating = null;
3005
3006        if (typeof $('#starRating').barrating === 'function') {
3007            try {
3008                barRating = $('#starRating').barrating('show');
3009            } catch (e) {
3010                console.log('Error getting barrating value in validateRating:', e);
3011            }
3012        }
3013
3014        // Determine which rating to use
3015        if (barRating && barRating !== "" && barRating !== "0") {
3016            rating = barRating;
3017        } else if (selectRating && selectRating !== "" && selectRating !== "0") {
3018            rating = selectRating;
3019        } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") {
3020            rating = selectedOption;
3021        } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") {
3022            rating = jqueryRating;
3023        }
3024
3025        var success = true;
3026        if (!rating || rating === "" || rating === "0") {
3027            $('.br-widget').addClass('error');
3028            success = false;
3029        }
3030        return success;
3031    }
3032</script>
3032
3033</body>
3034</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.