PageSourceSearch

https://rocksolidforminginc.com/

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