PageSourceSearch

https://www.banham.co.uk/

html banham.co.uk collected 2026-10-02 11:58:36 UTC 596,296 bytes, 10,198 lines download raw bytes

1<!doctype html>
2<html lang="en">
3<head >
4    <meta charset="utf-8"/>
5<meta name="title" content="Banham | Experts in Security Services Since 1926"/>
6<meta name="description" content="Welcome to Banham, market-leaders in the security industry since 1926, and the perfect people to help secure your property"/>
7<meta name="robots" content="INDEX,FOLLOW"/>
8<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
9<title>Banham | Experts in Security Services Since 1926</title>
10        <link rel="stylesheet" type="text/css" media="all" href="https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/css/styles.min.css" />
11<link rel="stylesheet" type="text/css" media="all" href="https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Amasty_Storelocator/vendor/chosen/chosen.min.css" />
12<link rel="stylesheet" type="text/css" media="all" href="https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Trustpilot_Reviews/css/trustpilot.min.css" />
13
14<link rel="icon" type="image/x-icon" href="https://www.banham.co.uk/media/favicon/stores/1/Banham_Logo_FA-04.png" />
15<link rel="shortcut icon" type="image/x-icon" href="https://www.banham.co.uk/media/favicon/stores/1/Banham_Logo_FA-04.png" />
16<!-- [HEAD Scripts and Style Sheets (store)] -->
17<link rel="preload" as="image" href="https://www.banham.co.uk/media/wysiwyg/Stronger_Together_-_Desktop_Compressed_.gif"/>
18<link rel="preload" as="image" href="https://www.banham.co.uk/media/wysiwyg/Stronger_Together_-_Mobile_4.gif"/>
19
20<meta name="google-site-verification" content="tlRCJ39nLLEuusvkrLQgs0hMLKjni_c_coG3u7dexYs" />
21
22<meta name="p:domain_verify" content="FXieQwTo44FvqeK7UsLQWQazWnZ4AsMS"/>
23
24<meta name="trustpilot-one-time-domain-verification-id" content="uzIvKWRHCcxSIDidTTo2LpYtOOFSJrSEaWynJNnM"/>
25<link rel="dns-prefetch" href="//consent.cookiebot.com" />
26
27<style type="text/css">
28  /* to hide slide out form on these 2 pages */
29.catalog-category-view.categorypath-safes .enquiries-slide ,
30.catalog-category-view.category-gates-grilles-shutters .enquiries-slide  {
31                display: none !important;
32 }
33.product-social-links__items a.action.mailto.friend {display:none; }
34
35
36.product-add-form .wishlist {
37    margin-top: 13px;
38    display: block;
39}
40.product-add-form .wishlist svg {
41    width: 20px;
42}
43
44.payment-method input#sagepaysuitepi + label {
45display: inline-block !important;
46}
47
48
49
50
51</style>
52
53<meta name="google-site-verification" content="jaCDjXkWDNHwKHL7TPsqP_5XnPTLp5HMop_7H2Cu5SE" />
54
55
56<style>
57/*style for task BAN-2451*/
58.nav-sections .navigation li.level0.mofx-mmn-our-difference {
59  order: -1;
60}
61 @media only screen and (max-width: 991px) {
62    .navigation ul {
63      display: flex;
64      flex-direction: column;
65    }
66}
67/* end style for task BAN-2451*/
68.enquiries-slide-open .pca .pcaautocomplete {
69                max-width: 260px;
70            }
71.enquiries-slide-open .pca .pcaitem {
72                white-space: normal;
73            }
74.pca .pcaautocomplete {
75        max-width: 80vw;
76    }
77
78    .pca .pcaitem {
79        white-space: normal!important;
80    }
81/* M60 hotfix */
82.product-item-info.empty-carousel-item { visibility:hidden; }
83.admin__data-grid-loading-mask {display:none;}
84.catalogsearch-result-index #instant-search-results-container .ais-Hits-item>[class^=col-] {
85    width: 100% !important;
86}
87
88
89
90</style>
91
92<!-- [/HEAD Scripts and Style Sheets (store)] -->
93<meta name="p:domain_verify" content="sYFFWHIheNKJDGZA1eZkGvMNvgwmO745"/>
94
95
96<!-- AB experiment code for doors page -->
97
98
99
100<meta name="facebook-domain-verification" content="v18ynkkipzgbfnaq7fxpdsfu3en2s9" />
101
102
103<!-- Start VWO Async SmartCode -->
104<link rel="preconnect" href="https://dev.visualwebsiteoptimizer.com" />
105
106<!-- End VWO Async SmartCode -->
107        
108
109<meta name="og:title" content="Banham | Experts in Security Services Since 1926">
110<meta name="og:description" content="Welcome to Banham, market-leaders in the security industry since 1926, and the perfect people to help secure your property">
111<meta name="og:image" content="https://a.storyblok.com/f/286600090739628/1200x630/18282bfc13/homepage-og.png">
112<meta name="twitter:title" content="Banham | Experts in Security Services Since 1926">
113<meta name="twitter:description" content="Welcome to Banham, market-leaders in the security industry since 1926, and the perfect people to help secure your property">
114<meta name="twitter:image" content="https://a.storyblok.com/f/286600090739628/1200x630/18282bfc13/homepage-og.png">
115<link rel="canonical" href="https://www.banham.co.uk/">
116 </head>
117<body class="store-default logged-out storyblok-home storyblok-page-view page-layout-1column" id="html-body">
118 <!-- [BODY Miscellaneous HTML/ Scripts (store)] -->
119
120<!-- [/BODY Miscellaneous HTML/ Scripts (store)] -->
121<style>
122    #webform-slide-out-yk8I5y {
123        background: #ffffff;
124        border-color: #ffffff;
125        width: 100%;
126    }
127
128    @media (min-width: 768px) {
129        #webform-slide-out-yk8I5y {
130            width: 720px;
131        }
132    }
133
134    /* #webform-slide-out-button-yk8I5y {
135        background: #3c4a54;
136        color: #ffffff;
137        width: 25px;
138        height: 160px;
139    }
140    .slide-out-button-icon{
141        fill:#ffffff;
142        width: 1.25rem;
143        height: 1.25rem;
144        margin-right: .5rem;
145    } */
146</style>
147
148     <style>.webforms .actions-toolbar{border:none}.webforms .actions-toolbar.submit-center .primary{margin:0 auto}.webforms .actions-toolbar.submit-left{flex-direction:row}.webforms .actions-toolbar.submit-left .primary{float:left}.webforms .actions-toolbar.submit-right{flex-direction:row-reverse}.webforms .actions-toolbar.submit-right .primary{float:right}.webforms .actions-toolbar button.sbtn-l{line-height:2rem;font-size:1.5rem}.webforms .actions-toolbar button.sbtn-xl{line-height:2.3rem;font-size:1.8rem}.webforms .field-error input,.webforms .field-error textarea,.webforms .field-error .drop-zone{border-color:red}.webforms .inline-elements .choice{display:inline-flex}@media screen and (min-width:640px){.webforms .wf-sm-row{clear:left}}@media screen and (min-width:768px){.webforms .wf-md-row{clear:left}.webforms .wf-sm-row{clear:unset}}@media screen and (min-width:1024px){.webforms .wf-lg-row{clear:left !important}.webforms .wf-md-row,.webforms .wf-sm-row{clear:unset}}.webforms figcaption{padding:5px 0;margin:5px}.webforms .image_picker_image{height:auto}.webforms .mm-map{height:400px;width:100%}.webforms .mm-map-search{margin:2px;width:40%}.webforms .mm-logic-hidden{display:none !important}</style>      
149<div x-data="{ isOpen: false }"
150
151     x-init="$watch('isOpen', function(val) { if (val && window.resetSlideOutForm) window.resetSlideOutForm('yk8I5y'); })">
152    <!-- Slide-out form -->
153    <div id="webform-slide-out-yk8I5y"
154         x-cloak
155         class="webform-content fixed top-0 right-0 md:max-w-[80%] md:max-w-auto md:w-1/3 lg:w-1/4 h-full shadow-2xl transform transition-transform duration-300 ease-in-out z-[9999]"
156         :class="{ 'translate-x-full': !isOpen }"
157         @click="isOpen && (document.documentElement.style.overflow = isOpen ? 'hidden' : 'auto')"
158         x-effect="document.documentElement.style.overflow = isOpen ? 'hidden' : 'auto'">
159        <div class="md:px-36 md:pt-[60px] md:pb-10 px-5 py-10 h-full overflow-y-auto relative max-h-svh flex flex-col">
160            <!-- Close button -->
161            <button @click="isOpen = false" class="close-btn absolute top-5 right-5 text-black hover:text-gray-700">
162                <i class="ti ti-x text-xl"></i>
163            </button>
164
165            <div id="webform_yk8I5y_heading">
166            
167                        </div>
168
169                            <div id="webform_yk8I5y_success_text" class="form-success-message flex flex-col h-full hyva-success-msg"
170                     style="display:none"></div>
171
172            
173                            
174                <div id="webform_yk8I5y_form"
175                     class="webforms webform-slide-out-form flex-shrink-0 flex-grow">
176
177                                            <div id="yk8I5yform_description" class="webforms-description-text text-center">
178                            <p class="absolute top-0 left-0 right-0 bg-primary-darkGray mb-6 !text-sm" style="padding: 10px;">Prefer to call? Reach us on <a style="text-decoration:none" class="!text-sm" href="tel:+442078193730">020 7819 3730&nbsp;&nbsp;</a></p>
179                        </div>
180                    
181                     
182
183<form method="post"
184      name="webform_yk8I5y"
185      id="webform_yk8I5y" enctype="multipart/form-data"
186      class="form h-full enquiry-form survey-booking-form"
187      style=""
188      x-cloak
189      x-data="bbPCAForm({ loqateFindUrl: window.loqateFindUrl, loqateRetrieveUrl: window.loqateRetrieveUrl })"
190      @alpine:initialized="init()"
191>
192
193    <input name="form_key" type="hidden" value=""/>
194    <input type="hidden" name="submitForm_2" value="1"/>
195    <input type="hidden" name="form_id" value="2"/>
196        
197    
198    <input name='field[1035]'
199       id="enquiry_topic_product"
200       type='hidden'
201       value=''
202    /><input name='field[762]'
203       id="utm_source"
204       type='hidden'
205       value=''
206    /><input name='field[768]'
207       id="utm_campaign"
208       type='hidden'
209       value=''
210    /><input name='field[765]'
211       id="utm_medium"
212       type='hidden'
213       value=''
214    />
215    
216            <div id="wizardyk8I5y" class="h-full">
217            
218            <div class="step-app h-full flex flex-col pt-6" >
219                                <div x-data="stepProgress()" x-init="init()" class="">
220                    <!-- Header: Question X of N -->
221                    <div class="text-black text-sm font-normal leading-tight mb-5">
222                        Question <span x-text="currentStep"></span> of <span x-text="totalSteps"></span>
223                    </div>
224
225                    <!-- Progress bar -->
226                    <div class="w-full h-1 bg-[#EDEDED] rounded">
227                        <div class="h-1 bg-primary rounded transition-all duration-300"
228                            :style="`width: ${percent()}%`"></div>
229                    </div>
230
231                    <!-- Keep original steps for wizard logic, but hide them -->
232                    <ul class="step-steps hidden" x-ref="stepList">
233                                                    <li id="title_fieldset_yk8I5y
23356"
234                                class="">
235                                <a href="#stepyk8I5y56">
236                                     Which Banham products are you interested in?                                </a>
237                            </li>
238                                                    <li id="title_fieldset_yk8I5y59"
239                                class="">
240                                <a href="#stepyk8I5y59">
241                                    About Your Enquiry                                </a>
242                            </li>
243                                                    <li id="title_fieldset_yk8I5y62"
244                                class="">
245                                <a href="#stepyk8I5y62">
246                                    We’ll need a little information about you                                </a>
247                            </li>
248                                                    <li id="title_fieldset_yk8I5y65"
249                                class="">
250                                <a href="#stepyk8I5y65">
251                                    Search for the property you’d like surveyed                                </a>
252                            </li>
253                                                    <li id="title_fieldset_yk8I5y68"
254                                class="">
255                                <a href="#stepyk8I5y68">
256                                    Choose your preferred survey date                                </a>
257                            </li>
258                                            </ul>
259                </div>
260                <div class="step-content">
261                                            <div class="step-tab-panel form-step active [&_h3]:my-10" id="stepyk8I5y56">
262                             <fieldset id="fieldset_yk8I5y56" class="fieldset-56 hyva-fieldset  lg:w-full md:w-full w-full " style="" role="group" aria-labelledby="legend_yk8I5y56"> <h3 class="hyva-fieldset-label" id="legend_yk8I5y56"><span> Which Banham products are you interested in?</span></h3>  <div id="field_yk8I5y626" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-626 webforms-fields-enquiry-topic "  > <div class="control" role="group" ><input id='enquiry-topic'
263       name='field[626]'
264       type='text'
265       class='input-text  hyva-text'
266       style=''
267       value=""
268       placeholder=""
269                     aria-label="Enquiry Topic"
270                                   />
271  </div></div> <div id="field_yk8I5y1778" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-swatches webforms-fields-1778 webforms-fields-also_interested_in "  > <div class="control" role="group" > <style></style>
272<div class="mm-swatches">
273    
274            <div class='field choice option-0 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
275                 style=''
276            >
277                <label id="fieldyk8I5y17780_label" class="w-full ">
278                    <input id='fieldyk8I5y17780'
279                           name='field[1778][]'
280                           type='checkbox'
281                           value="Locks"
282                           class='  text-sm leading-5 w-full'
283                                                                           data-uid="yk8I5y1778"
284                           aria-labelledby="fieldyk8I5y17780_label"
285                                                                    />
286                    <span style='' class="text-sm leading-5 w-full ">Locks</span>
287                </label>
288                
289            </div>
290
291            
292            <div class='field choice option-1 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
293                 style=''
294            >
295                <label id="fieldyk8I5y17781_label" class="w-full ">
296                    <input id='fieldyk8I5y17781'
297                           name='field[1778][]'
298                           type='checkbox'
299                           value="Intruder Alarm"
300                           class='  text-sm leading-5 w-full'
301                                                                           data-uid="yk8I5y1778"
302                           aria-labelledby="fieldyk8I5y17781_label"
303                                                                    />
304                    <span style='' class="text-sm leading-5 w-full ">Alarms</span>
305                </label>
306                
307            </div>
308
309            
310            <div class='field choice option-2 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
311                 style=''
312            >
313                <label id="fieldyk8I5y17782_label" class="w-full ">
314                    <input id='fieldyk8I5y17782'
315                           name='field[1778][]'
316                           type='checkbox'
317                           value="Doors"
318                           class='  text-sm leading-5 w-full'
319                                                                           data-uid="yk8I5y1778"
320                           aria-labelledby="fieldyk8I5y17782_label"
321                                                                    />
322                    <span style='' class="text-sm leading-5 w-full ">Doors</span>
323                </label>
324                
325            </div>
326
327            
328            <div class='field choice option-3 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
329                 style=''
330            >
331                <label id="fieldyk8I5y17783_label" class="w-full ">
332                    <input id='fieldyk8I5y17783'
333                           name='field[1778][]'
334                           type='checkbox'
335                           value="Keyholding"
336                           class='  text-sm leading-5 w-full'
337                                                                           data-uid="yk8I5y1778"
338                           aria-labelledby="fieldyk8I5y17783_label"
339                                                                    />
340                    <span style='' class="text-sm leading-5 w-full ">Keyholding</span>
341                </label>
342                
343            </div>
344
345            
346            <div class='field choice option-4 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
347                 style=''
348            >
349                <label id="fieldyk8I5y17784_label" class="w-full ">
350                    <input id='fieldyk8I5y17784'
351                           name='field[1778][]'
352                           type='checkbox'
353                           value="Safes"
354                           class='  text-sm leading-5 w-full'
355                                                                           data-uid="yk8I5y1778"
356                           aria-labelledby="fieldyk8I5y17784_label"
357                                                                    />
358                    <span style='' class="text-sm leading-5 w-full ">Safes</span>
359                </label>
360                
361            </div>
362
363            
364            <div class='field choice option-5 mr-3 overflow-hidden text-sm leading-5 w-full self-stretch  rounded inline-flex flex-col justify-start items-start gap-2'
365                 style=''
366            >
367                <label id="fieldyk8I5y17785_label" class="w-full ">
368                    <input id='fieldyk8I5y17785'
369                           name='field[1778][]'
370                           type='checkbox'
371                           value="Metalwork"
372                           class='  text-sm leading-5 w-full'
373                                                                           data-uid="yk8I5y1778"
374                           aria-labelledby="fieldyk8I5y17785_label"
375                                                                    />
376                    <span style='' class="text-sm leading-5 w-full ">Gates / Grilles & Shutters</span>
377                </label>
378                
379            </div>
380
381                </div>
382
383
384  </div></div></fieldset>
385                            <div class="actions-toolbar w-full">
386                                                            </div>
387                        </div>
388                                                <div class="step-tab-panel form-step  [&_h3]:my-10" id="stepyk8I5y59">
389                             <fieldset id="fieldset_yk8I5y59" class="fieldset-59 hyva-fieldset  lg:w-full md:w-full w-full " style="" role="group" aria-labelledby="legend_yk8I5y59"> <h3 class="hyva-fieldset-label" id="legend_yk8I5y59"><span>About Your Enquiry</span></h3>  <div id="field_yk8I5y8" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-textarea webforms-fields-8 webforms-fields-enquiry required"  > <div class="control" role="group" > <textarea id='fieldyk8I5y8'
390          name='field[8]'
391          class=' hyva-textarea'
392          rows='5'
393          style=''
394          placeholder="Enter your enquiry here"
395                        data-validate="{'required-entry':true}"
396            aria-label="Your Enquiry"
397           aria-required="true"   ></textarea>    </div></div></fieldset>
398                            <div class="actions-toolbar w-full">
399                                                            </div>
400                        </div>
401                                                <div class="step-tab-panel form-step  [&_h3]:my-10" id="stepyk8I5y62">
402                             <fieldset id="fieldset_yk8I5y62" class="fieldset-62 hyva-fieldset  lg:w-full md:w-full w-full " style="" role="group" aria-labelledby="legend_yk8I5y62"> <h3 class="hyva-fieldset-label" id="legend_yk8I5y62"><span>We’ll need a little information about you</span></h3>  <div id="field_yk8I5y5" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-select webforms-fields-5 webforms-fields-enquiry-type required"  > <div class="control" role="group" >  <select id='fieldyk8I5y5' name='field[5]' class=' hyva-select' style=''  data-validate="{'validate-select':true}"   aria-label="Enquiry Type"  aria-required="true"    > <option value="Residential"  >Residential</option> <option value="Business"  >Business</option></select>   </div></div> <div id="field_yk8I5y23" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text mm-logic-hidden webforms-fields-23 webforms-fields-company_name required"  > <div class="control" role="group" ><input id='company_name'
403       name='field[23]'
404       type='text'
405       class='input-text  hyva-text'
406       style=''
407       value=""
408       placeholder="Company name"
409                  data-validate="{'required-entry':true, 'validate-length-max':'60'}"
410                     aria-label="Company Name"
411              aria-required="true"                     />
412  </div></div> <div id="field_yk8I5y11" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-11 webforms-fields-firstname required"  > <div class="control" role="group" ><input id='firstname'
413       name='field[11]'
414       type='text'
415       class='input-text  hyva-text'
416       style=''
417       value=""
418       placeholder="Please enter your first name here"
419                  data-validate="{'required-entry':true, 'validate-length-max':'30'}"
420                     aria-label="First name"
421              aria-required="true"                                x-data="MageMe.WebForms.customerData()"
422           @private-content-loaded.window="receiveCustomerData($event.detail.data)"
423           x-model="customer.customer_firstname"
424       />
425  </div></div> <div id="field_yk8I5y14" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-14 webforms-fields-lastname required"  > <div class="control" role="group" ><input id='lastname'
426       name='field[14]'
427       type='text'
428       class='input-text  hyva-text'
429       style=''
430       value=""
431       placeholder="Please enter your last name here"
432                  data-validate="{'required-entry':true, 'validate-length-max':'30'}"
433                     aria-label="Last name"
434              aria-required="true"                                x-data="MageMe.WebForms.customerData()"
435           @private-content-loaded.window="receiveCustomerData($event.detail.data)"
436           x-model="customer.customer_lastname"
437       />
438  </div></div> <div id="field_yk8I5y2" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-email webforms-fields-2 webforms-fields-email required"  > <div class="control" role="group" > <input id='fieldyk8I5y2' name='field[2]' type='email' class='input-text  hyva-text' style='' value="" placeholder="[email protected]"  data-validate="{'required-entry':true, 'validate-email':true}"   aria-label="Email"  aria-required="true"    x-data="mmWebformsEmailDatafieldyk8I5y2" @input="trimSpace"  @private-content-loaded.window="setCustomerData"  />   </div></div> <div id="field_yk8I5y17" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-17 webforms-fields-contact-number required"  > <div class="control" role="group" ><input id='contact-number'
439       name='field[17]'
440       type='text'
441       class='input-text  hyva-text'
442       style=''
443       value=""
444       placeholder="Contact number"
445                  data-validate="{'required-entry':true, 'mm-pattern':'^((\\d[\\-. ]?)?((\\(\\{d3}\\))|\\d{3}))?[\\-. ]?\\d{3,4}[\\-. ]?\\d{4}$'}"
446              data-msg-required-entry="Please enter a valid phone number."data-msg-mm-pattern="Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890."       aria-label="Contact number"
447              aria-required="true"                     />
448  <div style="display:none" class="hyva-comment-label" id="advice-required-entry-fieldyk8I5y17">Please enter a valid phone number.</div> </div></div></fieldset>
449                            <div class="actions-toolbar w-full">
450                                                            </div>
451                        </div>
452                                                <div class="step-tab-panel form-step  [&_h3]:my-10" id="stepyk8I5y65">
453                             <fieldset id="fieldset_yk8I5y65" class="fieldset-65 hyva-fieldset address-search lg:w-full md:w-full w-full " style="" role="group" aria-labelledby="legend_yk8I5y65"> <h3 class="hyva-fieldset-label" id="legend_yk8I5y65"><span>Search for the property you’d like surveyed</span></h3>
453  <div id="field_yk8I5y1781" role="group" class="field hyva-field search-address lg:w-full md:w-full w-full type-text webforms-fields-1781 "  > <div class="control" role="group" ><input id=''
454       name='field[1781]'
455       type='text'
456       class='input-text  hyva-text'
457       style=''
458       value=""
459       placeholder="Search Address"
460                     aria-label="Search Address"
461                                   />
462  </div></div> <div id="field_yk8I5y20" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-20 webforms-fields-street required"  > <div class="control" role="group" ><input id='street'
463       name='field[20]'
464       type='text'
465       class='input-text  hyva-text'
466       style=''
467       value=""
468       placeholder="Address Line 1"
469                  data-validate="{'required-entry':true, 'validate-length-max':'40'}"
470                     aria-label="Street & Number"
471              aria-required="true"                     />
472  </div></div> <div id="field_yk8I5y629" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-629 webforms-fields-street1 "  > <div class="control" role="group" ><input id='street1'
473       name='field[629]'
474       type='text'
475       class='input-text  hyva-text'
476       style=''
477       value=""
478       placeholder="Address Line 2"
479                  data-validate="{'validate-length-max':'40'}"
480                     aria-label="Street 1"
481                                   />
482  </div></div> <div id="field_yk8I5y632" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-632 webforms-fields-street2 "  > <div class="control" role="group" ><input id='street2'
483       name='field[632]'
484       type='text'
485       class='input-text  hyva-text'
486       style=''
487       value=""
488       placeholder="Address Line 3"
489                  data-validate="{'validate-length-max':'40'}"
490                     aria-label="Street 2"
491                                   />
492  </div></div> <div id="field_yk8I5y26" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-26 webforms-fields-city required"  > <div class="control" role="group" ><input id='city'
493       name='field[26]'
494       type='text'
495       class='input-text  hyva-text'
496       style=''
497       value=""
498       placeholder="Town / City"
499                  data-validate="{'required-entry':true, 'validate-length-max':'30'}"
500                     aria-label="Town / City"
501              aria-required="true"                     />
502  </div></div> <div id="field_yk8I5y29" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-29 webforms-fields-country required"  > <div class="control" role="group" ><input id='country'
503       name='field[29]'
504       type='text'
505       class='input-text  hyva-text'
506       style=''
507       value=""
508       placeholder="Country"
509                  data-validate="{'required-entry':true, 'validate-length-max':'30'}"
510                     aria-label="Country"
511              aria-required="true"                     />
512  </div></div> <div id="field_yk8I5y32" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-text webforms-fields-32 webforms-fields-postcode required"  > <div class="control" role="group" ><input id='postcode'
513       name='field[32]'
514       type='text'
515       class='input-text  hyva-text'
516       style=''
517       value=""
518       placeholder="Postcode"
519                  data-validate="{'required-entry':true, 'validate-length-max':'10'}"
520                     aria-label="Postcode"
521              aria-required="true"                     />
522  </div></div></fieldset>
523                            <div class="actions-toolbar w-full">
524                                                            </div>
525                        </div>
526                                                <div class="step-tab-panel form-step  [&_h3]:my-10" id="stepyk8I5y68">
527                             <fieldset id="fieldset_yk8I5y68" class="fieldset-68 hyva-fieldset  lg:w-full md:w-full w-full " style="" role="group" aria-labelledby="legend_yk8I5y68"> <h3 class="hyva-fieldset-label" id="legend_yk8I5y68"><span>Choose your preferred survey date</span></h3>
527  <div id="field_yk8I5y1032" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-date webforms-fields-1032 webforms-fields-survey-date required"  > <div class="control" role="group" ><div class='webforms-datepicker ddd'>
528    <div id='fieldyk8I5y1032_calendar' class='webforms-calendar'>
529        <div class="relative">
530            <input id='fieldyk8I5y1032'
531                   name='field[1032]'
532                   type='text'
533                   class='input-text  _has-datepicker hyva-text pr-10'
534                   style=''
535                   value=''
536                   placeholder=""
537                                          data-validate="{'required-entry':true}"
538                                                         aria-label="Preferred Survey Date"
539                                      aria-required="true"                               />
540
541            <svg class="text-gray-400 pointer-events-none" style="position: absolute; top:20px; right:20px; width:20px;"viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
542                <path d="M3.33337 5.83329C3.33337 5.39127 3.50897 4.96734 3.82153 4.65478C4.13409 4.34222 4.55801 4.16663 5.00004 4.16663H15C15.4421 4.16663 15.866 4.34222 16.1786 4.65478C16.4911 4.96734 16.6667 5.39127 16.6667 5.83329V15.8333C16.6667 16.2753 16.4911 16.6992 16.1786 17.0118C15.866 17.3244 15.4421 17.5 15 17.5H5.00004C4.55801 17.5 4.13409 17.3244 3.82153 17.0118C3.50897 16.6992 3.33337 16.2753 3.33337 15.8333V5.83329Z" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
543                <path d="M13.3334 2.5V5.83333" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
544                <path d="M6.66663 2.5V5.83333" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
545                <path d="M3.33337 9.16663H16.6667" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
546                <path d="M5.83337 11.6666H5.84421" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
547                <path d="M8.34167 11.6666H8.34667" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
548                <path d="M10.8417 11.6666H10.8467" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
549                <path d="M13.3458 11.6666H13.3508" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
550                <path d="M10.8458 14.1666H10.8508" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
551                <path d="M5.84167 14.1666H5.84667" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
552                <path d="M8.34167 14.1666H8.34667" stroke="black" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
553            </svg>
554        </div>
555    </div>
556</div>
557  </div></div> <div id="field_yk8I5y38" role="group" class="field hyva-field  lg:w-full md:w-full w-full type-subscribe choice webforms-fields-38 webforms-fields-subscribe "  aria-describedby="comment_fieldyk8I5y38"> <div class="control" role="group" > <div class="field choice option-0"><input id='fieldyk8I5y380' name='field[38]' type='checkbox' class='hyva-checkbox' style='float:left' value='1'     /><label for='fieldyk8I5y380' class=' hyva-checkbox-label' style='' >Subscribe</label></div>    <p class="hyva-comment-label" id="comment_fieldyk8I5y38" tabindex="0">I consent to Banham sending me email updates on special offers, products, and services.  If you would like further information on how we use your personal data, please check our <a href="/privacy-promise" target="_blank">Privacy Policy</a>.</p></div></div></fieldset>
558                            <div class="actions-toolbar w-full">
559                                                                                                            <div id="captcha-container-yk8I5y"></div>
560                                                                                                </div>
561                        </div>
562                                        </div>
563
564               <div class="step-footer mt-auto"
565                        x-data="{
566                            handleKey(e) {
567                                const btnNext = this.$root.querySelector('button[data-direction=\'next\']');
568                                const btnPrev = this.$root.querySelector('button[data-direction=\'prev\']');
569                                const btnFinish = this.$root.querySelector('button[data-direction=\'finish\']');
570                                if (e.key === 'ArrowRight') {
571                                    if (btnNext && btnNext.offsetParent !== null) btnNext.focus();
572                                    else if (btnFinish && btnFinish.offsetParent !== null) btnFinish.focus();
573                                }
574                                if (e.key === 'ArrowLeft') {
575                                    if (btnPrev && btnPrev.offsetParent !== null) btnPrev.focus();
576                                }
577                            }
578                        }"
579                        @keydown.window="handleKey($event)"
580                    >
581
582                    <div class="please-wait text-center" id="webform_yk8I5y_sending_data"
583                         style="display:none;">
584                        <div class="loading-indicator"></div>
585                        <span id="webform_yk8I5y_progress_text">Sending...</span>
586                    </div>
587                    <button type="button" tabindex="0"
588                            data-direction="next"
589                             @click="handleNextStep"
590                            class="btn btn-primary step-btn action primary w-full">Next</button>
591                    <button type="submit" tabindex="0"
592                            data-direction="finish"
593                            id="webform_yk8I5y_submit_button"
594                            style="display:none"
595                            class="btn btn-primary step-btn action submit primary w-full ">Next</button>
596                    <button type="button" tabindex="0"
597                            data-direction="prev"
598                            style="display:none"
599                            class=" leading-5 text-sm m-auto mt-5 border-b border-primary-darker">Back</button>
600                    <div class="w-full text-center grecaptcha-legal mt-5">
601                        <p class="my-4 text-sm">
602    <em>This site is protected by reCAPTCHA.</em>
603</p>                    </div>
604
605                </div>
606            </div>
607        </div>  <!--wizard-->
608    </form>
609
610
611                    
612                </div>
613
614                         <style> .recaptcha-position-inline{ clear: both; box-sizing: border-box; padding: 0 2rem 2rem 0; width: 100%; float: left; }</style>         
615                        </div>
616    </div>
617
618 
619    <div id="webform-slide-out-button-yk8I5y"
620        x-data="{ isScrolled: false }"
621        @scroll.window="isScrolled = window.scrollY > 0"
622        @click="
623            isOpen = true;
624            window.surveyOpening = window.surveyOpeningSource === 'Opened from CTA'
625                ? 'Opened from CTA'
626                : 'Opened from sidebar';
627            if (!window.surveyStartedPushed) {
628                var openingSource = window.surveyOpening;
629                var enquiryTopicEl = document.getElementById('enquiry-topic');
630                window.surveyTypeVal = '';
631                window.logged_in_status = false;
632                window.dataLayer = window.dataLayer || [];
633                window.dataLayer.push({
634                    event: 'survey_started',
635                    site_type: window.site_type,
636                                        logged_in_status: false,
637                    journey_type: 'product',
638                    survey_opening: openingSource,
639                                                                            });
640                window.surveyStartedPushed = true;
641            }
642            window.surveyOpeningSource = null;
643        "
644        class="open-slide-form-button fixed z-30 py-4 pl-6 pr-4 right-5 md:right-10 bottom-5 md:bottom-16 lg:bottom-10 group flex items-center bg-primary text-white rounded-full overflow-hidden transition-all duration-300 ease-in-out hover:!w-[350px] justify-end cursor-pointer text-base shadow-md"
645        :class="isScrolled ? 'w-14' : 'w-[350px]'"
646        >
647        <span
648            class="whitespace-nowrap mr-auto transition-all duration-300 group-hover:!opacity-100 font-heading"
649            :class="isScrolled ? 'opacity-0' : 'opacity-100'"
650        >
651            Book a Free Survey        </span>
652        <i class="ti ti-calendar-check text-2xl flex items-center justify-center">
653        </i>
654    </div>
655
656            <div id="webform-slide-out-overlayyk8I5y"
657             x-cloak
658             class="fixed inset-0 bg-black opacity-50 z-[999]"
659             x-show="isOpen"
660             @click="isOpen = false"></div>
661    </div>
662
663
664<input name="form_key" type="hidden" value="9ScZqxAtVshasw9c" />
665    <noscript>
666        <section
667            class="message global noscript border-b-2 border-blue-500 bg-blue-50 shadow-none m-0 px-0 rounded-none font-normal"
668            aria-labelledby="messageGlobalNoScriptMessage"
669        >
670            <div class="container text-center">
671                <p id="messageGlobalNoScriptMessage">
672                    <strong>JavaScript seems to be disabled in your browser.</strong>
673                    <span>
674                        For the best experience on our site, be sure to turn on Javascript in your browser.                    </span>
675                </p>
676            </div>
677        </section>
678    </noscript>
679
680
681
682  <div class="page-wrapper"><header class="page-header"><a class="action skip sr-only focus:not-sr-only focus:absolute focus:z-40 focus:bg-white
683   contentarea"
684   href="#contentarea">
685    <span>
686        Skip to Content    </span>
687</a><!-- Action Name: /home -->
688<div id="header" role="banner"
689    x-data="{
690        ...initHeader(),
691        isSticky: false
692    }"
693
694    x-init="
695        const updateHeaderHeight = () => {
696            const headerEl = document.querySelector('#header');
697            const bannerEl = document.querySelector('.announcement-banner');
698            const headerHeight = headerEl ? headerEl.offsetHeight : 0;
699            const bannerHeight = bannerEl ? bannerEl.offsetHeight : 0;
700            document.documentElement.style.setProperty('--header-height', (headerHeight + bannerHeight) + 'px');
701        };
702        window.addEventListener('scroll', () => {
703            isSticky = window.scrollY > 50
704        });
705        window.addEventListener('resize', updateHeaderHeight);
706        updateHeaderHeight();
707    "
708    :class="isSticky
709    ? 'fixed top-0 left-0 z-100 w-full bg-white'
710    : 'relative z-30 w-full bg-white header-sticky [&_.mini-count]:!bg-white [&_.header-search]:bg-transparent [&_.header-search_.form-input]:bg-transparent [&_.header-search_.form-input]:text-white [&_.header-search_.form-input]:border-white [&_.header-search_.form-input]:placeholder:text-white'"
711    @private-content-loaded.window="getData(event.detail.data)"
712>
713    <div class="relative container flex flex-wrap lg:flex-nowrap items-center justify-between w-full min-h-[60px] px-5 py-5 mx-auto mt-0 md:px-10 lg:min-h-[84px]">
714
715        <!--Main Navigation-->
716        <div class="flex items-center gap-4 lg:gap-7">
717            <nav
718    x-data="initMenuMobile_6abf56c059c8f()"
719    @keydown.window.escape="closeMenu()"
720    @private-content-loaded.window="setCustomerState($event.detail.data)"
721    class="z-20 navigation leading-none"
722    aria-label="Site&#x20;navigation"
723    role="navigation"
724>
725    <button
726        x-ref="mobileMenuTrigger"
727        @click="openMenu()"
728        type="button"
729        aria-label="Open&#x20;menu"
730        aria-haspopup="menu"
731        :aria-expanded="open"
732        class="h-5 focus:border-primary-lighter focus:outline-none focus:ring-0 leading-none"
733        title="Navigation"
734    >
735        <i class="ti ti-menu text-xl"></i>
736    </button>
737    <div
738        x-ref="mobileMenuNavLinks"
739        class="
740            fixed top-0 left-0 w-full h-full flex
741            flex-col
742            -translate-x-full
743            z-40
744            transition-transform duration-300 ease-in-out
745            overflow-y-auto overflow-x-hidden max-w-[350px] md:max-w-[384px] lg:max-w-[100%] focus:border-primary-lighter focus:outline-none focus:ring-0"
746        :class="{
747            'translate-x-0': open,
748            '-translate-x-full': !open,
749        }"
750        :aria-hidden="open ? 'false' : 'true'"
751        role="dialog"
752        aria-modal="true"
753    >
754      <div
755            class="fixed inset-0 z-[-1]"
756            @click="closeMenu()"
757        ></div>
758        <div
759            class="lg:max-w-[480px] h-full bg-white shadow "
760            :class="{
761                'max-lg:-translate-x-full': mobilePanelActiveId,
762            }"
763        >
764            <div class="w-full h-full pb-[60px] overflow-y-auto overflow-x-hidden"
765                :class="{ 'submenu-open': mobilePanelActiveId !== null && mobilePanelActiveId !== 0 }"
766            >
767                <button
768                    @click="closeMenu()"
769                    class="flex justify-start w-full self-start py-5 px-5 md:px-10 focus:border-primary-lighter focus:outline-none focus:ring-0"
770                    aria-label="Close&#x20;menu"
771                    type="button"
772                >
773                    <i class="ti ti-x text-xl"></i>
774                </button>
775                <ul
776
777                    class="flex flex-col"
778                    aria-label="Site&#x20;navigation&#x20;links"
779                    >
780
781                                                                        <li x-show="open"
782                               x-transition:enter="transition ease-out duration-400"
783                                x-transition:enter-start="opacity-0 -translate-y-2"
784                                x-transition:enter-end="opacity-100 translate-y-0"
785                                style="transition-delay: 90ms;"
786                                class="md:hidden level-0 px-5 py-[6px] md:px-10">
787                                <a class="relative flex items-center cursor-pointer level-0 focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker" href="/book-a-survey/" title="Book a Survey"><span>Book a Survey</span></a>
788                            </li>
789                                                                                                                <li
790                            x-show="open"
791                            data-child-id="category-node-469-main"
792                            x-transition:enter="transition ease-out duration-700"
793                            x-transition:enter-start="opacity-0 -translate-y-2"
794                            x-transition:enter-end="opacity-100 translate-y-0"
795                            style="transition-delay: 0ms;"
796                            class="level-0 px-5 py-[6px] md:px-10"
797                            :class="{ 'active': mobilePanelActiveId === 'category-node-469' }"
798                        >
799                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
800                                                                        <a
801                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
802                                            title="Locks"
803                                            @click="openSubcategory('category-node-469')"
804                                            aria-label="Open&#x20;Locks&#x20;subcategories"
805                                                aria-haspopup="true"
806                                                :aria-expanded="mobilePanelActiveId === 'category-node-469'"
807                                        >
808                                            Locks                                            <i class="ti ti-chevron-right text-base"></i>
809                                        </a>
810                                                            </div>
811                                                            <div
812                                    data-child-id="category-node-469"
813                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
814                                    :class="{
815                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-469',
816                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-469',
817
818                                    }"
819                                >
820                                    <button
821                                        type="button"
822                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
822s:border-primary-lighter focus:outline-none focus:ring-0"
823                                        @click="backToMainCategories('category-node-469-main')"
824                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
825                                        >
826                                        <i class="ti ti-arrow-left text-xl"></i>
827                                    </button>
828                                                                        <ul aria-label="Subcategories">
829                                                                                <li x-show="mobilePanelActiveId === 'category-node-469'"
830                                            x-transition:enter="transition ease-out duration-700"
831                                            x-transition:enter-start="opacity-0 -translate-y-2"
832                                            x-transition:enter-end="opacity-100 translate-y-0"
833                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
834                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
835                                                Locks                                            </span>
836                                        </li>
837                                        <li x-show="mobilePanelActiveId === 'category-node-469'"
838                                            x-transition:enter="transition ease-out duration-700"
839                                            x-transition:enter-start="opacity-0 -translate-y-2"
840                                            x-transition:enter-end="opacity-100 translate-y-0"
841                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
842                                            <a
843                                                href="https://www.banham.co.uk/locks/"
844                                                title="Locks"
845                                            >
846                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
847                                                    All Locks                                                </span>
848                                            </a>
849                                        </li>
850                                                                                    <li
851                                            x-show="mobilePanelActiveId === 'category-node-469'"
852                                            x-transition:enter="transition ease-out duration-700"
853                                            x-transition:enter-start="opacity-0 -translate-y-2"
854                                            x-transition:enter-end="opacity-100 translate-y-0"
855                                            style="transition-delay: 80ms;"
856                                            class="px-5 pb-2 md:px-10">
857                                                <a
858                                                    href="https://www.banham.co.uk/locks/door-locks/"
859                                                    title="Door&#x20;Locks"
860                                                >
861                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
862                                                        Door Locks                                                    </span>
863                                                </a>
864                                            </li>
865                                                                                    <li
866                                            x-show="mobilePanelActiveId === 'category-node-469'"
867                                            x-transition:enter="transition ease-out duration-700"
868                                            x-transition:enter-start="opacity-0 -translate-y-2"
869                                            x-transition:enter-end="opacity-100 translate-y-0"
870                                            style="transition-delay: 120ms;"
871                                            class="px-5 pb-2 md:px-10">
872                                                <a
873                                                    href="https://www.banham.co.uk/locks/locks-additional-security/"
874                                                    title="Window&#x20;Locks&#x20;&amp;&#x20;Door&#x20;Bolts"
875                                                >
876                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
877                                                        Window Locks &amp; Door Bolts                                                    </span>
878                                                </a>
879                                            </li>
880                                                                                    <li
881                                            x-show="mobilePanelActiveId === 'category-node-469'"
882                                            x-transition:enter="transition ease-out duration-700"
883                                            x-transition:enter-start="opacity-0 -translate-y-2"
884                                            x-transition:enter-end="opacity-100 translate-y-0"
885                                            style="transition-delay: 160ms;"
886                                            class="px-5 pb-2 md:px-10">
887                                                <a
888                                                    href="https://www.banham.co.uk/locks/keys-and-accessories/"
889                                                    title="Keys,&#x20;Fobs&#x20;&amp;&#x20;Accessories"
890                                                >
891                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
892                                                        Keys, Fobs &amp; Accessories                                                    </span>
893                                                </a>
894                                            </li>
895                                                                            </ul>
896                                                                                                                    <ul class="submenu-custom-link">
897                                                <li x-show="mobilePanelActiveId === 'category-node-469'"
898                                                    x-transition:enter="transition ease-out duration-700"
899                                                    x-transition:enter-start="opacity-0 -translate-y-2"
900                                                    x-transition:enter-end="opacity-100 translate-y-0"
901                                                    style="transition-delay: 200ms;"
902                                                    class="px-5 pt-10 pb-2 md:px-10">
903                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">SERVICES</span>
904                                                </li>
905                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-469'"
906                                                        x-transition:enter="transition ease-out duration-700"
907                                                        x-transition:enter-start="opacity-0 -translate-y-2"
908                                                        x-transition:enter-end="opacity-100 translate-y-0"
909                                                        style="transition-delay: 240ms;"
910                                                        class="px-5 pb-2 md:px-10">
911                                                        <a href="/locks/key-cutting-key-registration/" title="Keycutting and Key Registration">
912                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keycutting and Key Registration</span>
913                                                        </a>
914                                                    </li>
915                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-469'"
916                                                        x-transition:enter="transition ease-out duration-700"
917                                                        x-transition:enter-start="opacity-0 -translate-y-2"
918                                                        x-transition:enter-end="opacity-100 translate-y-0"
919                                                        style="transition-delay: 280ms;"
920                                                        class="px-5 pb-2 md:px-10">
921                                                        <a href="/locksmith-service/" title="Emergency Locksmiths">
922                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Emergency Locksmiths</span>
923                                                        </a>
924                                                    </li>
925                                                                                            </ul>
926                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-469'"
927                                                    x-transition:enter="transition ease-out duration-700"
928                                                    x-transition:enter-start="opacity-0 -translate-y-2"
929                                                    x-transition:enter-end="opacity-100 translate-y-0"
930                                                    style="transition-delay: 320ms;"
931                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
932                                                    <img src="https://a.storyblok.com/f/286600090739628/400x400/b01178a975/banham-locks-menu.png" alt="Banham&#x20;door&#x20;lock&#x20;with&#x20;a&#x20;reflective&#x20;surface,&#x20;mounted&#x20;on&#x20;a&#x20;dark&#x20;blue&#x20;door&#x20;next&#x20;to&#x20;a&#x20;white&#x20;frame." class="w-full"/>
933                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
934                                                        <h4 class="text-white mb-0">Trusted Since 1926</h4>
935                                                        <p class="text-white mb-0"> Elegant, strong and secure: our locks come in
936a range of quality finishes.</p>
937                                                        <a href="/locks" class="underline-link"><span class="text-white">Learn More</span></a>
938                                                    </div>
939                                                </div>
940                                                                                                                                                        </div>
941                                                    </li>
942                                                                    <li
943                            x-show="open"
944                            data-child-id="category-node-472-main"
945                            x-transition:enter="transition ease-out duration-700"
946                            x-transition:enter-start="opacity-0 -translate-y-2"
947                            x-transition:enter-end="opacity-100 translate-y-0"
948                            style="transition-delay: 40ms;"
949                            class="level-0 px-5 py-[6px] md:px-10"
950                            :class="{ 'active': mobilePanelActiveId === 'category-node-472' }"
951                        >
952                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
953                                                                        <a
954                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
955                                            title="Doors"
956                                            @click="openSubcategory('category-node-472')"
957                                            aria-label="Open&#x20;Doors&#x20;subcategories"
958                                                aria-haspopup="true"
959                                                :aria-expanded="mobilePanelActiveId === 'category-node-472'"
960                                        >
961                                            Doors                                            <i class="ti ti-chevron-right text-base"></i>
962                                        </a>
963                                                            </div>
964                                                            <div
965                                    data-child-id="category-node-472"
966                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
967                                    :class="{
968                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-472',
969                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-472',
970
971                                    }"
972                                >
973                                    <button
974                                        type="button"
975                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
975s:border-primary-lighter focus:outline-none focus:ring-0"
976                                        @click="backToMainCategories('category-node-472-main')"
977                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
978                                        >
979                                        <i class="ti ti-arrow-left text-xl"></i>
980                                    </button>
981                                                                        <ul aria-label="Subcategories">
982                                                                                <li x-show="mobilePanelActiveId === 'category-node-472'"
983                                            x-transition:enter="transition ease-out duration-700"
984                                            x-transition:enter-start="opacity-0 -translate-y-2"
985                                            x-transition:enter-end="opacity-100 translate-y-0"
986                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
987                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
988                                                Doors                                            </span>
989                                        </li>
990                                        <li x-show="mobilePanelActiveId === 'category-node-472'"
991                                            x-transition:enter="transition ease-out duration-700"
992                                            x-transition:enter-start="opacity-0 -translate-y-2"
993                                            x-transition:enter-end="opacity-100 translate-y-0"
994                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
995                                            <a
996                                                href="https://www.banham.co.uk/doors/"
997                                                title="Doors"
998                                            >
999                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1000                                                    All Doors                                                </span>
1001                                            </a>
1002                                        </li>
1003                                                                                    <li
1004                                            x-show="mobilePanelActiveId === 'category-node-472'"
1005                                            x-transition:enter="transition ease-out duration-700"
1006                                            x-transition:enter-start="opacity-0 -translate-y-2"
1007                                            x-transition:enter-end="opacity-100 translate-y-0"
1008                                            style="transition-delay: 80ms;"
1009                                            class="px-5 pb-2 md:px-10">
1010                                                <a
1011                                                    href="https://www.banham.co.uk/doors/security-doors/"
1012                                                    title="Front&#x20;Doors"
1013                                                >
1014                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1015                                                        Front Doors                                                    </span>
1016                                                </a>
1017                                            </li>
1018                                                                                    <li
1019                                            x-show="mobilePanelActiveId === 'category-node-472'"
1020                                            x-transition:enter="transition ease-out duration-700"
1021                                            x-transition:enter-start="opacity-0 -translate-y-2"
1022                                            x-transition:enter-end="opacity-100 translate-y-0"
1023                                            style="transition-delay: 120ms;"
1024                                            class="px-5 pb-2 md:px-10">
1025                                                <a
1026                                                    href="https://www.banham.co.uk/doors/fire-doors/"
1027                                                    title="Fire&#x20;Doors"
1028                                                >
1029                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1030                                                        Fire Doors                                                    </span>
1031                                                </a>
1032                                            </li>
1033                                                                                    <li
1034                                            x-show="mobilePanelActiveId === 'category-node-472'"
1035                                            x-transition:enter="transition ease-out duration-700"
1036                                            x-transition:enter-start="opacity-0 -translate-y-2"
1037                                            x-transition:enter-end="opacity-100 translate-y-0"
1038                                            style="transition-delay: 160ms;"
1039                                            class="px-5 pb-2 md:px-10">
1040                                                <a
1041                                                    href="https://www.banham.co.uk/doors/door-furniture/"
1042                                                    title="Door&#x20;Furniture"
1043                                                >
1044                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1045                                                        Door Furniture                                                    </span>
1046                                                </a>
1047                                            </li>
1048                                                                            </ul>
1049                                                                                                                    <ul class="submenu-custom-link">
1050                                                <li x-show="mobilePanelActiveId === 'category-node-472'"
1051                                                    x-transition:enter="transition ease-out duration-700"
1052                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1053                                                    x-transition:enter-end="opacity-100 translate-y-0"
1054                                                    style="transition-delay: 200ms;"
1055                                                    class="px-5 pt-10 pb-2 md:px-10">
1056                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Services</span>
1057                                                </li>
1058                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-472'"
1059                                                        x-transition:enter="transition ease-out duration-700"
1060                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1061                                                        x-transition:enter-end="opacity-100 translate-y-0"
1062                                                        style="transition-delay: 240ms;"
1063                                                        class="px-5 pb-2 md:px-10">
1064                                                        <a href="/locks/key-cutting-key-registration/" title="Keycutting & Key Registration">
1065                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keycutting & Key Registration</span>
1066                                                        </a>
1067                                                    </li>
1068                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-472'"
1069                                                        x-transition:enter="transition ease-out duration-700"
1070                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1071                                                        x-transition:enter-end="opacity-100 translate-y-0"
1072                                                        style="transition-delay: 280ms;"
1073                                                        class="px-5 pb-2 md:px-10">
1074                                                        <a href="/locksmith-service/" title="Emergency Locksmiths">
1075                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Emergency Locksmiths</span>
1076                                                        </a>
1077                                                    </li>
1078                                                                                            </ul>
1079                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-472'"
1080                                                    x-transition:enter="transition ease-out duration-700"
1081                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1082                                                    x-transition:enter-end="opacity-100 translate-y-0"
1083                                                    style="transition-delay: 320ms;"
1084                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1085                                                    <img src="https://a.storyblok.com/f/286600090739628/400x400/4dcd04b053/banham-doors-menu.png" alt="Bespoke&#x20;Banham&#x20;Blue&#x20;door&#x20;with&#x20;stained&#x20;glass&#x20;panels&#x20;featuring&#x20;geometric&#x20;patterns.&#x20;Gold&#x20;hardware&#x20;and&#x20;mail&#x20;slot.&#x20;Greenery&#x20;visible&#x20;on&#x20;the&#x20;side." class="w-full"/>
1086                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1087                                                        <h4 class="text-white mb-0">Doors</h4>
1088                                                        <p class="text-white mb-0"> Security doors with bespoke design.</p>
1089                                                        <a href="/doors" class="underline-link"><span class="text-white">Learn More</span></a>
1090                                                    </div>
1091                                                </div>
1092                                                                                                                                                        </div>
1093                                                    </li>
1094                                                                    <li
1095                            x-show="open"
1096                            data-child-id="category-node-15-main"
1097                            x-transition:enter="transition ease-out duration-700"
1098                            x-transition:enter-start="opacity-0 -translate-y-2"
1099                            x-transition:enter-end="opacity-100 translate-y-0"
1100                            style="transition-delay: 80ms;"
1101                            class="level-0 px-5 py-[6px] md:px-10"
1102                            :class="{ 'active': mobilePanelActiveId === 'category-node-15' }"
1103                        >
1104                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1105                                                                        <a
1106                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1107                                            title="Burglar&#x20;Alarms"
1108                                            @click="openSubcategory('category-node-15')"
1109                                            aria-label="Open&#x20;Burglar&#x20;Alarms&#x20;subcategories"
1110                                                aria-haspopup="true"
1111                                                :aria-expanded="mobilePanelActiveId === 'category-node-15'"
1112                                        >
1113                                            Burglar Alarms                                            <i class="ti ti-chevron-right text-base"></i>
1114                                        </a>
1115                                                            </div>
1116                                                            <div
1117                                    data-child-id="category-node-15"
1118                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1119                                    :class="{
1120                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-15',
1121                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-15',
1122
1123                                    }"
1124                                >
1125                                    <button
1126                                        type="button"
1127                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1127s:border-primary-lighter focus:outline-none focus:ring-0"
1128                                        @click="backToMainCategories('category-node-15-main')"
1129                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1130                                        >
1131                                        <i class="ti ti-arrow-left text-xl"></i>
1132                                    </button>
1133                                                                        <ul aria-label="Subcategories">
1134                                                                                <li x-show="mobilePanelActiveId === 'category-node-15'"
1135                                            x-transition:enter="transition ease-out duration-700"
1136                                            x-transition:enter-start="opacity-0 -translate-y-2"
1137                                            x-transition:enter-end="opacity-100 translate-y-0"
1138                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1139                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1140                                                Burglar Alarms                                            </span>
1141                                        </li>
1142                                        <li x-show="mobilePanelActiveId === 'category-node-15'"
1143                                            x-transition:enter="transition ease-out duration-700"
1144                                            x-transition:enter-start="opacity-0 -translate-y-2"
1145                                            x-transition:enter-end="opacity-100 translate-y-0"
1146                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1147                                            <a
1148                                                href="https://www.banham.co.uk/burglar-alarms/"
1149                                                title="Burglar&#x20;Alarms"
1150                                            >
1151                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1152                                                    All Burglar Alarms                                                </span>
1153                                            </a>
1154                                        </li>
1155                                                                                    <li
1156                                            x-show="mobilePanelActiveId === 'category-node-15'"
1157                                            x-transition:enter="transition ease-out duration-700"
1158                                            x-transition:enter-start="opacity-0 -translate-y-2"
1159                                            x-transition:enter-end="opacity-100 translate-y-0"
1160                                            style="transition-delay: 80ms;"
1161                                            class="px-5 pb-2 md:px-10">
1162                                                <a
1163                                                    href="https://www.banham.co.uk/burglar-alarms/alarm-consultation/"
1164                                                    title="Alarm&#x20;Consultation"
1165                                                >
1166                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1167                                                        Alarm Consultation                                                    </span>
1168                                                </a>
1169                                            </li>
1170                                                                                    <li
1171                                            x-show="mobilePanelActiveId === 'category-node-15'"
1172                                            x-transition:enter="transition ease-out duration-700"
1173                                            x-transition:enter-start="opacity-0 -translate-y-2"
1174                                            x-transition:enter-end="opacity-100 translate-y-0"
1175                                            style="transition-delay: 120ms;"
1176                                            class="px-5 pb-2 md:px-10">
1177                                                <a
1178                                                    href="https://www.banham.co.uk/burglar-alarms/alarm-installation/"
1179                                                    title="Alarm&#x20;Installation"
1180                                                >
1181                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1182                                                        Alarm Installation                                                    </span>
1183                                                </a>
1184                                            </li>
1185                                                                                    <li
1186                                            x-show="mobilePanelActiveId === 'category-node-15'"
1187                                            x-transition:enter="transition ease-out duration-700"
1188                                            x-transition:enter-start="opacity-0 -translate-y-2"
1189                                            x-transition:enter-end="opacity-100 translate-y-0"
1190                                            style="transition-delay: 160ms;"
1191                                            class="px-5 pb-2 md:px-10">
1192                                                <a
1193                                                    href="https://www.banham.co.uk/burglar-alarms/car-shield/"
1194                                                    title="Car&#x20;Shield"
1195                                                >
1196                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1197                                                        Car Shield                                                    </span>
1198                                                </a>
1199                                            </li>
1200                                                                                    <li
1201                                            x-show="mobilePanelActiveId === 'category-node-15'"
1202                                            x-transition:enter="transition ease-out duration-700"
1203                                            x-transition:enter-start="opacity-0 -translate-y-2"
1204                                            x-transition:enter-end="opacity-100 translate-y-0"
1205                                            style="transition-delay: 200ms;"
1206                                            class="px-5 pb-2 md:px-10">
1207                                                <a
1208                                                    href="https://www.banham.co.uk/burglar-alarms/alarm-system-upgrade/"
1209                                                    title="Upgrade&#x20;Your&#x20;Alarm&#x20;System"
1210                                                >
1211                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1212                                                        Upgrade Your Alarm System                                                    </span>
1213                                                </a>
1214                                            </li>
1215                                                                            </ul>
1216                                                                                                                    <ul class="submenu-custom-link">
1217                                                <li x-show="mobilePanelActiveId === 'category-node-15'"
1218                                                    x-transition:enter="transition ease-out duration-700"
1219                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1220                                                    x-transition:enter-end="opacity-100 translate-y-0"
1221                                                    style="transition-delay: 240ms;"
1222                                                    class="px-5 pt-10 pb-2 md:px-10">
1223                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Services</span>
1224                                                </li>
1225                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-15'"
1226                                                        x-transition:enter="transition ease-out duration-700"
1227                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1228                                                        x-transition:enter-end="opacity-100 translate-y-0"
1229                                                        style="transition-delay: 280ms;"
1230                                                        class="px-5 pb-2 md:px-10">
1231                                                        <a href="/burglar-alarms/alarm-monitoring/" title="Alarm Monitoring">
1232                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Alarm Monitoring</span>
1233                                                        </a>
1234                                                    </li>
1235                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-15'"
1236                                                        x-transition:enter="transition ease-out duration-700"
1237                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1238                                                        x-transition:enter-end="opacity-100 translate-y-0"
1239                                                        style="transition-delay: 320ms;"
1240                                                        class="px-5 pb-2 md:px-10">
1241                                                        <a href="/burglar-alarms/banham-smart-security-app/" title="Smart Security App">
1242                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Smart Security App</span>
1243                                                        </a>
1244                                                    </li>
1245                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-15'"
1246                                                        x-transition:enter="transition ease-out duration-700"
1247                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1248                                                        x-transition:enter-end="opacity-100 translate-y-0"
1249                                                        style="transition-delay: 360ms;"
1250                                                        class="px-5 pb-2 md:px-10">
1251                                                        <a href="/keyholding/" title="Keyholding and Alarm Response">
1252                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keyholding and Alarm Response</span>
1253                                                        </a>
1254                                                    </li>
1255                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-15'"
1256                                                        x-transition:enter="transition ease-out duration-700"
1257                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1258                                                        x-transition:enter-end="opacity-100 translate-y-0"
1259                                                        style="transition-delay: 400ms;"
1260                                                        class="px-5 pb-2 md:px-10">
1261                                                        <a href="/commercial" title="Banham Commercial">
1262                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Banham Commercial</span>
1263                                                        </a>
1264                                                    </li>
1265                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-15'"
1266                                                        x-transition:enter="transition ease-out duration-700"
1267                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1268                                                        x-transition:enter-end="opacity-100 translate-y-0"
1269                                                        style="transition-delay: 440ms;"
1270                                                        class="px-5 pb-2 md:px-10">
1271                                                        <a href="/pstn/" title="Digital Phone Switchover">
1272                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Digital Phone Switchover</span>
1273                                                        </a>
1274                                                    </li>
1275                                                                                            </ul>
1276                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-15'"
1277                                                    x-transition:enter="transition ease-out duration-700"
1278                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1279                                                    x-transition:enter-end="opacity-100 translate-y-0"
1280                                                    style="transition-delay: 480ms;"
1281                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1282                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/e65714dc7f/alarms-q3-megamenu.jpg" alt="" class="w-full"/>
1283                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1284                                                        <h4 class="text-white mb-0">Alarms</h4>
1285                                                        <p class="text-white mb-0"> Bespoke-designed alarm systems installed and maintained by experts.</p>
1286                                                        <a href="/burglar-alarms" class="underline-link"><span class="text-white">Learn More</span></a>
1287                                                    </div>
1288                                                </div>
1289                                                                                                                                                        </div>
1290                                                    </li>
1291                                                                    <li
1292                            x-show="open"
1293                            data-child-id="category-node-4-main"
1294                            x-transition:enter="transition ease-out duration-700"
1295                            x-transition:enter-start="opacity-0 -translate-y-2"
1296                            x-transition:enter-end="opacity-100 translate-y-0"
1297                            style="transition-delay: 120ms;"
1298                            class="level-0 px-5 py-[6px] md:px-10"
1299                            :class="{ 'active': mobilePanelActiveId === 'category-node-4' }"
1300                        >
1301                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1302                                                                        <a
1303                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1304                                            title="CCTV"
1305                                            @click="openSubcategory('category-node-4')"
1306                                            aria-label="Open&#x20;CCTV&#x20;subcategories"
1307                                                aria-haspopup="true"
1308                                                :aria-expanded="mobilePanelActiveId === 'category-node-4'"
1309                                        >
1310                                            CCTV                                            <i class="ti ti-chevron-right text-base"></i>
1311                                        </a>
1312                                                            </div>
1313                                                            <div
1314                                    data-child-id="category-node-4"
1315                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1316                                    :class="{
1317                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-4',
1318                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-4',
1319
1320                                    }"
1321                                >
1322                                    <button
1323                                        type="button"
1324                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1324s:border-primary-lighter focus:outline-none focus:ring-0"
1325                                        @click="backToMainCategories('category-node-4-main')"
1326                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1327                                        >
1328                                        <i class="ti ti-arrow-left text-xl"></i>
1329                                    </button>
1330                                                                        <ul aria-label="Subcategories">
1331                                                                                <li x-show="mobilePanelActiveId === 'category-node-4'"
1332                                            x-transition:enter="transition ease-out duration-700"
1333                                            x-transition:enter-start="opacity-0 -translate-y-2"
1334                                            x-transition:enter-end="opacity-100 translate-y-0"
1335                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1336                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1337                                                CCTV                                            </span>
1338                                        </li>
1339                                        <li x-show="mobilePanelActiveId === 'category-node-4'"
1340                                            x-transition:enter="transition ease-out duration-700"
1341                                            x-transition:enter-start="opacity-0 -translate-y-2"
1342                                            x-transition:enter-end="opacity-100 translate-y-0"
1343                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1344                                            <a
1345                                                href="https://www.banham.co.uk/cctv-entry/"
1346                                                title="CCTV"
1347                                            >
1348                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1349                                                    All CCTV                                                </span>
1350                                            </a>
1351                                        </li>
1352                                                                                    <li
1353                                            x-show="mobilePanelActiveId === 'category-node-4'"
1354                                            x-transition:enter="transition ease-out duration-700"
1355                                            x-transition:enter-start="opacity-0 -translate-y-2"
1356                                            x-transition:enter-end="opacity-100 translate-y-0"
1357                                            style="transition-delay: 80ms;"
1358                                            class="px-5 pb-2 md:px-10">
1359                                                <a
1360                                                    href="https://www.banham.co.uk/cctv-entry/cctv/"
1361                                                    title="CCTV&#x20;Systems"
1362                                                >
1363                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1364                                                        CCTV Systems                                                    </span>
1365                                                </a>
1366                                            </li>
1367                                                                                    <li
1368                                            x-show="mobilePanelActiveId === 'category-node-4'"
1369                                            x-transition:enter="transition ease-out duration-700"
1370                                            x-transition:enter-start="opacity-0 -translate-y-2"
1371                                            x-transition:enter-end="opacity-100 translate-y-0"
1372                                            style="transition-delay: 120ms;"
1373                                            class="px-5 pb-2 md:px-10">
1374                                                <a
1375                                                    href="https://www.banham.co.uk/cctv-entry/entry-access-control-systems/"
1376                                                    title="Entry&#x20;&amp;&#x20;Access&#x20;Control&#x20;Systems"
1377                                                >
1378                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1379                                                        Entry &amp; Access Control Systems                                                    </span>
1380                                                </a>
1381                                            </li>
1382                                                                            </ul>
1383                                                                                                                    <ul class="submenu-custom-link">
1384                                                <li x-show="mobilePanelActiveId === 'category-node-4'"
1385                                                    x-transition:enter="transition ease-out duration-700"
1386                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1387                                                    x-transition:enter-end="opacity-100 translate-y-0"
1388                                                    style="transition-delay: 160ms;"
1389                                                    class="px-5 pt-10 pb-2 md:px-10">
1390                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Services</span>
1391                                                </li>
1392                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1393                                                        x-transition:enter="transition ease-out duration-700"
1394                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1395                                                        x-transition:enter-end="opacity-100 translate-y-0"
1396                                                        style="transition-delay: 200ms;"
1397                                                        class="px-5 pb-2 md:px-10">
1398                                                        <a href="/cctv-entry/cctv/cctv-monitoring-services/" title="CCTV Monitoring">
1399                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">CCTV Monitoring</span>
1400                                                        </a>
1401                                                    </li>
1402                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1403                                                        x-transition:enter="transition ease-out duration-700"
1404                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1405                                                        x-transition:enter-end="opacity-100 translate-y-0"
1406                                                        style="transition-delay: 240ms;"
1407                                                        class="px-5 pb-2 md:px-10">
1408                                                        <a href="/keyholding/" title="Keyholding and Alarm Response">
1409                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keyholding and Alarm Response</span>
1410                                                        </a>
1411                                                    </li>
1412                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1413                                                        x-transition:enter="transition ease-out duration-700"
1414                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1415                                                        x-transition:enter-end="opacity-100 translate-y-0"
1416                                                        style="transition-delay: 280ms;"
1417                                                        class="px-5 pb-2 md:px-10">
1418                                                        <a href="/cctv-entry/cctv/routine-cctv-maintenance-24-hour-service/" title="Routine CCTV Maintenance and 24-Hour Service">
1419                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Routine CCTV Maintenance and 24-Hour Service</span>
1420                                                        </a>
1421                                                    </li>
1422                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1423                                                        x-transition:enter="transition ease-out duration-700"
1424                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1425                                                        x-transition:enter-end="opacity-100 translate-y-0"
1426                                                        style="transition-delay: 320ms;"
1427                                                        class="px-5 pb-2 md:px-10">
1428                                                        <a href="/commercial" title="Banham Commercial">
1429                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Banham Commercial</span>
1430                                                        </a>
1431                                                    </li>
1432                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1433                                                        x-transition:enter="transition ease-out duration-700"
1434                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1435                                                        x-transition:enter-end="opacity-100 translate-y-0"
1436                                                        style="transition-delay: 360ms;"
1437                                                        class="px-5 pb-2 md:px-10">
1438                                                        <a href="/pstn/" title="Digital Phone Switchover">
1439                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Digital Phone Switchover</span>
1440                                                        </a>
1441                                                    </li>
1442                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-4'"
1443                                                        x-transition:enter="transition ease-out duration-700"
1444                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1445                                                        x-transition:enter-end="opacity-100 translate-y-0"
1446                                                        style="transition-delay: 400ms;"
1447                                                        class="px-5 pb-2 md:px-10">
1448                                                        <a href="/direct-debits/" title="Direct Debit Options">
1449                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Direct Debit Options</span>
1450                                                        </a>
1451                                                    </li>
1452                                                                                            </ul>
1453                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-4'"
1454                                                    x-transition:enter="transition ease-out duration-700"
1455                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1456                                                    x-transition:enter-end="opacity-100 translate-y-0"
1457                                                    style="transition-delay: 440ms;"
1458                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1459                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/5e9a2dae8f/meganav_cctv_entry2.jpg" alt="" class="w-full"/>
1460                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1461                                                        <h4 class="text-white mb-0">CCTV &amp; Entry</h4>
1462                                                        <p class="text-white mb-0"> Intelligent CCTV and entry systems tailored to your property.</p>
1463                                                        <a href="/cctv-entry" class="underline-link"><span class="text-white">Learn More</span></a>
1464                                                    </div>
1465                                                </div>
1466                                                                                                                                                        </div>
1467                                                    </li>
1468                                                                    <li
1469                            x-show="open"
1470                            data-child-id="category-node-30-main"
1471                            x-transition:enter="transition ease-out duration-700"
1472                            x-transition:enter-start="opacity-0 -translate-y-2"
1473                            x-transition:enter-end="opacity-100 translate-y-0"
1474                            style="transition-delay: 160ms;"
1475                            class="level-0 px-5 py-[6px] md:px-10"
1476                            :class="{ 'active': mobilePanelActiveId === 'category-node-30' }"
1477                        >
1478                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1479                                                                        <a
1480                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1481                                            title="Fire&#x20;Alarms"
1482                                            @click="openSubcategory('category-node-30')"
1483                                            aria-label="Open&#x20;Fire&#x20;Alarms&#x20;subcategories"
1484                                                aria-haspopup="true"
1485                                                :aria-expanded="mobilePanelActiveId === 'category-node-30'"
1486                                        >
1487                                            Fire Alarms                                            <i class="ti ti-chevron-right text-base"></i>
1488                                        </a>
1489                                                            </div>
1490                                                            <div
1491                                    data-child-id="category-node-30"
1492                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1493                                    :class="{
1494                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-30',
1495                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-30',
1496
1497                                    }"
1498                                >
1499                                    <button
1500                                        type="button"
1501                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1501s:border-primary-lighter focus:outline-none focus:ring-0"
1502                                        @click="backToMainCategories('category-node-30-main')"
1503                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1504                                        >
1505                                        <i class="ti ti-arrow-left text-xl"></i>
1506                                    </button>
1507                                                                            <ul aria-label="Category&#x20;content">
1508                                            <li x-show="mobilePanelActiveId === 'category-node-30'"
1509                                                x-transition:enter="transition ease-out duration-700"
1510                                                x-transition:enter-start="opacity-0 -translate-y-2"
1511                                                x-transition:enter-end="opacity-100 translate-y-0"
1512                                                style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1513                                                <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1514                                                    Fire Alarms                                                </span>
1515                                            </li>
1516                                            <li x-show="mobilePanelActiveId === 'category-node-30'"
1517                                                x-transition:enter="transition ease-out duration-700"
1518                                                x-transition:enter-start="opacity-0 -translate-y-2"
1519                                                x-transition:enter-end="opacity-100 translate-y-0"
1520                                                style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1521                                                <a
1522                                                    href="https://www.banham.co.uk/fire-alarms/"
1523                                                    title="Fire&#x20;Alarms"
1524                                                >
1525                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1526                                                        All Fire Alarms                                                    </span>
1527                                                </a>
1528                                            </li>
1529                                        </ul>
1530                                                                                                                    <ul class="submenu-custom-link">
1531                                                <li x-show="mobilePanelActiveId === 'category-node-30'"
1532                                                    x-transition:enter="transition ease-out duration-700"
1533                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1534                                                    x-transition:enter-end="opacity-100 translate-y-0"
1535                                                    style="transition-delay: 80ms;"
1536                                                    class="px-5 pt-10 pb-2 md:px-10">
1537                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Related products and services</span>
1538                                                </li>
1539                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1540                                                        x-transition:enter="transition ease-out duration-700"
1541                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1542                                                        x-transition:enter-end="opacity-100 translate-y-0"
1543                                                        style="transition-delay: 120ms;"
1544                                                        class="px-5 pb-2 md:px-10">
1545                                                        <a href="/fire-extinguishers/" title="Fire Extinguishers">
1546                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Fire Extinguishers</span>
1547                                                        </a>
1548                                                    </li>
1549                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1550                                                        x-transition:enter="transition ease-out duration-700"
1551                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1552                                                        x-transition:enter-end="opacity-100 translate-y-0"
1553                                                        style="transition-delay: 160ms;"
1554                                                        class="px-5 pb-2 md:px-10">
1555                                                        <a href="/doors/fire-doors/" title="Fire Doors">
1556                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Fire Doors</span>
1557                                                        </a>
1558                                                    </li>
1559                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1560                                                        x-transition:enter="transition ease-out duration-700"
1561                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1562                                                        x-transition:enter-end="opacity-100 translate-y-0"
1563                                                        style="transition-delay: 200ms;"
1564                                                        class="px-5 pb-2 md:px-10">
1565                                                        <a href="/burglar-alarms/alarm-monitoring/" title="Alarm Monitoring">
1566                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Alarm Monitoring</span>
1567                                                        </a>
1568                                                    </li>
1569                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1570                                                        x-transition:enter="transition ease-out duration-700"
1571                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1572                                                        x-transition:enter-end="opacity-100 translate-y-0"
1573                                                        style="transition-delay: 240ms;"
1574                                                        class="px-5 pb-2 md:px-10">
1575                                                        <a href="/keyholding/" title="Keyholding and Alarm Response">
1576                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keyholding and Alarm Response</span>
1577                                                        </a>
1578                                                    </li>
1579                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1580                                                        x-transition:enter="transition ease-out duration-700"
1581                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1582                                                        x-transition:enter-end="opacity-100 translate-y-0"
1583                                                        style="transition-delay: 280ms;"
1584                                                        class="px-5 pb-2 md:px-10">
1585                                                        <a href="/burglar-alarms/routine-alarm-maintenance-24-hour-service/" title="Alarm Maintenance 24/7">
1586                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Alarm Maintenance 24/7</span>
1587                                                        </a>
1588                                                    </li>
1589                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-30'"
1590                                                        x-transition:enter="transition ease-out duration-700"
1591                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1592                                                        x-transition:enter-end="opacity-100 translate-y-0"
1593                                                        style="transition-delay: 320ms;"
1594                                                        class="px-5 pb-2 md:px-10">
1595                                                        <a href="/commercial" title="Banham Commercial">
1596                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Banham Commercial</span>
1597                                                        </a>
1598                                                    </li>
1599                                                                                            </ul>
1600                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-30'"
1601                                                    x-transition:enter="transition ease-out duration-700"
1602                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1603                                                    x-transition:enter-end="opacity-100 translate-y-0"
1604                                                    style="transition-delay: 360ms;"
1605                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1606                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/acdca88f26/burglar_alarms_and_fire.jpg" alt="" class="w-full"/>
1607                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1608                                                        <h4 class="text-white mb-0">Alarms &amp; CCTV</h4>
1609                                                        <p class="text-white mb-0"> Bespoke-designed alarm systems installed and maintained by experts.</p>
1610                                                        <a href="/fire-alarms" class="underline-link"><span class="text-white">Learn More</span></a>
1611                                                    </div>
1612                                                </div>
1613                                                                                                                                                        </div>
1614                                                    </li>
1615                                                                    <li
1616                            x-show="open"
1617                            data-child-id="category-node-6-main"
1618                            x-transition:enter="transition ease-out duration-700"
1619                            x-transition:enter-start="opacity-0 -translate-y-2"
1620                            x-transition:enter-end="opacity-100 translate-y-0"
1621                            style="transition-delay: 200ms;"
1622                            class="level-0 px-5 py-[6px] md:px-10"
1623                            :class="{ 'active': mobilePanelActiveId === 'category-node-6' }"
1624                        >
1625                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1626                                                                        <a
1627                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1628                                            title="Safes"
1629                                            @click="openSubcategory('category-node-6')"
1630                                            aria-label="Open&#x20;Safes&#x20;subcategories"
1631                                                aria-haspopup="true"
1632                                                :aria-expanded="mobilePanelActiveId === 'category-node-6'"
1633                                        >
1634                                            Safes                                            <i class="ti ti-chevron-right text-base"></i>
1635                                        </a>
1636                                                            </div>
1637                                                            <div
1638                                    data-child-id="category-node-6"
1639                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1640                                    :class="{
1641                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-6',
1642                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-6',
1643
1644                                    }"
1645                                >
1646                                    <button
1647                                        type="button"
1648                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1648s:border-primary-lighter focus:outline-none focus:ring-0"
1649                                        @click="backToMainCategories('category-node-6-main')"
1650                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1651                                        >
1652                                        <i class="ti ti-arrow-left text-xl"></i>
1653                                    </button>
1654                                                                        <ul aria-label="Subcategories">
1655                                                                                <li x-show="mobilePanelActiveId === 'category-node-6'"
1656                                            x-transition:enter="transition ease-out duration-700"
1657                                            x-transition:enter-start="opacity-0 -translate-y-2"
1658                                            x-transition:enter-end="opacity-100 translate-y-0"
1659                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1660                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1661                                                Safes                                            </span>
1662                                        </li>
1663                                        <li x-show="mobilePanelActiveId === 'category-node-6'"
1664                                            x-transition:enter="transition ease-out duration-700"
1665                                            x-transition:enter-start="opacity-0 -translate-y-2"
1666                                            x-transition:enter-end="opacity-100 translate-y-0"
1667                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1668                                            <a
1669                                                href="https://www.banham.co.uk/safes/"
1670                                                title="Safes"
1671                                            >
1672                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1673                                                    All Safes                                                </span>
1674                                            </a>
1675                                        </li>
1676                                                                                    <li
1677                                            x-show="mobilePanelActiveId === 'category-node-6'"
1678                                            x-transition:enter="transition ease-out duration-700"
1679                                            x-transition:enter-start="opacity-0 -translate-y-2"
1680                                            x-transition:enter-end="opacity-100 translate-y-0"
1681                                            style="transition-delay: 80ms;"
1682                                            class="px-5 pb-2 md:px-10">
1683                                                <a
1684                                                    href="https://www.banham.co.uk/bespoke-safes/"
1685                                                    title="Bespoke&#x20;Safes"
1686                                                >
1687                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1688                                                        Bespoke Safes                                                    </span>
1689                                                </a>
1690                                            </li>
1691                                                                                    <li
1692                                            x-show="mobilePanelActiveId === 'category-node-6'"
1693                                            x-transition:enter="transition ease-out duration-700"
1694                                            x-transition:enter-start="opacity-0 -translate-y-2"
1695                                            x-transition:enter-end="opacity-100 translate-y-0"
1696                                            style="transition-delay: 120ms;"
1697                                            class="px-5 pb-2 md:px-10">
1698                                                <a
1699                                                    href="https://www.banham.co.uk/safes/freestanding-safes/"
1700                                                    title="Freestanding&#x20;Safes"
1701                                                >
1702                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1703                                                        Freestanding Safes                                                    </span>
1704                                                </a>
1705                                            </li>
1706                                                                            </ul>
1707                                                                                                                    <ul class="submenu-custom-link">
1708                                                <li x-show="mobilePanelActiveId === 'category-node-6'"
1709                                                    x-transition:enter="transition ease-out duration-700"
1710                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1711                                                    x-transition:enter-end="opacity-100 translate-y-0"
1712                                                    style="transition-delay: 160ms;"
1713                                                    class="px-5 pt-10 pb-2 md:px-10">
1714                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Services</span>
1715                                                </li>
1716                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-6'"
1717                                                        x-transition:enter="transition ease-out duration-700"
1718                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1719                                                        x-transition:enter-end="opacity-100 translate-y-0"
1720                                                        style="transition-delay: 200ms;"
1721                                                        class="px-5 pb-2 md:px-10">
1722                                                        <a href="/safes/safe-services/" title="Safe Services">
1723                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Safe Services</span>
1724                                                        </a>
1725                                                    </li>
1726                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-6'"
1727                                                        x-transition:enter="transition ease-out duration-700"
1728                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1729                                                        x-transition:enter-end="opacity-100 translate-y-0"
1730                                                        style="transition-delay: 240ms;"
1731                                                        class="px-5 pb-2 md:px-10">
1732                                                        <a href="/locksmith-service/" title="Emergency Locksmiths">
1733                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Emergency Locksmiths</span>
1734                                                        </a>
1735                                                    </li>
1736                                                                                            </ul>
1737                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-6'"
1738                                                    x-transition:enter="transition ease-out duration-700"
1739                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1740                                                    x-transition:enter-end="opacity-100 translate-y-0"
1741                                                    style="transition-delay: 280ms;"
1742                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1743                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/2f56f4ebea/meganav_safes.png" alt="" class="w-full"/>
1744                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1745                                                        <h4 class="text-white mb-0">Safes</h4>
1746                                                        <p class="text-white mb-0"> Beautifully-designed, insurance-approved safes to keep your valuables secure.</p>
1747                                                        <a href="/safes" class="underline-link"><span class="text-white">Learn More</span></a>
1748                                                    </div>
1749                                                </div>
1750                                                                                                                                                        </div>
1751                                                    </li>
1752                                                                    <li
1753                            x-show="open"
1754                            data-child-id="category-node-7-main"
1755                            x-transition:enter="transition ease-out duration-700"
1756                            x-transition:enter-start="opacity-0 -translate-y-2"
1757                            x-transition:enter-end="opacity-100 translate-y-0"
1758                            style="transition-delay: 240ms;"
1759                            class="level-0 px-5 py-[6px] md:px-10"
1760                            :class="{ 'active': mobilePanelActiveId === 'category-node-7' }"
1761                        >
1762                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1763                                                                        <a
1764                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1765                                            title="Gates&#x20;&amp;&#x20;Grilles"
1766                                            @click="openSubcategory('category-node-7')"
1767                                            aria-label="Open&#x20;Gates&#x20;&amp;&#x20;Grilles&#x20;subcategories"
1768                                                aria-haspopup="true"
1769                                                :aria-expanded="mobilePanelActiveId === 'category-node-7'"
1770                                        >
1771                                            Gates &amp; Grilles                                            <i class="ti ti-chevron-right text-base"></i>
1772                                        </a>
1773                                                            </div>
1774                                                            <div
1775                                    data-child-id="category-node-7"
1776                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1777                                    :class="{
1778                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-7',
1779                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-7',
1780
1781                                    }"
1782                                >
1783                                    <button
1784                                        type="button"
1785                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1785s:border-primary-lighter focus:outline-none focus:ring-0"
1786                                        @click="backToMainCategories('category-node-7-main')"
1787                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1788                                        >
1789                                        <i class="ti ti-arrow-left text-xl"></i>
1790                                    </button>
1791                                                                        <ul aria-label="Subcategories">
1792                                                                                <li x-show="mobilePanelActiveId === 'category-node-7'"
1793                                            x-transition:enter="transition ease-out duration-700"
1794                                            x-transition:enter-start="opacity-0 -translate-y-2"
1795                                            x-transition:enter-end="opacity-100 translate-y-0"
1796                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1797                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1798                                                Gates &amp; Grilles                                            </span>
1799                                        </li>
1800                                        <li x-show="mobilePanelActiveId === 'category-node-7'"
1801                                            x-transition:enter="transition ease-out duration-700"
1802                                            x-transition:enter-start="opacity-0 -translate-y-2"
1803                                            x-transition:enter-end="opacity-100 translate-y-0"
1804                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1805                                            <a
1806                                                href="https://www.banham.co.uk/gates-grilles-shutters/"
1807                                                title="Gates&#x20;&amp;&#x20;Grilles"
1808                                            >
1809                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1810                                                    All Gates &amp; Grilles                                                </span>
1811                                            </a>
1812                                        </li>
1813                                                                                    <li
1814                                            x-show="mobilePanelActiveId === 'category-node-7'"
1815                                            x-transition:enter="transition ease-out duration-700"
1816                                            x-transition:enter-start="opacity-0 -translate-y-2"
1817                                            x-transition:enter-end="opacity-100 translate-y-0"
1818                                            style="transition-delay: 80ms;"
1819                                            class="px-5 pb-2 md:px-10">
1820                                                <a
1821                                                    href="https://www.banham.co.uk/gates-grilles-shutters/gates/"
1822                                                    title="Security&#x20;Gates"
1823                                                >
1824                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1825                                                        Security Gates                                                    </span>
1826                                                </a>
1827                                            </li>
1828                                                                                    <li
1829                                            x-show="mobilePanelActiveId === 'category-node-7'"
1830                                            x-transition:enter="transition ease-out duration-700"
1831                                            x-transition:enter-start="opacity-0 -translate-y-2"
1832                                            x-transition:enter-end="opacity-100 translate-y-0"
1833                                            style="transition-delay: 120ms;"
1834                                            class="px-5 pb-2 md:px-10">
1835                                                <a
1836                                                    href="https://www.banham.co.uk/gates-grilles-shutters/gr
1836illes/"
1837                                                    title="Security&#x20;Grilles"
1838                                                >
1839                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1840                                                        Security Grilles                                                    </span>
1841                                                </a>
1842                                            </li>
1843                                                                                    <li
1844                                            x-show="mobilePanelActiveId === 'category-node-7'"
1845                                            x-transition:enter="transition ease-out duration-700"
1846                                            x-transition:enter-start="opacity-0 -translate-y-2"
1847                                            x-transition:enter-end="opacity-100 translate-y-0"
1848                                            style="transition-delay: 160ms;"
1849                                            class="px-5 pb-2 md:px-10">
1850                                                <a
1851                                                    href="https://www.banham.co.uk/gates-grilles-shutters/railings/"
1852                                                    title="Railings"
1853                                                >
1854                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1855                                                        Railings                                                    </span>
1856                                                </a>
1857                                            </li>
1858                                                                                    <li
1859                                            x-show="mobilePanelActiveId === 'category-node-7'"
1860                                            x-transition:enter="transition ease-out duration-700"
1861                                            x-transition:enter-start="opacity-0 -translate-y-2"
1862                                            x-transition:enter-end="opacity-100 translate-y-0"
1863                                            style="transition-delay: 200ms;"
1864                                            class="px-5 pb-2 md:px-10">
1865                                                <a
1866                                                    href="https://www.banham.co.uk/gates-grilles-shutters/roller-shutters/"
1867                                                    title="Roller&#x20;Shutters"
1868                                                >
1869                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1870                                                        Roller Shutters                                                    </span>
1871                                                </a>
1872                                            </li>
1873                                                                            </ul>
1874                                                                                                                    <ul class="submenu-custom-link">
1875                                                <li x-show="mobilePanelActiveId === 'category-node-7'"
1876                                                    x-transition:enter="transition ease-out duration-700"
1877                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1878                                                    x-transition:enter-end="opacity-100 translate-y-0"
1879                                                    style="transition-delay: 240ms;"
1880                                                    class="px-5 pt-10 pb-2 md:px-10">
1881                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Related Products </span>
1882                                                </li>
1883                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-7'"
1884                                                        x-transition:enter="transition ease-out duration-700"
1885                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1886                                                        x-transition:enter-end="opacity-100 translate-y-0"
1887                                                        style="transition-delay: 280ms;"
1888                                                        class="px-5 pb-2 md:px-10">
1889                                                        <a href="/locks/key-cutting-key-registration/" title="Keycutting and Key Registration">
1890                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Keycutting and Key Registration</span>
1891                                                        </a>
1892                                                    </li>
1893                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-7'"
1894                                                        x-transition:enter="transition ease-out duration-700"
1895                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1896                                                        x-transition:enter-end="opacity-100 translate-y-0"
1897                                                        style="transition-delay: 320ms;"
1898                                                        class="px-5 pb-2 md:px-10">
1899                                                        <a href="/locksmith-service/" title="Emergency Locksmiths">
1900                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Emergency Locksmiths</span>
1901                                                        </a>
1902                                                    </li>
1903                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-7'"
1904                                                        x-transition:enter="transition ease-out duration-700"
1905                                                        x-transition:enter-start="opacity-0 -translate-y-2"
1906                                                        x-transition:enter-end="opacity-100 translate-y-0"
1907                                                        style="transition-delay: 360ms;"
1908                                                        class="px-5 pb-2 md:px-10">
1909                                                        <a href="/commercial" title="Banham Commercial">
1910                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Banham Commercial</span>
1911                                                        </a>
1912                                                    </li>
1913                                                                                            </ul>
1914                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-7'"
1915                                                    x-transition:enter="transition ease-out duration-700"
1916                                                    x-transition:enter-start="opacity-0 -translate-y-2"
1917                                                    x-transition:enter-end="opacity-100 translate-y-0"
1918                                                    style="transition-delay: 400ms;"
1919                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
1920                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/4001e6e188/meganav_gates_grilles_shutters.png" alt="" class="w-full"/>
1921                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
1922                                                        <h4 class="text-white mb-0">Gates, Grilles &amp; Shutters</h4>
1923                                                        <p class="text-white mb-0"> Sturdy gates, grilles and shutters we can customise to match your property.</p>
1924                                                        <a href="/gates-grilles-shutters/" class="underline-link"><span class="text-white">Learn More</span></a>
1925                                                    </div>
1926                                                </div>
1927                                                                                                                                                        </div>
1928                                                    </li>
1929                                                                    <li
1930                            x-show="open"
1931                            data-child-id="category-node-54-main"
1932                            x-transition:enter="transition ease-out duration-700"
1933                            x-transition:enter-start="opacity-0 -translate-y-2"
1934                            x-transition:enter-end="opacity-100 translate-y-0"
1935                            style="transition-delay: 280ms;"
1936                            class="level-0 px-5 py-[6px] md:px-10"
1937                            :class="{ 'active': mobilePanelActiveId === 'category-node-54' }"
1938                        >
1939                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
1940                                                                        <a
1941                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
1942                                            title="Keyholding"
1943                                            @click="openSubcategory('category-node-54')"
1944                                            aria-label="Open&#x20;Keyholding&#x20;subcategories"
1945                                                aria-haspopup="true"
1946                                                :aria-expanded="mobilePanelActiveId === 'category-node-54'"
1947                                        >
1948                                            Keyholding                                            <i class="ti ti-chevron-right text-base"></i>
1949                                        </a>
1950                                                            </div>
1951                                                            <div
1952                                    data-child-id="category-node-54"
1953                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
1954                                    :class="{
1955                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-54',
1956                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-54',
1957
1958                                    }"
1959                                >
1960                                    <button
1961                                        type="button"
1962                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
1962s:border-primary-lighter focus:outline-none focus:ring-0"
1963                                        @click="backToMainCategories('category-node-54-main')"
1964                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
1965                                        >
1966                                        <i class="ti ti-arrow-left text-xl"></i>
1967                                    </button>
1968                                                                        <ul aria-label="Subcategories">
1969                                                                                <li x-show="mobilePanelActiveId === 'category-node-54'"
1970                                            x-transition:enter="transition ease-out duration-700"
1971                                            x-transition:enter-start="opacity-0 -translate-y-2"
1972                                            x-transition:enter-end="opacity-100 translate-y-0"
1973                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
1974                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
1975                                                Keyholding                                            </span>
1976                                        </li>
1977                                        <li x-show="mobilePanelActiveId === 'category-node-54'"
1978                                            x-transition:enter="transition ease-out duration-700"
1979                                            x-transition:enter-start="opacity-0 -translate-y-2"
1980                                            x-transition:enter-end="opacity-100 translate-y-0"
1981                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
1982                                            <a
1983                                                href="https://www.banham.co.uk/keyholding/"
1984                                                title="Keyholding"
1985                                            >
1986                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
1987                                                    All Keyholding                                                </span>
1988                                            </a>
1989                                        </li>
1990                                                                                    <li
1991                                            x-show="mobilePanelActiveId === 'category-node-54'"
1992                                            x-transition:enter="transition ease-out duration-700"
1993                                            x-transition:enter-start="opacity-0 -translate-y-2"
1994                                            x-transition:enter-end="opacity-100 translate-y-0"
1995                                            style="transition-delay: 80ms;"
1996                                            class="px-5 pb-2 md:px-10">
1997                                                <a
1998                                                    href="https://www.banham.co.uk/keyholding/residential/"
1999                                                    title="For&#x20;Homes"
2000                                                >
2001                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
2002                                                        For Homes                                                    </span>
2003                                                </a>
2004                                            </li>
2005                                                                                    <li
2006                                            x-show="mobilePanelActiveId === 'category-node-54'"
2007                                            x-transition:enter="transition ease-out duration-700"
2008                                            x-transition:enter-start="opacity-0 -translate-y-2"
2009                                            x-transition:enter-end="opacity-100 translate-y-0"
2010                                            style="transition-delay: 120ms;"
2011                                            class="px-5 pb-2 md:px-10">
2012                                                <a
2013                                                    href="https://www.banham.co.uk/keyholding/pricing/"
2014                                                    title="Pricing"
2015                                                >
2016                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
2017                                                        Pricing                                                    </span>
2018                                                </a>
2019                                            </li>
2020                                                                            </ul>
2021                                                                                                                    <ul class="submenu-custom-link">
2022                                                <li x-show="mobilePanelActiveId === 'category-node-54'"
2023                                                    x-transition:enter="transition ease-out duration-700"
2024                                                    x-transition:enter-start="opacity-0 -translate-y-2"
2025                                                    x-transition:enter-end="opacity-100 translate-y-0"
2026                                                    style="transition-delay: 160ms;"
2027                                                    class="px-5 pt-10 pb-2 md:px-10">
2028                                                    <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">Related Services</span>
2029                                                </li>
2030                                                                                                    <li x-show="mobilePanelActiveId === 'category-node-54'"
2031                                                        x-transition:enter="transition ease-out duration-700"
2032                                                        x-transition:enter-start="opacity-0 -translate-y-2"
2033                                                        x-transition:enter-end="opacity-100 translate-y-0"
2034                                                        style="transition-delay: 200ms;"
2035                                                        class="px-5 pb-2 md:px-10">
2036                                                        <a href="/commercial" title="Banham Commercial">
2037                                                            <span class="relative text-sm text-primary-darker hover:text-primary-darker">Banham Commercial</span>
2038                                                        </a>
2039                                                    </li>
2040                                                                                            </ul>
2041                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-54'"
2042                                                    x-transition:enter="transition ease-out duration-700"
2043                                                    x-transition:enter-start="opacity-0 -translate-y-2"
2044                                                    x-transition:enter-end="opacity-100 translate-y-0"
2045                                                    style="transition-delay: 240ms;"
2046                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
2047                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/64109011f1/meganav-trade-more-from-banham.jpg" alt="" class="w-full"/>
2048                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
2049                                                        <h4 class="text-white mb-0">Keyholding &amp; Alarm Response</h4>
2050                                                        <p class="text-white mb-0"> Peace of mind knowing we&#039;ll be there when you need us.</p>
2051                                                        <a href="/keyholding" class="underline-link"><span class="text-white">Learn More</span></a>
2052                                                    </div>
2053                                                </div>
2054                                                                                                                                                        </div>
2055                                                    </li>
2056                                                                    <li
2057                            x-show="open"
2058                            data-child-id="category-node-47-main"
2059                            x-transition:enter="transition ease-out duration-700"
2060                            x-transition:enter-start="opacity-0 -translate-y-2"
2061                            x-transition:enter-end="opacity-100 translate-y-0"
2062                            style="transition-delay: 320ms;"
2063                            class="level-0 px-5 py-[6px] md:px-10"
2064                            :class="{ 'active': mobilePanelActiveId === 'category-node-47' }"
2065                        >
2066                            <div class="flex items-center transition-transform duration-150 ease-in-out transform">
2067                                                                        <a
2068                                            class="relative flex items-center justify-between cursor-pointer level-0 w-full focus:border-primary-lighter focus:outline-none focus:ring-0 hover:text-primary-darker"
2069                                            title="Locksmith"
2070                                            @click="openSubcategory('category-node-47')"
2071                                            aria-label="Open&#x20;Locksmith&#x20;subcategories"
2072                                                aria-haspopup="true"
2073                                                :aria-expanded="mobilePanelActiveId === 'category-node-47'"
2074                                        >
2075                                            Locksmith                                            <i class="ti ti-chevron-right text-base"></i>
2076                                        </a>
2077                                                            </div>
2078                                                            <div
2079                                    data-child-id="category-node-47"
2080                                    class="absolute top-[0] left-[0] flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
2081                                    :class="{
2082                                        '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'category-node-47',
2083                                        'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'category-node-47',
2084
2085                                    }"
2086                                >
2087                                    <button
2088                                        type="button"
2089                                        class="absolute top-5 left-5 flex justify-start w-auto self-start cursor-pointer w-full md:left-10 lg:hidden focu
2089s:border-primary-lighter focus:outline-none focus:ring-0"
2090                                        @click="backToMainCategories('category-node-47-main')"
2091                                        aria-label="Back&#x20;to&#x20;main&#x20;categories"
2092                                        >
2093                                        <i class="ti ti-arrow-left text-xl"></i>
2094                                    </button>
2095                                                                        <ul aria-label="Subcategories">
2096                                                                                <li x-show="mobilePanelActiveId === 'category-node-47'"
2097                                            x-transition:enter="transition ease-out duration-700"
2098                                            x-transition:enter-start="opacity-0 -translate-y-2"
2099                                            x-transition:enter-end="opacity-100 translate-y-0"
2100                                            style="transition-delay: 0ms;"  class="px-5 pb-2 md:px-10">
2101                                            <span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">
2102                                                Locksmith                                            </span>
2103                                        </li>
2104                                        <li x-show="mobilePanelActiveId === 'category-node-47'"
2105                                            x-transition:enter="transition ease-out duration-700"
2106                                            x-transition:enter-start="opacity-0 -translate-y-2"
2107                                            x-transition:enter-end="opacity-100 translate-y-0"
2108                                            style="transition-delay: 40ms;"  class="px-5 pb-2 md:px-10">
2109                                            <a
2110                                                href="https://www.banham.co.uk/locksmith-service/"
2111                                                title="Locksmith"
2112                                            >
2113                                                <span class="relative text-sm text-primary-darker hover:text-primary-darker">
2114                                                    All Locksmith                                                </span>
2115                                            </a>
2116                                        </li>
2117                                                                                    <li
2118                                            x-show="mobilePanelActiveId === 'category-node-47'"
2119                                            x-transition:enter="transition ease-out duration-700"
2120                                            x-transition:enter-start="opacity-0 -translate-y-2"
2121                                            x-transition:enter-end="opacity-100 translate-y-0"
2122                                            style="transition-delay: 80ms;"
2123                                            class="px-5 pb-2 md:px-10">
2124                                                <a
2125                                                    href="https://www.banham.co.uk/locksmith-service/emergency-locksmith/"
2126                                                    title="Emergency&#x20;Locksmith"
2127                                                >
2128                                                    <span class="relative text-sm text-primary-darker hover:text-primary-darker">
2129                                                        Emergency Locksmith                                                    </span>
2130                                                </a>
2131                                            </li>
2132                                                                            </ul>
2133                                                                                                                                                                <div x-show="mobilePanelActiveId === 'category-node-47'"
2134                                                    x-transition:enter="transition ease-out duration-700"
2135                                                    x-transition:enter-start="opacity-0 -translate-y-2"
2136                                                    x-transition:enter-end="opacity-100 translate-y-0"
2137                                                    style="transition-delay: 120ms;"
2138                                                    class="menu-cutom-block px-5 mt-[60px] md:px-10">
2139                                                    <img src="https://a.storyblok.com/f/286600090739628/359x261/eb8d21273f/locksmith-menu.jpg" alt="" class="w-full"/>
2140                                                    <div class="inner-detials flex flex-col gap-4 bg-primary px-7 pt-7 pb-[60px]">
2141                                                        <h4 class="text-white mb-0">Locksmith Services</h4>
2142                                                        <p class="text-white mb-0"> Expert locksmiths providing lock changes, cylinder changes, emergency lock outs and more.</p>
2143                                                        <a href="/locksmith-service/emergency-locksmith" class="underline-link"><span class="text-white">Learn More</span></a>
2144                                                    </div>
2145                                                </div>
2146                                                                                                                                                        </div>
2147                                                    </li>
2148                                    </ul>
2149                                    <div class="menu-custom-links">
2150                        <ul>
2151                                                                                        <li x-show="open"
2152                                    x-transition:enter="transition ease-out duration-700"
2153                                    x-transition:enter-start="opacity-0 -translate-y-2"
2154                                    x-transition:enter-end="opacity-100 translate-y-0"
2155                                    style="transition-delay: 360ms;">
2156                                                                            <a
2157                                            href="/customer/account/login/"
2158                                            :href="isLoggedIn ? accountUrl : '\u002Fcustomer\u002Faccount\u002Flogin\u002F'"
2159                                            :title="isLoggedIn ? accountText : signInText"
2160                                            class="relative flex items-center justify-between w-full"
2161                                            @click="if (isLoggedIn) { $event.preventDefault(); openSubcategory('account') }"
2162                                        >
2163                                            <span class="relative" x-text="isLoggedIn ? accountText : signInText">Sign In</span>
2164                                            <i class="ti ti-chevron-right text-base" x-show="isLoggedIn" x-cloak></i>
2165                                        </a>
2166                                                                    </li>
2167                                                            <li x-show="open && !isLoggedIn"
2168                                    x-transition:enter="transition ease-out duration-700"
2169                                    x-transition:enter-start="opacity-0 -translate-y-2"
2170                                    x-transition:enter-end="opacity-100 translate-y-0"
2171                                    style="transition-delay: 400ms;">
2172                                                                            <a href="/customer/account/login/"><span>Make a Payment</span></a>
2173                                                                    </li>
2174                                                            <li x-show="open"
2175                                    x-transition:enter="transition ease-out duration-700"
2176                                    x-transition:enter-start="opacity-0 -translate-y-2"
2177                                    x-transition:enter-end="opacity-100 translate-y-0"
2178                                    style="transition-delay: 440ms;">
2179                                                                            <a href="/customer-help-centre"><span>Help and Support</span></a>
2180                                                                    </li>
2181                                                            <li x-show="open"
2182                                    x-transition:enter="transition ease-out duration-700"
2183                                    x-transition:enter-start="opacity-0 -translate-y-2"
2184                                    x-transition:enter-end="opacity-100 translate-y-0"
2185                                    style="transition-delay: 480ms;">
2186                                                                            <a href="/contact/""><span>Contact Us</span></a>
2187                                                                    </li>
2188                                                            <li x-show="open"
2189                                    x-transition:enter="transition ease-out duration-700"
2190                                    x-transition:enter-start="opacity-0 -translate-y-2"
2191                                    x-transition:enter-end="opacity-100 translate-y-0"
2192                                    style="transition-delay: 520ms;">
2193                                                                            <a href="/trade/trade-area"><span>Trade Site</span></a>
2194                                                                    </li>
2195                                                            <li x-show="open"
2196                                    x-transition:enter="transition ease-out duration-700"
2197                                    x-transition:enter-start="opacity-0 -translate-y-2"
2198                                    x-transition:enter-end="opacity-100 translate-y-0"
2199                                    style="transition-delay: 560ms;">
2200                                                                            <a href="/about-us"><span>About Us</span></a>
2201                                                                    </li>
2202                                                            <li x-show="open"
2203                                    x-transition:enter="transition ease-out duration-700"
2204                                    x-transition:enter-start="opacity-0 -translate-y-2"
2205                                    x-transition:enter-end="opacity-100 translate-y-0"
2206                                    style="transition-delay: 600ms;">
2207                                                                            <a href="/journal"><span>Journal</span></a>
2208                                                                    </li>
2209                                                            <li x-show="open"
2210                                    x-transition:enter="transition ease-out duration-700"
2211                                    x-transition:enter-start="opacity-0 -translate-y-2"
2212                                    x-transition:enter-end="opacity-100 translate-y-0"
2213                                    style="transition-delay: 640ms;">
2214                                                                            <a href="/showrooms"><span>Showrooms</span></a>
2215                                                                    </li>
2216                                                            <li x-show="open"
2217                                    x-transition:enter="transition ease-out duration-700"
2218                                    x-transition:enter-start="opacity-0 -translate-y-2"
2219                                    x-transition:enter-end="opacity-100 translate-y-0"
2220                                    style="transition-delay: 680ms;">
2221                                                                            <a href="/book-a-survey"><span>Arrange a Consultation</span></a>
2222                                                                    </li>
2223                                                            <li x-show="open"
2224                                    x-transition:enter="transition ease-out duration-700"
2225                                    x-transition:enter-start="opacity-0 -translate-y-2"
2226                                    x-transition:enter-end="opacity-100 translate-y-0"
2227                                    style="transition-delay: 720ms;">
2228                                                                            <a href="tel:+442076225151""><span>020 7622 5151</span></a>
2229                                                                    </li>
2230                                                    </ul>
2231                    </div>
2232                    <div
2233                        data-child-id="account"
2234                        class="absolute top-0 left-0 flex flex-col w-full h-full bg-white border-l border-primary pt-16 pb-[60px] overflow-y-auto overflow-x-hidden lg:left-[480px] lg:max-w-[480px] lg:translate-x-0 max-lg:translate-x-full transition-transform duration-150 ease-in-out z-[-1] invisible pointer-events-none"
2235                        :class="{
2236                            '!-translate-x-full invisible pointer-events-none': mobilePanelActiveId !== 'account',
2237                            'translate-x-0 visible pointer-events-auto': mobilePanelActiveId === 'account',
2238                        }"
2239                    >
2240                        <button type="button" class="absolute top-5 left-5 md:left-10 lg:hidden" @click="mobilePanelActiveId = 0">
2241                            <i class="ti ti-arrow-left text-xl"></i>
2242                        </button>
2243                        <ul>
2244                            <li class="px-5 pb-2 md:px-10"><span class="relative text-[10px] text-primary font-grotesk uppercase tracking-[0.8px]">My Account</span></li>
2245                            <li class="px-5 pb-2 md:px-10"><a href="https://www.banham.co.uk/customer/account/"><span class="relative text-sm text-primary-darker">View</span></a></li>
2246                            <li class="px-5 pb-2 md:px-10"><a href="https://www.banham.co.uk/banham-payment/customer/view/"><span class="relative text-sm text-primary-darker">Make Payment</span></a></li>
2247                            <li class="px-5 pb-2 md:px-10"><a href="https://www.banham.co.uk/customer/account/logout/" @click.prevent="hyva.postForm({action: signOutUrl, data: {form_key: hyva.getFormKey()}})"><span class="relative text-sm text-primary-darker">Sign Out</span></a></li>
2248                        </ul>
2249                    </div>
2250                            </div>
2251        </div>
2252    </div>
2253    <div
2254        class="menu-overlay bg-black fixed inset-0 z-[-1] transition-opacity duration-300 opacity-0"
2255        :class="{ 'opacity-50': open, 'opacity-0 pointer-events-none': !open }"
2256    ></div>
2257</nav>
2258                             <div class="header-custom-links gap-4 flex">
2259                                            <a href="#open_enquiry_form" title="Book a Survey "><i class="ti ti-phone lg:hidden text-xl"></i><span class="text-[0] lg:text-sm">Book a Survey </span></a>
2260                                            <a href="tel:+442076225151" title="020 7622 5151"><i class="ti ti-phone lg:hidden text-xl"></i><span class="text-[0] lg:text-sm">Call Us</span></a>
2261                                    </div>
2262                    </div>
2263
2264        <!--Logo-->
2265        <div class="absolute left-1/2 transform -translate-x-1/2">
2266    <a
2267        class="flex items-center justify-center text-xl font-medium tracking-wide text-gray-800
2268            no-underline hover:no-underline font-title"
2269        href="https://www.banham.co.uk/"
2270        aria-label="Go&#x20;to&#x20;Home&#x20;page"
2271    >
2272        <svg class="w-[135px] lg:w-auto" width="190" height="28" viewBox="0 0 190 28" fill="none" xmlns="http://www.w3.org/2000/svg">
2273            <g clip-path="url(#clip0_645_11687)">
2274            <mask id="mask0_645_11687" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="190" height="28">
2275            <path d="M189.5 0H0.5V28H189.5V0Z" fill="white"/>
2276            </mask>
2277            <g mask="url(#mask0_645_11687)">
2278            <path d="M22.7401 19.7514C22.7401 24.5436 18.5183 27.5017 11.8285 27.5017H0.626192L0.5 25.9176L2.29703 25.3762C3.13245 25.1263 3.42637 24.7092 3.42637 23.6679V3.83374C3.42637 2.79252 3.13405 2.37539 2.29703 2.12543L0.5 1.58412L0.626192 0H11.747C17.5566 0 21.0261 2.45818 21.0261 6.54188C21.0261 9.49997 19.0198 11.834 15.8427 12.8752C20.1492 13.6251 22.7401 16.1676 22.7401 19.7498M10.5746 2.37539H8.1913V12.1253H10.3653C13.9194 12.1253 16.2612 10.0429 16.2612 6.91761C16.2612 4.12668 14.0872 2.37539 10.5
2278762 2.37539M10.9515 25.1263C15.258 25.1263 17.8074 23.168 17.8074 20.0014C17.8074 16.6261 15.0488 14.5007 10.7423 14.5007H8.1929V25.1263H10.9515Z" fill="black"/>
2279            <path d="M54.4701 27.5017H43.8093L43.6831 25.9176L45.2725 25.5418C46.3172 25.2919 46.6942 24.792 46.3172 23.7077L44.6447 18.9156H34.821L33.0239 23.6648C32.6469 24.6646 32.8977 25.2903 33.944 25.5402L35.5334 25.916L35.4072 27.5001H26.8373L26.7127 25.916L27.8405 25.6246C28.9698 25.3333 29.5129 24.9161 29.8899 23.9577L37.5397 4.24769C38.0412 2.95651 37.832 2.24803 36.7873 1.95668L35.4503 1.58095L35.5749 -0.00158691H42.8493C43.4339 1.91528 44.5217 5.04055 46.0265 9.16564L51.3776 23.8319C51.7115 24.749 52.2562 25.2489 53.1331 25.4988L54.5963 25.916L54.4701 27.5001V27.5017ZM41.3015 9.29141C40.5491 7.12459 40.2137 5.49907 39.9629 3.29085C39.629 5.49907 39.2105 7.12459 38.4166 9.25002L35.6995 16.5418H43.8509L41.3015 9.29141Z" fill="black"/>
2280            <path d="M77.504 16.209C78.9256 18.2501 79.9703 20.2083 81.0166 22.7923C80.6396 20.3341 80.5565 18.1673 80.5565 15.1678V3.83374C80.5565 2.79252 80.2642 2.334 79.4272 2.12543L77.2947 1.58412L77.4209 0H86.2L86.3262 1.58412L84.5292 2.12543C83.6937 2.37539 83.3998 2.79252 83.3998 3.83374V13.7508C83.3998 20.5841 83.4414 23.3766 83.6091 27.1259L80.0134 28.0016L68.6833 11.834C66.8432 9.20862 65.6739 6.91761 64.7953 4.41804C65.0877 6.54347 65.1723 8.79309 65.1723 11.834V23.6679C65.1723 24.7092 65.4646 25.1677 66.3017 25.3762L68.4341 25.9176L68.3079 27.5017H59.5288L59.4042 25.9176L61.2013 25.3762C62.0367 25.1263 62.3306 24.7092 62.3306 23.6679V3.83374C62.3306 2.79252 62.0383 2.37539 61.2013 2.12543L59.4042 1.58412L59.5272 0H66.1755L77.504 16.209Z" fill="black"/>
2281            <path d="M116.885 23.6679C116.885 24.7092 117.178 25.1263 118.015 25.3762L119.812 25.9175L119.687 27.5017H108.985L108.859 25.9175L110.991 25.3762C111.827 25.1677 112.121 24.7092 112.121 23.6679V14.3335H99.8704V23.6679C99.8704 24.7092 100.163 25.1677 101 25.3762L103.132 25.9175L103.006 27.5017H92.3036L92.1774 25.9175L93.9745 25.3762C94.8115 25.1263 95.1038 24.7092 95.1038 23.6679V3.83374C95.1038 2.79251 94.8115 2.37539 93.9745 2.12543L92.1774 1.58412L92.3036 0.00158691H103.006L103.132 1.58412L101 2.12543C100.164 2.33399 99.8704 2.79251 99.8704 3.83374V11.9581H112.121V3.83374C112.121 2.79251 111.828 2.33399 110.991 2.12543L108.859 1.58412L108.985 0.00158691H119.687L119.812 1.58412L118.015 2.12543C117.179 2.37539 116.885 2.79251 116.885 3.83374V23.6679Z" fill="black"/>
2282            <path d="M152.377 27.5017H141.716L141.59 25.9176L143.18 25.5418C144.224 25.2919 144.601 24.792 144.224 23.7077L142.552 18.9156H132.728L130.931 23.6648C130.554 24.6646 130.805 25.2903 131.851 25.5402L133.439 25.916L133.314 27.5001H124.744L124.62 25.916L125.748 25.6246C126.877 25.3333 127.42 24.9161 127.797 23.9577L135.447 4.24769C135.948 2.95651 135.739 2.24803 134.694 1.95668L133.357 1.58095L133.482 -0.00158691H140.756C141.341 1.91528 142.429 5.04055 143.933 9.16564L149.285 23.8319C149.619 24.749 150.163 25.2489 151.04 25.4988L152.503 25.916L152.377 27.5001V27.5017ZM139.208 9.29141C138.456 7.12459 138.121 5.49907 137.87 3.29085C137.536 5.49907 137.118 7.12459 136.324 9.25002L133.607 16.5418H141.758L139.208 9.29141Z" fill="black"/>
2283            <path d="M186.573 23.6679C186.573 24.7092 186.866 25.1263 187.703 25.3762L189.5 25.9176L189.375 27.5017H178.673L178.547 25.9176L180.679 25.3762C181.515 25.1677 181.807 24.7092 181.807 23.6679V13.1267C181.807 9.41878 182.016 6.75203 182.35 4.29385C181.513 6.75203 180.636 8.75328 179.297 11.4614L174.029 22.087H170.728L165.293 11.5872C164.039 9.17041 163.161 6.79502 162.533 4.33684C162.91 7.04498 163.076 9.75311 163.076 13.1283V23.6695C163.076 24.7108 163.369 25.1693 164.206 25.3778L166.338 25.9191L166.212 27.5033H157.433L157.308 25.9191L159.105 25.3778C159.942 25.1279 160.235 24.7108 160.235 23.6695V3.83374C160.235 2.79252 159.942 2.37539 159.105 2.12543L157.308 1.58412L157.433 0.00159209H164.498L170.769 12.0855C171.772 14.0438 172.525 15.7107 173.362 17.8361C174.156 15.8365 174.908 14.1696 175.911 12.0855L181.807 0H189.374L189.498 1.58253L187.701 2.12384C186.866 2.3738 186.572 2.79093 186.572 3.83215V23.6663L186.573 23.6679Z" fill="black"/>
2284            </g>
2285            </g>
2286            <defs>
2287            <clipPath id="clip0_645_11687">
2288            <rect width="189" height="28" fill="white" transform="translate(0.5)"/>
2289            </clipPath>
2290            </defs>
2291        </svg>
2292
2293            </a>
2294</div>
2295        <div class="flex items-center gap-4 md:gap-4 order-3">
2296            <!--Search Icon-->
2297            <button
2298                id="menu-search-icon"
2299                class="leading-none"
2300                @click.prevent="
2301                    searchOpen = !searchOpen;
2302                    $dispatch('search-open');
2303                "
2304                aria-label="Toggle&#x20;search&#x20;form"
2305                aria-haspopup="true"
2306                :aria-expanded="searchOpen"
2307                x-ref="searchButton"
2308                title="Search"
2309            >
2310                <i class="ti ti-search text-xl"></i>
2311            </button>
2312
2313            <!-- Additional Header Elements -->
2314            
2315            <!--Customer Icon & Dropdown-->
2316            <!-- BLOCK header.customer -->
2317<div
2318    class="relative hidden lg:inline-block"
2319    x-data="{ open: false }"
2320    @keyup.escape="open = false"
2321    @click.outside="open = false"
2322>
2323    <button
2324        type="button"
2325        id="customer-menu"
2326        class="block leading-none"
2327        @click="open = !open"
2328        :aria-expanded="open ? 'true' : 'false'"
2329        aria-label="My&#x20;Account"
2330        aria-haspopup="true"
2331        title="My&#x20;Account"
2332    >
2333        <i class="ti ti-user text-xl"></i>
2334    </button>
2335    <nav
2336        class="
2337            absolute right-0 z-20 w-40 py-2 mt-2 -mr-4 px-1 overflow-auto origin-top-right rounded-sm
2338            shadow-lg sm:w-48 lg:mt-3 bg-container-lighter
2339        "
2340        x-cloak
2341        x-show="open"
2342        aria-labelledby="customer-menu"
2343    >
2344                    
2345<a id="customer.header.sign.in.link"
2346   class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100"
2347   onclick="hyva.setCookie && hyva.setCookie(
2348       'login_redirect',
2349       window.location.href,
2350       1
2351   )"
2352   href="https://www.banham.co.uk/customer/account/index/"
2353   title="Sign&#x20;In"
2354>
2355    Sign In</a>
2356    <a id="customer.header.register.link"
2357       class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100"
2358       href="https://www.banham.co.uk/customer/account/create/"
2359       title="Create&#x20;an&#x20;Account"
2360    >
2361        Create an Account    </a>
2362  <a id="customer.header.online.payment.link.guest" class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100" href="https://www.banham.co.uk/banham-payment/customer/view/" title="Online&#x20;Payment" >Online Payment</a>             </nav>
2363</div><!-- /BLOCK header.customer -->
2364            <!--Cart Icon-->
2365                            <button
2366                            id="menu-cart-icon"
2367                class="relative inline-block leading-none"
2368                x-ref="cartButton"
2369                :aria-disabled="isCartEmpty()"
2370                :aria-label="`
2371                    Toggle&#x20;minicart,
2372                    ${isCartEmpty()
2373                        ? 'Cart&#x20;is&#x20;empty'
2374                        : cart.summary_count > 1
2375                            ? hyva.str('&#x25;1&#x20;items', cart.summary_count)
2376                            : hyva.str('&#x25;1&#x20;item', cart.summary_count)
2377                    }`"
2378                    title="View&#x20;cart"
2379                                    @click.prevent="() => {
2380                        $dispatch('toggle-cart', { isOpen: true })
2381                    }"
2382                    @toggle-cart.window="toggleCart($event)"
2383                    :aria-expanded="isCartOpen"
2384                    aria-haspopup="dialog"
2385                            >
2386                <i class="ti ti-shopping-bag text-xl"></i>
2387                <span
2388                    x-text="cart.summary_count"
2389                    x-show="!isCartEmpty()"
2390                    x-cloak
2391                    class="mini-count absolute bottom-[1px] right-[1px] w-[7px] h-[7px] border-0 rounded-full bg-primary text-white text-[0]"
2392                    aria-hidden="true"
2393                ></span>
2394                            </button>
2395                    </div>
2396    </div>
2397    <!--Search-->
2398    <div class="header-search absolute z-10 w-full border-t bg-white border-container-lighter"
2399         id="search-content"
2400         x-cloak x-show="searchOpen"
2401         @click.outside="searchOpen = false"
2402         @keydown.escape="
2403            searchOpen = false;
2404            $refs.searchButton.focus();
2405         "
2406    >
2407        
2408<div class="container py-10 mx-auto text-black" x-data="initMiniSearch()">
2409    <search title="Store" role="search">
2410        <form
2411            id="search_mini_form"
2412            class="form minisearch flex justify-center"
2413            action="https://www.banham.co.uk/catalogsearch/result/"
2414            method="get"
2415            @submit.prevent="search()"
2416            x-ref="form"
2417        >   
2418        <div class="relative flex w-full lg:max-w-[660px]">
2419            <i class="ti ti-search absolute left-5 top-1/2 transform -translate-y-1/2 text-xl"></i>
2420            <input
2421                id="search"
2422                x-ref="searchInput"
2423                type="search"
2424                autocomplete="off"
2425                name="q"
2426                value=""
2427                placeholder="Search"
2428                maxlength="64"
2429                aria-label="Search"
2430                class="form-input min-h-[53px] py-4 pl-12 placeholder:text-black"
2431                @search-open.window.debounce.10="$el.focus(); $el.select()"
2432                            >
2433        </div>
2434            <button
2435                type="submit"
2436                class="hidden action search btn btn-primary rounded-l-none rounded-r shrink-0 p-3 shadow-none"
2437                title="Search"
2438                aria-label="Search"
2439            >
2440                <i class="ti ti-search text-xl"></i>
2441            </button>
2442        </form>
2443    </search>
2444    </div>    </div>
2445
2446    <!--Cart Drawer-->
2447    
2448<section x-cloak
2449         x-show="cart"
2450         id="cart-drawer"
2451         x-data="initCartDrawer()"
2452         @private-content-loaded.window="getData($event.detail.data)"
2453         @toggle-cart.window="toggleCartDrawer($event)"
2454         @keydown.escape="closeCartDrawer"
2455>
2456    <div role="dialog"
2457         aria-labelledby="cart-drawer-title"
2458         aria-modal="true"
2459         :aria-hidden="!open"
2460         class="fixed inset-y-0 right-0 z-50 flex max-w-full">
2461        <div class="backdrop"
2462             x-show="open"
2463             x-transition:enter="ease-in-out duration-500"
2464             x-transition:enter-start="opacity-0"
2465             x-transition:enter-end="opacity-100"
2466             x-transition:leave="ease-in-out duration-500"
2467             x-transition:leave-start="opacity-100"
2468             x-transition:leave-end="opacity-0"
2469             role="button"
2470             @click="closeCartDrawer"
2471             aria-label="Close&#x20;minicart"></div>
2472        <div class="relative w-screen max-w-[430px] shadow-2xl"
2473             x-show="open"
2474             x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700"
2475             x-transition:enter-start="translate-x-full"
2476             x-transition:enter-end="translate-x-0"
2477             x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700"
2478             x-transition:leave-start="translate-x-0"
2479             x-transition:leave-end="translate-x-full"
2480             x-ref="cartDialogContent"
2481             role="region"
2482             :tabindex="open ? 0 : -1"
2483             aria-label="Bag"
2484
2485        >
2486            <div class="flex flex-col h-full max-h-screen bg-white text-black shadow-xl">
2487                
2488                <header class="relative flex justify-between items-center px-5 sm:px-6 md:px-10 bg-white text-primary ">
2489                    <div class="relative flex justify-between items-center w-full py-5 border-b border-container">
2490                        <h4 id="cart-drawer-title" class="flex items-center m-0">
2491                            Bag                            <span class="ml-2">
2492                                (<span x-text="itemsCount"></span>)
2493                            </span>
2494                            <!-- <span class="items-total text-xs"
2495                                x-show="maxItemsToDisplay && maxItemsToDisplay < itemsCount"
2496                                x-text="getItemCountTitle()">
2497                            </span> -->
2498                        </h4>
2499                        <button
2500                            type="button"
2501                            @click="closeCartDrawer"
2502                            aria-label="Close&#x20;minicart"
2503                            class="transition-colors hover:text-primary leading-none"
2504                            title="Close&#x20;minicart"
2505                        >
2506                            <i class="ti ti-x text-xl"></i>
2507                        </button>
2508                    </div>
2509                </header>
2510
2511                
2512                <template x-if="!itemsCount">
2513                    <div class="relative flex items-center justify-center px-10 py-6 bg-white border-bs sm:px-6 border-container">
2514                        You have no items in your bag.                    </div>
2515                </template>
2516
2517                <template x-if="itemsCount">
2518                    <div class="relative grid bg-white overflow-y-auto overscroll-y-contain px-5 sm:px-6 md:px-10">
2519                        <template x-for="item in cartItems">
2520                            <div class="item-wrapper flex items-start space-x-4 py-5 border-b border-container last:border-0">
2521                                <div class="flex items-start">
2522                                    <template x-if="item.product_has_url && item.is_visible_in_site_visibility">
2523                                        <a :href="item.product_url"
2524                                        class="w-1/4 !ml-0"
2525                                        :aria-label="hyva.strf('Product\u0020\u0022\u00250\u0022', item.product_name)"
2526                                        >
2527                                            <img class="w-full object-cover"
2528                                                :src="item.product_image.src"
2529                                                :width="item.product_image.width"
2530                                                :height="item.product_image.height"
2531                                                loading="lazy"
2532                                                :alt="item.product_name"
2533                                            />
2534                                        </a>
2535                                    </template>
2536                                    <template x-if="!item.product_has_url || !item.is_visible_in_site_visibility">
2537                                        <div class="w-1/4 !ml-0">
2538                                            <img class="w-full object-cover"
2539                                                :src="item.product_image.src"
2540                                                :width="item.product_image.width"
2541                                                :height="item.product_image.height"
2542                                                loading="lazy"
2543                                                :alt="item.product_name"
2544                                            />
2545                                        </div>
2546                                    </template>
2547                                    <div class="w-3/4">
2548                                        <div>
2549                                            <p class="mb-0"><span x-html="item.product_sku"></span></p>
2550                                            <p>
2551                                                <span x-html="item.product_name"></span>
2552                                            </p>
2553                                        </div>
2554                                        <template x-for="option in item.options">
2555                                            <div class="flex gap-1 mb-3">
2556                                                <p class="mb-0" x-text="option.label + ':'"></p>
2557                                                <p class="mb-0" x-html="option.value"></p>
2558                                            </div>
2559                                        </template>
2560                                        <div class="flex items-center justify-between m-0 p-0">                                    
2561                                            <div class="flex items-center gap-2">
2562                                                <div class="flex border border-primary rounded">
2563                                                    <button @click="decrementQty(item)"
2564                                                            class="flex items-center justify-center w-[32px] h-[32px]"
2565                                                            aria-label="Decrease&#x20;Quantity">
2566                                                        <i class="ti ti-minus"></i>
2567                                                    </button>
2568                                                    <input x-model="item.qty"
2569                                                        x-on:change="updateItemQty(item)"
2570                                                        type="number"
2571                                                        size="4"
2572                                                        step="any"
2573                                                        class="flex items-center justify-center border-primary border-t-0 border-b-0 w-[60px] h-[32px] text-center [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [-moz-appearance:textfield]"
2574                                                        min="1"
2575                                                        data-role="cart-item-qty">
2576                                                    <button @click="incrementQty(item)"
2577                                                            class="flex items-center justify-center w-[32px] h-[32px]"
2578                                                            aria-label="Increase&#x20;Quantity">
2579                                                        <i class="ti ti-plus"></i>
2580                                                    </button>
2581                                                </div>
2582                                                <button type="button"
2583                                                        class="flex p-[6px] h-[33px] btn btn-lighter"
2584                                                        @click="deleteItemFromCart(item.item_id)"
2585                                                        :aria-label="hyva.strf('Remove\u0020product\u0020\u0022\u00250\u0022\u0020from\u0020cart', item.product_name)"
2586                                                        title="Remove&#x20;product"
2587                                                >
2588                                                    <i class="ti ti-trash text-lg"></i>
2589                                                </button>
2590                                            </div>
2591                                            <span x-html="hyva.formatPrice(item.product_price_value * item.qty)" class="text-sm"></span>
2592                                        </div>
2593                                    </div>
2594                                </div>
2595                            </div>
2596                        </template>
2597                    </div>
2598                </template>
2599
2600                <template x-if="itemsCount">
2601                    <div class="mt-auto pb-10 px-5 sm:px-6 md:px-10">
2602                                                <div x-show="extraProducts.length > 0" class="flex flex-col gap-3 pt-5 border-t border-primary">
2603                            <h4 class="mb-0" x-text="extraProducts[0]?.title"></h4>
2604                            <p class="mb-0 text-xs" x-text="extraProducts[0]?.description"></p>
2605                        </div>
2606                        <!-- Extra Products Section -->
2607                        <template x-if="extraProducts.length > 0">
2608                            <div class="extra-products-section py-5">
2609                                <div
2610                                    x-ref="extraProductsSplide"
2611                                    class="extra-products-splide"
2612                                    :class="{ 'splide': extraProducts.length > 1 }"
2613                                >
2614                                    <div class="splide__track">
2615                                        <ul class="splide__list">
2616                                            <template x-for="(product, index) in extraProducts" :key="product.id">
2617                                                <li class="splide__slide">
2618                                                    <div class="extra-product-item flex gap-3">
2619                                                        <div class="flex-shrink-0 w-16">
2620                                                            <img class="w-full h-auto object-cover rounded"
2621                                                                 :src="product.image"
2622                                                                 :alt="product.name"
2623                                                                 loading="lazy" />
2624                                                        </div>
2625                                                        <div class="flex-1 min-w-0">
2626                                                            <p class="mb-0" x-text="product.name"></p>
2627                                                            <div class="flex justify-between"> 
2628                                                                <p class="mb-0" x-text="product.sku"></p>
2629                                                                <sp
2629an class="text-sm" x-html="product.price"></span>
2630                                                            </div>
2631                                                        
2632                                                            <div class="flex gap-2 mt-2">
2633                                                                <div class="flex items-center justify-between">
2634                                                                    <div class="flex items-center border rounded">
2635                                                                        <button type="button"
2636                                                                                @click="decrementExtraQty(index)"
2637                                                                                class="flex items-center justify-center w-[32px] [34px]">
2638                                                                            <span class="text-sm">−</span>
2639                                                                        </button>
2640                                                                        <input type="number"
2641                                                                            x-model.number="extraProductQtys[index]" min="1" max="10000"
2642                                                                            class="flex items-center justify-center border-primary border-t-0 border-b-0 w-[60px] h-[34px] text-center [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [-moz-appearance:textfield]" />
2643                                                                        <button type="button"
2644                                                                                @click="incrementExtraQty(index)"
2645                                                                                class="flex items-center justify-center w-[32px] h-[34px]">
2646                                                                            <span class="">+</span>
2647                                                                        </button>
2648                                                                    </div>
2649                                                                </div>
2650                                                                <button type="button"
2651                                                                        @click="addExtraProduct(product, index)"
2652                                                                        class="btn btn-primary btn-size-xs w-full">
2653                                                                    Add to Bag                                                                </button>
2654                                                            </div>
2655                                                        </div>
2656                                                    </div>
2657                                                </li>
2658                                            </template>
2659                                        </ul>
2660                                    </div>
2661                                </div>
2662                            </div>
2663                        </template>
2664
2665                        <div class="relative grid bg-white">
2666                            <div class="relative flex justify-between items-center w-full py-5 bg-white text-primary border-t border-container">
2667                                <p class="flex items-center justify-between w-full mb-0">Subtotal: <span x-html="cart.subtotal"></span></p>
2668                            </div>
2669                            <div class="flex gap-3 w-full">
2670                                <a @click.prevent.stop="closeCartDrawer; $dispatch('toggle-authentication',
2671                                    {url: 'https://www.banham.co.uk/checkout/'});"
2672                                   href="https://www.banham.co.uk/checkout/"
2673                                   class="w-full btn btn-primary"
2674                                >
2675                                    Checkout                                </a>
2676                                <a href="https://www.banham.co.uk/checkout/cart/"
2677                                   class="w-full btn btn-light-gray"
2678                                >
2679                                    View Bag                                </a>
2680                            </div>
2681                            <div x-html="getSectionDataExtraActions()"></div>
2682                                                    </div>
2683                    </div>
2684                </template>
2685
2686                            </div>
2687        </div>
2688        <div
2689    class="z-50 fixed inset-0 flex justify-center items-center bg-white/70 select-none"
2690    x-show="isLoading"
2691    x-cloak
2692    x-transition.opacity.duration.200ms
2693>
2694    <div class="flex items-center">
2695        <svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" stroke-linecap="round" class="animate-spin" aria-hidden="true">
2696    <circle style="opacity: .3;" cx="12" cy="12" r="10"/>
2697    <path fill="none" stroke-width="2" d="M12,2 a10,10 0 0,1 10,10"/>
2698</svg>
2699        <div class="ml-10 text-xl">
2700            Loading...        </div>
2701    </div>
2702</div>    </div>
2703
2704</section>
2705    <!--Authentication Pop-Up-->
2706    <!-- BLOCK authentication-popup -->
2707
2708<dialog
2709    id="authentication-popup"
2710    aria-labelledby="cart-drawer-title"
2711    class="open:flex flex-col transition ease-out duration-300 motion-reduce:duration-0 p-0"
2712    x-data="initAuthentication"
2713    x-bind="eventListeners"
2714    x-show="open"
2715    x-htmldialog="close"
2716    closeby="any"
2717    x-transition
2718>
2719    <div class="pt-8 px-8">
2720        <div class="flex gap-2 justify-between items-center">
2721            <p class="text-xl">
2722                <strong>Customer Login</strong>
2723            </p>
2724            <button
2725                type="button"
2726                class="btn bg-transparent border-transparent p-2"
2727                @click="close"
2728                aria-label="Close&#x20;panel"
2729            >
2730                <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>
2731            </button>
2732        </div>
2733
2734        <div class="message error" x-show="errors" x-cloak>
2735            <template x-for="(message, index) in errorMessages" :key="index">
2736                <div>
2737                    <template x-if="message">
2738                        <span x-html="message"></span>
2739                    </template>
2740                </div>
2741            </template>
2742        </div>
2743    </div>
2744
2745    <div class="block-customer-login p-8">
2746        <p id="authenticate-customer-login" class="text-lg mb-2">
2747            <strong>Checkout using your account</strong>
2748        </p>
2749
2750        <form
2751            id="login-form"
2752            class="form form-login"
2753            method="post"
2754            @submit.prevent="submitForm"
2755        >
2756            <div class="control">
2757    <input type="hidden"
2758           value=""
2759           name="g-recaptcha-response"
2760    >
2761</div>            <input name="context" type="hidden" value="checkout">
2762
2763            <div class="flex flex-col gap-4">
2764                <div class="field email required">
2765                    <label for="form-login-username">
2766                        <span>Email Address</span>
2767                    </label>
2768                    <div class="control">
2769                        <input
2770                            id="form-login-username"
2771                            name="username"
2772                            type="email"
2773                            class="form-input w-full"
2774                            required
2775                            autocomplete="off"
2776                            x-ref="customer-email"
2777                            @change="resetErrors"
2778                        >
2779                    </div>
2780                </div>
2781                <div class="field password required">
2782                    <label for="form-login-password">
2783                        <span>Password</span>
2784                    </label>
2785                    <div class="control">
2786                        <input
2787                            id="form-login-password"
2788                            name="password"
2789                            type="password"
2790                            class="form-input w-full"
2791                            required
2792                            autocomplete="off"
2793                            x-ref="customer-password"
2794                            @change="resetErrors"
2795                        >
2796                    </div>
2797                </div>
2798            </div>
2799
2800            <div class="actions-toolbar">
2801                <button
2802                    type="submit"
2803                                        class="btn btn-primary"
2804                >
2805                    Sign In                </button>
2806                <a
2807                    href="https://www.banham.co.uk/customer/account/forgotpassword/"
2808                    class="underline hover:no-underline"
2809                >
2810                    Forgot Your Password?                </a>
2811            </div>
2812        </form>
2813        <p class="my-4 text-sm">
2814    <em>This site is protected by reCAPTCHA.</em>
2815</p>    </div>
2816    <div class="block-new-customer p-8 border-t border-gray-300">
2817        <p id="authenticate-new-customer" class="text-lg mb-2">
2818            <strong>Checkout as a new customer</strong>
2819        </p>
2820
2821        <div class="block-content">
2822            <p class="mb-1">
2823                Creating an account has many benefits:            </p>
2824            <ul class="list-disc pl-5">
2825                <li> See order and shipping status</li>
2826                <li> Track order history</li>
2827                <li> Check out faster</li>
2828            </ul>
2829            <div class="actions-toolbar mt-6 mb-2">
2830                <a href="https://www.banham.co.uk/customer/account/create/"
2831                    class="inline-flex btn btn-primary">
2832                    Create an Account                </a>
2833            </div>
2834        </div>
2835    </div>
2836</dialog><!-- /BLOCK authentication-popup --></div></header><div class="top-container"><!-- Action Name: /home -->
2837<nav class="breadcrumbs text-black border-b hidden" aria-label="Breadcrumb">
2838    <div class="container">
2839        <ol class="items list-reset py-5 flex flex-wrap text-black leading-tight">
2840                            <li class="item flex home">
2841                                                    <span class="text-sm leading-tight" aria-current="page">     
2842                        Home                    </span>
2843                                </li>
2844                                    </ol>
2845    </div>
2846</nav>
2847
2848    
2849</div><main id="maincontent" class="page-main"><div id="contentarea" tabindex="-1"></div><div class="page messages"><!-- Action Name: /home -->
2850<section id="messages" x-data="initMessages" :class="sectionClass" x-bind="eventListeners" role="alert">
2851    <template x-if="hasMessages">
2852        <div class="w-full">
2853            <div class="messages">
2854                <template x-for="(message, index) in messages" :key="index">
2855                    <div class="flex item-center gap-2">
2856                        <template x-if="hasMessage">
2857                            <div class="message"
2858                                 :class="message.type"
2859                                 :ui-id="getMessageUiId"
2860                            >
2861                                <div class="container flex justify-between">
2862                                    <span class="mx-auto text-white" x-html="message.text"></span>
2863                                    <button
2864                                        type="button"
2865                                        class="text-white hover:text-primary-lighter"
2866                                        aria-label="Close message"
2867                                        @click.prevent="removeMessage"
2868                                    >
2869                                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="stroke-current" width="18" height="18" aria-hidden="true">
2870  <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
2871</svg>
2872                                    </button>
2873                                </div>
2874                            </div>
2875                        </template>
2876                    </div>
2877                </template>
2878            </div>
2879        </div>
2880    </template>
2881</section></div><!-- action name: / --><div class="columns"><div class="column main"> <div id="monkey_campaign" style="display:none;" data-mage-init='{"campaigncatcher":{"checkCampaignUrl": "https://www.banham.co.uk/mailchimp/campaign/check/"}}'></div>  <div>
2882<div class="hero-carousel hero-carousel-167baedb-527e-4e20-95f7-f8f91ddbb9c4">
2883    <div class="splide-wrapper">
2884        <div class="splide">
2885            <div class="splide__track">
2886                                    <div class="hero-slide splide__list">
2887                        <div class="hero-text-299bf8e1-0b4a-4f78-a5be-d01af54ed0bf flex w-full h-screen [&_figure]:h-full [&_img]:h-full splide__slide">
2888    <div class="wrapper relative w-full [&_.video-controller]:!flex">     
2889                            <div class="absolute inset-0 w-full h-full overflow-hidden bg-black">
2890                <iframe
2891                    id="vimeo-299bf8e1-0b4a-4f78-a5be-d01af54ed0bf"
2892                    src="https://player.vimeo.com/video/1215733291?background=1&auto
2892play=1&loop=1&muted=1&transparent=0&api=1&player_id=vimeo-299bf8e1-0b4a-4f78-a5be-d01af54ed0bf"
2893                    frameborder="0"
2894                    allow="autoplay; fullscreen"
2895                    allowfullscreen
2896                    class="pointer-events-none block"
2897                    style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:177.78vh;height:56.25vw;min-width:100%;min-height:100%;border:0;background:#000;"
2898                ></iframe>
2899            </div>
2900            <div class="bg-black absolute inset-0 pointer-events-none z-0" style="opacity: 0.3;"></div>
2901            <div class="video-controller hidden absolute right-10 bottom-10 z-100 gap-2 max-md:left-5 max-md:right-5 max-md:bottom-[30px] max-md:justify-between"
2902                 x-data="{
2903                    isPlaying: true,
2904                    isMuted: true,
2905                    postMessage(method, value) {
2906                        const player = document.getElementById('vimeo-299bf8e1-0b4a-4f78-a5be-d01af54ed0bf');
2907                        if (!player?.contentWindow) return;
2908                        player.contentWindow.postMessage(JSON.stringify(value !== undefined ? { method, value } : { method }), '*');
2909                    },
2910                    togglePlay() {
2911                        this.postMessage(this.isPlaying ? 'pause' : 'play');
2912                        this.isPlaying = !this.isPlaying;
2913                    },
2914                    toggleMute() {
2915                        this.isMuted = !this.isMuted;
2916                        this.postMessage('setVolume', this.isMuted ? 0 : 1);
2917                    }
2918                 }">
2919                <!-- Mute/Unmute Button -->
2920                <button
2921                    type="button"
2922                    class="w-9 h-9 px-2 py-1.5 bg-white/30 text-stone-950 rounded-[50px] backdrop-blur-[20px] inline-flex justify-center items-center hover:bg-white"
2923                    @click="toggleMute()"
2924                >
2925                    <svg x-show="!isMuted" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
2926                        <g clip-path="url(#clip0_1123_18554)">
2927                            <path fill-rule="evenodd" clip-rule="evenodd" d="M2 8H4L8 5V15L4 12H2V8Z" fill="black"/>
2928                            <path d="M13 14C15.2091 11.7909 15.2091 8.20914 13 6" stroke="black" stroke-width="0.942809"/>
2929                            <path d="M11 12C12.1046 10.8954 12.1046 9.10457 11 8" stroke="black" stroke-width="0.942809"/>
2930                            <path d="M15 16C18.3137 12.6863 18.3137 7.31371 15 4" stroke="black" stroke-width="0.942809"/>
2931                        </g>
2932                        <defs>
2933                            <clipPath id="clip0_1123_18554">
2934                                <rect width="20" height="20" fill="white"/>
2935                            </clipPath>
2936                        </defs>
2937                    </svg>
2938                    <svg x-show="isMuted" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
2939                        <path fill-rule="evenodd" clip-rule="evenodd" d="M2 8H4L8 5V15L4 12H2V8Z" fill="black"/>
2940                        <path d="M11 7L17 13" stroke="black"/>
2941                        <path d="M17 7L11 13" stroke="black"/>
2942                    </svg>
2943                </button>
2944                <!-- Play/Pause Button -->
2945                <button
2946                    type="button"
2947                    class="w-9 h-9 px-2 py-1.5 bg-white/30 text-stone-950 rounded-[50px] backdrop-blur-[20px] inline-flex justify-center items-center hover:bg-white"
2948                    @click="togglePlay()"
2949                >
2950                    <i class="ti" :class="isPlaying ? ' ti-player-pause-filled' : ' ti-player-play-filled'"></i>
2951                </button>
2952            </div>
2953                
2954        <div class="content absolute inset-0 z-5">
2955            <div class="container flex flex-col gap-5 h-full py-24 md:py-[60px] lg:py-24 justify-end items-center text-center">
2956                                    <h1 class="text-4xl lg:text-5xl text-white font-normal font-heading leading-10 lg:leading-[52.80px] tracking-wide mb-0 max-w-[310px] md:max-w-[466px] lg:max-w-[426px]">Protect What You Cherish</h1>
2957                 
2958                                    <p class="!text-base text-white max-w-[310px] md:max-w-[466px] lg:max-w-[426px] mb-2">To celebrate 100 years of Banham, we went behind closed doors to discover what you keep under lock and key. Meet Keith & Sue and their collection of 8,500 teapots.</p>
2959                                
2960<a class="btn&#x20;btn-lighter&#x20;default" href="/journal/keith-and-sue-teapot-collection" target="" aria-label="Read&#x20;More" title="Read&#x20;More">
2961    <span>Read More</span>
2962</a>            </div>
2963        </div>
2964    </div>
2965</div>                    </div>
2966                            </div>
2967        </div>
2968    </div>
2969</div>
2970
2971
2972<style>
2973    .hero-text-f46eac5b-da6e-4951-b68e-72ebe8000369  {
2974        background-color: #ffffff;    }
2975</style>
2976
2977<div class="hero-text-f46eac5b-da6e-4951-b68e-72ebe8000369 flex w-full  top-padding-lg bottom-padding-lg">
2978    <div class="hero-text container flex flex-col gap-[60px]">
2979                <div class="wrapper relative [&_.video-controller]:!flex  " style="background-color: ;  ">
2980                                    <div class="content inset-0 z-5 flex flex-col gap-5 justify-center items-center text-center px-5 md:px-10 lg:px-20" style="">
2981                                    <h1 class="text-4xl lg:text-5xl font-normal font-heading leading-10 lg:leading-[52.80px] tracking-[0.36px] lg:tracking-[0.48px] mb-0 max-w-[310px] md:max-w-[400px] lg:max-w-[426px]" style="color:#000;">Handcrafted in Britain Since 1926</h1>
2982                                                    <p class="text-base max-w-[290px] md:max-w-[466px] lg:max-w-[426px] mb-2" style="color:#000;">Marrying innovation with time honoured techniques, every detail of every Banham product is made to last. </p>
2983                                            </div>
2984        </div>
2985    </div>
2986</div>
2987
2988<style>
2989    .image-columns-124654cd-adcc-44af-a35f-5fa10c06f697  {
2990        background-color: #ffffff;    }
2991    .image-columns-124654cd-adcc-44af-a35f-5fa10c06f697 .image-grid {
2992        grid-template-columns: repeat(1, minmax(0, 1fr));
2993
2994        @media screen and (min-width: 1024px) {
2995            grid-template-columns: repeat(2, minmax(0, 1fr));
2996        }
2997    }
2998</style>
2999
3000<div class="image-columns-124654cd-adcc-44af-a35f-5fa10c06f697 flex  top-padding-sm bottom-padding-md">
3001    <div class="w-full flex flex-col gap-[60px]">
3002                            <div class="image-grid grid gap-[2px]">
3003                <div class="image-column-card relative flex flex-col items-center [&_.img-wrapper]:relative [&_.img-wrapper]:after:content-[''] [&_.img-wrapper]:after:absolute [&_.img-wrapper]:after:top-0 [&_.img-wrapper]:after:w-full [&_.img-wrapper]:after:h-full [&_.img-wrapper]:after:bg-black [&_.img-wrapper]:after:opacity-20">
3004    
3005    
3006    <figure class="w-full h-full" 
3007            x-data="responsiveMedia('https://a.storyblok.com/f/286600090739628/678x1020/477258de5b/banham-handcrafted-locks.png','','','https://a.storyblok.com/f/286600090739628/678x1020/477258de5b/banham-handcrafted-locks.png','0')">
3008
3009        
3010                    <div class="img-wrapper w-full">
3011            <img
3012                :src="src"
3013                :data-src="src"
3014                alt="A&#x20;gloved&#x20;hand&#x20;holds&#x20;a&#x20;Banham&#x20;lock,&#x20;handcrafted&#x20;in&#x20;the&#x20;UK&#x20;at&#x20;the&#x20;highest&#x20;standards&#x20;of&#x20;craftsmanship."
3015                class="lazyload w-full h-auto object-cover object-center">
3016            </div>
3017        
3018            </figure>
3019
3020    
3021    <div class="card-details absolute bottom-[60px] left-0 w-full h-full flex flex-col items-center justify-end text-center gap-4 z-30">
3022                    <h3 class="mb-0 text-white">
3023                Signature Locks            </h3>
3024        
3025                    <p class="max-w-[398px] !mb-0 text-primary-darker !tracking-normal text-white">
3026                Meticulously crafted, step by step: before you turn the key, each of our locks passes through the hands of our expert makers.            </p>
3027                
3028        
3029<a class="btn&#x20;btn-lighter&#x20;btn-size-md&#x20;" href="/locks" target="" aria-label="Discover&#x20;Locks" title="Discover&#x20;Locks">
3030    <span>Discover Locks</span>
3031</a>    </div>
3032</div><div class="image-column-card relative flex flex-col items-center [&_.img-wrapper]:relative [&_.img-wrapper]:after:content-[''] [&_.img-wrapper]:after:absolute [&_.img-wrapper]:after:top-0 [&_.img-wrapper]:after:w-full [&_.img-wrapper]:after:h-full [&_.img-wrapper]:after:bg-black [&_.img-wrapper]:after:opacity-20">
3033    
3034    
3035    <figure class="w-full h-full" 
3036            x-data="responsiveMedia('https://a.storyblok.com/f/286600090739628/1143x1720/ec5ea5ecf8/banham-bespoke-doors.png','','','https://a.storyblok.com/f/286600090739628/1143x1720/ec5ea5ecf8/banham-bespoke-doors.png','0')">
3037
3038        
3039                    <div class="img-wrapper w-full">
3040            <img
3041                :src="src"
3042                :data-src="src"
3043                alt="A&#x20;blue&#x20;Banham&#x20;bespoke&#x20;door&#x20;with&#x20;intricate&#x20;stained&#x20;glass&#x20;panels&#x20;and&#x20;a&#x20;gold&#x20;letterbox,&#x20;partially&#x20;open,&#x20;surrounded&#x20;by&#x20;ornate&#x20;floral&#x20;decorations."
3044                class="lazyload w-full h-auto object-cover object-center">
3045            </div>
3046        
3047            </figure>
3048
3049    
3050    <div class="card-details absolute bottom-[60px] left-0 w-full h-full flex flex-col items-center justify-end text-center gap-4 z-30">
3051                    <h3 class="mb-0 text-white">
3052                Bespoke Doors            </h3>
3053        
3054                    <p class="max-w-[398px] !mb-0 text-primary-darker !tracking-normal text-white">
3055                Kerb appeal with a difference: our reinforced steel doors are handcrafted and tailor made for your home.            </p>
3056                
3057        
3058<a class="btn&#x20;btn-lighter&#x20;btn-size-md&#x20;" href="/doors" target="" aria-label="Discover&#x20;Doors" title="Discover&#x20;Doors">
3059    <span>Discover Doors</span>
3060</a>    </div>
3061</div>            </div>
3062            </div>
3063</div>
3064
3065<style>
3066    .image-card-grid-1d86e92d-ab20-4142-b0cc-277bc945a160  {
3067        background-color: #FAFAFA;    }
3068
3069    .image-card-grid-1d86e92d-ab20-4142-b0cc-277bc945a160 .image-grid {
3070        @media screen and (min-width: 1024px) {
3071            grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
3072        }
3073    }
3074
3075</style> 
3076
3077
3078
3079<div class="image-card-grid-1d86e92d-ab20-4142-b0cc-277bc945a160  top-padding-md bottom-padding-md">
3080    <div class="container">
3081        <div class="relative splide-wrapper flex flex-col gap-[60px] max-sm:-mx-5 max-lg:-mx-10">
3082                            <div class="flex flex-col gap-4 items-center justify-center text-center">
3083                    <h2 class="heading-3 text-center m-0">
3084                        Explore Banham                    </h2>
3085                                    </div>
3086            
3087            <div class="!static flex flex-col splide">
3088                <div class="splide__track">
3089                                            <div class="image-grid lg:!grid lg:gap-10 splide__list">
3090                            <div class="image-card splide__slide">
3091    <a class="flex flex-col gap-5" href="/keyholding" title="Keyholding">
3092                    <img src="https://a.storyblok.com/f/286600090739628/426x426/208a6378d0/banham-keyholding.png" alt="Banham Keyholding service for residencial and commercial properties in London." 
3092class="lazyload w-full h-auto object-cover object-center">
3093                <div class="card-details flex flex-col items-center text-center gap-4">
3094                            <h4 class="mb-0">
3095                    Keyholding                </h4>
3096                                        <p class="!mb-0 text-primary-darker !tracking-normal px-5">
3097                    From misplaced passports to trusted tradesmen access, our concierge service is there for life’s unexpected moments.                </p>
3098                                        <span class="underline-link pb-[3px]">
3099                    <span>Discover Keyholding</span>
3100                </span>
3101                    </div>
3102    </a>
3103</div><div class="image-card splide__slide">
3104    <a class="flex flex-col gap-5" href="burglar-alarms/" title="Alarms">
3105                    <img src="https://a.storyblok.com/f/286600090739628/426x426/b59785f203/banham_alarms.png" alt="Shield-shaped Banham logo featuring &quot;Since 1926&quot; and &quot;London England&quot; on a black background." class="lazyload w-full h-auto object-cover object-center">
3106                <div class="card-details flex flex-col items-center text-center gap-4">
3107                            <h4 class="mb-0">
3108                    Alarms                </h4>
3109                                        <p class="!mb-0 text-primary-darker !tracking-normal px-5">
3110                    Tailored alarm systems with 24 hour monitoring and rapid response, for complete peace of mind.                </p>
3111                                        <span class="underline-link pb-[3px]">
3112                    <span>Discover Alarms</span>
3113                </span>
3114                    </div>
3115    </a>
3116</div><div class="image-card splide__slide">
3117    <a class="flex flex-col gap-5" href="/safes" title="Bespoke&#x20;Safes">
3118                    <img src="https://a.storyblok.com/f/286600090739628/426x426/ae30e525ed/discover-banham-safes.png" alt="Banham bespoke luxury safes" class="lazyload w-full h-auto object-cover object-center">
3119                <div class="card-details flex flex-col items-center text-center gap-4">
3120                            <h4 class="mb-0">
3121                    Bespoke Safes                </h4>
3122                                        <p class="!mb-0 text-primary-darker !tracking-normal px-5">
3123                    From solid wood veneers to leather linings, our insurance-graded safes can be tailored to you in side and out.                </p>
3124                                        <span class="underline-link pb-[3px]">
3125                    <span>Discover Safes</span>
3126                </span>
3127                    </div>
3128    </a>
3129</div>                        </div>
3130                                    </div>
3131            </div>
3132        </div>
3133        <div class="block-btn flex items-center justify-center">
3134                    </div>
3135    </div>
3136</div>
3137
3138
3139
3140
3141<style>
3142    .split-wrapper-a1ffa33b-4c0b-4fb8-889c-0219aa1f0b55  {
3143        background-color: #FAFAFA;    }
3144</style>
3145
3146<div class="split-wrapper split-wrapper-a1ffa33b-4c0b-4fb8-889c-0219aa1f0b55 flex  top-padding-md bottom-padding-md">
3147    <div class="container flex flex-col gap-[60px]">
3148                            <div class="split-grid grid gap-[60px] lg:gap-10">
3149                
3150<style>
3151    .split-card-d422af4d-69e6-4bca-b8c4-ecda07a6f7d8 {
3152        background: #333E48;
3153
3154        @media screen and (min-width: 1024px) {
3155            grid-template-columns: 4fr 3fr;        }
3156    }
3157</style>
3158
3159<div id="theBanhamLockWinsProductOfTheYear" class="split-card-d422af4d-69e6-4bca-b8c4-ecda07a6f7d8 grid gap-0 [&_img]:bg-white [&_img]:h-full">
3160    <div class="img-box flex  [&_img]:aspect-[3/2]    ">
3161        
3162    <figure class="w-full h-full" 
3163            x-data="responsiveMedia('https://a.storyblok.com/f/286600090739628/1120x800/cbe3f156e5/banham-best-locks-temporary.png','https://a.storyblok.com/f/286600090739628/1120x800/cbe3f156e5/banham-best-locks-temporary.png','https://a.storyblok.com/f/286600090739628/1120x800/cbe3f156e5/banham-best-locks-temporary.png','https://a.storyblok.com/f/286600090739628/1120x800/cbe3f156e5/banham-best-locks-temporary.png','0')">
3164
3165        
3166                    <div class="img-wrapper w-full">
3167            <img
3168                :src="src"
3169                :data-src="src"
3170                alt=""
3171                class="lazyload w-full h-auto object-cover object-center">
3172            </div>
3173        
3174            </figure>
3175
3176    
3177    </div>
3178    <div class="split-details flex flex-col gap-4 justify-center  items-center !pt-[60px] sm:px-[160px] lg:px-[120px] lg:!pt-10 text-center pt-5 sm:pt-10 lg:pb-10 px-10 pb-[60px] text-white ">
3179                    <h3 class="mb-0 text-white">
3180                The Banham Lock Wins Product of the Year            </h3>
3181        
3182                    <div class="split-info color-white">
3183                <p>We are proud to announce our signature locks have won Great British Brand&#039;s Best Product 2026.</p>            </div>
3184                <div class="flex gap-4 items-center">
3185            
3186<a class="btn&#x20;btn-lighter&#x20;default" href="/journal/banham-wins-product-of-the-year" target="" aria-label="About&#x20;Our&#x20;Award" title="About&#x20;Our&#x20;Award">
3187    <span>About Our Award</span>
3188</a>        </div>
3189    </div>
3190</div>            </div>
3191            </div>
3192</div>
3193
3194<style>
3195    .tabs-box-888e495f-a2a6-4e0c-b8ab-4d005bc23af8  {
3196        background-color: #ffffff;    }
3197</style>
3198
3199<div class="tabs-box tabs-box-888e495f-a2a6-4e0c-b8ab-4d005bc23af8 flex justify-center  top-padding-md bottom-padding-lg" x-data="{ activeTab: 'our-services' }" >
3200    <div class="tab-section flex flex-col gap-[60px] outline-none focus:outline-none overflow-hidden">
3201                    <div class="flex flex-col gap-4 items-center justify-center text-center">
3202                <h3 class="heading-3 text-center m-0">
3203                    At Your Service                </h3>
3204                            </div>
3205                
3206                    <div class="tab-links container max-md:z-10 flex flex-col splide md:!visible">
3207                <div class="splide__track">
3208                    <div class="md:!flex md:justify-center splide__list">
3209                                                                                <div data-id="our-services"
3210                                class="tab-btn cursor-pointer splide__slide two-tabs"
3211                                :class="{ 'active': activeTab === 'our-services' }"
3212                                @click="activeTab = 'our-services'"
3213                            >
3214                                Our Services                            </div>
3215                                                                                <div data-id="customer-help"
3216                                class="tab-btn cursor-pointer splide__slide two-tabs"
3217                                :class="{ 'active': activeTab === 'customer-help' }"
3218                                @click="activeTab = 'customer-help'"
3219                            >
3220                                Customer Support                            </div>
3221                                            </div>
3222                </div>
3223            </div>
3224
3225            <div class="tab-contents relative overflow-hidden">
3226                
3227<div 
3228    class="tab-content overflow-hidden"
3229    id="our-services"
3230    x-show="activeTab === 'our-services'"
3231    x-transition:enter="transition-opacity duration-300 ease-out"
3232    x-transition:enter-start="opacity-0"
3233    x-transition:enter-end="opacity-100"
3234    x-transition:leave="transition-opacity duration-200 ease-in absolute inset-0"
3235    x-transition:leave-start="opacity-100"
3236    x-transition:leave-end="opacity-0"
3237    x-cloak
3238>
3239    
3240
3241<style>
3242    .image-card-grid-c56b845a-9bdb-4f24-a123-cabcd9cef9b0  {
3243        background-color: #ffffff;    }
3244
3245    .image-card-grid-c56b845a-9bdb-4f24-a123-cabcd9cef9b0 .image-grid {
3246        @media screen and (min-width: 1024px) {
3247            grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
3248        }
3249    }
3250
3251</style> 
3252
3253
3254
3255<div class="image-card-grid-c56b845a-9bdb-4f24-a123-cabcd9cef9b0  top-padding-sm bottom-padding-sm">
3256    <div class="container">
3257        <div class="relative splide-wrapper flex flex-col gap-[60px] max-sm:-mx-5 max-lg:-mx-10">
3258            
3259            <div class="!static flex flex-col splide">
3260                <div class="splide__track">
3261                                            <div class="image-grid lg:!grid lg:gap-10 splide__list">
3262                            <div class="image-card splide__slide">
3263    <a class="flex flex-col gap-5" href="/about-us" title="About&#x20;Banham">
3264                    <img src="https://a.storyblok.com/f/286600090739628/310x465/efb40ca642/banham-1926-store.png" alt="About Banham" class="lazyload w-full h-auto object-cover object-center">
3265                <div class="card-details flex flex-col items-center text-center gap-4">
3266                            <h4 class="mb-0">
3267                    About Banham                </h4>
3268                                                    <span class="underline-link pb-[3px]">
3269                    <span>Learn More</span>
3270                </span>
3271                    </div>
3272    </a>
3273</div><div class="image-card splide__slide">
3274    <a class="flex flex-col gap-5" href="keyholding/" title="Keyholding&#x20;Plans">
3275                    <img src="https://a.storyblok.com/f/286600090739628/310x465/dbf7058dba/banham-keyholding-service.png" alt="Banham keyholding service for commercial and residential properties" class="lazyload w-full h-auto object-cover object-center">
3276                <div class="card-details flex flex-col items-center text-center gap-4">
3277                            <h4 class="mb-0">
3278                    Keyholding Plans                </h4>
3279                                                    <span class="underline-link pb-[3px]">
3280                    <span>Learn More</span>
3281                </span>
3282                    </div>
3283    </a>
3284</div><div class="image-card splide__slide">
3285    <a class="flex flex-col gap-5" href="/burglar-alarms/alarm-monitoring/" title="24&#x20;Hour&#x20;Alarm&#x20;Monitoring">
3286                    <img src="https://a.storyblok.com/f/286600090739628/310x465/e94c658cd3/banham-alarm-monitoring-service.png" alt="24 Hour Alarm Monitoring" class="lazyload w-full h-auto object-cover object-center">
3287                <div class="card-details flex flex-col items-center text-center gap-4">
3288                            <h4 class="mb-0">
3289                    24 Hour Alarm Monitoring                </h4>
3290                                                    <span class="underline-link pb-[3px]">
3291                    <span>Learn More</span>
3292                </span>
3293                    </div>
3294    </a>
3295</div><div class="image-card splide__slide">
3296    <a class="flex flex-col gap-5" href="/doors/ " title="Bespoke&#x20;Solutions">
3297                    <img src="https://a.storyblok.com/f/286600090739628/310x465/7bb24af69a/installation.png" alt="Bespoke Solutions" class="lazyload w-full h-auto object-cover object-center">
3298                <div class="card-details flex flex-col items-center text-center gap-4">
3299                            <h4 class="mb-0">
3300                    Bespoke Solutions                </h4>
3301                                                    <span class="underline-link pb-[3px]">
3302                    <span>Learn More</span>
3303                </span>
3304                    </div>
3305    </a>
3306</div>                        </div>
3307                                    </div>
3308            </div>
3309        </div>
3310        <div class="block-btn flex items-center justify-center">
3311                    </div>
3312    </div>
3313</div>
3314
3315
3316</div>
3317<div 
3318    class="tab-content overflow-hidden"
3319    id="customer-help"
3320    x-show="activeTab === 'customer-help'"
3321    x-transition:enter="transition-opacity duration-300 ease-out"
3322    x-transition:enter-start="opacity-0"
3323    x-transition:enter-end="opacity-100"
3324    x-transition:leave="transition-opacity duration-200 ease-in absolute inset-0"
3325    x-transition:leave-start="opacity-100"
3326    x-transition:leave-end="opacity-0"
3327    x-cloak
3328>
3329    
3330
3331<style>
3332    .image-card-grid-101c06c1-0443-420c-ace6-4f1b76dbf01e  {
3333        background-color: #ffffff;    }
3334
3335    .image-card-grid-101c06c1-0443-420c-ace6-4f1b76dbf01e .image-grid {
3336        @media screen and (min-width: 1024px) {
3337            grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
3338        }
3339    }
3340
3341</style> 
3342
3343
3344
3345<div class="image-card-grid-101c06c1-0443-420c-ace6-4f1b76dbf01e  top-padding-sm bottom-padding-sm">
3346    <div class="container">
3347        <div class="relative splide-wrapper flex flex-col gap-[60px] max-sm:-mx-5 max-lg:-mx-10">
3348            
3349            <div class="!static flex flex-col splide">
3350                <div class="splide__track">
3351                                            <div class="image-grid lg:!grid lg:gap-10 splide__list">
3352                            <div class="image-card splide__slide">
3353    <a class="flex flex-col gap-5" href="moving-home/" title="Moving&#x20;Home">
3354                    <img src="https://a.storyblok.com/f/286600090739628/310x465/778fecc9b0/banham-moving-home-service.png" alt="Black and white image of a brick townhouse facade with ornate wrought iron balcony railing and detailed architectural moldings." class="lazyload w-full h-auto object-cover object-center">
3355                <div class="card-details flex flex-col items-center text-center gap-4">
3356                            <h4 class="mb-0">
3357                    Moving Home                </h4>
3358                                                    <span class="underline-link pb-[3px]">
3359                    <span>Learn More</span>
3360                </span>
3361                    </div>
3362    </a>
3363</div><div class="image-card splide__slide">
3364    <a class="flex flex-col gap-5" href="key-cutting-key-registration/" title="Key&#x20;Cutting&#x20;">
3365                    <img src="https://a.storyblok.com/f/286600090739628/310x465/88ce71a5ad/banham-key-cutting.png" alt="Close-up of a Banham key being cut on a precision key-cutting machine, with metal shavings and grooves visible." class="lazyload w-full h-auto object-cover object-center">
3366                <div class="card-details flex flex-col items-center text-center gap-4">
3367                            <h4 class="mb-0">
3368                    Key Cutting                 </h4>
3369                                                    <span class="underline-link pb-[3px]">
3370                    <span>Learn More</span>
3371                </span>
3372                    </div>
3373    </a>
3374</div><div class="image-card splide__slide">
3375    <a class="flex flex-col gap-5" href="customer-help-centre" title="Help&#x20;Centre">
3376                    <img src="https://a.storyblok.com/f/286600090739628/310x465/63aef67a40/banham-security.png" alt="Help Centre" class="lazyload w-full h-auto object-cover object-center">
3377                <div class="card-details flex flex-col items-center text-center gap-4">
3378                            <h4 class="mb-0">
3379                    Help Centre                </h4>
3380                                                    <span class="underline-link pb-[3px]">
3381                    <span>Learn More</span>
3382                </span>
3383                    </div>
3384    </a>
3385</div><div class="image-card splide__slide">
3386    <a class="flex flex-col gap-5" href="contact/" title="Contact&#x20;Us">
3387                    <img src="https://a.storyblok.com/f/286600090739628/310x465/9fd54da42a/banham-alarm-monitoring.png" alt="Contact Us" class="lazyload w-full h-auto object-cover object-center">
3388                <div class="card-details flex flex-col items-center text-center gap-4">
3389                            <h4 class="mb-0">
3390                    Contact Us                </h4>
3391                                                    <span class="underline-link pb-[3px]">
3392                    <span>Learn More</span>
3393                </span>
3394                    </div>
3395    </a>
3396</div>                        </div>
3397                                    </div>
3398            </div>
3399        </div>
3400        <div class="block-btn flex items-center justify-center">
3401                    </div>
3402    </div>
3403</div>
3404
3405
3406</div>            </div>
3407            </div>
3408</div>
3409
3410
3411<div class="hero-carousel hero-carousel-f984a7ff-5d45-49c3-9473-9cca511cfa65">
3412    <div class="splide-wrapper">
3413        <div class="splide">
3414            <div class="splide__track">
3415                                    <div class="hero-slide splide__list">
3416                        <div class="hero-text-9a04c72a-376c-48ac-9d25-7f6a554be009 flex w-full h-screen [&_figure]:h-full [&_img]:h-full splide__slide">
3417    <div class="wrapper relative w-full [&_.video-controller]:!flex">     
3418                            <div class="absolute inset-0 w-full h-full overflow-hidden bg-black">
3419                <iframe
3420                    id="vimeo-9a04c72a-376c-48ac-9d25-7f6a554be009"
3421                    src="https://player.vimeo.com/video/1215113358?background=1&autoplay=1&loop=1&muted=1&transparent=0&api=1&player_id=vimeo-9a04c72a-376c-48ac-9d25-7f6a554be009"
3422                    frameborder="0"
3423                    allow="autoplay; fullscreen"
3424                    allowfullscreen
3425                    class="pointer-events-none block"
3426                    style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:177.78vh;height:56.25vw;min-width:100%;min-height:100%;border:0;background:#000;"
3427                ></iframe>
3428            </div>
3429            <div class="bg-black absolute inset-0 pointer-events-none z-0" style="opacity: 0.3;"></div>
3430            <div class="video-controller hidden absolute right-10 bottom-10 z-100 gap-2 max-md:left-5 max-md:right-5 max-md:bottom-[30px] max-md:justify-between"
3431                 x-data="{
3432                    isPlaying: true,
3433                    isMuted: true,
3434                    postMessage(method, value) {
3435                        const player = document.getElementById('vimeo-9a04c72a-376c-48ac-9d25-7f6a554be009');
3436                        if (!player?.contentWindow) return;
3437                        player.contentWindow.postMessage(JSON.stringify(value !== undefined ? { method, value } : { method }), '*');
3438                    },
3439                    togglePlay() {
3440                        this.postMessage(this.isPlaying ? 'pause' : 'play');
3441                        this.isPlaying = !this.isPlaying;
3442                    },
3443                    toggleMute() {
3444                        this.isMuted = !this.isMuted;
3445                        this.postMessage('setVolume', this.isMuted ? 0 : 1);
3446                    }
3447                 }">
3448                <!-- Mute/Unmute Button -->
3449                <button
3450                    type="button"
3451                    class="w-9 h-9 px-2 py-1.5 bg-white/30 text-stone-950 rounded-[50px] backdrop-blur-[20px] inline-flex justify-center items-center hover:bg-white"
3452                    @click="toggleMute()"
3453                >
3454                    <svg x-show="!isMuted" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
3455                        <g clip-path="url(#clip0_1123_18554)">
3456                            <path fill-rule="evenodd" clip-rule="evenodd" d="M2 8H4L8 5V15L4 12H2V8Z" fill="black"/>
3457                            <path d="M13 14C15.2091 11.7909 15.2091 8.20914 13 6" stroke="black" stroke-width="0.942809"/>
3458                            <path d="M11 12C12.1046 10.8954 12.1046 9.10457 11 8" stroke="black" stroke-width="0.942809"/>
3459                            <path d="M15 16C18.3137 12.6863 18.3137 7.31371 15 4" stroke="black" stroke-width="0.942809"/>
3460                        </g>
3461                        <defs>
3462                            <clipPath id="clip0_1123_18554">
3463                                <rect width="20" height="20" fill="white"/>
3464                            </clipPath>
3465                        </defs>
3466                    </svg>
3467                    <svg x-show="isMuted" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
3468                        <path fill-rule="evenodd" clip-rule="evenodd" d="M2 8H4L8 5V15L4 12H2V8Z" fill="black"/>
3469                        <path d="M11 7L17 13" stroke="black"/>
3470                        <path d="M17 7L11 13" stroke="black"/>
3471                    </svg>
3472                </button>
3473                <!-- Play/Pause Button -->
3474                <button
3475                    type="button"
3476                    class="w-9 h-9 px-2 py-1.5 bg-white/30 text-stone-950 rounded-[50px] backdrop-blur-[20px] inline-flex justify-center items-center hover:bg-white"
3477                    @click="togglePlay()"
3478                >
3479                    <i class="ti" :class="isPlaying ? ' ti-player-pause-filled' : ' ti-player-play-filled'"></i>
3480                </button>
3481            </div>
3482                
3483        <div class="content absolute inset-0 z-5">
3484            <div class="container flex flex-col gap-5 h-full py-24 md:py-[60px] lg:py-24 justify-end items-center text-center">
3485                                    <h1 class="text-4xl lg:text-5xl text-white font-normal font-heading leading-10 lg:leading-[52.80px] tracking-wide mb-0 max-w-[310px] md:max-w-[466px] lg:max-w-[426px]">The Spice Girls Hall of Fame</h1>
3486                 
3487                                    <p class="!text-base text-white max-w-[310px] md:max-w-[466px] lg:max-w-[426px] mb-2">Meet Liz West and her record-breaking collection. 
3488</p>
3489                                
3490<a class="btn&#x20;btn-lighter&#x20;default" href="/journal/liz-west-spice-girls-collection" target="" aria-label="Read&#x20;More" title="Read&#x20;More">
3491    <span>Read More</span>
3492</a>            </div>
3493        </div>
3494    </div>
3495</div>                    </div>
3496                            </div>
3497        </div>
3498    </div>
3499</div>
3500
3501
3502
3503
3504<style>
3505    .split-wrapper-208209ca-f5e7-4ca0-bd24-6ff9a8a9d47e  {
3506        background-color: #FAFAFA;    }
3507</style>
3508
3509<div class="split-wrapper split-wrapper-208209ca-f5e7-4ca0-bd24-6ff9a8a9d47e flex  top-padding-md bottom-padding-md">
3510    <div class="container flex flex-col gap-[60px]">
3511                            <div class="split-grid grid gap-[60px] lg:gap-10">
3512                
3513<style>
3514    .split-card-6816fe3b-3871-4e66-8045-6ff0e67208d9 {
3515        background: #333E48;
3516
3517        @media screen and (min-width: 1024px) {
3518            grid-template-columns: 3fr 4fr;        }
3519    }
3520</style>
3521
3522<div id="getInTouch" class="split-card-6816fe3b-3871-4e66-8045-6ff0e67208d9 grid gap-0 [&_img]:bg-white [&_img]:h-full">
3523    <div class="img-box flex  [&_img]:aspect-[3/2]    ">
3524        
3525    <figure class="w-full h-full" 
3526            x-data="responsiveMedia('https://a.storyblok.com/f/286600090739628/777x520/ecd6fe3594/banham-survey-service.png','https://a.storyblok.com/f/286600090739628/777x520/ecd6fe3594/banham-survey-service.png','https://a.storyblok.com/f/286600090739628/777x520/ecd6fe3594/banham-survey-service.png','https://a.storyblok.com/f/286600090739628/777x520/ecd6fe3594/banham-survey-service.png','0')">
3527
3528        
3529                    <div class="img-wrapper w-full">
3530            <img
3531                :src="src"
3532                :data-src="src"
3533                alt=""
3534                class="lazyload w-full h-auto object-cover object-center">
3535            </div>
3536        
3537            </figure>
3538
3539    
3540    </div>
3541    <div class="split-details flex flex-col gap-4 justify-center  items-center !pt-[60px] sm:px-[160px] lg:px-[120px] lg:!pt-10 text-center pt-5 sm:pt-10 lg:pb-10 px-10 pb-[60px] text-white lg:order-[-1]">
3542                    <h3 class="mb-0 text-white">
3543                Get in Touch            </h3>
3544        
3545                    <div class="split-info color-white">
3546                <p>Request a free security consultation today and our experts will help you design the best way to protect your home.</p>            </div>
3547                <div class="flex gap-4 items-center">
3548            
3549<a class="underline-link&#x20;white-color" href="#open_enquiry_form" target="" aria-label="Enquire&#x20;Now" title="Enquire&#x20;Now">
3550    <span>Enquire Now</span>
3551</a>        </div>
3552    </div>
3553</div>            </div>
3554            </div>
3555</div>
3556
3557<style>
3558    .image-card-grid-5266d2bf-33d3-4ffc-9f52-7e13d43c1af9  {
3559        background-color: #FAFAFA;    }
3560
3561    .image-card-grid-5266d2bf-33d3-4ffc-9f52-7e13d43c1af9 .image-grid {
3562        @media screen and (min-width: 1024px) {
3563            grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
3564        }
3565    }
3566
3567</style> 
3568
3569
3570
3571<div class="image-card-grid-5266d2bf-33d3-4ffc-9f52-7e13d43c1af9  top-padding-md bottom-padding-md">
3572    <div class="container">
3573        <div class="relative splide-wrapper flex flex-col gap-[60px] max-sm:-mx-5 max-lg:-mx-10">
3574                            <div class="flex flex-col gap-4 items-center justify-center text-center">
3575                    <h2 class="heading-3 text-center m-0">
3576                        Banham Journal                    </h2>
3577                                    </div>
3578            
3579            <div class="!static flex flex-col splide">
3580                <div class="splide__track">
3581                                            <div class="image-grid lg:!grid lg:gap-10 splide__list">
3582                            <div class="image-card splide__slide">
3583    <a class="flex flex-col gap-5" href="/journal/keith-and-sue-teapot-collection" title="Protect&#x20;What&#x20;You&#x20;Cherish&#x3A;&#x20;8,500&#x20;Teapots,&#x20;1&#x20;Perfect&#x20;Cuppa">
3584                    <img src="https://a.storyblok.com/f/286600090739628/955x519/ed128a8428/protect-what-you-cherish-banham-teap
3584ots-small.png" alt="Protect What You Cherish: 8,500 Teapots, 1 Perfect Cuppa" class="lazyload w-full h-auto object-cover object-center">
3585                <div class="card-details flex flex-col items-center text-center gap-4">
3586                            <h4 class="mb-0">
3587                    Protect What You Cherish: 8,500 Teapots, 1 Perfect Cuppa                </h4>
3588                                                    <span class="underline-link pb-[3px]">
3589                    <span>Read More</span>
3590                </span>
3591                    </div>
3592    </a>
3593</div><div class="image-card splide__slide">
3594    <a class="flex flex-col gap-5" href="journal/how-to-choose-your-banham-front-door" title="How&#x20;to&#x20;Choose&#x20;Your&#x20;Banham&#x20;Front&#x20;Door">
3595                    <img src="https://a.storyblok.com/f/286600090739628/955x519/07319e1f60/front-door-banham-thumbnail.png" alt="Blue Banham door with ornate stained glass panels, golden hardware, next to a lush arrangement of vibrant flowers and greenery." class="lazyload w-full h-auto object-cover object-center">
3596                <div class="card-details flex flex-col items-center text-center gap-4">
3597                            <h4 class="mb-0">
3598                    How to Choose Your Banham Front Door                </h4>
3599                                                    <span class="underline-link pb-[3px]">
3600                    <span>Read More</span>
3601                </span>
3602                    </div>
3603    </a>
3604</div><div class="image-card splide__slide">
3605    <a class="flex flex-col gap-5" href="/journal/protect-what-you-cherish-the-joy-of-collecting" title="Protect&#x20;What&#x20;You&#x20;Cherish&#x3A;&#x20;The&#x20;Joy&#x20;of&#x20;Collecting">
3606                    <img src="https://a.storyblok.com/f/286600090739628/955x519/baefb411c1/protect-what-you-cherish-banham-collectors-thumbnail.png" alt="Protect What You Cherish: The Joy of Collecting" class="lazyload w-full h-auto object-cover object-center">
3607                <div class="card-details flex flex-col items-center text-center gap-4">
3608                            <h4 class="mb-0">
3609                    Protect What You Cherish: The Joy of Collecting                </h4>
3610                                                    <span class="underline-link pb-[3px]">
3611                    <span>Read More</span>
3612                </span>
3613                    </div>
3614    </a>
3615</div>                        </div>
3616                                    </div>
3617            </div>
3618        </div>
3619        <div class="block-btn flex items-center justify-center">
3620            
3621<a class="btn&#x20;btn-primary&#x20;default" href="/journal" target="" aria-label="Read&#x20;More" title="Read&#x20;More">
3622    <span>Read More</span>
3623</a>        </div>
3624    </div>
3625</div>
3626
3627
3628  
3629
3630 
3631    
3632</div> </div></div></main><footer class="footer-container"><style>
3633    .pre-footer {
3634        background-color: #ffffff;    }
3635</style>
3636<div class="footer-wrapper" role="contentinfo">
3637                                        <div class="pre-footer text-white text-center splide  top-padding-lg bottom-padding-lg">
3638                    <div class="container mx-auto splide__track">
3639                        <div class="splide__list md:!flex md:justify-around">
3640                                                                                                <a href="/locksmith-service/" class="splide__slide lg:w-1/3 no-underline text-sm max-md:block max-md:mb-1">                        
3641                                        <h4 class="mb-4">Emergency Locksmiths</h4>
3642                                        <p class="mb-4">24/7 locksmith support when you need it most.</p>
3643                                        <span class="relative inline-block pb-[3px] after:content-[''] after:absolute after:left-0 after:bottom-0 after:h-[1px] after:w-full after:bg-current after:transition-all after:duration-300 after:ease-out hover:after:w-0"><span>Learn More</span></span>
3644                                    </a>
3645                                                        
3646                                                                                                <a href="/locks" class="splide__slide lg:w-1/3 no-underline text-sm max-md:block max-md:mb-1">                        
3647                                        <h4 class="mb-4">Insurance Approved</h4>
3648                                        <p class="mb-4">Our locks are certified to meet the highest security standards.</p>
3649                                        <span class="relative inline-block pb-[3px] after:content-[''] after:absolute after:left-0 after:bottom-0 after:h-[1px] after:w-full after:bg-current after:transition-all after:duration-300 after:ease-out hover:after:w-0"><span>Learn More</span></span>
3650                                    </a>
3651                                                        
3652                                                                                                <a href="/about-us" class="splide__slide lg:w-1/3 no-underline text-sm max-md:block max-md:mb-1">                        
3653                                        <h4 class="mb-4">Trusted Since 1926</h4>
3654                                        <p class="mb-4">100 years of British security expertise.</p>
3655                                        <span class="relative inline-block pb-[3px] after:content-[''] after:absolute after:left-0 after:bottom-0 after:h-[1px] after:w-full after:bg-current after:transition-all after:duration-300 after:ease-out hover:after:w-0"><span>Learn More</span></span>
3656                                    </a>
3657                                                        
3658                                                    </div>
3659                    </div>
3660                </div>
3661                        <div class="page-footer bg-[#333E48] bg-gradient-to-b from-black/0 to-black/20 text-white [&_*]:text-white">
3662                <div class="footer content container max-md:max-w-[490px] mx-auto grid grid-cols-1 md:grid-cols-[2fr_1fr_1fr] py-[60px] justify-between"  aria-label="Footer navigation">
3663                    <div class="flex flex-col md:max-w-[427px]">
3664                        <div class="footer-newsletter">
3665                            <p class="heading-2 max-md:text-center">Get Exclusive Updates,<br/>News, and Advice</p>                            <div class="footer-newsletter">
3666    <form
3667        class="form subscribe"
3668        action="https://www.banham.co.uk/newsletter/subscriber/new/"
3669        method="post"
3670        x-data="initNewsletterForm"
3671        @submit.prevent="submitForm"
3672        id="newsletter-validate-detail"
3673        aria-label="Subscribe&#x20;to&#x20;Newsletter"
3674        >
3675        <div class="flex border-b mb-10">
3676            <input
3677                name="email"
3678                type="email"
3679                required
3680                id="newsletter-subscribe"
3681                class="form-input inline-flex w-full text-white bg-transparent border-0 placeholder:text-white/50 p-0"
3682                placeholder="Email&#x20;Address"
3683                autocomplete="email"
3684                aria-describedby="footer-newsletter-heading"
3685            >
3686            <input name="form_key" type="hidden" value="9ScZqxAtVshasw9c" />                        <button class="inline-flex items-center text-sm leading-5 hover:text-white/75 focus:outline-none focus:text-white transition ease-in-out duration-150 font-medium" title="Subscribe">
3687                Subscribe            </button>
3688        </div>
3689        <div>
3690            <template x-if="displayErrorMessage">
3691                <p class="flex items-center text-red">
3692                    <span class="inline-block w-8 h-8 mr-3">
3693                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true">
3694  <path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
3695</svg>
3696                    </span>
3697                    <template x-for="errorMessage in errorMessages">
3698                        <span x-html="errorMessage"></span>
3699                    </template>
3700                </p>
3701            </template>
3702        </div>
3703    </form>
3704    <div class="w-full">
3705            </div>
3706    
3707    </div>                            <p class="text-sm [&_a]:underline mb-[60px] max-md:text-center max-md:max-w-96 max-md:mx-auto">If you would like further information on how we use your personal data, please check our <a href="/privacy-promise">Privacy Policy</a>.</p>                        </div>
3708                                                    <ul class="flex gap-5 max-md:justify-center max-md:mb-[60px]">
3709                                                                    <li>
3710                                        <a href="https://www.facebook.com/Banh
3710am.Group/"
3711                                        class="flex items-center justify-center w-9 h-9 rounded-full bg-white/20 hover:bg-white [&:hover>i]:text-primary-darker transition-all duration-300"
3712                                        target="_blank"
3713                                        aria-label="brand-facebook"
3714                                        rel="noopener noreferrer"
3715                                        >
3716                                                                                            <i class="ti ti-brand-facebook text-xl"></i>
3717                                                                                    </a>
3718                                    </li>
3719                                                                    <li>
3720                                        <a href="https://www.instagram.com/banhamgroup/"
3721                                        class="flex items-center justify-center w-9 h-9 rounded-full bg-white/20 hover:bg-white [&:hover>i]:text-primary-darker transition-all duration-300"
3722                                        target="_blank"
3723                                        aria-label="brand-instagram"
3724                                        rel="noopener noreferrer"
3725                                        >
3726                                                                                            <i class="ti ti-brand-instagram text-xl"></i>
3727                                                                                    </a>
3728                                    </li>
3729                                                                    <li>
3730                                        <a href="https://x.com/banhamsecurity"
3731                                        class="flex items-center justify-center w-9 h-9 rounded-full bg-white/20 hover:bg-white [&:hover>i]:text-primary-darker transition-all duration-300"
3732                                        target="_blank"
3733                                        aria-label="brand-x"
3734                                        rel="noopener noreferrer"
3735                                        >
3736                                                                                            <i class="ti ti-brand-x text-xl"></i>
3737                                                                                    </a>
3738                                    </li>
3739                                                                    <li>
3740                                        <a href="https://uk.pinterest.com/banhamgroup/"
3741                                        class="flex items-center justify-center w-9 h-9 rounded-full bg-white/20 hover:bg-white [&:hover>i]:text-primary-darker transition-all duration-300"
3742                                        target="_blank"
3743                                        aria-label="brand-pinterest"
3744                                        rel="noopener noreferrer"
3745                                        >
3746                                                                                            <i class="ti ti-brand-pinterest text-xl"></i>
3747                                                                                    </a>
3748                                    </li>
3749                                                            </ul>
3750                                                <span class="text-5xl mt-auto max-md:hidden">Trusted,<br/>Since 1926</span>                    </div>
3751
3752                    <div class="footer-middle-col flex flex-col justify-between md:gap-14 gap-5 max-md:mb-5" x-data="{}">
3753                                                    <div x-data="{ index: 0 }">
3754                                <h3 class="text-[10px] uppercase leading-4 max-md:mb-0 max-md:flex items-center justify-between font-grotesk tracking-wide"
3755                                    @click="$store.footerResponsive.isMobile && $store.footerResponsive.toggle(index)">
3756                                    Banham                                    <i class="ti ti-chevron-down inline-block ml-auto text-sm md:hidden transition-transform duration-300"
3757                                    :class="$store.footerResponsive.isOpen(index) ? 'rotate-180' : 'rotate-0'"></i>
3758                                </h3>
3759
3760                                <ul class="flex flex-col gap-2 max-md:[&>li:first-child]:mt-3 mb-5 md:mb-0"
3761                                    x-show="!$store.footerResponsive.isMobile || $store.footerResponsive.isOpen(index)"
3762                                    x-collapse>
3763                                                                            <li>
3764                                            <a href="/about-us/" aria-label="About Us"
3765                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3766                                                About Us                                            </a>
3767                                        </li>
3768                                                                            <li>
3769                                            <a href="/showrooms/" aria-label="Showrooms"
3770                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3771                                                Showrooms                                            </a>
3772                                        </li>
3773                                                                            <li>
3774                                            <a href="/key-cutting-key-registration/" aria-label="Key Registration"
3775                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3776                                                Key Registration                                            </a>
3777                                        </li>
3778                                                                            <li>
3779                                            <a href="https://www.banham.co.uk/trade/trade-area/" aria-label="Trade Buy Online"
3780                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3781                                                Trade Buy Online                                            </a>
3782                                        </li>
3783                                                                            <li>
3784                                            <a href="/banham-payment/customer/view/" aria-label="Online Payment"
3785                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3786                                                Online Payment                                            </a>
3787                                        </li>
3788                                                                            <li>
3789                                            <a href="/moving-home/" aria-label="Moving Home"
3790                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3791                                                Moving Home                                            </a>
3792                                        </li>
3793                                                                            <li>
3794                                            <a href="/patents/" aria-label="Patents"
3795                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3796                                                Patents                                            </a>
3797                                        </li>
3798                                                                            <li>
3799                                            <a href="/deliveries-returns/" aria-label="Deliveries and Returns"
3800                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3801                                                Deliveries and Returns                                            </a>
3802                                        </li>
3803                                                                            <li>
3804                                            <a href="/commercial" aria-label="Banham Commercial"
3805                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3806                                                Banham Commercial                                            </a>
3807                                        </li>
3808                                                                            <li>
3809                                            <a href="/book-a-survey/" aria-label="Book a Free Survey"
3810                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3811                                                Book a Free Survey                                            </a>
3812                                        </li>
3813                                                                    </ul>
3814                            </div>
3815                                                    <div x-data="{ index: 1 }">
3816                                <h3 class="text-[10px] uppercase leading-4 max-md:mb-0 max-md:flex items-center justify-between font-grotesk tracking-wide"
3817                                    @click="$store.footerResponsive.isMobile && $store.footerResponsive.toggle(index)">
3818                                    Customer Support                                    <i class="ti ti-chevron-down inline-block ml-auto text-sm md:hidden transition-transform duration-300"
3819                                    :class="$store.footerResponsive.isOpen(index) ? 'rotate-180' : 'rotate-0'"></i>
3820                                </h3>
3821
3822                                <ul class="flex flex-col gap-2 max-md:[&>li:first-child]:mt-3 mb-5 md:mb-0"
3823                                    x-show="!$store.footerResponsive.isMobile || $store.footerResponsive.isOpen(index)"
3824                                    x-collapse>
3825                                                                            <li>
3826                                            <a href="/customer-help-centre/" aria-label="Support Centre"
3827                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3828                                                Support Centre                                            </a>
3829                                        </li>
3830                                                                            <li>
3831                                            <a href="/contact/" aria-label="Contact Us"
3832                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3833                                                Contact Us                                            </a>
3834                                        </li>
3835                                                                            <li>
3836                                            <a href="/update-your-details/" aria-label="Update Your Details"
3837                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3838                                                Update Your Details                                            </a>
3839                                        </li>
3840                                                                            <li>
3841                                            <a href="/pstn/" aria-label="Digital Phone Switchover"
3842                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3843                                                Digital Phone Switchover                                            </a>
3844                                        </li>
3845                                                                            <li>
3846                                            <a href="/complaints/" aria-label="Complaints Procedure"
3847                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3848                                                Complaints Procedure                                            </a>
3849                                        </li>
3850                                                                            <li>
3851                                            <a href="/annual-contract-details/" aria-label="Annual Contracts Details"
3852                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3853                                                Annual Contracts Details                                            </a>
3854                                        </li>
3855                                                                            <li>
3856                                            <a href="/direct-debits/" aria-label="Direct Debit Details"
3857                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3858                                                Direct Debit Details                                            </a>
3859                                        </li>
3860                                                                    </ul>
3861                            </div>
3862                                                    <div x-data="{ index: 2 }">
3863                                <h3 class="text-[10px] uppercase leading-4 max-md:mb-0 max-md:flex items-center justify-between font-grotesk tracking-wide"
3864                                    @click="$store.footerResponsive.isMobile && $store.footerResponsive.toggle(index)">
3865                                    What’s New                                    <i class="ti ti-chevron-down inline-block ml-auto text-sm md:hidden transition-transform duration-300"
3866                                    :class="$store.footerResponsive.isOpen(index) ? 'rotate-180' : 'rotate-0'"></i>
3867                                </h3>
3868
3869                                <ul class="flex flex-col gap-2 max-md:[&>li:first-child]:mt-3 mb-5 md:mb-0"
3870                                    x-show="!$store.footerResponsive.isMobile || $store.footerResponsive.isOpen(index)"
3871                                    x-collapse>
3872                                                                            <li>
3873                                            <a href="/pstn/" aria-label="Digital Phone Switchover"
3874                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3875                                                Digital Phone Switchover                                            </a>
3876                                        </li>
3877                                                                            <li>
3878                                            <a href="/journal" aria-label="Journal"
3879                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3880                                                Journal                                            </a>
3881                                        </li>
3882                                                                            <li>
3883                                            <a href="/media/wysiwyg/pdf/online-brochure-banham.pdf" aria-label="Banham Brochure"
3884                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3885                                                Banham Brochure                                            </a>
3886                                        </li>
3887                                                                    </ul>
3888                            </div>
3889                         
3890                    </div>
3891
3892                    <div class="footer-right-col flex flex-col md:gap-14 gap-5" x-data="{}">
3893                                                    <div x-data="{ index: 3 }">
3894                                <h3 class="text-[10px] uppercase leading-none max-md:mb-0 max-md:flex items-center justify-between font-grotesk tracking-wide"
3895                                    @click="$store.footerResponsive.isMobile && $store.footerResponsive.toggle(index)">
3896                                    Join Us                                    <i class="ti ti-chevron-down inline-block ml-auto text-sm md:hidden transition-transform duration-300"
3897                                    :class="$store.footerResponsive.isOpen(index) ? 'rotate-180' : 'rotate-0'"></i>
3898                                </h3>
3899
3900                                <ul class="flex flex-col gap-2 max-md:[&>li:first-child]:mt-3"
3901                                    x-show="!$store.footerResponsive.isMobile || $store.footerResponsive.isOpen(index)"
3902                                    x-collapse>
3903                                                                            <li>
3904                                            <a href="https://careers.banham.com/" aria-label="Banham Careers"
3905                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3906                                                Banham Careers                                            </a>
3907                                        </li>
3908                                                                            <li>
3909                                            <a href="https://www.banhamacademy.co.uk/" aria-label="Banham Academy"
3910                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3911                                                Banham Academy                                            </a>
3912                                        </li>
3913                                                                            <li>
3914                                            <a href="/media-enquiries" aria-label="Media Enquiries"
3915                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3916                                                Media Enquiries                                            </a>
3917                                        </li>
3918                                                                    </ul>
3919                            </div>
3920                                                    <div x-data="{ index: 4 }">
3921                                <h3 class="text-[10px] uppercase leading-none max-md:mb-0 max-md:flex items-center justify-between font-grotesk tracking-wide"
3922                                    @click="$store.footerResponsive.isMobile && $store.footerResponsive.toggle(index)">
3923                                    Policies                                    <i class="ti ti-chevron-down inline-block ml-auto text-sm md:hidden transition-transform duration-300"
3924                                    :class="$store.footerResponsive.isOpen(index) ? 'rotate-180' : 'rotate-0'"></i>
3925                                </h3>
3926
3927                                <ul class="flex flex-col gap-2 max-md:[&>li:first-child]:mt-3"
3928                                    x-show="!$store.footerResponsive.isMobile || $store.footerResponsive.isOpen(index)"
3929                                    x-collapse>
3930                                                                            <li>
3931                                            <a href="/terms-conditions/" aria-label="Terms and Conditions"
3932                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3933                                                Terms and Conditions                                            </a>
3934                                        </li>
3935                                                                            <li>
3936                                            <a href="/website-terms-conditions/" aria-label="Website Terms and Conditions"
3937                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3938                                                Website Terms and Conditions                                            </a>
3939                                        </li>
3940                                                                            <li>
3941                                            <a href="/privacy-promise/" aria-label="Privacy Promise"
3942                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3943                                                Privacy Promise                                            </a>
3944                                        </li>
3945                                                                            <li>
3946                                            <a href="/eula/" aria-label="Banham App EULA"
3947                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3948                                                Banham App EULA                                            </a>
3949                                        </li>
3950                                                                            <li>
3951                                            <a href="/cookie-notice/" aria-label="Cookie Notice"
3952                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3953                                                Cookie Notice                                            </a>
3954                                        </li>
3955                                                                            <li>
3956                                            <a href="/media/wysiwyg/pdf/banham-patent-locks-ltd-section-172-statement-companies-act-2006.pdf" aria-label="Section 172 Policy"
3957                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3958                                                Section 172 Policy                                            </a>
3959                                        </li>
3960                                                                            <li>
3961                                            <a href="/media/wysiwyg/pdf/sexual-harassment-statement.pdf" aria-label="Zero Tolerance policy"
3962                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3963                                                Zero Tolerance policy                                            </a>
3964                                        </li>
3965                                                                            <li>
3966                                            <a href="https://a.storyblok.com/f/286600090739628/x/3672f2235d/modern_slavery_statement_dec-2025.pdf" aria-label="Modern Slavery Policy Statement"
3967                                            class="inline-block text-sm font-normal leading-tight hover:underline">
3968                                                Modern Slavery Policy Statement                                            </a>
3969                                        </li>
3970                                                                    </ul>
3971                            </div>
3972                                            </div>
3973                    <span class="text-4xl leading-[43.2px] text-center mt-[60px] md:hidden">Trusted,<br/>Since 1926</span>                </div>
3974                <div class="footer-bottom container max-md:max-w-[406px] text-xs leading-[18px] pb-[60px] [&_*]:text-xs [&_p]:mb-0 [&_a]:underline text-center max-md:[&_p]:inline">
3975                    <p>Registered in England and Wales under the Registration Number 00457812. Company address: 20 Thornsett Road, Earlsfield, London, SW18 4EF</p>
3976<p>This site is protected by reCAPTCHA and our <a href="https://www.banham.co.uk/privacy-promise/">Privacy Policy</a> and <a href="https://www.banham.co.uk/website-terms-conditions/">Website T&Cs</a> apply.</p>                </div>
3977            </div>
3978                </div>
3979
3980    <div x-data="initNewsletterFormModal">
3981        <template x-if="shouldShowModal">
3982            <dialog
3983                id="newsletter-modal"
3984                x-show="open"
3985                x-transition
3986                x-htmldialog="closeModal"
3987                class="open:flex flex-col justify-end md:justify-center md:h-fit h-full max-md:mt-auto my-0 md:m-auto bg-transparent lg:flex-row max-w-full md:max-w-fit after:content-[''] after:flex after:fixed after:inset-0 after:bg-black after:w-full after:h-full after:bg-opacity-50 after:z-[-1]">
3988
3989                                    <div class="hidden lg:flex lg:w-[343px] h-auto">
3990                        <img
3991                            class="w-full h-full object-cover"
3992                            alt="Unlock&#x20;the&#x20;latest&#x20;with&#x20;the&#x20;Banham&#x20;newsletter."
3993                            loading="eager"
3994                            src="https://a.storyblok.com/f/286600090739628/343x515/516aee5d3b/banham-locks-newsletter.png">
3995                    </div>
3996                
3997                <div class="relative flex flex-col items-center justify-center w-full md:w-[426px] lg:w-[506px] gap-10 px-5 md:px-10 pt-10 pb-[60px] text-center bg-white">
3998
3999                    <button
4000                        class="absolute right-5 top-5 text-black hover:text-primary-darker focus:outline-none focus:ring-0"
4001                        aria-label="Close&#x20;panel"
4002                        @click="closeModal">
4003                        <i class="ti ti-x text-xl"></i>
4004                    </button>
4005
4006                                            <h3 class="m-0 md:max-w-[320px]">Unlock the latest with the Banham newsletter.</h3>
4007                    
4008                    <form
4009                        id="newsletter-validate-modal"
4010                        action="https://www.banham.co.uk/newsletter/subscriber/new/"
4011                        method="post"
4012                        @submit.prevent="submitForm"
4013                        class="flex flex-col w-full gap-5"
4014                    >
4015                        <div class="flex flex-col items-start gap-3" :class="{'field-error': errors.firstname}">
4016                            <input
4017                                type="text"
4018                                name="firstname"
4019                                id="newsletter-firstname-modal"
4020                                x-model="firstname"
4021                                @blur="validateField('firstname')"
4022                                :class="{'error': errors.firstname}"
4023                                class="form-input"
4024                                placeholder="First&#x20;Name&#x20;&#x2A;"
4025                            >
4026                            <span class="text-error text-xs" x-show="errors.firstname" class="mage-error" x-text="errors.firstname"></span>
4027                        </div>
4028                        <div class="flex flex-col items-start gap-3" :class="{'field-error': errors.lastname}">
4029                            <input
4030                                type="text"
4031                                name="lastname"
4032                                id="newsletter-lastname-modal"
4033                                x-model="lastname"
4034                                @blur="validateField('lastname')"
4035                                :class="{'error': errors.lastname}"
4036                                class="form-input"
4037                                placeholder="Last&#x20;Name&#x20;&#x2A;"
4038                            >
4039                            <span class="text-error text-xs" x-show="errors.lastname" class="mage-error" x-text="errors.lastname"></span>
4040                        </div>
4041                        <div class="relative email-box flex flex-col items-start gap-3" :class="{'field-error': errors.email}">
4042                            <input
4043                                type="email"
4044                                name="email"
4045                                id="newsletter-subscribe-modal"
4046                                x-model="email"
4047                                @blur="validateField('email')"
4048                                :class="{'error': errors.email}"
4049                                class="form-input"
4050                                placeholder="Email&#x20;Address&#x20;&#x2A;"
4051                            >
4052                            <span class="text-error text-xs" x-show="errors.email" class="mage-error" x-text="errors.email"></span>
4053                        </div>
4054
4055                        <input name="form_key" type="hidden" value="9ScZqxAtVshasw9c" />
4056                        <button type="submit" class="btn btn-primary">
4057                            Subscribe                        </button>
4058                                            </form>
4059
4060                    
4061                                            <div class="bottom-note m-0 text-primary-lighter [&_p]:m-0 [&_p]:text-primary-lighter"><p>If you would like further information on how we use your
personal data, please check our<a href="/privacy-promise" target="_self"> Privacy Policy</a>.</p></div>
4062                                    </div>
4063            </dialog>
4064        </template>
4065    </div>
4066
4067
4068
4069</footer>
4070
4071
4072
4073
4074     
4075        
4076
4077<style>
4078        @keyframes splide-loading{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.splide__track--draggable{-webkit-touch-callout:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.splide__track--fade>.splide__list>.splide__slide{margin:0!important;opacity:0;z-index:0}.splide__track--fade>.splide__list>.splide__slide.is-active{opacity:1;z-index:1}.splide--rtl{direction:rtl}.splide__track--ttb>.splide__list{display:block}.splide__container{box-sizing:border-box;position:relative}.splide__list{backface-visibility:hidden;display:-ms-flexbox;display:flex;height:100%;margin:0!important;padding:0!important}.splide.is-initialized:not(.is-active) .splide__list{display:grid}.splide__pagination{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center;margin:0;pointer-events:none}.splide__pagination li{display:inline-block;line-height:1;list-style-type:none;margin:0;pointer-events:auto}.splide:not(.is-overflow) .splide__pagination{display:none}.splide__progress__bar{width:0}.splide{position:relative;visibility:hidden}.splide.is-initialized,.splide.is-rendered{visibility:visible}.splide__slide{backface-visibility:hidden;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0;list-style-type:none!important;margin:0;position:relative}.splide__slide img{vertical-align:bottom}.splide__spinner{animation:splide-loading 1s linear infinite;border:2px solid #999;border-left-color:transparent;border-radius:50%;bottom:0;contain:strict;display:inline-block;height:20px;left:0;margin:auto;position:absolute;right:0;top:0;width:20px}.splide__sr{clip:rect(0 0 0 0);border:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.splide__toggle.is-active .splide__toggle__play,.splide__toggle__pause{display:none}.splide__toggle.is-active .splide__toggle__pause{display:inline}.splide__track{overflow:hidden;position:relative;z-index:0}
4079
4080    /* Custom additions from the splide.min.css but without the custom style */
4081    .splide__pagination--ttb {
4082        position: absolute;
4083        display: inline-flex;
4084        flex-direction: column;
4085        top: 0;
4086        bottom: 0;
4087        right: 100%;
4088    }
4089
4090    /* Hide the pagination dots when the input device is a touch based input */
4091    @media (pointer: coarse) or (max-width: 639px) {
4092        .splide__pagination { display: none }
4093    }
4094</style>
4095
4096
4097
4098
4099
4100
4101
4102
4103      <!-- [FOOTER Miscellaneous HTML (store)] -->
4104
4105<!-- [/FOOTER Miscellaneous HTML (store)] -->
4106
4107
4108
4109<!-- Google Tag Manager -->
4110
4111<!-- End Google Tag Manager -->
4112
4113<!-- Google Tag Manager (noscript) -->
vendor: 73 bytes, lines 4113-4115
4113
4114<noscript>
4115    <iframe src="https://www.googletagmanager.com/ns.html?id=
4115GTM-5VC2G8L
vendor: 92 bytes, lines 4115-4117
4115" height="0"
4116        width="0" style="display:none;visibility:hidden"></iframe>
4117</noscript>
4118<!-- Google Tag Manager -->
4119
4120<!-- End Google Tag Manager -->
4121
4122<!-- Google Tag Manager (noscript) -->
vendor: 73 bytes, lines 4122-4124
4122
4123<noscript>
4124    <iframe src="https://www.googletagmanager.com/ns.html?id=
4124GTM-5VC2G8L
vendor: 95 bytes, lines 4124-4126
4124" height="0"
4125        width="0" style="display:none;visibility:hidden"></iframe>
4126</noscript>    
4126</div> <div style="display: none"><div class="block popup-newsletter"><div class="content"><style>#html-body [data-pb-style=GAY0OEC]{justify-content:flex-start;display:flex;flex-direction:column;background-position:center center;background-size:cover;background-repeat:no-repeat;background-attachment:scroll;min-height:188px}</style><div data-content-type="row" data-appearance="full-bleed" data-enable-parallax="0" data-parallax-speed="0.5" data-background-images='{\"desktop_image\":\"https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-newsletter.jpg\",\"mobile_image\":\"https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-page_1.png\"}' data-background-type="image" data-video-loop="true" data-video-play-only-visible="true" data-video-lazy-load="true" data-video-fallback-src="" data-element="main" data-pb-style="GAY0OEC" data-src="https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-newsletter.jpg" data-mobile-source="https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-page_1.png" class=" lazy background-image-6abf643a29a25"></div><style type="text/css">.background-image-6abf643a29a25 {background-image: url(https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-newsletter.jpg);}@media only screen and (max-width: 767px) and (min-width: 640px) {.background-image-6abf643a29a25 {background-image: url(https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-page_1.png);}}@media only screen and (max-width: 640px) {.background-image-6abf643a29a25 {background-image: url(https://www.banham.co.uk/media/wysiwyg/locks-q3-hero-page_1.png);}}</style> <div class="right"><h3>STAY UP TO DATE WITH <br> THE BANHAM NEWSLETTER</h3><h4>For product updates, company news <br> and the latest stylish products</h4><div class="relative container">
4127    <div class="flex flex-col items-center justify-center w-full md:w-[426px] lg:w-[506px] gap-10 mx-auto pt-10 lg:pt-20 text-center">
4128                    <div class="flex flex-col gap-4 text-center w-full md:max-w-[320px]">
4129                <h3 class="m-0">Unlock the latest with the Banham newsletter.</h3>
4130                                    <p class="mb-0">We’d love to stay in touch. Sign up to our newsletter and be the first to hear our latest news, launches, and innovations.</p>
4131                            </div>
4132                <form
4133            id="newsletter-validate-detail"
4134            action="https://www.banham.co.uk/newsletter/subscriber/new/"
4135            method="post"
4136            x-data="newsletterForm()"
4137            @submit.prevent="submitForm"
4138            class="flex flex-col w-full gap-5"
4139        >
4140            <div class="flex flex-col items-start gap-3" :class="{'field-error': errors.firstname}">
4141                <input
4142                    type="text"
4143                    name="firstname"
4144                    id="firstname"
4145                    x-model="firstname"
4146                    @blur="validateField('firstname')"
4147                    :class="{'error': errors.firstname}"
4148                    class="form-input"
4149                    placeholder="First&#x20;Name&#x20;&#x2A;"
4150                >
4151                <span class="text-error text-xs mage-error" x-show="errors.firstname" x-text="errors.firstname"></span>
4152            </div>
4153
4154            <div class="flex flex-col items-start gap-3" :class="{'field-error': errors.lastname}">
4155                <input
4156                    type="text"
4157                    name="lastname"
4158                    id="lastname"
4159                    x-model="lastname"
4160                    @blur="validateField('lastname')"
4161                    :class="{'error': errors.lastname}"
4162                    class="form-input"
4163                    placeholder="Last&#x20;Name&#x20;&#x2A;"
4164                >
4165                <span class="text-error text-xs mage-error" x-show="errors.lastname" x-text="errors.lastname"></span>
4166            </div>
4167
4168            <div class="relative flex flex-col items-start gap-3" :class="{'field-error': errors.email}">
4169                <input
4170                    type="email"
4171                    name="email"
4172                    id="email"
4173                    x-model="email"
4174                    @blur="validateField('email')"
4175                    :class="{'error': errors.email}"
4176                    class="form-input"
4177                    placeholder="Email&#x20;Address&#x20;&#x2A;"
4178                >
4179                <span class="text-error text-xs mage-error" x-show="errors.email" x-text="errors.email"></span>
4180            </div>
4181
4182            <input name="form_key" type="hidden" value="9ScZqxAtVshasw9c" />
4183            <button type="submit" class="btn-primary btn btn-primary btn-size-md w-full mb-4">
4184                Subscribe            </button>
4185
4186                    </form>
4187
4188                    <p class="bottom-note m-0 text-primary-lighter"><p>If you would like further information on how we use your
personal data, please check our<a href="/privacy-promise" target="_self"> Privacy Policy</a>.</p></p>
4189            </div>
4190</div>
4191
4192 <a class="not-now" href="#">Not Now</a> <style>#html-body [data-pb-style=I98KDDQ]{justify-content:flex-start;display:flex;flex-direction:column;background-position:left top;background-size:cover;background-repeat:no-repeat;background-attachment:scroll}</style><div data-content-type="row" data-appearance="full-bleed" data-enable-parallax="0" data-parallax-speed="0.5" data-background-images="{}" data-background-type="image" data-video-loop="true" data-video-play-only-visible="true" data-video-lazy-load="true" data-video-fallback-src="" data-element="main" data-pb-style="I98KDDQ"><div data-content-type="text" data-appearance="default" data-element="main"><p>If you would like further information on how we use your personal data, please check our <a style="text-decoration: none;" tabindex="0" href="/privacy-promise/">Privacy Policy</a>.</p></div></div></div></div></div></div> 
4193<script type="text/javascript">window.amasty_checkout_disabled=true;</script>
vendor: 1 bytes, line 4193
4193
4194<script type="text/javascript" src="https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/BestResponseMedia_MagemeModification/js/source.js"></script>
vendor: 1 bytes, line 4194
4194
4195<script src="https://eu1-config.doofinder.com/2.x/37bb0b70-b046-4147-8e74-bf61c063a23b.js" async></script>
vendor: 1 bytes, line 4195
4195
4196<script src="https://www.googleoptimize.com/optimize.js?id=OPT-PNJW7FQ"></script>
vendor: 1 bytes, line 4196
4196
4197<script>(function(n,t,i,r){var u,f;n[i]=n[i]||{},n[i].initial={accountCode:"BANHA11114",host:"BANHA11114.pcapredict.com"},n[i].on=n[i].on||function(){(n[i].onq=n[i].onq||[]).push(arguments)},u=t.createElement("script"),u.async=!0,u.src=r,f=t.getElementsByTagName("script")[0],f.parentNode.insertBefore(u,f)})(window,document,"pca","//BANHA11114.pcapredict.com/js/sensor.js")</script>
vendor: 1 bytes, line 4197
4197
4198<script type='text/javascript' id='vwoCode'>
4199window._vwo_code || (function() {
4200var account_id=996012,
4201version=2.1,
4202settings_tolerance=2000,
4203hide_element='body',
4204hide_element_style = 'opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important;transition:none !important;',
4205/* DO NOT EDIT BELOW THIS LINE */
4206f=false,w=window,d=document,v=d.querySelector('#vwoCode'),cK='_vwo_'+account_id+'_settings',cc={};try{var c=JSON.parse(localStorage.getItem('_vwo_'+account_id+'_config'));cc=c&&typeof c==='object'?c:{}}catch(e){}var stT=cc.stT==='session'?w.sessionStorage:w.localStorage;code={nonce:v&&v.nonce,use_existing_jquery:function(){return typeof use_existing_jquery!=='undefined'?use_existing_jquery:undefined},library_tolerance:function(){return typeof library_tolerance!=='undefined'?library_tolerance:undefined},settings_tolerance:function(){return cc.sT||settings_tolerance},hide_element_style:function(){return'{'+(cc.hES||hide_element_style)+'}'},hide_element:function(){if(performance.getEntriesByName('first-contentful-paint')[0]){return''}return typeof cc.hE==='string'?cc.hE:hide_element},getVersion:function(){return version},finish:function(e){if(!f){f=true;var t=d.getElementById('_vis_opt_path_hides');if(t)t.parentNode.removeChild(t);if(e)(new Image).src='https://dev.visualwebsiteoptimizer.com/ee.gif?a='+account_id+e}},finished:function(){return f},addScript:function(e){var t=d.createElement('script');t.type='text/javascript';if(e.src){t.src=e.src}else{t.text=e.text}v&&t.setAttribute('nonce',v.nonce);d.getElementsByTagName('head')[0].appendChild(t)},load:function(e,t){var n=this.getSettings(),i=d.createElement('script'),r=this;t=t||{};if(n){i.textContent=n;d.getElementsByTagName('head')[0].appendChild(i);if(!w.VWO||VWO.caE){stT.removeItem(cK);r.load(e)}}else{var o=new XMLHttpRequest;o.open('GET',e,true);o.withCredentials=!t.dSC;o.responseType=t.responseType||'text';o.onload=function(){if(t.onloadCb){return t.onloadCb(o,e)}if(o.status===200||o.status===304){_vwo_code.addScript({text:o.responseText})}else{_vwo_code.finish('&e=loading_failure:'+e)}};o.onerror=function(){if(t.onerrorCb){return t.onerrorCb(e)}_vwo_code.finish('&e=loading_failure:'+e)};o.send()}},getSettings:function(){try{var e=stT.getItem(cK);if(!e){return}e=JSON.parse(e);if(Date.now()>e.e){stT.removeItem(cK);return}return e.s}catch(e){return}},init:function(){if(d.URL.indexOf('__vwo_disable__')>-1)return;var e=this.settings_tolerance();w._vwo_settings_timer=setTimeout(function(){_vwo_code.finish();stT.removeItem(cK)},e);var t;if(this.hide_element()!=='body'){t=d.createElement('style');var n=this.hide_element(),i=n?n+this.hide_element_style():'',r=d.getElementsByTagName('head')[0];t.setAttribute('id','_vis_opt_path_hides');v&&t.setAttribute('nonce',v.nonce);t.setAttribute('type','text/css');if(t.styleSheet)t.styleSheet.cssText=i;else t.appendChild(d.createTextNode(i));r.appendChild(t)}else{t=d.getElementsByTagName('head')[0];var i=d.createElement('div');i.style.cssText='z-index: 2147483647 !important;position: fixed !important;left: 0 !important;top: 0 !important;width: 100% !important;height: 100% !important;background: white !important;display: block !important;';i.setAttribute('id','_vis_opt_path_hides');i.classList.add('_vis_hide_layer');t.parentNode.insertBefore(i,t.nextSibling)}var o=window._vis_opt_url||d.URL,s='https://dev.visualwebsiteoptimizer.com/j.php?a='+account_id+'&u='+encodeURIComponent(o)+'&vn='+version;if(w.location.search.indexOf('_vwo_xhr')!==-1){this.addScript({src:s})}else{this.load(s+'&x=true')}}};w._vwo_code=code;code.init();})();
4207</script>
vendor: 1 bytes, line 4207
4207
4208<script>
4209(function () {
4210    function shouldOpen() {
4211        return window.location.hash === '#open_enquiry_form' ||
4212               window.location.search.includes('open=enquiry');
4213    }
4214
4215    function triggerEnquiryForm() {
4216        if (!shouldOpen()) return;
4217
4218        let tries = 0;
4219        const maxTries = 40;
4220
4221        const timer = setInterval(function () {
4222            const btn = document.querySelector('.open-slide-form-button');
4223
4224            if (btn) {
4225                window.surveyOpeningSource = 'Opened from CTA';
4226                btn.click();
4227                clearInterval(timer);
4228                return;
4229            }
4230
4231            tries++;
4232            if (tries >= maxTries) {
4233                clearInterval(timer);
4234            }
4235        }, 250);
4236    }
4237
4238    if (document.readyState === 'loading') {
4239        document.addEventListener('DOMContentLoaded', triggerEnquiryForm);
4240    } else {
4241        triggerEnquiryForm();
4242    }
4243
4244    window.addEventListener('hashchange', triggerEnquiryForm);
4245})();
4246</script>
vendor: 1 bytes, line 4246
4246
4247<script  type="text/javascript"  data-routing="commerce=rum" defer="defer" src="https://rum.hlx.page/.rum/@adobe/helix-rum-js@^2/dist/rum-standalone.js"></script>
vendor: 1 bytes, line 4247
4247
4248<script type="text&#x2F;javascript" src="" defer="defer">
4249</script>
vendor: 1 bytes, line 4249
4249
4250<script>
4251    var BASE_URL = 'https://www.banham.co.uk/';
4252    var THEME_PATH = 'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB';
4253    var COOKIE_CONFIG = {
4254        "expires": null,
4255        "path": "\u002F",
4256        "domain": ".www.banham.co.uk",
4257        "secure": true,
4258        "lifetime": "24800",
4259        "cookie_restriction_enabled": false    };
4260    var CURRENT_STORE_CODE = 'default';
4261    var CURRENT_WEBSITE_ID = '1';
4262
4263    window.hyva = window.hyva || {}
4264
4265    window.cookie_consent_groups = window.cookie_consent_groups || {}
4266    window.cookie_consent_groups['necessary'] = true;
4267
4268    window.cookie_consent_config = window.cookie_consent_config || {};
4269    window.cookie_consent_config['necessary'] = [].concat(
4270        window.cookie_consent_config['necessary'] || [],
4271        [
4272            'user_allowed_save_cookie',
4273            'form_key',
4274            'mage-messages',
4275            'private_content_version',
4276            'mage-cache-sessid',
4277            'last_visited_store',
4278            'section_data_ids'
4279        ]
4280    );</script>
vendor: 1 bytes, line 4280
4280
4281<script>
4282    (function( hyva, undefined ) {
4283
4284        function lifetimeToExpires(options, defaults) {
4285
4286            const lifetime = options.lifetime || defaults.lifetime;
4287
4288            if (lifetime) {
4289                const date = new Date;
4290                date.setTime(date.getTime() + lifetime * 1000);
4291                return date;
4292            }
4293
4294            return null;
4295        }
4296
4297        function generateRandomString() {
4298
4299            const allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
4300                length = 16;
4301
4302            let formKey = '',
4303                charactersLength = allowedCharacters.length;
4304
4305            for (let i = 0; i < length; i++) {
4306                formKey += allowedCharacters[Math.round(Math.random() * (charactersLength - 1))]
4307            }
4308
4309            return formKey;
4310        }
4311
4312        const sessionCookieMarker = {noLifetime: true}
4313
4314        const cookieTempStorage = {};
4315
4316        const internalCookie = {
4317            get(name) {
4318                const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
4319                return v ? v[2] : null;
4320            },
4321            set(name, value, days, skipSetDomain) {
4322                let expires,
4323                    path,
4324                    domain,
4325                    secure,
4326                    samesite;
4327
4328                const defaultCookieConfig = {
4329                    expires: null,
4330                    path: '/',
4331                    domain: null,
4332                    secure: false,
4333                    lifetime: null,
4334                    samesite: 'lax'
4335                };
4336
4337                const cookieConfig = window.COOKIE_CONFIG || {};
4338
4339                expires = days && days !== sessionCookieMarker
4340                    ? lifetimeToExpires({lifetime: 24 * 60 * 60 * days, expires: null}, defaultCookieConfig)
4341                    : lifetimeToExpires(window.COOKIE_CONFIG, defaultCookieConfig) || defaultCookieConfig.expires;
4342
4343                path = cookieConfig.path || defaultCookieConfig.path;
4344                domain = !skipSetDomain && (cookieConfig.domain || defaultCookieConfig.domain);
4345                secure = cookieConfig.secure || defaultCookieConfig.secure;
4346                samesite = cookieConfig.samesite || defaultCookieConfig.samesite;
4347
4348                document.cookie = name + "=" + encodeURIComponent(value) +
4349                    (expires && days !== sessionCookieMarker ? '; expires=' + expires.toGMTString() : '') +
4350                    (path ? '; path=' + path : '') +
4351                    (domain ? '; domain=' + domain : '') +
4352                    (secure ? '; secure' : '') +
4353                    (samesite ? '; samesite=' + samesite : 'lax');
4354            },
4355            isWebsiteAllowedToSaveCookie() {
4356                const allowedCookies = this.get('user_allowed_save_cookie');
4357                if (allowedCookies) {
4358                    const allowedWebsites = JSON.parse(unescape(allowedCookies));
4359
4360                    return allowedWebsites[CURRENT_WEBSITE_ID] === 1;
4361                }
4362                return false;
4363            },
4364            getGroupByCookieName(name) {
4365                const cookieConsentConfig = window.cookie_consent_config || {};
4366                let group = null;
4367                for (let prop in cookieConsentConfig) {
4368                    if (!cookieConsentConfig.hasOwnProperty(prop)) continue;
4369                    if (cookieConsentConfig[prop].includes(name)) {
4370                        group = prop;
4371                        break;
4372                    }
4373                }
4374                return group;
4375            },
4376            isCookieAllowed(name) {
4377                const cookieGroup = this.getGroupByCookieName(name);
4378                return cookieGroup
4379                    ? window.cookie_consent_groups[cookieGroup]
4380                    : this.isWebsiteAllowedToSaveCookie();
4381            },
4382            saveTempStorageCookies() {
4383                for (const [name, data] of Object.entries(cookieTempStorage)) {
4384                    if (this.isCookieAllowed(name)) {
4385                        this.set(name, data['value'], data['days'], data['skipSetDomain']);
4386                        delete cookieTempStorage[name];
4387                    }
4388                }
4389            }
4390        };
4391
4392        hyva.getCookie = (name) => {
4393            const cookieConfig = window.COOKIE_CONFIG || {};
4394
4395            if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) {
4396                return cookieTempStorage[name] ? cookieTempStorage[name]['value'] : null;
4397            }
4398
4399            return internalCookie.get(name);
4400        }
4401
4402        hyva.setCookie = (name, value, days, skipSetDomain) => {
4403            const cookieConfig = window.COOKIE_CONFIG || {};
4404
4405            if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) {
4406                cookieTempStorage[name] = {value, days, skipSetDomain};
4407                return;
4408            }
4409            return internalCookie.set(name, value, days, skipSetDomain);
4410        }
4411
4412
4413        hyva.setSessionCookie = (name, value, skipSetDomain) => {
4414            return hyva.setCookie(name, value, sessionCookieMarker, skipSetDomain)
4415        }
4416
4417        hyva.getBrowserStorage = () => {
4418            const browserStorage = window.localStorage || window.sessionStorage;
4419            if (!browserStorage) {
4420                console.warn('Browser Storage is unavailable');
4421                return false;
4422            }
4423            try {
4424                browserStorage.setItem('storage_test', '1');
4425                browserStorage.removeItem('storage_test');
4426            } catch (error) {
4427                console.warn('Browser Storage is not accessible', error);
4428                return false;
4429            }
4430            return browserStorage;
4431        }
4432
4433        hyva.postForm = (postParams) => {
4434            const form = document.createElement("form");
4435
4436            let data = postParams.data;
4437
4438            if (! postParams.skipUenc && ! data.uenc) {
4439                data.uenc = btoa(window.location.href);
4440            }
4441            form.method = "POST";
4442            form.action = postParams.action;
4443
4444            Object.keys(postParams.data).map(key => {
4445                const field = document.createElement("input");
4446                field.type = 'hidden'
4447                field.value = postParams.data[key];
4448                field.name = key;
4449                form.appendChild(field);
4450            });
4451
4452            const form_key = document.createElement("input");
4453            form_key.type = 'hidden';
4454            form_key.value = hyva.getFormKey();
4455            form_key.name="form_key";
4456            form.appendChild(form_key);
4457
4458            document.body.appendChild(form);
4459
4460            form.submit();
4461        }
4462
4463        hyva.getFormKey = function () {
4464            let formKey = hyva.getCookie('form_key');
4465
4466            if (!formKey) {
4467                formKey = generateRandomString();
4468                hyva.setCookie('form_key', formKey);
4469            }
4470
4471            return formKey;
4472        }
4473
4474        hyva.formatPrice = (value, showSign, options = {}) => {
4475            const groupSeparator = options.groupSeparator;
4476            const decimalSeparator = options.decimalSeparator
4477            delete options.groupSeparator;
4478            delete options.decimalSeparator;
4479            const formatter = new Intl.NumberFormat(
4480                'en\u002DGB',
4481                Object.assign({
4482                    style: 'currency',
4483                    currency: 'GBP',
4484                    signDisplay: showSign ? 'always' : 'auto'
4485                }, options)
4486            );
4487            return (typeof Intl.NumberFormat.prototype.formatToParts === 'function') ?
4488                formatter.formatToParts(value).map(({type, value}) => {
4489                    switch (type) {
4490                        case 'currency':
4491                            return '\u00A3' || value;
4492                        case 'minusSign':
4493                            return '- ';
4494                        case 'plusSign':
4495                            return '+ ';
4496                        case 'group':
4497                            return groupSeparator !== undefined ? groupSeparator : value;
4498                        case 'decimal':
4499                            return decimalSeparator !== undefined ? decimalSeparator : value;
4500                        default :
4501                            return value;
4502                    }
4503                }).reduce((string, part) => string + part) :
4504                formatter.format(value);
4505        }
4506
4507 const formatStr = function (str, nStart) {
4508            const args = Array.from(arguments).slice(2);
4509
4510            return str.replace(/(%+)([0-9]+)/g, (m, p, n) => {
4511                const idx = parseInt(n) - nStart;
4512
4513                if (args[idx] === null || args[idx] === void 0) {
4514                    return m;
4515                }
4516                return p.length % 2
4517                    ? p.slice(0, -1).replace('%%', '%') + args[idx]
4518                    : p.replace('%%', '%') + n;
4519            })
4520        }
4521
4522 hyva.str = function (string) {
4523            const args = Array.from(arguments);
4524            args.splice(1, 0, 1);
4525
4526            return formatStr.apply(undefined, args);
4527        }
4528
4529 hyva.strf = function () {
4530            const args = Array.from(arguments);
4531            args.splice(1, 0, 0);
4532
4533            return formatStr.apply(undefined, args);
4534        }
4535
4536        /**
4537         * Take a html string as `content` parameter and
4538         * extract an element from the DOM to replace in
4539         * the current page under the same selector,
4540         * defined by `targetSelector`
4541         */
4542        hyva.replaceDomElement = (targetSelector, content) => {
4543            
4544            const parser = new DOMParser();
4545            const doc = parser.parseFromString(content, 'text/html');
4546            const contentNode = doc.querySelector(targetSelector);
4547
4548            
4549            if (!contentNode || !document.querySelector(targetSelector)) {
4550                return;
4551            }
4552
4553             hyva.activateScripts(contentNode);
4554             document.querySelector(targetSelector).replaceWith(contentNode);
4555
4556            
4557            window.dispatchEvent(new CustomEvent("reload-customer-section-data"));
4558            hyva.initMessages();
4559        }
4560
4561        hyva.removeScripts = (contentNode) => {
4562            const scripts = contentNode.getElementsByTagName('script');
4563            for (let i = 0; i < scripts.length; i++) {
4564                scripts[i].parentNode.removeChild(scripts[i]);
4565            }
4566            const templates = contentNode.getElementsByTagName('template');
4567            for (let i = 0; i < templates.length; i++) {
4568                const container = document.createElement('div');
4569                container.innerHTML = templates[i].innerHTML;
4570                hyva.removeScripts(container);
4571                templates[i].innerHTML = container.innerHTML;
4572            }
4573        }
4574
4575        hyva.activateScripts = (contentNode) => {
4576 const scripts = Array.from(contentNode.getElementsByTagName('script'));
4577
4578            
4579            for (const original of scripts) {
4580                const script = document.createElement('script');
4581                original.type && (script.type = original.type);
4582                script.innerHTML = original.innerHTML;
4583
4584                
4585                original.parentNode.removeChild(original)
4586
4587                
4588                document.head.appendChild(script);
4589            }
4590
4591            return contentNode;
4592        }
4593
4594 const replace = {['+']: '-', ['/']: '_', ['=']: ','};
4595        hyva.getUenc = () => btoa(window.location.href).replace(/[+/=]/g, match => replace[match]);
4596
4597        let currentTrap;
4598
4599        const focusableElements = (rootElement) => {
4600            const selector = 'button, [href], input, select, textarea, details, [tabindex]:not([tabindex="-1"]';
4601            return Array.from(rootElement.querySelectorAll(selector))
4602                .filter(el => {
4603                    return el.style.display !== 'none'
4604                        && !el.disabled
4605                        && el.tabIndex !== -1
4606                        && (el.offsetWidth || el.offsetHeight || el.getClientRects().length)
4607                })
4608        }
4609
4610        const focusTrap = (e) => {
4611            const isTabPressed = e.key === 'Tab' || e.keyCode === 9;
4612            if (!isTabPressed) return;
4613
4614            const focusable = focusableElements(currentTrap)
4615            const firstFocusableElement = focusable[0]
4616            const lastFocusableElement = focusable[focusable.length - 1]
4617
4618            e.shiftKey
4619                ? document.activeElement === firstFocusableElement && (lastFocusableElement.focus(), e.preventDefault())
4620                : document.activeElement === lastFocusableElement && (firstFocusableElement.focus(), e.preventDefault())
4621        };
4622
4623        hyva.releaseFocus = (rootElement) => {
4624            if (currentTrap && (!rootElement || rootElement === currentTrap)) {
4625                currentTrap.removeEventListener('keydown', focusTrap)
4626                currentTrap = null
4627            }
4628        }
4629        hyva.trapFocus = (rootElement) => {
4630            if (!rootElement) return;
4631            hyva.releaseFocus()
4632            currentTrap = rootElement
4633            rootElement.addEventListener('keydown', focusTrap)
4634            const firstElement = focusableElements(rootElement)[0]
4635            firstElement && firstElement.focus()
4636        }
4637
4638 hyva.safeParseNumber = (rawValue) => {
4639            const number = rawValue ? parseFloat(rawValue) : null;
4640
4641            return Array.isArray(number) || isNaN(number) ? rawValue : number;
4642        }
4643
4644 const toCamelCase = s => s.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
4645        hyva.createBooleanObject = (name, value = false, additionalMethods = {}) => {
4646
4647            const camelCase = toCamelCase(name);
4648 const key = '__hyva_bool_' + name
4649
4650            return new Proxy(Object.assign(
4651                additionalMethods,
4652                {
4653                    [key]: !!value,
4654                    [name]() {return !!this[key]},
4655                    ['!' + name]() {return !this[key]}, 
4656                    ['not' + camelCase]() {return !this[key]},
4657                    ['toggle' + camelCase]() {this[key] = !this[key]},
4658                    [`set${camelCase}True`]() {this[key] = true},
4659                    [`set${camelCase}False`]() {this[key] = false},
4660                }
4661            ), {
4662                set(target, prop, value) {
4663                    return prop === name
4664                        ? (target[key] = !!value)
4665                        : Reflect.set(...arguments);
4666                }
4667            })
4668        }
4669
4670                hyva.alpineInitialized = (fn) => window.addEventListener('alpine:initialized', fn, {once: true})
4671        window.addEventListener('alpine:init', () => Alpine.data('{}', () => ({})), {once: true});
4672         window.addEventListener('user-allowed-save-cookie', () => internalCookie.saveTempStorageCookies())
4673
4674    }( window.hyva = window.hyva || {} ));</script>
vendor: 1 bytes, line 4674
4674
4675<script type="speculationrules">
4676{
4677    "tag": "Hyva Theme",
4678    "prefetch": [{
4679        "source": "document",
4680        "where": {
4681            "and": [
4682                { "href_matches": "/*" },
4683                { "not": {
4684                    "href_matches": ["/customer/*","/search/*","/sales/*","/wishlist/*","/checkout/*","/paypal/*","/newsletter/*","/stores/store/redirect/*"]                }},
4685                { "not": {
4686                    "selector_matches": [".no-preload", ".do-not-prerender", "[download]", "[rel~=nofollow]", "[target]"]
4687                }}
4688            ]
4689        },
4690        "eagerness": "moderate"
4691    }]
4692}</script>
vendor: 1 bytes, line 4692
4692
4693<script>
4694    const viewTransitionToGalleryPageStorage = 'view-transition-to-gallery-page-type';
4695    const setTransitionNameBetweenGallery = async (url, promise) => {
4696        if (window.matchMedia('(prefers-reduced-motion)').matches) return;
4697
4698        const productGallery = document.getElementById('gallery-main');
4699        const productListItem = document.querySelector(`.product-item-photo[href="${url}"]`);
4700        const targetElement = productListItem || productGallery;
4701
4702        if (targetElement) {
4703            targetElement.style.viewTransitionName = 'view-transition-to-gallery';
4704
4705            await promise;
4706            targetElement.style.viewTransitionName = '';
4707        }
4708    };
4709
4710    const getViewTransitionToGalleryPageIsProduct = () => {
4711        return document.body.classList.contains('catalog-product-view') ? 'product-page' : 'other'
4712    }
4713
4714    window.addEventListener('pageswap', async (e) => {
4715        if (!e.viewTransition) return;
4716        const pageType = getViewTransitionToGalleryPageIsProduct();
4717        const target = new URL(e.activation.entry.url);
4718
4719        sessionStorage.setItem(viewTransitionToGalleryPageStorage, pageType);
4720        setTransitionNameBetweenGallery(target.href, e.viewTransition.finished);
4721    });
4722
4723    window.addEventListener('pagereveal', async (e) => {
4724        if (!e.viewTransition || (window.navigation && !window.navigation.activation.from)) return;
4725        const previousPageType = sessionStorage.getItem(viewTransitionToGalleryPageStorage);
4726        const pageType = getViewTransitionToGalleryPageIsProduct();
4727        sessionStorage.removeItem(viewTransitionToGalleryPageStorage);
4728
4729        if (previousPageType === pageType) return;
4730        const target = new URL(window.navigation.activation.from.url);
4731        setTransitionNameBetweenGallery(target.href, e.viewTransition.ready);
4732    });
4733</script>
vendor: 1 bytes, line 4733
4733
4734<script>
4735    (function () {
4736        let amSplideProcessed = false;
4737
4738        window.addEventListener('load-amsplide', () => {
4739            if (amSplideProcessed) {
4740                window?.Splide && window.dispatchEvent(new CustomEvent('amsplide-loaded', {}));
4741                return;
4742            }
4743
4744            const script = document.createElement('script');
4745            script.src = 'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Amasty_LibSplideJs/4.1.3/js/splide/splide.min.js';
4746            script.async = true;
4747            document.body.appendChild(script);
4748
4749            amSplideProcessed = true;
4750
4751            script.onload = () => {
4752                window.dispatchEvent(new CustomEvent('amsplide-loaded', {}));
4753            }
4754
4755            const stylesHref = 'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Amasty_LibSplideJs/4.1.3/css/splide/splide.min.css';
4756
4757            if (document.querySelector(`link[href="${stylesHref}"]`)) {
4758                return;
4759            }
4760
4761            const styles = document.createElement('link');
4762            styles.rel = 'stylesheet';
4763            styles.type = 'text/css';
4764            styles.href = stylesHref;
4765
4766            document.head.appendChild(styles);
4767        });
4768    }());</script>
vendor: 1 bytes, line 4768
4768
4769<script>"use strict";"object"!=typeof window.MageMe&&(window.MageMe={}),window.MageMe.loader={addScript:(e,r,d)=>{if(!window[e]){let d=[];window[e]={"-isLoading":e=>d.push(e)};var t=document.createElement("script");t.src=r,t.onload=()=>{d.map(e=>e()),d=[]},document.head.append(t)}window[e]["-isLoading"]&&window[e]["-isLoading"](()=>MageMe.loader.addScript(e,r,d)),!window[e]["-isLoading"]&&d&&d()},addScriptWoCb:e=>{var d;document.querySelector('script[src="'+e+'"]')||((d=document.createElement("script")).src=e,document.head.append(d))},addCss:e=>{var d;document.querySelector('link[href="'+e+'"]')||((d=document.createElement("link")).rel="stylesheet",d.href=e,document.head.appendChild(d))},addCssOrdered:(e,d)=>{var r;document.querySelector('link[href="'+e+'"]')||(d=(d=Number(d))||0,(r=document.createElement("link")).rel="stylesheet",r.href=e,r.setAttribute("data-mm-order",d),(e=Array.from(document.head.querySelectorAll("[data-mm-order]")).filter(e=>Number(e.dataset.mmOrder)>d)).length?document.head.insertBefore(r,e[0]):document.head.appendChild(r))}};</script>
vendor: 1 bytes, line 4769
4769
4770<script>
4771    'use strict';
4772    (function(webfroms) {
4773         const formValidationRules = {
4774            required(value, options, field, context) {
4775                const el = field.element.type === 'hidden' ? createTextInputFrom(field.element) : field.element,
4776                    msg = 'This\u0020is\u0020a\u0020required\u0020field.';
4777
4778                if (el.type === 'radio' || el.type === 'checkbox') {
4779                    return (value === undefined || value.length === 0) ? msg : true;
4780                }
4781
4782                el.setAttribute('required', '');
4783                el.checkValidity();
4784
4785                return el.validity.valueMissing ? msg : true;
4786            },
4787            maxlength(value, options, field, context) {
4788                const n = Number(options)
4789                if (value.length > n) {
4790                    return n === 1
4791                        ? strf('Please\u0020enter\u0020no\u0020more\u0020than\u00201\u0020character.')
4792                        : strf('Please\u0020enter\u0020no\u0020more\u0020than\u0020\u00250\u0020characters.', options)
4793                }
4794                return true;
4795            },
4796            minlength(value, options, field, context) {
4797                const n = Number(options)
4798                if (value.length > 0 && value.length < n) {
4799                    return n === 1
4800                        ? strf('Please\u0020enter\u0020at\u0020least\u00201\u0020character.')
4801                        : strf('Please\u0020enter\u0020at\u0020least\u0020\u00250\u0020characters.', options)
4802                }
4803                return true;
4804            },
4805            max(value, options, field, context) {
4806                field.element.setAttribute('max', options);
4807                field.element.checkValidity();
4808                if (field.element.validity.rangeOverflow) {
4809                    return strf('Please\u0020enter\u0020a\u0020value\u0020less\u0020than\u0020or\u0020equal\u0020to\u0020\u0022\u00250\u0022.', options);
4810                }
4811                return true;
4812            },
4813            min(value, options, field, context) {
4814                field.element.setAttribute('min', options);
4815                field.element.checkValidity();
4816                if (field.element.validity.rangeUnderflow) {
4817                    return strf('Please\u0020enter\u0020a\u0020value\u0020greater\u0020than\u0020or\u0020equal\u0020to\u0020\u0022\u00250\u0022.', options);
4818                }
4819                return true;
4820            },
4821            step(value, options, field, context) {
4822                field.element.setAttribute('step', options);
4823                field.element.checkValidity();
4824                if (field.element.validity.stepMismatch) {
4825                    const val = Number(value);
4826                    const step = Number(options);
4827                    const msg = 'Please\u0020enter\u0020a\u0020valid\u0020value.\u0020The\u0020two\u0020nearest\u0020valid\u0020values\u0020are\u0020\u0022\u00250\u0022\u0020and\u0020\u0022\u00251\u0022.';
4828                    return strf(msg, Math.floor(val / step) * step, Math.ceil(val / step) * step);
4829                }
4830                return true;
4831            },
4832            pattern(value, options, field, context) {
4833                field.element.setAttribute('pattern', options);
4834                field.element.checkValidity();
4835                if (field.element.validity.patternMismatch) {
4836                    return field.element.title
4837                        ? strf('Please\u0020match\u0020the\u0020requested\u0020format\u003A\u0020\u00250.', field.element.title)
4838                        : 'Please\u0020match\u0020the\u0020requested\u0020format.'
4839                }
4840                return true;
4841            },
4842            email(value, options, field, context) {
4843                 const rule = /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i;
4844                if (value.length > 0 && !rule.test(value)) {
4845                    return 'Please\u0020enter\u0020a\u0020valid\u0020email\u0020address.';
4846                }
4847                return true;
4848            },
4849            password(value, options, field, context) {
4850                const rule = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/;
4851                if (value.length > 0 && !rule.test(value)) {
4852                    return 'Please\u0020provide\u0020at\u0020least\u0020one\u0020upper\u0020case,\u0020one\u0020lower\u0020case,\u0020one\u0020digit\u0020and\u0020one\u0020special\u0020character\u0020\u0028\u0023\u003F\u0021\u0040\u0024\u0025\u005E\u0026\u002A\u002D\u0029';
4853                }
4854                return true;
4855            },
4856            equalTo(value, options, field, context) {
4857                const dependencyField = context.fields[options].element;
4858                if (value !== dependencyField.value) {
4859                    const dependencyFieldName =
4860                        dependencyField.label ||
4861                        dependencyField.title ||
4862                        (dependencyField.labels && dependencyField.labels[0] && dependencyField.labels[0].innerText) ||
4863                        dependencyField.name;
4864                    return strf('This\u0020field\u0020value\u0020must\u0020be\u0020the\u0020same\u0020as\u0020\u0022\u00250\u0022.', dependencyFieldName);
4865                }
4866                return true;
4867            }
4868        };
4869
4870         function raceSome(promises, pred) {
4871            return new Promise((resolve, reject) => {
4872
4873                if (promises.length === 0) {
4874                    return resolve();
4875                }
4876
4877                let settled = false, nDone = 0;
4878
4879                const resolveIf = v => {
4880                    if (!settled && (pred(v) || ++nDone === promises.length)) {
4881                        settled = true;
4882                        resolve(v);
4883                    }
4884                    return v;
4885                }
4886
4887                promises.map(promise => {
4888                    promise.then(resolveIf).catch(reason => {
4889                        settled = true;
4890                        reject(reason)
4891                    });
4892                    return promise;
4893                });
4894            });
4895        }
4896
4897        const INPUT_ATTRIBUTE_RULES = {min: 'min', max: 'max', required: 'required', minlength: 'minlength', maxlength: 'maxlength', step: 'step', pattern: 'pattern'}
4898        const INPUT_TYPE_RULES = {email: 'email'}
4899
4900        function getRules(element) {
4901            let rules = {};
4902            Object.keys(INPUT_ATTRIBUTE_RULES).forEach(attrName => {
4903                if (element.hasAttribute(attrName)) {
4904                    rules[INPUT_ATTRIBUTE_RULES[attrName]] = element.getAttribute(attrName);
4905                }
4906            })
4907            if (INPUT_TYPE_RULES[element.type]) {
4908                rules[INPUT_TYPE_RULES[element.type]] = true;
4909            }
4910
4911            if (element.dataset.validate) {
4912                try {
4913                    const validateRulesStr = element.dataset.validate.replace(/'/g,"\"");
4914                    Object.assign(rules, JSON.parse(validateRulesStr));
4915                } catch (error) {
4916                    console.error('Validator error. Cannot parse data-validate attribute of element:\n', element);
4917                }
4918            }
4919
4920            return rules;
4921        }
4922
4923        function isInvalidRuleResult(ruleState) {
4924            return typeof ruleState === 'string' || !ruleState || (ruleState.type && ruleState.content);
4925        }
4926
4927        async function runValidateFn(rule, options, value, field) {
4928            return formValidationRules[rule](value, options, field, this);
4929        }
4930
4931        function generateId() {
4932            let id;
4933            do {
4934                id = `${this.idPrefix}-${++this.idSeq}`;
4935            } while (document.getElementById(id));
4936            return id;
4937        }
4938
4939        function isVisible(element) {
4940            const el = element.type !== 'hidden' ? element : (element.parentElement || {});
4941            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
4942        }
4943
4944        function elementWillValidate(element) {
4945            return (element.willValidate || element.type === 'hidden')
4946                && element.tagName !== 'BUTTON'
4947                && element.disabled === false
4948                && !(element.tagName === 'INPUT' && element.type === 'submit')
4949                && (element.hasAttribute('data-validate-hidden')
4950                    || element.classList.contains('validate-hidden')
4951                    || isVisible(element))
4952        }
4953
4954        function createMessageContainer(el, fieldWrapperClassName) {
4955            if (! el.parentElement) {
4956                return;
4957            }
4958            const refocus = document.activeElement === el;
4959            const wrapper = document.createElement('div');
4960            wrapper.classList.add.apply(wrapper.classList, fieldWrapperClassName.split(' '));
4961            el.parentElement.insertBefore(wrapper, el);
4962            wrapper.appendChild(el);
4963            refocus && document.activeElement !== el && el.focus();
4964            return wrapper;
4965        }
4966
4967        function containerNotFound(selector, el) {
4968            const msg = `Cannot find message container element ${selector} of ${el.name}`;
4969            console.error(msg, el);
4970            throw msg;
4971        }
4972
4973        function createTextInputFrom(el) {
4974            const text = document.createElement('INPUT');
4975            text.type = 'text';
4976            text.value = el.value;
4977            return text;
4978        }
4979
4980        function classNamesToSelector(classNames) {
4981            return classNames.split(' ')
4982                .filter(className => className.length > 0)
4983                .map(className => `.${className}`)
4984                .join('')
4985        }
4986
4987        function hasMessagesWrapper(field, messagesWrapperClassName) {
4988            return this.getMessageContainer(field).querySelector(classNamesToSelector(messagesWrapperClassName));
4989        }
4990
4991        function getMessagesWrapper(field, messagesWrapperClassName) {
4992            if (hasMessagesWrapper.call(this, field, messagesWrapperClassName)) {
4993                return this.getMessageContainer(field).querySelector(classNamesToSelector(messagesWrapperClassName));
4994            }
4995
4996            const msgWrapper = document.createElement('ul');
4997            const msgId = generateId.call(this);
4998            msgWrapper.id = msgId;
4999            field.element.setAttribute('aria-errormessage', msgId);
5000            field.element.setAttribute('aria-describedby', msgId);
5001            msgWrapper.classList.add.apply(msgWrapper.classList, messagesWrapperClassName.split(' '));
5002            if (field.validateOnChange) {
5003                msgWrapper.setAttribute('aria-live', 'polite');
5004            }
5005            this.getMessageContainer(field).appendChild(msgWrapper);
5006
5007            return msgWrapper;
5008        }
5009
5010        function getCheckedValues(field) {
5011            const name = field.element.name.replace(/([\\"])/g, '\\$1');
5012            const elements = field.element.form.querySelectorAll('input[name="' + name + '"]:checked');
5013            return Array.from(elements).map(el => el.value);
5014        }
5015
5016        function escapeHtml(s) {
5017            const div = document.createElement('div')
5018            div.innerText = s;
5019            return div.innerHTML;
5020        }
5021
5022        function str(string) {
5023            const args = Array.from(arguments);
5024            args.splice(1, 0, 1);
5025
5026            return formatStr.apply(undefined, args);
5027        }
5028
5029        function strf() {
5030            const args = Array.from(arguments);
5031            args.splice(1, 0, 0);
5032
5033            return formatStr.apply(undefined, args);
5034        }
5035
5036        const formatStr = function (str, nStart) {
5037            const args = Array.from(arguments).slice(2);
5038
5039            return str.replace(/(%+)([0-9]+)/g, (m, p, n) => {
5040                const idx = parseInt(n) - nStart;
5041
5042                if (args[idx] === null || args[idx] === void 0) {
5043                    return m;
5044                }
5045                return p.length % 2
5046                    ? p.slice(0, -1).replace('%%', '%') + args[idx]
5047                    : p.replace('%%', '%') + n;
5048            })
5049        }
5050
5051         function formValidation(form, options = {}) {
5052            const formElement = form || this.$el;
5053
5054            if (formElement.dataset && formElement.dataset.options) {
5055                try {
5056                    options = Object.assign(options, JSON.parse(formElement.dataset.options || '{}'));
5057                } catch (e) {
5058                    throw new Error('Cannot read the form options from the data-options attribute: not val
5058id JSON');
5059                }
5060            }
5061
5062            
5063            if (formElement.tagName === 'FORM') {
5064                formElement.setAttribute('novalidate', '');
5065            } else {
5066                console.error('formValidation can be initialized only on FORM element', formElement);
5067                return;
5068            }
5069
5070            options = Object.assign({
5071                fieldWrapperClassName: 'field field-reserved',
5072                messagesWrapperClassName: 'messages',
5073                validClassName: 'field-success',
5074                invalidClassName: 'field-error',
5075                pageMessagesWrapperSelector: null,
5076                scrollToFirstError: true,
5077            }, options || {});
5078
5079            return {
5080                state: {
5081                    valid: false,
5082                },
5083                fields: {},
5084                idSeq: 0,
5085                idPrefix: formElement.id || 'vld-msg',
5086                setupFields(elements) {
5087                    this.fields = {};
5088                    Array.from(elements).forEach(element => {
5089                        if (elementWillValidate(element)) {
5090                            this.setupField(element);
5091                        }
5092                    });
5093                },
5094                setupField(element) {
5095                    if (! element) return;
5096                    const onChange = !!element.dataset.onChange;
5097                    if (elementWillValidate(element)) {
5098                        const rules = getRules(element);
5099                        if (Object.keys(rules).length > 0) {
5100                            if (this.fields[element.name]) {
5101                                Object.assign(this.fields[element.name].rules, rules);
5102                            } else {
5103                                this.fields[element.name] = {
5104                                    element,
5105                                    rules: rules,
5106                                    validateOnChange: onChange,
5107                                    state: {
5108                                        valid: null,
5109                                        rules: {}
5110                                    }
5111                                }
5112                            }
5113                        }
5114                    } else {
5115                        console.error('Element will not validate', element);
5116                    }
5117                },
5118                onSubmit(event) {
5119                    if (event.target.tagName === 'FORM') {
5120                        event.preventDefault();
5121
5122                        this.validate()
5123                            .then(() => event.target.submit())
5124                            .catch(invalidElements => {});
5125                    }
5126                },
5127                onChange(event) {
5128                    event.target.dataset.onChange = 'true';
5129                    if (!Object.keys(this.fields).length) {
5130                        this.setupFields(formElement.elements);
5131                    }
5132                    if (!Object.keys(this.fields).includes(event.target.name)) {
5133                        this.setupField(event.target);
5134                    }
5135                    const field = this.fields[event.target.name];
5136
5137                    this.validateField(field);
5138                    field && field.element.removeAttribute('data-on-change')
5139                },
5140                validateSafe() {
5141                    return new Promise(resolve => this.validate().then(() => resolve(true)).catch(() => {}))
5142                },
5143                validate() {
5144                    if (!Object.keys(this.fields).length || !Object.keys(this.fields).length !== formElement.elements.length) {
5145                        this.setupFields(formElement.elements);
5146                    }
5147                    return new Promise(async (resolve, reject) => {
5148                        if (formElement.elements) {
5149                             await raceSome(this.validateFields(), result => result !== true)
5150                            const invalidFields = Object.values(this.fields).filter(field => !field.state.valid);
5151                            this.state.valid = invalidFields.length === 0;
5152                            if (this.state.valid) {
5153                                resolve();
5154                            } else {
5155                                if (options.scrollToFirstError && invalidFields.length > 0) {
5156
5157                                    
5158                                    if (invalidFields[0].element.classList.contains('validate-hidden')) {
5159                                        const uid = invalidFields[0].element.dataset.uid;
5160                                        if (uid) {
5161                                            const parent = document.querySelector("#field_" + uid);
5162                                            if (parent) {
5163                                                parent.scrollIntoView();
5164                                            }
5165                                        }
5166                                    }
5167                                    invalidFields[0].element.focus()
5168                                    invalidFields[0].element.select && invalidFields[0].element.select();
5169                                }
5170                                reject(invalidFields.map(field => field.element));
5171                            }
5172                        }
5173                    });
5174                },
5175                 validateFields() {
5176                    const fields = Object.values(this.fields);
5177
5178                     fields.forEach(field => {
5179                        this.getMessageContainer(field).classList.remove(options.validClassName, options.invalidClassName)
5180                    });
5181                     return fields.map(field => this.validateField(field))
5182                },
5183                 validateField(field) {
5184                     if (! field || ! elementWillValidate(field.element)) {
5185                        return new Promise(resolve => resolve(true))
5186                    }
5187
5188                    const uid = field.element.dataset.uid;
5189                    if (uid) {
5190                        const parent = document.querySelector("#field_" + uid);
5191                        if (parent) {
5192                            if (window.getComputedStyle(parent).display == 'none') {
5193                                field.state.valid = true;
5194                                return new Promise(resolve => resolve(true));
5195                            }
5196                        }
5197                    }
5198
5199                    let value;
5200                    if (field.element.type === 'checkbox') {
5201                        value = getCheckedValues(field);
5202                    } else if (field.element.type === 'radio') {
5203                        value = getCheckedValues(field)[0] || undefined;
5204                    } else if (field.element.tagName === 'SELECT' && field.element.multiple) {
5205                        value = Array.from(field.element.selectedOptions).map(opt => opt.value);
5206                    } else {
5207                        value = field.element.value;
5208                    }
5209
5210                    const rules = field.rules || {};
5211
5212                     field.state.valid = true;
5213                    this.showFieldState(field);
5214
5215                  const fieldValidations = Object.keys(rules).filter(rule => formValidationRules[rule]).map(async rule => {
5216                        return runValidateFn.call(this, rule, rules[rule], value, field).then(result => {
5217                            field.state.rules[rule] = result;
5218                            return result;
5219                        })
5220                    });
5221
5222                    return new Promise(resolve => {
5223                         Promise.all(fieldValidations).then(results => {
5224                              field.state.valid = !elementWillValidate(field.element) || rules.length === 0 || !results.some(isInvalidRuleResult)
5225                            this.showFieldState(field);
5226                            resolve(field.state.valid);
5227                        })
5228                    });
5229                },
5230                 getMessagesByField(field) {
5231                    const messages = [];
5232                    const invalidRules = Object.keys(field.state.rules).filter(rule => isInvalidRuleResult(field.state.rules[rule]));
5233
5234                    field.rules && Object.keys(field.rules).forEach((rule) => {
5235                        if (invalidRules.includes(rule)) {
5236                            const customMessage = field.element.getAttribute('data-msg-' + rule);
5237                            const message = customMessage ? customMessage : field.state.rules[rule];
5238                            const ruleOptions = JSON.parse(JSON.stringify(field.rules[rule]));
5239
5240                            if (typeof message === 'undefined' || message === null || (typeof message !== 'string' && ! message.type)) {
5241                                messages.push(strf('Validation rule "%0" failed.', rule));
5242                            } else if (Array.isArray(ruleOptions)) {
5243                                ruleOptions.unshift(message.type ? message.content : message);
5244                                const content = strf.apply(null, ruleOptions);
5245                                messages.push(message.type ? {type: message.type, content} : content);
5246                            } else {
5247                                const content = strf(message.type ? message.content : message, ruleOptions)
5248                                messages.push(message.type ? {type: message.type, content} : content);
5249                            }
5250                        }
5251                    });
5252                    return messages;
5253                },
5254                /** @deprecated */
5255                getFieldWrapper(field) {
5256                     return this.getMessageContainer(field)
5257                },
5258                getMessageContainer(field) {
5259                    let container;
5260                    const pageSelector = field.element.getAttribute('data-validation-container') || options.pageMessagesContainerSelector;
5261                    if (pageSelector) {
5262                        container = document.querySelector(pageSelector)
5263                            || containerNotFound(pageSelector, field.element)
5264                    } else {
5265                        const containerSelector = classNamesToSelector(options.fieldWrapperClassName);
5266                        container = field.element.closest(containerSelector)
5267                            || createMessageContainer(field.element, options.fieldWrapperClassName)
5268                            || containerNotFound(containerSelector, field.element);
5269                    }
5270
5271                    return container;
5272                },
5273                showFieldState(field) {
5274                    const container = this.getMessageContainer(field),
5275                        hasErrorMessages = hasMessagesWrapper.call(this, field, options.messagesWrapperClassName),
5276                        messages = this.getMessagesByField(field).map(m => {
5277                            return m.type !== 'html' ? escapeHtml(m.type ? m.content : m) : m.content;
5278                        });
5279                    container.classList.toggle(options.validClassName, field.state.valid && ! hasErrorMessages);
5280                    container.classList.toggle(options.invalidClassName, !field.state.valid || hasErrorMessages);
5281                    this.createHtmlErrorMessage(field, messages);
5282
5283                    if (field.state.valid) {
5284                        field.element.removeAttribute('aria-invalid');
5285                    } else {
5286                        field.element.setAttribute('aria-invalid', 'true');
5287                        if (! document.activeElement) {
5288                            field.element.focus();
5289                        }
5290                    }
5291                },
5292                removeMessages(field, messagesClass) {
5293                    if (! hasMessagesWrapper.call(this, field, messagesClass || options.messagesWrapperClassName)) {
5294                        return;
5295                    }
5296
5297                    const msgWrapper = getMessagesWrapper.call(this, field, messagesClass || options.messagesWrapperClassName);
5298                    const messages = msgWrapper.querySelectorAll(`[data-msg-field='${field.element.name}']`);
5299                    Array.from(messages).forEach(msg => msg.remove());
5300                    if (msgWrapper && msgWrapper.childElementCount === 0) {
5301                        field.element.removeAttribute('aria-errormessage');
5302                        field.element.removeAttribute('aria-describedby');
5303                        msgWrapper.remove();
5304                    }
5305                },
5306                createErrorMessage(field, messages) {
5307                    const htmlMessages = (Array.isArray(messages) ? messages : [messages]).map(escapeHtml)
5308                    this.createHtmlErrorMessage(field, htmlMessages);
5309                },
5310                createHtmlErrorMessage(field, messages) {
5311                    this.removeMessages(field, options.messagesWrapperClassName);
5312                    field.element.removeAttribute('aria-errormessage');
5313                    field.element.removeAttribute('aria-describedby');
5314
5315                    if (!field.state.valid) {
5316                        const msgWrapper = this.addHtmlMessages(field, options.messagesWrapperClassName, messages);
5317                        field.element.setAttribute('aria-errormessage', msgWrapper.id);
5318                        field.element.setAttribute('aria-describedby', msgWrapper.id);
5319                    }
5320                },
5321                /** @deprecated */
5322                createMessage(field, message) {
5323                     return this.addMessages(field, options.messagesWrapperClassName, message);
5324                },
5325                addMessages(field, messagesClass, messages) {
5326                    const htmlMessages = (Array.isArray(messages) ? messages : [messages]).map(escapeHtml)
5327                    return this.addHtmlMessages(field, messagesClass, htmlMessages);
5328                },
5329                addHtmlMessages(field, messagesClass, htmlMessages) {
5330                    const msgWrapper = getMessagesWrapper.call(this, field, messagesClass);
5331
5332                    (Array.isArray(htmlMessages) ? htmlMessages : [htmlMessages]).forEach((htmlMessage) => {
5333                        const li = document.createElement('li');
5334                        li.innerHTML = htmlMessage;
5335                        li.setAttribute('data-msg-field', field.element.name);
5336                        msgWrapper.appendChild(li);
5337                    });
5338
5339                    return msgWrapper;
5340                },
5341                setField(name, value) {
5342                    this.fields[name].element.value = value;
5343                    this.fields[name].element.dispatchEvent((new Event('input')));
5344                    this.validateField(this.fields[name]);
5345                }
5346            }
5347        }
5348
5349        webfroms.formValidation = formValidation;
5350        webfroms.formValidation.rules = formValidationRules;
5351        webfroms.formValidation.setInputAttributeRuleName = (attrName, ruleName) => INPUT_ATTRIBUTE_RULES[attrName] = ruleName || attrName;
5352        webfroms.formValidation.setInputTypeRuleName = (typeName, ruleName) => INPUT_TYPE_RULES[typeName] = ruleName || typeName;
5353        webfroms.formValidation.addRule = (name, validator) => formValidationRules[name] = validator;
5354
5355        
5356        webfroms.formValidation.addRule('dateFromTo', (value, options, field, context) => {
5357            const dateFrom = field.element;
5358            const dateTo = document.getElementById(options);
5359
5360            if (!field || !options || isNaN(dateFrom.valueAsNumber) || isNaN(dateTo.valueAsNumber)) {
5361                return true;
5362            }
5363
5364            const valid = dateFrom.valueAsNumber <= dateTo.valueAsNumber;
5365
5366            return !valid ? 'The\u0020\u0027From\u0027\u0020date\u0020must\u0020precede\u0020the\u0020\u0027To\u0027\u0020date.' : true;
5367        });
5368
5369        
5370        webfroms.formValidation.setInputAttributeRuleName('accept', 'file-type');  webfroms.formValidation.addRule('file-type', function (value, options, field, context) {
5371            if (field.element.type !== 'file' || !field.element.files.length || !field.element.accept) {
5372                return true;
5373            }
5374
5375            for (const file of Object.values(field.element.files)) {
5376                const allowedFileTypesArray = field.element.accept.split(',');
5377                const filenameSplit = file.name.split('.');
5378                const fileExtension = `.${filenameSplit[filenameSplit.length - 1]}`;
5379
5380                if (!allowedFileTypesArray.includes(fileExtension)) {
5381                    return `${str('\u0022\u00251\u0022\u0020is\u0020not\u0020a\u0020valid\u0020file\u0020extension.', fileExtension)} Allowed\u0020file\u0020types: ${field.element.accept}`;
5382                }
5383            }
5384
5385            return true;
5386        });
5387
5388        webfroms.formValidation.addRule('file-max-size', function (value, options, field, context) {
5389            if (!field.element.files.length || !options) {
5390                return true;
5391            }
5392
5393            for (const file of Object.values(field.element.files)) {
5394                const maxFileSize = options;
5395
5396                if (file.size > maxFileSize) {
5397                    const maxSizeMb = maxFileSize / (1024 * 1024);
5398                    return `Maximum\u0020file\u0020size: ${maxSizeMb} MB.`;
5399                }
5400            }
5401
5402            return true;
5403        });
5404
5405        webfroms.formValidation.addRule('image-max-dimensions', async function (value, options, field, context) {
5406            if (!field.element.files.length) {
5407                return true;
5408            }
5409
5410            const {width: maxWidth, height: maxHeight} = options;
5411
5412            if ((!maxWidth && !maxHeight) || (maxWidth === 0 && maxHeight === 0)) {
5413                return true;  }
5414
5415            try {
5416                const dimensions = await new Promise((resolve, reject) => {
5417                    const reader = new FileReader();
5418                    reader.onload = function (e) {
5419                        const img = new Image();
5420
5421                        img.onload = function () {
5422                            resolve({
5423                                width: this.width,
5424                                height: this.height
5425                            });
5426                        };
5427
5428                        img.onerror = function (e) {
5429                            reject(new Error('Failed to load the image.'));
5430                        };
5431
5432                        img.src = e.target.result;
5433                    };
5434
5435                    reader.onerror = function (e) {
5436                        reject(new Error('Failed to read the file.'));
5437                    };
5438
5439                    reader.readAsDataURL(field.element.files[0]);
5440                });
5441
5442                const errorMessages = [];
5443                if (maxWidth && dimensions.width > maxWidth) {
5444                    errorMessages.push(
5445                        str(
5446                            '\u0022\u00251\u0022\u0020width\u0020exceeds\u0020allowed\u0020value\u0020of\u0020\u00252\u0020px.',
5447                            `${dimensions.width} px`,
5448                            maxWidth
5449                        )
5450                    );
5451                }
5452                if (maxHeight && dimensions.height > maxHeight) {
5453                    errorMessages.push(
5454                        str(
5455                            '\u0022\u00251\u0022\u0020height\u0020exceeds\u0020allowed\u0020value\u0020of\u0020\u00252\u0020px.',
5456                            `${dimensions.height} px`,
5457                            maxHeight
5458                        )
5459                    );
5460                }
5461
5462                if (errorMessages.length > 0) {
5463                    return errorMessages.join(' ');
5464                }
5465
5466                return true;
5467            } catch (error) {
5468                console.error('Error:', error);
5469                return false;
5470            }
5471        });
5472
5473        
5474        webfroms.formValidation.addRule('alpha', function (value, options, field, context) {
5475             const rule = /^[a-zA-Z]+$/;
5476            if (value.length > 0 && !rule.test(value)) {
5477                return 'Please\u0020use\u0020letters\u0020only\u0020\u0028a\u002Dz\u0020or\u0020A\u002DZ\u0029\u0020in\u0020this\u0020field.';
5478            }
5479
5480            return true;
5481        });
5482
5483        webfroms.formValidation.addRule('alphanum', function (value, options, field, context) {
5484             const rule = /^[a-zA-Z0-9]+$/;
5485            if (value.length > 0 && !rule.test(value)) {
5486                return 'Please\u0020use\u0020only\u0020letters\u0020\u0028a\u002Dz\u0020or\u0020A\u002DZ\u0029\u0020
5486or\u0020numbers\u0020\u00280\u002D9\u0029\u0020in\u0020this\u0020field.\u0020No\u0020spaces\u0020or\u0020other\u0020characters\u0020are\u0020allowed.';
5487            }
5488
5489            return true;
5490        });
5491
5492        webfroms.formValidation.addRule('alphanum-with-spaces', function (value, options, field, context) {
5493             const rule = /^[a-zA-Z0-9 ]+$/;
5494            if (value.length > 0 && !rule.test(value)) {
5495                return 'Please\u0020use\u0020only\u0020letters\u0020\u0028a\u002Dz\u0020or\u0020A\u002DZ\u0029,\u0020numbers\u0020\u00280\u002D9\u0029\u0020or\u0020spaces\u0020only\u0020in\u0020this\u0020field.';
5496            }
5497
5498            return true;
5499        });
5500
5501        webfroms.formValidation.setInputTypeRuleName('url');  webfroms.formValidation.addRule('url', function (value, options, field, context) {
5502             const rule = /^(http|https|ftp):\/\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\d+))?(\/[A-Z0-9~](([A-Z0-9_~-]|\.)*[A-Z0-9~]|))*\/?(.*)?$/i;
5503            if (value.length > 0 && !rule.test(value)) {
5504                return 'Please\u0020enter\u0020a\u0020valid\u0020URL.';
5505            }
5506
5507            return true;
5508        });
5509
5510        
5511        webfroms.formValidation.addRule('minMax', (value, options, field, context) => {
5512            const min = field.element;
5513            const max = document.getElementById(options);
5514
5515            if (!min || !max || min.value === '' || max.value === '') {
5516                return true;
5517            }
5518
5519            const valid = !(Number(min.value) > Number(max.value));
5520
5521            return !valid ? 'The\u0020\u0027Min\u0027\u0020value\u0020must\u0020be\u0020lower\u0020than\u0020the\u0020\u0027Max\u0027\u0020value.' : true;
5522        });
5523    }((() => {
5524        if (!window.MageMe) window.MageMe = {};
5525        if (!window.MageMe.WebForms) window.MageMe.WebForms = {}
5526        return window.MageMe.WebForms
5527    })()));</script>
vendor: 1 bytes, line 5527
5527
5528<script id="mm_validation">
5529    'use strict';
5530    (() => {
5531        const messages = {
5532            "validate-match-value": "Please make sure your input matches the <i>%1</i>.",
5533            "required-dropzone-file": "Please select a file.",
5534            "validate-options-checkbox-min": "Please check at least %1 options",
5535            "validate-options-checkbox-max": "Please check not more than %1",
5536            "validate-length-min": "The minimum length for this field is %1 characters.",
5537            "validate-length-max": "The maximum length for this field is %1 characters.",
5538            "required-entry": "This is a required field.",
5539            "pattern": "Invalid format.",
5540            "validate-email": "Please enter a valid email address.",
5541            "validate-number": "Please enter a valid number in this field.",
5542            "validate-number-range": "The value is not within the specified range.",
5543            "validate-customer-password": "Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.",
5544            "validate-customer-password-cl": "Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.",
5545            "validate-select": "Please select an option.",
5546            "validate-one-required-by-name": "Please select one of the options.",
5547            "time": "Please enter a valid time, between 00:00 and 23:59",
5548            "validate-url": "Please enter a valid URL. Protocol is required (http://, https:// or ftp://).",
5549        };
5550
5551        
5552        MageMe.WebForms.formValidation.addRule(
5553            'validate-match-value', function (value, options, field, context) {
5554                const matchInputId = field.element.getAttribute('data-match-id');
5555                let validateMessage = "Incorrect match validation data, please check validation rules.";
5556                if (!matchInputId) {
5557                    return validateMessage;
5558                }
5559                const matchInput = document.getElementById(matchInputId);
5560                if (!matchInput) {
5561                    return validateMessage;
5562                }
5563                const label = document.querySelector("label[for='" + matchInputId + "']");
5564                const fieldLabel = label.value ? label.value : matchInput.getAttribute('placeholder');
5565                validateMessage = messages["validate-match-value"].replace('%1', fieldLabel);
5566                return matchInput.value === value ? true : validateMessage;
5567            }
5568        );
5569        MageMe.WebForms.formValidation.addRule(
5570            'validate-dropzone', function (value, options, field, context) {
5571                const uid = field.element.dataset.uid;
5572                if (!uid) {
5573                    return messages["validate-dropzone"];
5574                }
5575                return !document.getElementById('field' + uid + '_preview').querySelectorAll('.drop-zone-error').length ?
5576                    true : messages["validate-dropzone"];
5577            }
5578        );
5579        MageMe.WebForms.formValidation.addRule(
5580            'validate-dropzone-required', function (value, options, field, context) {
5581                let result = false;
5582                const uid = field.element.dataset.uid;
5583                if (!uid) {
5584                    return messages["validate-dropzone-required"];
5585                }
5586                if (document.getElementById('field' + uid + '_preview').querySelectorAll('.drop-zone-preview-file').length) {
5587                    result = true;
5588                }
5589                if (!result) {
5590                    if (getDropzoneUploadedCount(uid)) {
5591                        result = true;
5592                    }
5593                }
5594                return result ? true : messages["validate-dropzone-required"];
5595            }
5596        );
5597        MageMe.WebForms.formValidation.addRule(
5598            'validate-dropzone-max-files', function (value, options, field, context) {
5599                const uid = field.element.dataset.uid,
5600                    max = field.element.getAttribute('data-max-files');
5601                if (!uid) {
5602                    return messages["validate-dropzone-max-files"];
5603                }
5604                if (!max) {
5605                    return true;
5606                }
5607                const newFiles = document.getElementById('field' + uid + '_preview').querySelectorAll('.drop-zone-preview-file').length;
5608                const uploaded = getDropzoneUploadedCount(uid);
5609                return (newFiles + uploaded <= max) ? true : messages["validate-dropzone-max-files"];
5610            }
5611        );
5612        MageMe.WebForms.formValidation.addRule(
5613            'required-dropzone-file', function (value, options, field, context) {
5614                let result = isEmptyNoTrim(value),
5615                    ovId,
5616                    uid = field.element.dataset.uid;
5617
5618                if (!result) {
5619                    ovId = document.getElementById(field.element.getAttribute('id') + '_value');
5620
5621                    if (ovId) {
5622                        result = isEmptyNoTrim(ovId.value);
5623                    }
5624                }
5625
5626                if (!result && uid) {
5627                    if (getDropzoneUploadedCount(uid)) {
5628                        result = true;
5629                    }
5630                }
5631
5632                return result ? true : messages["required-dropzone-file"];
5633            }
5634        );
5635        MageMe.WebForms.formValidation.addRule(
5636            'validate-options-checkbox-min',
5637            function (value, options, field, context) {
5638                const uid = field.element.dataset.uid,
5639                    count = parseInt(options);
5640                if (isNaN(count)) {
5641                    return "Incorrect min value, please check validation rules.";
5642                }
5643                const counter = document.getElementById('field_'+uid).querySelectorAll('input:checked').length;
5644                return (counter === 0 || counter >= count) ? true : messages["validate-options-checkbox-min"].replace('%1', count);
5645            }
5646        );
5647        MageMe.WebForms.formValidation.addRule(
5648            'validate-options-checkbox-max',
5649            function (value, options, field, context) {
5650                const uid = field.element.dataset.uid,
5651                    count = parseInt(options);
5652                if (isNaN(count)) {
5653                    return "Incorrect max value, please check validation rules.";
5654                }
5655                const counter = document.getElementById('field_'+uid).querySelectorAll('input:checked').length;
5656                return (counter === 0 || counter <= count) ? true : messages["validate-options-checkbox-max"].replace('%1', count);
5657            }
5658        );
5659        MageMe.WebForms.formValidation.addRule(
5660            'validate-length-min',
5661            function (value, options, field, context) {
5662                const length = parseInt(options);
5663                if (isNaN(length)) {
5664                    return "Incorrect min value, please check validation rules.";
5665                }
5666                if (length <= 0 || !value) {
5667                    return true;
5668                }
5669                return value.length >= length ? true : messages["validate-length-min"].replace('%1', length);
5670            }
5671        );
5672        MageMe.WebForms.formValidation.addRule(
5673            'validate-length-max',
5674            function (value, options, field, context) {
5675                const length = parseInt(options);
5676                if (isNaN(length)) {
5677                    return "Incorrect max value, please check validation rules.";
5678                }
5679                if (!value) {
5680                    return true;
5681                }
5682                return value.length <= length ? true : messages["validate-length-max"].replace('%1', length);
5683            }
5684        );
5685        MageMe.WebForms.formValidation.addRule(
5686            'validate-intl-phone-number',
5687            function (value, options, field, context) {
5688                if (!window.intlTelInput) {
5689                    return true;
5690                }
5691                if (!value) {
5692                    return true;
5693                }
5694                const phone = window.intlTelInputGlobals.getInstance(field.element);
5695                return phone.isValidNumber() ? true : "Incorrect number.";
5696            }
5697        );
5698        MageMe.WebForms.formValidation.addRule(
5699            'validate-input-mask-complete',
5700            function (value, options, field, context) {
5701                if (!window.Inputmask) {
5702                    return true;
5703                }
5704                if (!value) {
5705                    return true;
5706                }
5707                return field.element.inputmask.isComplete() ? true : "Incorrect value.";
5708            }
5709        );
5710        MageMe.WebForms.formValidation.addRule(
5711            'mm-pattern',
5712            function (value, options, field, context) {
5713                const pattern = options;
5714                const flags = field.element.getAttribute('data-mm-pattern-flags') ?? '';
5715                if (!value) {
5716                    return true;
5717                }
5718                return new RegExp(pattern, flags).test(value) ? true : "Invalid format.";
5719            }
5720        );
5721        
5722
5723        
5724        MageMe.WebForms.formValidation.addRule(
5725            'required-entry', function (value, options, field, context) {
5726                return !isEmpty(value) ? true : messages["required-entry"];
5727            }
5728        );
5729        MageMe.WebForms.formValidation.addRule(
5730            'pattern', function (value, options, field, context) {
5731                if (isEmptyNoTrim(value)) {
5732                    return true;
5733                }
5734                return new RegExp(options).test(value) ? true : messages["pattern"];
5735            }
5736        );
5737        MageMe.WebForms.formValidation.addRule(
5738            'validate-email', function (value, options, field, context) {
5739                if (isEmptyNoTrim(value)) {
5740                    return true;
5741                }
5742                return /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i.test(value) ?
5743                    true : messages["validate-email"];
5744
5745            }
5746        );
5747        MageMe.WebForms.formValidation.addRule(
5748            'validate-number', function (value, options, field, context) {
5749                if (isEmptyNoTrim(value)) {
5750                    return true;
5751                }
5752                return (!isNaN(parseNumber(value)) && /^\s*-?\d*(\.\d*)?\s*$/.test(value)) ? true : messages["validate-number"];
5753
5754            }
5755        );
5756        MageMe.WebForms.formValidation.addRule(
5757            'validate-number-range', function (value, options, field, context) {
5758                let numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;
5759
5760                if (isEmptyNoTrim(value)) {
5761                    return true;
5762                }
5763
5764                numValue = parseNumber(value);
5765
5766                if (isNaN(numValue)) {
5767                    return messages["validate-number-range"];
5768                }
5769
5770                dataAttrRange = /^(-?[\d.,]+)?-(-?[\d.,]+)?$/;
5771                classNameRange = /^number-range-(-?[\d.,]+)?-(-?[\d.,]+)?$/;
5772                result = true;
5773                range = options;
5774
5775                if (typeof range === 'string') {
5776                    m = dataAttrRange.exec(range);
5777
5778                    if (m) {
5779                        result = result && isBetween(numValue, m[1], m[2]);
5780                    } else {
5781                        result = false;
5782                    }
5783                } else if (field.element && field.element.className) {
5784                    classes = field.element.className.split(' ');
5785                    ii = classes.length;
5786
5787                    while (ii--) {
5788                        range = classes[ii];
5789                        m = classNameRange.exec(range);
5790
5791                        if (m) { 
5792                            result = result && isBetween(numValue, m[1], m[2]);
5793                            break;
5794                        }
5795                    }
5796                }
5797
5798                return result ? true : messages["validate-number-range"];
5799            }
5800        );
5801        MageMe.WebForms.formValidation.addRule(
5802            'validate-customer-password', function (value, options, field, context) {
5803                let counter = 0;
5804                const passwordMinLength = field.element.getAttribute('data-password-min-length'),
5805                    passwordMinCharacterSets = field.element.getAttribute('data-password-min-character-sets'),
5806                    pass = value.trim();
5807
5808                if (pass.length < passwordMinLength) {
5809                    return messages["validate-customer-password"].replace('%1', passwordMinLength);
5810                }
5811
5812                if (pass.match(/\d+/)) {
5813                    counter++;
5814                }
5815
5816                if (pass.match(/[a-z]+/)) {
5817                    counter++;
5818                }
5819
5820                if (pass.match(/[A-Z]+/)) {
5821                    counter++;
5822                }
5823
5824                if (pass.match(/[^a-zA-Z0-9]+/)) {
5825                    counter++;
5826                }
5827
5828                if (counter < passwordMinCharacterSets) {
5829                    return messages["validate-customer-password-cl"].replace('%1', passwordMinCharacterSets); 
5830                }
5831
5832                return true;
5833            }
5834        );
5835        MageMe.WebForms.formValidation.addRule(
5836            'validate-select', function (value, options, field, context) {
5837                return (value !== 'none' && value != null && value.length !== 0) ? true : messages["validate-select"];
5838            }
5839        );
5840        MageMe.WebForms.formValidation.addRule(
5841            'validate-one-required-by-name', function (value, options, field, context) {
5842                const name = field.element.name.replace(/([\\"])/g, '\\$1');
5843                options = options === true ? 'input[name="' + name + '"]:checked' : options;
5844                return field.element.form.querySelectorAll(options).length ? true : messages["validate-one-required-by-name"];
5845            }
5846        );
5847        MageMe.WebForms.formValidation.addRule(
5848            'time', function (value, options, field, context) {
5849                if (isEmptyNoTrim(value)) {
5850                    return true;
5851                }
5852                return /^([01]\d|2[0-3])(:[0-5]\d){0,2}$/.test(value) ? true : messages["time"];
5853            }
5854        );
5855        MageMe.WebForms.formValidation.addRule(
5856            'validate-url', function (value, options, field, context) {
5857                if (isEmptyNoTrim(value)) {
5858                    return true;
5859                }
5860                value = (value || '').replace(/^\s+/, '').replace(/\s+$/, '');
5861
5862                return (/^(http|https|ftp):\/\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\d+))?(\/[A-Z0-9~](([A-Z0-9_~-]|\.)*[A-Z0-9~]|))*\/?(.*)?$/i).test(value) ?
5863                    true : messages["validate-url"];
5864            }
5865        );
5866
5867        /**
5868         * Uploaded count
5869         *
5870         * @param uid - From uid
5871         * @returns {number}
5872         */
5873        function getDropzoneUploadedCount(uid) {
5874            const selectAll = document.getElementById(uid + 'selectall');
5875            if (selectAll && selectAll.checked) {
5876                return 0;
5877            }
5878            const filePool = document.getElementById(uid + 'filepool');
5879            return filePool ? filePool.querySelectorAll("input[name^='delete_file_']:not(:checked)").length : 0;
5880        }
5881
5882        /**
5883         * Check if string is empty with trim.
5884         *
5885         * @param {String} value
5886         * @return {Boolean}
5887         */
5888        function isEmpty(value) {
5889            return value === '' || value == null || value.length === 0 || /^\s+$/.test(value);
5890        }
5891
5892        /**
5893         * Check if string is empty no trim.
5894         *
5895         * @param {String} value
5896         * @return {Boolean}
5897         */
5898        function isEmptyNoTrim(value) {
5899            return value === '' || value == null || value.length === 0;
5900        }
5901
5902        /**
5903         * Checks if {value} is between numbers {from} and {to}.
5904         *
5905         * @param {String} value
5906         * @param {String} from
5907         * @param {String} to
5908         * @return {Boolean}
5909         */
5910        function isBetween(value, from, to) {
5911            return (from === null || from === '' || value >= parseNumber(from)) &&
5912                (to === null || to === '' || value <= parseNumber(to));
5913        }
5914
5915        /**
5916         * Parse price string.
5917         *
5918         * @param {String} value
5919         * @return {Number}
5920         */
5921        function parseNumber(value) {
5922            let isDot, isComa;
5923
5924            if (typeof value !== 'string') {
5925                return parseFloat(value);
5926            }
5927            isDot = value.indexOf('.');
5928            isComa = value.indexOf(',');
5929
5930            if (isDot !== -1 && isComa !== -1) {
5931                if (isComa > isDot) {
5932                    value = value.replace('.', '').replace(',', '.');
5933                } else {
5934                    value = value.replace(',', '');
5935                }
5936            } else if (isComa !== -1) {
5937                value = value.replace(',', '.');
5938            }
5939
5940            return parseFloat(value);
5941        }
5942
5943        /**
5944         * Removes HTML tags and space characters, numbers and punctuation.
5945         *
5946         * @param {String} value -  Value being stripped.
5947         * @return {String}
5948         */
5949        function stripHtml(value) {
5950            return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')
5951                .replace(/[0-9.(),;:!?%#$'"_+=\/-]*/g, '');
5952        }
5953
5954        MageMe.WebForms.formValidation.utils = {
5955            getDropzoneUploadedCount: getDropzoneUploadedCount,
5956            isEmpty: isEmpty,
5957            isEmptyNoTrim: isEmptyNoTrim,
5958            isBetween: isBetween,
5959            parseNumber: parseNumber,
5960            stripHtml: stripHtml
5961        };
5962    })();</script>
vendor: 1 bytes, line 5962
5962
5963<script>
5964    'use strict';
5965
5966    (() => {
5967        if (typeof window.MageMe !== 'object') {
5968            window.MageMe = {};
5969        }
5970        if (typeof window.MageMe.WebForms !== 'object') {
5971            window.MageMe.WebForms = {};
5972        }
5973        window.MageMe.WebForms.loadValidation = () => {
5974            if (!document.getElementById("mm_validation")) {
5975                return fetch("https://www.banham.co.uk/webforms/form/validation/").then(
5976                    response => response.text()
5977                ).then(html => {
5978                    if (!document.getElementById("mm_validation"))
5979                        document.head.append(document.createRange().createContextualFragment(html));
5980                });
5981            } else {
5982                return Promise.resolve();
5983            }
5984        };
5985        window.MageMe.WebForms.customerData = () => {
5986            return {
5987                customer: false,
5988                receiveCustomerData(data) {
5989                    if (data.webforms) {
5990                        this.customer = data.webforms;
5991                    }
5992                },
5993            }
5994        };
5995    })();</script>
vendor: 1 bytes, line 5995
5995
5996<script>
5997    window.loqateFindUrl = "https:\/\/www.banham.co.uk\/loqate\/capture\/find\/";
5998    window.loqateRetrieveUrl = "https:\/\/www.banham.co.uk\/loqate\/capture\/retrieve\/";
5999</script>
vendor: 1 bytes, line 5999
5999
6000<script type="module">
6001    
6002    import { bbPCAForm } from 'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Hyva_MageMeWebForms/js/alpine-components/bb-pca-form.js';
6003
6004    if (!window.bbPCAFormRegistered) {
6005        console.log('Loading bbPCAForm component');
6006        window.bbPCAFormRegistered = true;
6007        if (window.Alpine) {
6008            window.Alpine.data('bbPCAForm', bbPCAForm);
6009        } else {
6010            document.addEventListener('alpine:init', () => {
6011                window.Alpine.data('bbPCAForm', bbPCAForm);
6012            });
6013        }
6014    }
6015</script>
vendor: 1 bytes, line 6015
6015
6016<script>
6017    'use strict';
6018    (() => {
6019        document.querySelectorAll('input[name="field[1778][]"]').forEach((el) => {
6020            el.initValidation = function (form) {
6021                el.parentElement.parentElement.parentElement.addEventListener('focusout', (e) => {
6022                    if (
6023                        e.relatedTarget !== e.currentTarget &&
6024                        !e.currentTarget.contains(e.relatedTarget)
6025                    ) {
6026                        form.validateField(el);
6027                    }
6028                });
6029                el.parentElement.parentElement.parentElement.tabIndex = -1;
6030            }
6031        });
6032    })();
6033</script>
vendor: 1 bytes, line 6033
6033
6034<script>
6035    function mmWebformsTextareaDatafieldyk8I5y8() {
6036        return Object.assign(
6037            MageMe.WebForms.customerData(),
6038            {
6039                setCustomerData(event) {
6040                    this.receiveCustomerData(event.detail.data)
6041                    if (this.$el) {
6042                        this.$el.value = this.customer[this.$el.dataset.hyvacspCustomerData] ?? '';
6043                    }
6044                },
6045            }
6046        );
6047    }
6048    window.addEventListener('alpine:init', () => Alpine.data('mmWebformsTextareaDatafieldyk8I5y8', mmWebformsTextareaDatafieldyk8I5y8), {once: true});</script>
vendor: 1 bytes, line 6048
6048
6049<script>
6050    function mmWebformsEmailDatafieldyk8I5y2() {
6051        return Object.assign(
6052            MageMe.WebForms.customerData(),
6053            {
6054                trimSpace() {
6055                    if (this.$el.value.search(' ') >= 0) {
6056                        this.$el.value = this.$el.value.replace(' ','');
6057                    }
6058                },
6059                setCustomerData(event) {
6060                    this.receiveCustomerData(event.detail.data)
6061                    if (this.$el) {
6062                        this.$el.value = this.customer['customer_email'] ?? '';
6063                    }
6064                },
6065            }
6066        );
6067    }
6068    window.addEventListener('alpine:init', () => Alpine.data('mmWebformsEmailDatafieldyk8I5y2', mmWebformsEmailDatafieldyk8I5y2), {once: true});</script>
vendor: 1 bytes, line 6068
6068
6069<script>
6070    'use strict';
6071
6072    (() => {
6073        if (!window.MageMe || !MageMe.loader) {
6074            return;
6075        }
6076        MageMe.loader.addCssOrdered(
6077            'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Hyva_MageMeWebForms/css/field/datepicker.min.css',
6078            '40'
6079        );
6080        MageMe.loader.addScript("Datepicker",
6081            "https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FHyva_MageMeWebForms\u002Fjs\u002Fdatepicker.min.js",
6082            () => {
6083                const isPastDisabled = true;
6084                const isFutureDisabled = false;
6085                const isTodayDisabled = false;
6086                const isWeekNumbersShowed = false;
6087                const pastOffset = 0;
6088                const futureOffset = 0;
6089                const disabledWeekDays = [6,0];
6090                const format = convertFormat('d/M/Y', 'date');
6091                const today = new Date();
6092                const elm = document.getElementById('fieldyk8I5y1032');
6093
6094                let config = {
6095                    autohide: true,
6096                    datesDisabled: [],
6097                    showWeekNumbers: isWeekNumbersShowed,
6098                    daysOfWeekDisabled: [],
6099                    weekStart: 1,
6100                    format: format
6101                };
6102                if (config.rtl) {
6103                    $('#fieldyk8I5y1032_calendar').addClass('rtl');
6104                }
6105                if (isPastDisabled) {
6106                    config.minDate = new Date();
6107                    if (pastOffset) {
6108                        config.minDate.setDate(config.minDate.getDate() + pastOffset)
6109                    }
6110                }
6111                if (isFutureDisabled) {
6112                    config.maxDate = new Date();
6113                    if (futureOffset) {
6114                        config.maxDate.setDate(config.maxDate.getDate() + futureOffset)
6115                    }
6116                }
6117                if (isTodayDisabled) {
6118                    config.datesDisabled.push(today);
6119                }
6120                for (let i = 0; i < disabledWeekDays.length; i++) {
6121                    config.daysOfWeekDisabled.push(disabledWeekDays[i]);
6122                }
6123                Datepicker.locales.en = {
6124                    days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
6125                    daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
6126                    daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
6127                    months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
6127November", "December"],
6128                    monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
6129                    today: "Today",
6130                    clear: "Clear",
6131                    titleFormat: "MM y",
6132                    format: "d/M/Y",
6133                    weekStart: 0
6134                };
6135
6136                new Datepicker(elm, config);
6137            });
6138    })();
6139</script>
vendor: 1 bytes, line 6139
6139
6140<script>
6141    'use strict';
6142    (() => {
6143        const input = document.getElementById('fieldyk8I5y380');
6144        if (input) {
6145            input.initValidation = function (form) {
6146                input.parentElement.addEventListener('focusout', (e) => {
6147                    if (
6148                        e.relatedTarget !== e.currentTarget &&
6149                        !e.currentTarget.contains(e.relatedTarget)
6150                    ) {
6151                        form.validateField(input);
6152                    }
6153                });
6154                input.parentElement.tabIndex = -1;
6155            }
6156        }
6157    })();</script>
vendor: 1 bytes, line 6157
6157
6158<script>
6159function stepProgress() {
6160    return {
6161        totalSteps: 1,
6162        currentStep: 1,
6163        items: [],
6164
6165        init() {
6166            const list = this.$refs.stepList;
6167            if (!list) return;
6168
6169            // Initialize items (exclude logically hidden)
6170            const computeItems = () => Array.from(list.querySelectorAll('li'))
6171                .filter(li => !li.classList.contains('mm-logic-hidden'));
6172
6173            const detectCurrentIndex = (arr) => {
6174                // Try common active markers that your wizard might use
6175                let idx = arr.findIndex(li =>
6176                    li.classList.contains('is-active') ||
6177                    li.classList.contains('active') ||
6178                    li.getAttribute('aria-current') === 'step'
6179                );
6180                // Fallback: if none marked, assume first visible step
6181                if (idx < 0) idx = 0;
6182                return idx + 1; // 1-based
6183            };
6184
6185            // Set initial state
6186            this.items = computeItems();
6187            this.totalSteps = this.items.length || 1;
6188            this.currentStep = detectCurrentIndex(this.items);
6189
6190            // Watch for step visibility or active class changes
6191            const updateState = () => {
6192                this.items = computeItems();
6193                this.totalSteps = this.items.length || 1;
6194                this.currentStep = Math.min(this.currentStep, this.totalSteps) || 1;
6195
6196                // If the wizard toggled which item is active, respect it
6197                const activeIdx = this.items.findIndex(li =>
6198                    li.classList.contains('is-active') ||
6199                    li.classList.contains('active') ||
6200                    li.getAttribute('aria-current') === 'step'
6201                );
6202                if (activeIdx >= 0) this.currentStep = activeIdx + 1;
6203            };
6204
6205            const mo = new MutationObserver(updateState);
6206            mo.observe(list, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'aria-current'] });
6207
6208            // Also sync on anchor clicks (in case wizard uses hash navigation)
6209            Array.from(list.querySelectorAll('li > a')).forEach((a, i) => {
6210                a.addEventListener('click', () => {
6211                    // Update current step optimistically;
6211 observer will correct if needed
6212                    const visibleIndex = computeItems().indexOf(a.closest('li'));
6213                    if (visibleIndex >= 0) this.currentStep = visibleIndex + 1;
6214                });
6215            });
6216        },
6217
6218        percent() {
6219            return (this.currentStep / this.totalSteps) * 100;
6220        }
6221    }
6222}
6223// data layer for survey
6224window.surveyTypeValue = '';
6225window.selectedCategories = [];
6226
6227function updateSurveyType() {
6228    let currentStepNumber = document.querySelector('span[x-text="currentStep"]')?.textContent || '';
6229    if (currentStepNumber === '1') {
6230        window.selectedCategories = Array.from(
6231            document.querySelectorAll('.mm-swatches input[type=checkbox]:checked')
6232        ).map(el => el.value);
6233        window.surveyTypeValue = window.selectedCategories.length > 0 ? window.selectedCategories.join(', ') : '';
6234    }
6235}
6236
6237document.querySelectorAll('.mm-swatches input[type=checkbox]').forEach(cb => {
6238    cb.addEventListener('change', updateSurveyType);
6239});
6240
6241updateSurveyType();
6242
6243document.addEventListener('change', function(e) {
6244    if (e.target && e.target.matches('.webforms-fields-enquiry-type select.hyva-select')) {
6245        e.target.dataset.userChanged = 'true';
6246    }
6247});
6248
6249function handleNextStep() {
6250    let currentStepNumber = parseInt(document.querySelector('span[x-text="currentStep"]')?.textContent || '', 10) + 1;
6251    console.log('Handling next step, current step:', currentStepNumber);
6252    window.dataLayer = window.dataLayer || [];
6253    const enquiryTopic = document.getElementById('enquiry-topic');
6254    var selectEl = document.querySelector('.webforms-fields-enquiry-type select.hyva-select');
6255    var survey_client_type = selectEl ? selectEl.value : '';
6256    var enquiryTopicVal = (enquiryTopic && enquiryTopic.value) ? (window.surveyTypeVal || enquiryTopic.value) : (window.surveyTypeVal || '');
6257    var onProductPage = !!window.product_name;
6258    var _cats = window.selectedCategories.length > 0
6259        ? [...window.selectedCategories]
6260        : (!onProductPage && enquiryTopicVal ? [enquiryTopicVal] : []);
6261    if (!onProductPage && enquiryTopicVal && !_cats.includes(enquiryTopicVal)) {
6262        _cats.unshift(enquiryTopicVal);
6263    }
6264    if (selectEl && selectEl.value && selectEl.dataset.userChanged === 'true' && !_cats.includes(selectEl.value)) {
6265        _cats.push(selectEl.value);
6266    }
6267    if (_cats.length === 0 && selectEl && selectEl.value) {
6268        _cats.push(selectEl.value);
6269    }
6270    const categoriesToUse = _cats;
6271    if (categoriesToUse.length > 0) {
6272        window.dataLayer.pushedSteps = window.dataLayer.pushedSteps || [];
6273        
6274        categoriesToUse.forEach(category => {
6275            const eventKey = `step_${currentStepNumber}_${category}`;
6276            
6277            if (!window.dataLayer.pushedSteps.includes(eventKey)) {
6278                const dataLayerEvent ={
6279                    event: 'survey_screen',
6280                    site_type: window.site_type,
6281                                        logged_in_status: false,
6282                    journey_type: 'product',
6283                    screen_number: currentStepNumber,
6284                    page_name: document.querySelector('.step-tab-panel.form-step.active .hyva-fieldset-label span')?.textContent || '',
6285                    survey_opening: window.surveyOpening,
6286                    survey_type: category,
6287                                                        };
6288                if (survey_client_type){
6289                    dataLayerEvent.survey_client_type = survey_client_type;
6290                }
6291                window.dataLayer.push(dataLayerEvent);
6292                window.dataLayer.pushedSteps.push(eventKey);
6293            }
6294        });
6295    }
6296
6297    if (currentStepNumber === 2 && categoriesToUse.length > 0) {
6298        categoriesToUse.forEach(category => {
6299            const eventKey = `step_${currentStepNumber}_${category}_category_selected`;
6300            
6301            if (!window.dataLayer.pushedSteps.includes(eventKey)) {
6302                window.dataLayer.push({
6303                    event: 'survey_category_selected',
6304                    site_type: window.site_type,
6305                                        logged_in_status: false,
6306                    journey_type: 'product',
6307                    screen_number: currentStepNumber,
6308                    survey_opening: window.surveyOpening,
6309                    survey_type: category,
6310                                                        
6311                });
6312                window.dataLayer.pushedSteps.push(eventKey);
6313            }
6314        });
6315    }
6316}
6317
6318window.user_id = '';
6319window.logged_in_status = false;
6320window.hasProduct = false;
6321window.product_id = '';
6322window.product_name = '';
6323window.surveyType = '';
6324window.surveyOpening = window.surveyOpening || 'Opened from CTA';
6325</script>
vendor: 1 bytes, line 6325
6325
6326<script>
6327    'use strict';
6328
6329    window.addEventListener('private-content-loaded', () => {
6330        MageMe.loader.addScript('swal', "https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FMageMe_Core\u002Fjs\u002Fsweetalert2.min.js", () => {
6331            MageMe.loader.addScript('tingle', "https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FMageMe_Core\u002Fjs\u002Ftingle.min.js", () => {
6332                const options = {
6333                    "submitUrl": "https://www.banham.co.uk/webforms/form/submit/ajax/1/",
6334                     "uid": "yk8I5y",
6335                    "formId": "2",
6336                    "ajax": true,
6337                    "success": false,
6338                    "displayAfterSubmission": false,
6339                    "scrollAfterSubmission": true,
6340                    "showReview": false,
6341                    "saveDataLocal": false,
6342                    "useCaptcha": true,
6343                    "captchaResponseName": "g-recaptcha-response",
6344                    "messages": {
6345                        "success": "Success!",
6346                        "redirecting": "Redirecting",
6347                        "complete": "Complete",
6348                        "error": "Error",
6349                        "captchaTxt": "Please click on the Captcha",
6350                        "errorTxt": "Error(s) occurred. Please try again.",
6351                        "unknownTxt": "Unknown error(s) occurred"
6352                    }
6353                }
6354
6355                options.afterInit = (form) => {
6356                    document.body.addEventListener('touchstart', MageMe.WebForms.loadValidation, {once: true});
6357                    document.body.addEventListener('mouseover', MageMe.WebForms.loadValidation, {once: true});
6358                }
6359
6360                options.validationCb = (form, valid) => new Promise(async (resolve, reject) => {
6361                    if (!valid) {
6362                        resolve(false);
6363                    }
6364                    MageMe.WebForms.loadValidation().then(() => {
6365                        return MageMe.WebForms.formValidation(form.controls.form, {
6366                            fieldWrapperClassName: 'control',
6367                            messagesWrapperClassName: 'hyva-validation'
6368                        });
6369                    }).then(validator => {
6370                        return validator.validate();
6371                    }).then(() => {
6372                        resolve(true);
6373                    }).catch((er) => {
6374                        resolve(false);
6375                    });
6376                });
6377                options.fieldValidationCb = (field, form, valid) => new Promise(async (resolve, reject) => {
6378                    if (!valid) {
6379                        resolve(false);
6380                    }
6381                    MageMe.WebForms.loadValidation().then(() => {
6382                        return MageMe.WebForms.formValidation(form.controls.form, {
6383                            fieldWrapperClassName: 'control',
6384                            messagesWrapperClassName: 'hyva-validation'
6385                        });
6386                    }).then(validator => {
6387                        validator.setupField(field);
6388                        const fieldObj = validator.fields[field.name];
6389                        return validator.validateField(fieldObj);
6390                    }).then((isValid) => {
6391                        resolve(isValid);
6392                    }).catch((er) => {
6393                        resolve(false);
6394                    });
6395                });
6396
6397                options.getFormKey = () => {
6398                    return hyva.getCookie('form_key');
6399                };
6400                options.swal = swal;
6401                options.tingle = tingle;
6402
6403                MageMe.loader.addScript('mmForm', "https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FHyva_MageMeWebForms\u002Fjs\u002Fform.min.js", () => {
6404                    new mmForm(options);
6405                });
6406            });
6407        });
6408    });</script>
vendor: 1 bytes, line 6408
6408
6409<script type="text/javascript">
6410        let logicRules_yk8I5y = [];
6411        const targets_yk8I5y = [{"id":"field_yk8I5y23","logic_visibility":"hidden","required":true}];
6412        const fieldMap_yk8I5y = {"fieldset_56":["626","1778"],"fieldset_59":["8"],"fieldset_62":["5","23","11","14","2","17"],"fieldset_65":["1781","20","629","632","26","29","32"],"fieldset_68":["1032","38"],"fieldset_0":["submit"]};
6413         logicRules_yk8I5y.push({
6414                    'field_id': '5',
6415                    'action': 'show',
6416                    'logic_condition': 'equal',
6417                    'aggregation': 'any',
6418                    'value': ["Business"],
6419                    'target': ["field_yk8I5y23"]                });
6420                 window.addEventListener("mm_webform_loadedyk8I5y", () => {
6421            MageMe.loader.addScript('mmLogic', "https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FHyva_MageMeWebForms\u002Fjs\u002Flogic.min.js", () => {
6422                new mmLogic({
6423                        targets: targets_yk8I5y,
6424                        logicRules: logicRules_yk8I5y,
6425                        fieldMap: fieldMap_yk8I5y,
6426                        uid: 'yk8I5y',
6427                        containerId: "webform_yk8I5y_form"
6428                    });
6429            });
6430        });</script>
vendor: 1 bytes, line 6430
6430
6431<script>
6432    'use strict';
6433    (() => {
6434        document.getElementById("captcha-container-yk8I5y").innerHTML = '<div class="captcha-wrapper" x-data="mmWebformsCaptchaDatayk8I5y" x-init="initCaptcha"><input type="hidden" name="g-recaptcha-response" class="required-entry"/><div class="recaptcha-position-bottomright"><div class="recaptcha-container"></div></div></div>';
6435    })();</script>
vendor: 1 bytes, line 6435
6435
6436<script>
6437    function mmWebformsCaptchaDatayk8I5y() {
6438        return {
6439            initCaptcha() {
6440                const options = {
6441                    globalOnLoadCallback: 'webformsCaptchaOnload',
6442                    captchaReadyEvent: 'webformsCaptchaApiReady',
6443                    languageCode: 'en',
6444                    publicKey: '6LfHDCMrAAAAACnDJl581eICSW3VnauItgp_hR2S',
6445                    scriptId: 'mm_captcha',
6446                    scriptExists: false,
6447                    responseFieldName: 'g-recaptcha-response',
6448                    version: '3',
6449                    position: 'bottomright',
6450                    theme: 'standard',
6451                    action: '',
6452                    checkboxChallenge: false,
6453                    render: 'explicit'
6454                }
6455
6456                addCaptchaScriptTag();
6457                let captcha;
6458                try {
6459                    captcha = getCaptchaObject();
6460                } catch {
6461                    captcha = false;
6462                }
6463                if (captcha && captcha.render) { 
6464                    initCaptcha();
6465                } else { 
6466                    window.addEventListener(options.captchaReadyEvent, function () {
6467                        initCaptcha();
6468                    });
6469                }
6470
6471                function initCaptcha() {
6472                    const captcha = getCaptchaObject();
6473                    const params = {theme: options.theme, sitekey: options.publicKey};
6474
6475                    
6476                    if (isEnterprise() && options.checkboxChallenge) {
6477                        params.size = 'normal';
6478                        params.callback = saveToken;
6479                    } else if (isEnterprise() && !options.checkboxChallenge) {
6480                        
6481                        params.size = 'invisible';
6482                    } else if (getIsInvisibleRecaptcha()) {
6483                        params.size = 'invisible';
6484                    } else {
6485                        params.callback = saveToken;
6486                    }
6487
6488                    const self = this;
6489                    captcha.ready(function () {
6490                        const captchaDivs = document.querySelectorAll('[class="recaptcha-container"]');
6491                        for (let i = 0; i < captchaDivs.length; i++) {
6492                            try {
6493                                const cid = captcha.render(captchaDivs[i], params);
6494                                captchaDivs[i].setAttribute('cid', cid);
6495                            } catch (e) { /* recaptcha was already rendered */ }
6496                        }
6497
6498                        window.addEventListener('mm-form-captcha-promise', (e) => {
6499                            let cid = null;
6500                            let form = null;
6501                            if (e && e.detail) {
6502                                cid = e.detail.cid;
6503                                form = e.detail.form;
6504                            }
6505                            if (typeof cid === "undefined" || cid === null) {
6506                                return;
6507                            }
6508                            if (typeof form === "undefined" || form === null) {
6509                                return;
6510                            }
6511                            captcha.reset(cid);
6512                            form.setCaptchaPromise(getToken.bind(self), self);
6513                        });
6514
6515                        window.addEventListener('mm-form-captcha-reload', (e) => {
6516                            let cid = null;
6517                            if (e && e.detail) {
6518                                cid = e.detail.cid;
6519                            }
6520                            if (typeof cid === "undefined" || cid === null) {
6521                                return;
6522                            }
6523                            captcha.reset(cid);
6524                        });
6525                    })
6526
6527                    function getToken(cid, form) {
6528                        const captcha = getCaptchaObject();
6529                        switch (options.version) {
6530                            case '3': {
6531                                return captcha.execute(cid);
6532                            }
6533                            case 'enterprise': {
6534                                
6535                                if (options.checkboxChallenge) {
6536                                    return new Promise(async (resolve, reject) => {
6537                                        const token = form.controls.form.querySelector(`[name="${options.responseFieldName}"]`);
6538                                        if (token) {
6539                                            resolve(token.value);
6540                                        }
6541                                        resolve('');
6542                                    });
6543                                }
6544                                return captcha.execute(cid, {action: options.action});
6545                            }
6546                            default: {
6547                                return new Promise(async (resolve, reject) => {
6548                                    const token = form.controls.form.querySelector(`[name="${options.responseFieldName}"]`);
6549                                    if (token) {
6550                                        resolve(token.value);
6551                                    }
6552                                    resolve('');
6553                                });
6554                            }
6555                        }
6556                    }
6557
6558                    function saveToken(token) {
6559                        const rFields = document.querySelectorAll(`[name="${options.responseFieldName}"]`);
6560                        for (let i = 0; i < rFields.length; i++) {
6561                            rFields[i].value = token;
6562                        }
6563                    }
6564                }
6565
6566                function getIsInvisibleRecaptcha() {
6567                    return options.version === '3';
6568                }
6569
6570                function isEnterprise() {
6571                    return options.version === 'enterprise';
6572                }
6573
6574                function addCaptchaScriptTag() {
6575                    if (!document.getElementById(options.scriptId)) {
6576                        const script = document.createElement('script');
6577                        const firstScriptTag = document.getElementsByTagName('script')[0];
6578                        const api = isEnterprise() ? 'enterprise' : 'api';
6579
6580                        script.async = true;
6581                        script.defer = true;
6582
6583                        script.src = `https://www.google.com/recaptcha/${api}.js?render=${options.render}`;
6584
6585                        if (options.languageCode) {
6586                            script.src += `&hl=${options.languageCode}`
6587                        }
6588                        if (options.position) {
6589                            script.src += `&badge=${options.position}`
6590                        }
6591                        script.onload = () => {
6592                            window.dispatchEvent(new CustomEvent(options.captchaReadyEvent));
6593                        }
6594                        firstScriptTag.parentNode.insertBefore(script, firstScriptTag);
6595                    }
6596                    options.scriptExists = true;
6597                }
6598
6599                function getCaptchaObject() {
6600                    return isEnterprise() ? window.grecaptcha.enterprise : window.grecaptcha;
6601                }
6602            }
6603        }
6604    }
6605
6606    window.addEventListener('alpine:init', () => Alpine.data('mmWebformsCaptchaDatayk8I5y', mmWebformsCaptchaDatayk8I5y), {once: true});</script>
vendor: 1 bytes, line 6606
6606
6607<script>
6608    (() => {
6609        if (!window.MageMe || !MageMe.loader) {
6610            return;
6611        }
6612        MageMe.loader.addCssOrdered(
6613            'https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/MageMe_WebForms/css/recaptcha.min.css',
6614            '50'
6615        );
6616    })();</script>
vendor: 1 bytes, line 6616
6616
6617<script>
6618    
6619    [...document.getElementById('webform_yk8I5y_form').querySelectorAll("input")].forEach((input) => {
6620        input.onkeydown = function(e) {
6621            const key = e.charCode || e.keyCode || 0;
6622            if (key === 13) {
6623                const index = [...input.form].indexOf(this);
6624                if (input.form.elements[index + 1] != null) {
6625                    input.form.elements[index + 1].focus();
6626                }
6627                e.preventDefault();
6628                return false;
6629            }
6630        }
6631    });
6632
6633
6634         document.addEventListener('alpine:init', () => {
6635    const enquiryTopic = window.enquiryTopic;
6636    const enquiryTopicProduct = window.enquiryTopicProduct;
6637    if (window.Alpine) {
6638        Alpine.store('CRMForm', window.CRMForm);
6639    }
6640    const topicField = document.querySelector('#enquiry-topic');
6641    if (!topicField) return;
6642    topicField.setAttribute('autocomplete', 'off');
6643    document.querySelectorAll('.type-swatches input').forEach(input => {
6644        input.setAttribute('autocomplete', 'off');
6645    });
6646    if (enquiryTopic !== '' && enquiryTopicProduct !== '') {
6647        topicField.setAttribute('required', 'true');
6648        topicField.closest('.form-group')?.classList.remove('!hidden');
6649        topicField.value = enquiryTopic;
6650        document.querySelectorAll('.type-swatches input').forEach(input => {
6651            const inputValue = input.value.toLowerCase();
6652            const topicLower = enquiryTopic.toLowerCase();
6653
6654            if (topicLower.includes(inputValue) || inputValue.includes(topicLower)) {
6655                input.closest('.field.choice')?.remove();
6656                return;
6657            }
6658            if (enquiryTopicProduct.toLowerCase().includes(input.value.toLowerCase())) {
6659                input.checked = true;
6660            }
6661            input.removeAttribute('data-validate');
6662        });
6663        window.selectedCategories = [enquiryTopicProduct];
6664    } else if (enquiryTopicProduct !== '') {
6665        topicField.removeAttribute('required');
6666        topicField.closest('.webforms-fields-enquiry-topic')?.classList.add('!hidden');
6667        document.querySelectorAll('.type-swatches input').forEach(input => {
6668            const inputValue = input.value.toLowerCase();
6669            const topicLower = enquiryTopic.toLowerCase();
6670            if (topicLower.includes(inputValue) || inputValue.includes(topicLower)) {
6671                input.closest('.field.choice')?.remove();
6672                return;
6673            }
6674            if (enquiryTopicProduct.toLowerCase().includes(input.value.toLowerCase())) {
6675                input.checked = true;
6676            }
6677            input.removeAttribute('data-validate');
6678        });
6679        window.selectedCategories = [enquiryTopicProduct];
6680    } else if (enquiryTopic !== '') {
6681        topicField.setAttribute('required', 'true');
6682        topicField.closest('.form-group')?.classList.remove('!hidden');
6683        topicField.value = enquiryTopic;
6684        document.querySelectorAll('.type-swatches input').forEach(input => {
6685            const inputValue = input.value.toLowerCase();
6686            const topicLower = enquiryTopic.toLowerCase();
6687
6688            if (topicLower.includes(inputValue) || inputValue.includes(topicLower)) {
6689                input.closest('.field.choice')?.remove();
6690                return;
6691            }
6692            input.removeAttribute('data-validate');
6693        });
6694    } else {
6695        topicField.removeAttribute('required');
6696        topicField.closest('.webforms-fields-enquiry-topic')?.classList.add('!hidden');
6697        document.querySelectorAll('.type-swatches input').forEach(input => {
6698            input.setAttribute('data-validate', JSON.stringify({
6699                'validate-one-required-by-name': true,
6700                'validate-options-checkbox-min': '1'
6701            }));
6702        });
6703    }
6704});     </script>
vendor: 1 bytes, line 6704
6704
6705<script>
6706    (() => {
6707        if (!window.MageMe || !MageMe.loader) {
6708            return;
6709        }
6710         })();</script>
vendor: 1 bytes, line 6710
6710
6711<script type="text/javascript">
6712    'use strict';
6713
6714    (() => {
6715        if (!window.MageMe || !MageMe.loader) {
6716            return;
6717        }
6718        MageMe.loader.addScript('mmWebformsMultistep',"https\u003A\u002F\u002Fwww.banham.co.uk\u002Fstatic\u002Fversion1790667712\u002Ffrontend\u002FBraveBison\u002Fdefault\u002Fen_GB\u002FHyva_MageMeWebForms\u002Fjs\u002Fmultistep.min.js", () => {
6719            const formId = 'webform_yk8I5y';
6720            const uid = 'yk8I5y';
6721            const showReview = false;
6722            const controls = {
6723                form: document.getElementById(formId),
6724                wizard: document.getElementById('wizardyk8I5y')
6725            };
6726            function isIntersecting(el) {
6727                return new Promise(resolve => {
6728                    const o = new IntersectionObserver(([entry]) => {
6729                        resolve(entry.intersectionRatio === 1);
6730                        o.disconnect();
6731                    });
6732                    o.observe(el);
6733                });
6734            }
6735
6736            MageMe.WebForms.loadValidation().then(() => {
6737                return MageMe.WebForms.formValidation(controls.form, {fieldWrapperClassName: 'control', messagesWrapperClassName: 'hyva-validation'});
6738            }).then(validator => {
6739                return {
6740                    uid: 'yk8I5y',
6741                    onFinish: () => {
6742                        validator.validate().then(() => {
6743                            if (window.mmForms && window.mmForms[uid]) {
6744                                if (showReview) {
6745                                    window.mmForms[uid].review();
6746                                } else {
6747                                    window.mmForms[uid].submit();
6748                                }
6749                            }
6750                        }).catch(fields => {
6751                            if (!controls.wizard) {
6752                                console.log('No wizard');
6753                                return;
6754                            }
6755                            const fieldset = controls.wizard.querySelector('.form-step.active fieldset');
6756                            if (!fieldset || fieldset.style.display === 'none') {
6757                                return;
6758                            }
6759                            for (let i = 0; i < fields.length; i++) {
6760                                if (fieldset.querySelector('[name="' + fields[i].name + '"]')) {
6761                                    throw new Error('jqstps');
6762                                }
6763                            }
6764                            if (window.mmForms && window.mmForms[uid]) {
6765                                if (showReview) {
6766                                    window.mmForms[uid].review();
6767                                } else {
6768                                    window.mmForms[uid].submit();
6769                                }
6770                            }
6771                        });
6772                    },
6773                    onChange: (currentIndex, newIndex, stepDirection) => {
6774                        if(stepDirection === 'forward') {
6775                            return validator.validate().then(() => {
6776                                isIntersecting(controls.wizard).then(result => {
6777                                    if (!result) {
6778                                        window.scrollTo({top: controls.wizard.offsetTop - 20, behavior: 'smooth'});
6779                                    }
6780                                });
6781                            }).catch(fields => {
6782                                if (!controls.wizard) {
6783                                    console.log('No wizard');
6784                                    return;
6785                                }
6786                                const fieldset = controls.wizard.querySelector('.form-step.active fieldset');
6787                                if (!fieldset) {
6788                                    console.log('No fieldset');
6789                                    return;
6790                                }
6791                                if (fieldset.style.display === 'none') {
6792                                    return;
6793                                }
6794                                if (fieldset.classList.contains('mm-logic-hidden')) {
6795                                    return;
6796                                }
6797                                for (let i = 0; i < fields.length; i++) {
6798                                    if (fieldset.querySelector('[name="' + fields[i].name + '"]')) {
6799                                        throw new Error('jqstps');
6800                                    }
6801                                    const errorMessage = controls.wizard.querySelector('[data-msg-field="' + fields[i].name + '"]');
6802                                    if (errorMessage) {
6803                                        errorMessage.remove();
6804                                    }
6805                                }
6806                            });
6807
6808                        } else return new Promise(async (resolve, reject) => {
6809                            resolve();
6810                        });
6811                    },
6812                }
6813            }).then(config => {
6814                window.addEventListener('unhandledrejection', function(event) {
6815                    if (event.reason.message === 'jqstps') {
6816                        event.preventDefault();
6817                    }
6818                });
6819                const mmSteps = new mmWebformsMultistep(document.getElementById('wizardyk8I5y'),config);
6820                mmSteps.init();
6821            }).catch((er) => {
6822                console.log(er);
6823            });
6824        });
6825    })();</script>
vendor: 1 bytes, line 6825
6825
6826<script defer>
6827    (() => {
6828        window.dispatchEvent(new CustomEvent("mm_webform_loadedyk8I5y"));
6829    })();</script>
vendor: 1 bytes, line 6829
6829
6830<script>
6831    window.surveyTypeVal = '';
6832    document.addEventListener("DOMContentLoaded", function () {
6833        document.querySelectorAll('a[href="#open_enquiry_form"]').forEach(function(el){
6834            el.addEventListener("click", function (e) {
6835                e.preventDefault();
6836                window.surveyOpeningSource = 'Opened from CTA';
6837                document.querySelector(".open-slide-form-button")?.click();
6838            });
6839        });
6840        const idEl = document.getElementById("open_enquiry_form");
6841        if (idEl) {
6842            idEl.addEventListener("click", function (e) {
6843                e.preventDefault();
6844                window.surveyOpeningSource = 'Opened from CTA';
6845                document.querySelector(".open-slide-form-button")?.click();
6846            });
6847        }
6848
6849        if (window.location.hash === '#open_enquiry_form' || window.location.search.includes('open=enquiry')) {
6850            setTimeout(function() {
6851                window.surveyOpeningSource = 'Opened from CTA';
6852                document.querySelector(".open-slide-form-button")?.click();
6853            }, 300);
6854        }
6855    });
6856
6857    (function () {
6858        var successDiv = document.getElementById('webform_yk8I5y_success_text');
6859        var headingDiv = document.getElementById('webform_yk8I5y_heading');
6860        var closeBtn = document.querySelector('#webform-slide-out-yk8I5y .close-btn');
6861        if (successDiv && headingDiv) {
6862            new MutationObserver(function () {
6863                var isSuccess = successDiv.style.display !== 'none';
6864                headingDiv.classList.toggle('hidden', isSuccess);
6865                if (closeBtn) closeBtn.classList.toggle('success-close', isSuccess);
6866            }).observe(successDiv, { attributes: true, attributeFilter: ['style'] });
6867        }
6868    })();
6869</script>
vendor: 1 bytes, line 6869
6869
6870<script>
6871    window.site_type = "Retail";
6872
6873    function ctaLabel(el) {
6874        return (el.innerText || el.value || '').trim().split('\n').pop().trim();
6875    }
6876
6877    function ctaHeading(start) {
6878        const inside = start.querySelector('h1, h2, h3, h4');
6879        if (inside) return inside.textContent.replace(/\s+/g, ' ').trim();
6880
6881        for (let el = start.parentElement; el && !el.matches('body, header, nav, footer'); el = el.parentElement) {
6882            const sibling = [...el.children].find(child => /^H[1-4]$/.test(child.tagName));
6883            if (sibling) return sibling.textContent.replace(/\s+/g, ' ').trim();
6884        }
6885        return '';
6886    }
6887
6888    function ctaSection(start, itemTitle, clickPath) {
6889        if (start.closest('#header, [role="banner"], header, nav, .pre-footer, [role="contentinfo"]')) {
6890            return '';
6891        }
6892
6893        for (let el = start.parentElement; el && !el.matches('body, header, nav, footer, main, #header, [role="banner"], [role="contentinfo"]'); el = el.parentElement) {
6894            if (el.querySelector('main, #header, [role="contentinfo"]')) break;
6895
6896            const repeats = [...el.querySelectorAll('.button, .btn, button, .underline-link, .pre-footer a')]
6897                .filter(cta => ctaLabel(cta) === clickPath).length > 1;
6898            if (!repeats) continue;
6899
6900            const section = [...el.querySelectorAll('h1, h2, h3, h4')]
6901                .find(h => h.textContent.replace(/\s+/g, ' ').trim() !== itemTitle && !h.closest('a, button, .btn, .underline-link'));
6902            if (section) return section.textContent.replace(/\s+/g, ' ').trim();
6903        }
6904        return '';
6905    }
6906
6907    document.addEventListener('click', function (event) {
6908        const target = event.target.closest('.button, .btn, button, .underline-link, .pre-footer a');
6909        if (!target) return;
6910
6911        const customer = JSON.parse(localStorage.getItem('mage-cache-storage') || '{}').customer || {};
6912        const clickPath = ctaLabel(target);
6913        const itemTitle = ctaHeading(target);
6914        const section = itemTitle && ctaSection(target, itemTitle, clickPath);
6915        const pageName = (section ? section + ' - ' + itemTitle : itemTitle) || document.title;
6916
6917        window.dataLayer = window.dataLayer || [];
6918        window.dataLayer.push({
6919            event: 'cta',
6920            site_type: window.site_type,
6921            logged_in_status: !!customer.id,
6922            page_name: pageName,
6923            click_path: clickPath,
6924            ...(customer.id && { user_id: customer.id })
6925        });
6926    });
6927    window.trackContentAccordion = function (clickPath, isOpen) {
6928        if (window.site_type !== 'Retail' || !clickPath) return;
6929        const customer = JSON.parse(localStorage.getItem('mage-cache-storage') || '{}').customer || {};
6930        window.dataLayer = window.dataLayer || [];
6931        window.dataLayer.push({
6932            event: 'content_accordion',
6933            site_type: window.site_type,
6934            logged_in_status: !!customer.id,
6935            page_name: document.title,
6936            click_path: String(clickPath).trim(),
6937            action: isOpen ? 'Expand' : 'Collapse',
6938            ...(customer.id && { user_id: customer.id })
6939        });
6940    };
6941</script>
vendor: 1 bytes, line 6941
6941
6942<script>
6943    document.body.addEventListener('touchstart', () => {}, {passive: true})
6944</script>
vendor: 1 bytes, line 6944
6944
6945<script>
6946    'use strict';
6947
6948    (function () {
6949        /**
6950         * @typedef amPickupLocalStorage
6951         * @property {Object} scheduleData
6952         * @property {Object} store
6953         * @property {boolean} isPickupSelected
6954         * @property {boolean} isCurbsideChecked
6955         * @property {string} curbsideComment
6956         * @property {Object} dateValue
6957         * @property {string} timeValue
6958         */
6959        window.amPickupLocalStorage = window.amPickupLocalStorage || {
6960            getObject: function () {
6961                return hyva.getBrowserStorage().getItem('amPickupLocation')
6962                    ? JSON.parse(hyva.getBrowserStorage().getItem('amPickupLocation'))
6963                    : {};
6964            },
6965            setObject: function (newObject) {
6966                hyva.getBrowserStorage().setItem('amPickupLocation', JSON.stringify(newObject));
6967            },
6968            remove: function () {
6969                hyva.getBrowserStorage().removeItem('amPickupLocation');
6970            },
6971            setIsPickupSelected: function (value) {
6972                this.setObject({
6973                    ...this.getObject(),
6974                    isPickupSelected: value
6975                });
6976            },
6977            isPickupSelected: function () {
6978                return (this.getObject().isPickupSelected && this.getObject().isPickupSelected !== undefined)
6979                    ? Boolean(Number(this.getObject().isPickupSelected))
6980                    : null;
6981            },
6982            setScheduleData: function (value) {
6983                this.setObject({
6984                    ...this.getObject(),
6985                    scheduleData: value
6986                });
6987            },
6988            getScheduleData: function () {
6989                return (this.getObject().scheduleData && this.getObject().scheduleData !== undefined)
6990                    ? this.getObject().scheduleData
6991                    : null;
6992            },
6993            setStore: function (value) {
6994                this.setObject({
6995                    ...this.getObject(),
6996                    store: value
6997                });
6998            },
6999            getStore: function () {
7000                return (this.getObject().store && this.getObject().store !== undefined)
7001                    ? this.getObject().store
7002                    : null;
7003            },
7004            setCurbsideChecked: function (value) {
7005                this.setObject({
7006                    ...this.getObject(),
7007                    isCurbsideChecked: value
7008                });
7009            },
7010            getCurbsideChecked: function () {
7011                return (this.getObject().isCurbsideChecked && this.getObject().isCurbsideChecked !== undefined)
7012                    ? this.getObject().isCurbsideChecked
7013                    : false;
7014            },
7015            setCurbsideComment: function (value) {
7016                this.setObject({
7017                    ...this.getObject(),
7018                    curbsideComment: value
7019                });
7020            },
7021            getCurbsideComment: function () {
7022                return (this.getObject().curbsideComment && this.getObject().curbsideComment !== undefined)
7023                    ? this.getObject().curbsideComment
7024                    : null;
7025            },
7026            setDateValue: function (value) {
7027                this.setObject({
7028                    ...this.getObject(),
7029                    dateValue: value
7030                });
7031            },
7032            getDateValue: function () {
7033                return (this.getObject().dateValue && this.getObject().dateValue !== undefined)
7034                    ? new Date(Number(this.getObject().dateValue))
7035                    : null;
7036            },
7037            setTimeValue: function (value) {
7038                this.setObject({
7039                    ...this.getObject(),
7040                    timeValue: value
7041                });
7042            },
7043            getTimeValue: function () {
7044                return (this.getObject().timeValue && this.getObject().timeValue !== undefined)
7045                    ? this.getObject().timeValue
7046                    : null;
7047            }
7048        };
7049    })();</script>
vendor: 1 bytes, line 7049
7049
7050<script>
7051    function initHeader () {
7052        return {
7053            searchOpen: false,
7054            cart: {},
7055            isCartOpen: false,
7056            getData(data) {
7057                if (data.cart) { this.cart = data.cart }
7058            },
7059            isCartEmpty() {
7060                return !this.cart.summary_count
7061            },
7062            toggleCart(event) {
7063                if (event.detail && event.detail.isOpen !== undefined) {
7064                    this.isCartOpen = event.detail.isOpen
7065                    if (!this.isCartOpen && this.$refs && this.$refs.cartButton) {
7066                        this.$refs.cartButton.focus()
7067                    }
7068                } else {
7069                                        this.isCartOpen = true
7070                }
7071            }
7072        }
7073    }
7074    function initCompareHeader() {
7075        return {
7076            compareProducts: null,
7077            itemCount: 0,
7078            receiveCompareData(data) {
7079                if (data['compare-products']) {
7080                    this.compareProducts = data['compare-products'];
7081                    this.itemCount = this.compareProducts.count;
7082                }
7083            }
7084        }
7085    }
7086</script>
vendor: 1 bytes, line 7086
7086
7087<script>
7088    'use strict';
7089
7090    const initMenuMobile_6abf56c059c8f = () => {
7091        return {
7092            mobilePanelActiveId: null,
7093            open: false,
7094            isLoggedIn: false,
7095            signInText: 'Sign\u0020In',
7096            accountText: 'My\u0020Account',
7097            accountUrl: 'https\u003A\u002F\u002Fwww.banham.co.uk\u002Fcustomer\u002Faccount\u002F',
7098            signOutText: 'Sign\u0020Out',
7099            signOutUrl: 'https\u003A\u002F\u002Fwww.banham.co.uk\u002Fcustomer\u002Faccount\u002Flogout\u002F',
7100            init() {
7101                this.setActiveMenu(this.$root);
7102                this.setCustomerStateFromStorage();
7103            },
7104            setCustomerState(data) {
7105                this.isLoggedIn = !!(data && data.customer && (data.customer.firstname || data.customer.id));
7106            },
7107            setCustomerStateFromStorage() {
7108                try {
7109                    const cached = JSON.parse(localStorage.getItem('mage-cache-storage') || '{}');
7110                    this.isLoggedIn = !!(cached.customer && (cached.customer.firstname || cached.customer.id));
7111                } catch (e) {
7112                    this.isLoggedIn = false;
7113                }
7114            },
7115            setActiveMenu(menuNode) {
7116                Array.from(menuNode.querySelectorAll('a')).filter(link => {
7117                    return link.href === window.location.href.split('?')[0];
7118                }).map(item => {
7119                    item.classList.add('active');
7120                    item.closest('li.level-0')?.classList.add('active');
7121                    item.closest('li.level-0') &&
7122                    item.closest('li.level-0').querySelector('a.level-0').classList.add('active');
7123                });
7124            },
7125            openMenu() {
7126                this.open = true
7127                this.$nextTick(() => hyva.trapFocus(this.$refs['mobileMenuNavLinks']));
7128                // Prevent from body scrolling while mobile menu opened
7129                document.body.style.overflow = 'hidden';
7130            },
7131            closeMenu() {
7132                document.body.style.overflow = '';
7133
7134                if (this.open) {
7135                    this.$nextTick(() => this.$refs['mobileMenuTrigger'].focus() || hyva.releaseFocus());
7136                }
7137
7138                this.open = false
7139                this.mobilePanelActiveId = null
7140            },
7141            openSubcategory(index) {
7142                const menuNodeRef = document.querySelector('[data-child-id=' + index + ']')
7143                this.mobilePanelActiveId = this.mobilePanelActiveId === index ? 0 : index
7144                this.$nextTick(() => hyva.trapFocus(menuNodeRef))
7145            },
7146            backToMainCategories(index) {
7147                const menuNodeRef = document.querySelector('[data-child-id=' + index + ']')
7148                this.mobilePanelActiveId = 0
7149                this.$nextTick(() => {
7150                    hyva.trapFocus(this.$refs['mobileMenuNavLinks'])
7151                    menuNodeRef.querySelector('a').focus()
7152                })
7153            }
7154        }
7155    }
7156</script>
vendor: 1 bytes, line 7156
7156
7157<script>
7158    'use strict';
7159
7160    function initMiniSearch() {
7161        return {
7162            minSearchLength: 3,
7163                        search(term) {
7164                const search = this.$refs.searchInput;
7165                term = term || search.value;
7166                if (term.length < this.minSearchLength) {
7167                    search.setCustomValidity('Minimum\u0020Search\u0020query\u0020length\u0020is\u00203');
7168                    search.reportValidity();
7169                } else {
7170                    search.setCustomValidity('');
7171                    search.value = term;
7172                    this.$refs.form.submit();
7173                }
7174            },
7175            focusElement(element) {
7176                if (element && element.nodeName === "DIV") {
7177                    element.focus();
7178                    return true;
7179                } else {
7180                    return false;
7181                }
7182            }
7183        }
7184    }
7185</script>
vendor: 1 bytes, line 7185
7185
7186<script>
7187    function initCartDrawer() {
7188        return {
7189            open: false,
7190            isLoading: false,
7191            cart: {},
7192            isLoggedIn: false,
7193            customerId: null,
7194            maxItemsToDisplay: 10,
7195            itemsCount: 0,
7196            extraProducts: [],
7197            extraProductQtys: {},
7198            extraSplideInstance: null,
7199            getData(data) {
7200                if (data.customer) {
7201                    this.isLoggedIn = !!(data.customer.firstname);
7202                    this.customerId = data.customer.id || null;
7203                }
7204                if (data.cart) {
7205                    this.cart = data.cart;
7206                    //this.itemsCount = data.cart.items && data.cart.items.length || 0;
7207                    this.itemsCount = data.cart.items ? data.cart.items.reduce((total, item) => total + parseInt(item.qty), 0) : 0;
7208                    this.setCartItems();
7209                    this.loadExtraProducts();
7210                }
7211                this.isLoading = false;
7212            },
7213            cartItems: [],
7214            getItemCountTitle() {
7215                return hyva.strf('\u00250\u0020of\u0020\u00251\u0020products\u0020in\u0020cart\u0020displayed', this.maxItemsToDisplay, this.itemsCount)
7216            },
7217            setCartItems() {
7218                this.cartItems = this.cart.items && this.cart.items.sort((a, b) => b.item_id - a.item_id) || [];
7219
7220                if (this.maxItemsToDisplay > 0) {
7221                    this.cartItems = this.cartItems.slice(0, parseInt(this.maxItemsToDisplay, 10));
7222                }
7223            },
7224            deleteItemFromCart(itemId) {
7225                this.isLoading = true;
7226
7227                const itemData = this.cart.items.filter((item) => item['item_id'] === itemId);
7228                const formKey = hyva.getFormKey();
7229                const postUrl = BASE_URL + 'checkout/sidebar/removeItem/';
7230
7231                fetch(postUrl, {
7232                    "headers": {
7233                        "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
7234                    },
7235                    "body": "form_key=" + formKey + "&item_id=" + itemId,
7236                    "method": "POST",
7237                    "mode": "cors",
7238                    "credentials": "include"
7239                }).then(response => {
7240                    if (response.redirected) {
7241                        window.location.href = response.url;
7242                    } else if (response.ok) {
7243                        return response.json();
7244                    } else {
7245                        window.dispatchMessages && window.dispatchMessages([{
7246                            type: 'warning',
7247                            text: 'Could\u0020not\u0020remove\u0020item\u0020from\u0020quote.'
7248                        }]);
7249                        this.isLoading = false;
7250                    }
7251                }).then(result => {
7252                    window.dispatchMessages && window.dispatchMessages([{
7253                        type: result.success ? 'success' : 'error',
7254                        text: result.success
7255                            ? 'You\u0020removed\u0020the\u0020item.'
7256                            : result.error_message
7257                    }], result.success ? 5000 : 0);
7258
7259                    if (result.success && itemData) {
7260                        const removedItem = itemData[0];
7261                        if (removedItem) {
7262                            this.pushCartEvent('remove_from_cart', removedItem, parseInt(removedItem.qty) || 1);
7263                        }
7264                        window.dispatchEvent(new CustomEvent('cart-item-removed', { detail: itemData }));
7265                    }
7266
7267                    window.dispatchEvent(new CustomEvent('reload-customer-section-data'));
7268                });
7269            },
7270            scrollLock(use = true) {
7271                document.body.style.overflow = use ? "hidden" : "";
7272            },
7273            toggleCartDrawer(event) {
7274                if (event.detail && event.detail.isOpen !== undefined) {
7275                    if (event.detail.isOpen) {
7276                        this.openCartDrawer();
7277                    } else {
7278                        this.open = false;
7279                        this.scrollLock(false);
7280                        this.$refs && this.$refs.cartDialogContent && hyva.releaseFocus(this.$refs.cartDialogContent);
7281                    }
7282                } else {
7283                                        this.openCartDrawer()
7284                }
7285            },
7286            openCartDrawer() {
7287                this.open = true;
7288                this.scrollLock(true);
7289                this.$nextTick(() => {
7290                    this.$refs && this.$refs.cartDialogContent && hyva.trapFocus(this.$refs.cartDialogContent)
7291                    this.initExtraProductsSplide();
7292                });
7293                // Fire view_cart GTM event when cart opens
7294                if (this.cart && this.cart.items) {
7295                    this.pushViewCartEvent();
7296                }
7297            },
7298            pushViewCartEvent() {
7299                window.dataLayer = window.dataLayer || [];
7300                window.dataLayer.push({ ecommerce: null });
7301                window.dataLayer.push({
7302                    event: 'view_cart',
7303                    site_type: this.cart.storeId == 1 ? 'Retail' : 'Trade',
7304                    journey_type: 'product',
7305                    logged_in_status: this.isLoggedIn,
7306                    ...(this.customerId ? { 'user_id': this.customerId } : {}),
7307                    page_type: 'cart_modal',
7308                    ecommerce: {
7309                        currency: 'GBP',
7310                        value: this.cart.subtotalAmount || 0,
7311                        items: (this.cart.items || []).map((item, index) => ({
7312                            item_id: item.product_sku,
7313                            item_name: item.product_name || '',
7314                            index: index,
7315                            item_category: 'product',
7316                            item_category2: item.item_category2 || '',
7317                            item_category3: item.item_category3 || '',
7318                            cta_type: 'add to cart',
7319                            price: parseFloat(item.product_price_value) || 0,
7320                            discount: item.discount_amount || 0,
7321                            quantity: item.qty
7322                        }))
7323                    }
7324                });
7325            },
7326            closeCartDrawer() {
7327                this.$dispatch('toggle-cart', { isOpen: false })
7328            },
7329            getSectionDataExtraActions() {
7330                if (!this.cart.extra_actions) {
7331                    return '';
7332                }
7333
7334                const contentNode = document.createElement('div');
7335                contentNode.innerHTML = this.cart.extra_actions;
7336
7337                hyva.activateScripts(contentNode);
7338
7339                return contentNode.innerHTML;
7340            },
7341            incrementQty(item) {
7342                item.qty = parseInt(item.qty) + 1;
7343                this.updateItemQty(item);
7344                this.pushCartEvent('add_to_cart', item, 1);
7345            },
7346            decrementQty(item) {
7347                if (parseInt(item.qty) > 1) {
7348                    item.qty = parseInt(item.qty) - 1;
7349                    this.updateItemQty(item);
7350                    this.pushCartEvent('remove_from_cart', item, 1);
7351                }
7352            },
7353            pushCartEvent(eventType, item, quantity) {
7354                window.dataLayer = window.dataLayer || [];
7355                window.dataLayer.push({ ecommerce: null });
7356                window.dataLayer.push({
7357                    event: eventType,
7358                    site_type: this.cart.storeId == 1 ? 'Retail' : 'Trade',
7359                    journey_type: 'product',
7360                    logged_in_status: this.isLoggedIn,
7361                    ...(this.customerId ? { 'user_id': this.customerId } : {}),
7362                    product_category: item.item_category2 || '',
7363                    product_id: item.product_sku,
7364                    product_name: item.product_name || '',
7365                    page_type: 'cart_modal',
7366                    ecommerce: {
7367                        currency: 'GBP',
7368                        value: parseFloat(item.product_price_value) * quantity,
7369                        items: [{
7370                            item_id: item.product_sku,
7371                            item_name: item.product_name || '',
7372                            index: -1,
7373                            item_category: 'product',
7374                            item_category2: item.item_category2 || '',
7375                            item_category3: item.item_category3 || '',
7376                            cta_type: 'cart',
7377                            price: parseFloat(item.product_price_value) || 0,
7378                            discount: item.discount_amount || 0,
7379                            quantity: quantity
7380                        }]
7381                    }
7382                });
7383            },
7384            updateItemQty(item) {
7385                this.isLoading = true;
7386                const formKey = hyva.getFormKey();
7387                const postUrl = BASE_URL + 'checkout/cart/updatePost/';
7388
7389                const body = new URLSearchParams();
7390                body.append("form_key", formKey);
7391                body.append("cart[" + item.item_id + "][qty]", item.qty);
7392
7393                fetch(postUrl, {
7394                    method: "POST",
7395                    credentials: "include",
7396                    headers: {
7397                        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
7398                        "X-Requested-With": "XMLHttpRequest"
7399                    },
7400                    body: body.toString(),
7401                    redirect: 'manual'
7402                }).then(response => {
7403                    if (response.type === 'opaqueredirect' || response.ok) {
7404                        // Refresh minicart data without following redirect
7405                        window.dispatchEvent(new CustomEvent('reload-customer-section-data'));
7406                        this.isLoading = false;
7407                    } else {
7408                        this.isLoading = false;
7409                        throw new Error("Failed to update cart");
7410                    }
7411                }).catch((error) => {
7412                    this.isLoading = false;
7413                    window.dispatchMessages && window.dispatchMessages([{
7414                        type: 'error',
7415                        text: 'Could\u0020not\u0020update\u0020cart.'
7416                    }]);
7417                });
7418            },
7419            loadExtraProducts() {
7420                fetch(BASE_URL + 'extracartproduct/minicart/product/')
7421                    .then(response => response.json())
7422                    .then(data => {
7423                        if (data.products && Array.isArray(data.products)) {
7424                            this.extraProducts = data.products;
7425                            data.products.forEach((p, i) => {
7426                                this.extraProductQtys[i] = 1;
7427                            });
7428                            this.$nextTick(() => this.initExtraProductsSplide());
7429                        } else {
7430                            this.extraProducts = [];
7431                            if (this.extraSplideInstance) {
7432                                this.extraSplideInstance.destroy();
7433                                this.extraSplideInstance = null;
7434                            }
7435                        }
7436                    })
7437                    .catch(() => {
7438                        this.extraProducts = [];
7439                        if (this.extraSplideInstance) {
7440                            this.extraSplideInstance.destroy();
7441                            this.extraSplideInstance = null;
7442                        }
7443                    });
7444            },
7445            initExtraProductsSplide() {
7446                if (!this.$refs || !this.$refs.extraProductsSplide) {
7447                    return;
7448                }
7449
7450                if (this.extraSplideInstance) {
7451                    this.extraSplideInstance.destroy();
7452                    this.extraSplideInstance = null;
7453                }
7454
7455                if (this.extraProducts.length <= 1) {
7456                    return;
7457                }
7458
7459                if (typeof Splide === 'undefined') {
7460                    return;
7461                }
7462
7463                this.extraSplideInstance = new Splide(this.$refs.extraProductsSplide, {
7464                    type: 'fade',
7465                    pagination: false,
7466                    autoplay: false,
7467                    arrows: true
7468                });
7469                this.extraSplideInstance.mount();
7470            },
7471            incrementExtraQty(index) {
7472                if (this.extraProductQtys[index] < 10000) {
7473                    this.extraProductQtys[index]++;
7474                }
7475            },
7476            decrementExtraQty(index) {
7477                if (this.extraProductQtys[index] > 1) {
7478                    this.extraProductQtys[index]--;
7479                }
7480            },
7481            addExtraProduct(product, index) {
7482                this.isLoading = true;
7483                const formKey = hyva.getFormKey();
7484                const postUrl = BASE_URL + 'checkout/cart/add/';
7485                const qty = this.extraProductQtys[index] || 1;
7486
7487                const body = new URLSearchParams();
7488                body.append('form_key', formKey);
7489                body.append('product', product.id);
7490                body.append('qty', qty);
7491
7492                fetch(postUrl, {
7493                    method: 'POST',
7494                    credentials: 'include',
7495                    headers: {
7496                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
7497                        'X-Requested-With': 'XMLHttpRequest'
7498                    },
7499                    body: body.toString()
7500                }).then(response => {
7501                    if (response.ok) {
7502                        window.dispatchEvent(new CustomEvent('reload-customer-section-data'));
7503                    }
7504                    this.isLoading = false;
7505                }).catch(() => {
7506                    this.isLoading = false;
7507                    window.dispatchMessages && window.dispatchMessages([{
7508                        type: 'error',
7509                        text: 'Could\u0020not\u0020add\u0020product\u0020to\u0020cart.'
7510                    }]);
7511                });
7512            }
7513        }
7514    }
7515</script>
vendor: 1 bytes, line 7515
7515
7516<script>
7517    function initAuthentication() {
7518        return {
7519            open: false,
7520            close() {
7521                this.open = false;
7522            },
7523            forceAuthentication: false,
7524            checkoutUrl: 'https://www.banham.co.uk/checkout/index/',
7525            errors: 0,
7526            hasCaptchaToken: 0,
7527            displayErrorMessage: false,
7528            errorMessages: [],
7529            setErrorMessages(message) {
7530                this.errorMessages = [message];
7531                this.displayErrorMessage = true;
7532            },
7533            submitForm() {
7534                // Do not rename $form, the variable is expected to be declared in the recaptcha output
7535                const $form = document.querySelector('#login-form');
7536                    if (!this.hasCaptchaToken) {
7537        this.errors = 1;
7538
7539        let retryCount = 0;
7540        const executeGreCaptcha = () => {
7541            grecaptcha.ready(() => {
7542                try {
7543                    grecaptcha.execute(
7544                        '6LfHDCMrAAAAACnDJl581eICSW3VnauItgp_hR2S',
7545                        {action: 'submit'}
7546                    ).then((token) => {
7547                        const tokenElement = $form['g\u002Drecaptcha\u002Dresponse'];
7548
7549                        if (tokenElement && token && token.length > 0) {
7550                            if (tokenElement.length !== undefined && !tokenElement.tagName) {
7551                                Array.from(tokenElement).forEach(el => el.value = token);
7552                            } else {
7553                                tokenElement.value = token;
7554                            }
7555                            this.errors = 0;
7556                            this.hasCaptchaToken = 1;
7557                            (this.submitForm || $form.submit).call(this);
7558                        } else {
7559                            this.errors = 1;
7560                            const error = tokenElement
7561                                ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again'
7562                                : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.';
7563                            if (this.setErrorMessages) {
7564                                this.setErrorMessages([error])
7565                                this.displayErrorMessage = true;
7566                            } else {
7567                                window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000);
7568                            }
7569                        }
7570                    }).catch(exception => {
7571                        console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`)
7572                    });
7573                } catch (e) {
7574                    if (e && e.message && e.message.includes('Invalid site key or not loaded in api.js') && retryCount < 20) {
7575                        retryCount++;
7576                        setTimeout(executeGreCaptcha, 250);
7577                    } else {
7578                        console.error('ReCaptcha validation failed: ', e);
7579                    }
7580                }
7581            })
7582        }
7583
7584        const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6LfHDCMrAAAAACnDJl581eICSW3VnauItgp_hR2S";
7585        let existingScript = document.querySelector(`script[src="${recaptchaUrl}"]`);
7586        
7587        if (!existingScript) {
7588            existingScript = document.createElement('script');
7589            existingScript.setAttribute('type', 'text/javascript');
7590            existingScript.setAttribute('src', recaptchaUrl);
7591            document.head.appendChild(existingScript);
7592        }
7593
7594        if (window.grecaptcha) {
7595            executeGreCaptcha();
7596        } else {
7597            existingScript.addEventListener("load", executeGreCaptcha, false);
7598        }
7599    }
7600
7601                if (this.errors === 0) {
7602                    this.dispatchLoginRequest($form);
7603                }
7604            },
7605            onPrivateContentLoaded() {
7606                const data = this.$event.detail.data;
7607                const isLoggedIn = data.customer && data.customer.firstname;
7608                if (data.cart && !isLoggedIn) {
7609                    this.forceAuthentication = !data.cart.isGuestCheckoutAllowed;
7610                }
7611            },
7612            redirectIfAuthenticated() {
7613                const event = this.$event;
7614                this.open = this.forceAuthentication;
7615
7616                if (event.detail && event.detail.url) {
7617                    this.checkoutUrl = event.detail.url;
7618                }
7619                if (!this.forceAuthentication) {
7620                    window.location.href = this.checkoutUrl;
7621                }
7622            },
7623            resetErrors() {
7624                this.errors = 0;
7625            },
7626            dispatchLoginRequest(form) {
7627                this.isLoading = true;
7628                const username = this.$refs['customer-email'].value;
7629                const password = this.$refs['customer-password'].value;
7630                const formKey = hyva.getFormKey();
7631                const bodyFields = {
7632                    'username': username,
7633                    'password': password,
7634                    'formKey': formKey
7635                };
7636                                const fieldName = 'g\u002Drecaptcha\u002Dresponse';
7637                const recaptchaField = fieldName && form[fieldName];
7638                if (recaptchaField) {
7639                    bodyFields[fieldName] = recaptchaField.value;
7640                }
7641                fetch('https://www.banham.co.uk/customer/ajax/login/', {
7642                        method: 'POST',
7643                        headers: {
7644                            'Content-Type': 'application/json',
7645                            'X-Requested-With': 'XMLHttpRequest'
7646                        },
7647                        body: JSON.stringify(bodyFields)
7648                    }
7649                ).then(response => {
7650                        return response.json()
7651                    }
7652                ).then(data => {
7653                    this.isLoading = false;
7654                    if (data.errors) {
7655                        this.setErrorMessages(data.message);
7656                        this.errors = 1;
7657                        this.hasCaptchaToken = 0;
7658                    } else {
7659                        window.location.href = this.checkoutUrl;
7660                    }
7661                });
7662            },
7663            eventListeners: {
7664                ['@private-content-loaded.window']() {
7665                    this.onPrivateContentLoaded();
7666                },
7667                ['@toggle-authentication.window']() {
7668                    this.redirectIfAuthenticated();
7669                },
7670                ['@pageshow.window'](event) {
7671                    if (event.persisted) {
7672                        this.close();
7673                    };
7674                }
7675            }
7676        }
7677    }
7678
7679    window.addEventListener('alpine:init', () => Alpine.data('initAuthentication', initAuthentication), {once: true})
7680</script>
vendor: 1 bytes, line 7680
7680
7681<script type="application/ld+json">
7682        { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type":"ListItem","position":1,"item":{"@id":"https:\/\/www.banham.co.uk\/","name":"Home"}}] }
7683    </script>
vendor: 1 bytes, line 7683
7683
7684<script>
7685        function initMessages() {
7686        "use strict";
7687        return {
7688            isSticky: false,
7689            messages: window.mageMessages || [],
7690            init() {
7691                window.addEventListener('scroll', () => {
7692                    this.isSticky = window.scrollY > 50;
7693                });
7694            },
7695            sectionClass() {
7696                return this.isSticky
7697                    ? 'fixed top-[60px] lg:top-[84px] left-0 z-[99] w-full'
7698                    : 'fixed\u0020w\u002Dfull\u0020top\u002D\u005B84px\u005D\u0020z\u002D\u005B99\u005D relative w-full';
7699            },
7700            isEmpty() {
7701                return this.messages.reduce(
7702                    function (isEmpty, message) {
7703                        return isEmpty && message === undefined
7704                    }, true
7705                )
7706            },
7707            hasMessages() {
7708                return !this.isEmpty();
7709            },
7710            hasMessage() {
7711                return !!this.message;
7712            },
7713            removeMessage() {
7714                this.messages[this.index] = undefined;
7715            },
7716            addMessages(messages, hideAfter) {
7717                messages.map((message) => {
7718                    this.messages = this.messages.concat(message);
7719                    if (hideAfter === undefined && message.type === 'success' && window.defaultSuccessMessageTimeout) {
7720                        hideAfter = window.defaultSuccessMessageTimeout;
7721                    }
7722                    if (hideAfter) {
7723                        this.setHideTimeOut(this.messages.length -1, hideAfter);
7724                    }
7725                });
7726            },
7727            setHideTimeOut(messageIndex, hideAfter) {
7728                setTimeout((messageIndex) => {
7729                    this.messages[messageIndex] = undefined;
7730                }, hideAfter, messageIndex);
7731            },
7732            eventListeners: {
7733                ['@messages-loaded.window'](event) {
7734                    this.addMessages(event.detail.messages, event.detail.hideAfter)
7735                },
7736                ['@private-content-loaded.window'](event) {
7737                    const data = event.detail.data;
7738                    if (
7739                        data.messages &&
7740                        data.messages.messages &&
7741                        data.messages.messages.length
7742                    ) {
7743                        this.addMessages(data.messages.messages);
7744                    }
7745                },
7746                ['@clear-messages.window']() {
7747                    this.messages = [];
7748                }
7749            },
7750            getMessageUiId() {
7751                return 'message-' + this.message.type;
7752            }
7753        }
7754    }
7755
7756    window.addEventListener('alpine:init', () => Alpine.data('initMessages', initMessages), {once: true})
7757</script>
vendor: 1 bytes, line 7757
7757
7758<script>
7759document.addEventListener('DOMContentLoaded', function () {
7760    let $carouselSettings = {"_uid":"1f4ec4e1-2e59-4398-b951-7d2158fe8fa5","dots":false,"arrows":false,"autoplay":false,"interval":"","component":"carousel","transition":"fade"};
7761    let $container = '.hero-carousel-167baedb-527e-4e20-95f7-f8f91ddbb9c4 .splide';
7762    let $slides = [{"_uid":"299bf8e1-0b4a-4f78-a5be-d01af54ed0bf","body":"To celebrate 100 years of Banham, we went behind closed doors to discover what you keep under lock and key. Meet Keith & Sue and their collection of 8,500 teapots.","link":[{"url":{"id":"","url":"\/journal\/keith-and-sue-teapot-collection","linktype":"url","fieldtype":"multilink","cached_url":"\/journal\/keith-and-sue-teapot-collection"},"_uid":"7d8177f5-d478-4178-acff-93591ed811a0","type":true,"title":"Read More","component":"link","text_color":"default","button_size":"default","button_style":"btn-lighter"}],"title":"Protect What You Cherish","component":"hero_slide","title_tag":"h1","vimeo_url":"https:\/\/vimeo.com\/1215733291","overlay_opacity":{"value":0.3,"plugin":"storyblok-slider"},"background_asset":[{"_uid":"81dd85be-c05f-408c-bbaa-63c24005065d","mobile":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"tablet":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"desktop":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"component":"image_block"}],"content_position":[{"_uid":"f19544e0-fd95-4d93-836e-938749c22649","vertical":"bottom","component":"text_position","horizontal":"center"}]}];
7763
7764    if ($slides.length > 1) {
7765        new Splide($container, {
7766            type: $carouselSettings['transition'] ?? 'slide',
7767            pagination: $carouselSettings['dots'] ?? true,
7768            autoplay: $carouselSettings['autoplay'] ?? false,
7769            interval: $carouselSettings['interval'] ? Number($carouselSettings['interval']) : 3000,
7770            perPage: 1,
7771            arrows: false,
7772            mediaQuery: 'min',
7773            breakpoints: {
7774                1024: {
7775                    arrows: $carouselSettings['arrows'] ?? false,
7776                },
7777            }
7778        }).mount();
7779    }
7780});
7781</script>
vendor: 1 bytes, line 7781
7781
7782<script>
7783        function responsiveMedia(desktop, tablet, mobile, fallback, isVideoFlag) {
7784            return {
7785                src: fallback,
7786                isVideo: isVideoFlag === '1',
7787                isPlaying: true,
7788                isMuted: true,
7789                updateSrc() {
7790                    const w = window.innerWidth;
7791                    let newSrc = fallback;
7792                    if (w <= 767 && mobile) {
7793                        newSrc = mobile;
7794                    } else if (w <= 1023 && tablet) {
7795                        newSrc = tablet;
7796                    } else {
7797                        newSrc = desktop || tablet || mobile;
7798                    }
7799                    this.src = newSrc;
7800                    this.isVideo = /\.(mp4|webm|ogg)$/i.test(newSrc);
7801                },
7802                init() {
7803                    this.updateSrc();
7804                    window.addEventListener('resize', () => this.updateSrc());
7805                    this.$nextTick(() => {
7806                        if (this.$refs.videoEl) {
7807                            this.$refs.videoEl.muted = this.isMuted;
7808                        }
7809                    });
7810                },
7811                togglePlay() {
7812                    const video = this.$refs.videoEl;
7813                    if (!video) return;
7814                    if (video.paused) {
7815                        video.play();
7816                        this.isPlaying = true;
7817                    } else {
7818                        video.pause();
7819                        this.isPlaying = false;
7820                    }
7821                },
7822                toggleMute() {
7823                    const video = this.$refs.videoEl;
7824                    if (!video) return;
7825                    this.isMuted = !this.isMuted;
7826                    video.muted = this.isMuted;
7827                }                
7828            }
7829        }
7830    </script>
vendor: 1 bytes, line 7830
7830
7831<script>
7832document.addEventListener('DOMContentLoaded', function () {
7833    let $container = '.image-card-grid-1d86e92d-ab20-4142-b0cc-277bc945a160 .splide';
7834
7835    new Splide($container, {
7836        type: 'slide',
7837        pagination: false,
7838        autoplay: false,
7839        interval: 3000,
7840        arrows: false,
7841        mediaQuery: 'min',
7842        breakpoints: {
7843            1024: {
7844                destroy: true,
7845            },
7846            768: {
7847                gap: '2.5rem',
7848                padding: { gap: '26rem' },
7849            },
7850
7851            0: {
7852                gap: '1.25rem',
7853                padding: { right: '6rem' }
7854            }
7855        }
7856    }).mount();
7857});
7858</script>
vendor: 1 bytes, line 7858
7858
7859<script>
7860document.addEventListener('DOMContentLoaded', function () {
7861    let $container = '.image-card-grid-c56b845a-9bdb-4f24-a123-cabcd9cef9b0 .splide';
7862
7863    new Splide($container, {
7864        type: 'slide',
7865        pagination: false,
7866        autoplay: false,
7867        interval: 3000,
7868        arrows: false,
7869        mediaQuery: 'min',
7870        breakpoints: {
7871            1024: {
7872                destroy: true,
7873            },
7874            768: {
7875                gap: '2.5rem',
7876                padding: { gap: '26rem' },
7877            },
7878
7879            0: {
7880                gap: '1.25rem',
7881                padding: { right: '6rem' }
7882            }
7883        }
7884    }).mount();
7885});
7886</script>
vendor: 1 bytes, line 7886
7886
7887<script>
7888document.addEventListener('DOMContentLoaded', function () {
7889    let $container = '.image-card-grid-101c06c1-0443-420c-ace6-4f1b76dbf01e .splide';
7890
7891    new Splide($container, {
7892        type: 'slide',
7893        pagination: false,
7894        autoplay: false,
7895        interval: 3000,
7896        arrows: false,
7897        mediaQuery: 'min',
7898        breakpoints: {
7899            1024: {
7900                destroy: true,
7901            },
7902            768: {
7903                gap: '2.5rem',
7904                padding: { gap: '26rem' },
7905            },
7906
7907            0: {
7908                gap: '1.25rem',
7909                padding: { right: '6rem' }
7910            }
7911        }
7912    }).mount();
7913});
7914</script>
vendor: 1 bytes, line 7914
7914
7915<script>
7916document.addEventListener('DOMContentLoaded', function () {
7917    const totalTabs = 2;
7918    const $container = '.tabs-box .tab-links.splide';
7919    let splide = null;
7920
7921    // Initialize Splide only if more than 2 tabs
7922    if (totalTabs > 2) {
7923        splide = new Splide($container, {
7924            type: 'slide',
7925            autoplay: false,
7926            pagination: false,
7927            arrows: true,
7928            interval: 3000,
7929            mediaQuery: 'min',
7930            drag: false,
7931            breakpoints: {
7932                1024: { destroy: true },
7933                768: { destroy: true }
7934            }
7935        });
7936
7937        splide.on('move', function (newIndex) {
7938            const slides = document.querySelectorAll($container + ' .splide__slide');
7939            const target = slides[newIndex];
7940            if (target) target.click();
7941        });
7942
7943        splide.mount();
7944    }
7945
7946    // --- Always handle hash navigation ---
7947    function activateTabFromHash() {
7948        const hash = window.location.hash.substring(1);
7949        if (!hash) return;
7950
7951        const allTabs = document.querySelectorAll('.tabs-box [data-id]');
7952        const target = document.querySelector('[data-id="' + hash + '"]');
7953        if (!target) return;
7954
7955        // If Splide exists, move to that slide
7956        if (splide) {
7957            const index = Array.from(allTabs).indexOf(target);
7958            if (index >= 0) splide.go(index);
7959        }
7960
7961        target.click();
7962
7963        const tabSection = document.querySelector('.tabs-box .tab-section');
7964        if (tabSection) {
7965            tabSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
7966        }
7967    }
7968
7969    activateTabFromHash();
7970    window.addEventListener('hashchange', activateTabFromHash);
7971
7972    // --- Keyboard navigation (desktop only, if Splide active) ---
7973    if (splide && window.innerWidth > 1024) {
7974        const tabSection = document.querySelector('.tabs-box .tab-section');
7975        tabSection.setAttribute('tabindex', '0');
7976
7977        tabSection.addEventListener('keydown', function (event) {
7978            if (!['ArrowLeft', 'ArrowRight'].includes(event.key)) return;
7979            event.preventDefault();
7980
7981            const slides = document.querySelectorAll($container + ' .splide__slide');
7982            const active = document.querySelector($container + ' .splide__slide.active');
7983            const activeIndex = Array.from(slides).indexOf(active);
7984
7985            if (event.key === 'ArrowRight' && activeIndex < slides.length - 1) {
7986                slides[activeIndex + 1].click();
7987                splide.go(activeIndex + 1);
7988            } else if (event.key === 'ArrowLeft' && activeIndex > 0) {
7989                slides[activeIndex - 1].click();
7990                splide.go(activeIndex - 1);
7991            }
7992        });
7993    }
7994});
7995</script>
vendor: 1 bytes, line 7995
7995
7996<script>
7997document.addEventListener('DOMContentLoaded', function () {
7998    let $carouselSettings = {"_uid":"ea93e016-cd35-44ef-b860-c10531eb902b","dots":false,"arrows":false,"autoplay":false,"interval":"","component":"carousel","transition":"fade"};
7999    let $container = '.hero-carousel-f984a7ff-5d45-49c3-9473-9cca511cfa65 .splide';
8000    let $slides = [{"_uid":"9a04c72a-376c-48ac-9d25-7f6a554be009","body":"Meet Liz West and her record-breaking collection. \n","link":[{"url":{"id":"","url":"\/journal\/liz-west-spice-girls-collection","linktype":"url","fieldtype":"multilink","cached_url":"\/journal\/liz-west-spice-girls-collection"},"_uid":"508ea678-b82d-4568-a627-eef14cdc28bb","type":true,"title":"Read More","component":"link","text_color":"default","button_size":"default","button_style":"btn-lighter"}],"title":"The Spice Girls Hall of Fame","component":"hero_slide","title_tag":"h1","vimeo_url":"https:\/\/vimeo.com\/1215113358","overlay_opacity":{"value":0.3,"plugin":"storyblok-slider"},"background_asset":[{"_uid":"ae1f8069-6678-4852-80f7-522c2a2ad1eb","mobile":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"tablet":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"desktop":{"id":null,"alt":null,"name":"","focus":null,"title":null,"filename":null,"copyright":null,"fieldtype":"asset","meta_data":[],"is_external_url":false},"component":"image_block"}],"content_position":[{"_uid":"54ee8a90-4c16-4075-ae2b-dcdd0cb29b1a","vertical":"bottom","component":"text_position","horizontal":"center"}]}];
8001
8002    if ($slides.length > 1) {
8003        new Splide($container, {
8004            type: $carouselSettings['transition'] ?? 'slide',
8005            pagination: $carouselSettings['dots'] ?? true,
8006            autoplay: $carouselSettings['autoplay'] ?? false,
8007            interval: $carouselSettings['interval'] ? Number($carouselSettings['interval']) : 3000,
8008            perPage: 1,
8009            arrows: false,
8010            mediaQuery: 'min',
8011            breakpoints: {
8012                1024: {
8013                    arrows: $carouselSettings['arrows'] ?? false,
8014                },
8015            }
8016        }).mount();
8017    }
8018});
8019</script>
vendor: 1 bytes, line 8019
8019
8020<script>
8021document.addEventListener('DOMContentLoaded', function () {
8022    let $container = '.image-card-grid-5266d2bf-33d3-4ffc-9f52-7e13d43c1af9 .splide';
8023
8024    new Splide($container, {
8025        type: 'slide',
8026        pagination: false,
8027        autoplay: false,
8028        interval: 3000,
8029        arrows: false,
8030        mediaQuery: 'min',
8031        breakpoints: {
8032            1024: {
8033                destroy: true,
8034            },
8035            768: {
8036                gap: '2.5rem',
8037                padding: { gap: '26rem' },
8038            },
8039
8040            0: {
8041                gap: '1.25rem',
8042                padding: { right: '6rem' }
8043            }
8044        }
8045    }).mount();
8046});
8047</script>
vendor: 1 bytes, line 8047
8047
8048<script type="application/ld+json">
8049        {
8050  "microdata": null,
8051  "jsonld": [
8052    {
8053      "@context": "https://schema.org/",
8054      "@type": "Service",
8055      "serviceType": "Security services",
8056      "provider": {
8057        "@type": "LocalBusiness",
8058        "name": "Banham Security",
8059        "address": {
8060          "@type": "PostalAddress",
8061          "streetAddress": "20 Thornsett Road",
8062          "addressLocality": "Earlsfield, London",
8063          "addressRegion": "SW18 4EF",
8064          "postalCode": "SW18 4EF",
8065          "addressCountry": "GB"
8066        },
8067        "telephone": "+44-20-7622-5151",
8068        "email": "[email protected]",
8069        "url": "https://www.banham.co.uk/",
8070        "knowsAbout": [
8071          "burglar alarms",
8072          "CCTV",
8073          "alarm monitoring"
8074        ],
8075        "priceRange": "1000 GBP",
8076        "image": "https://www.banham.co.uk/media/catalog/category/burglar_alarms_header.jpg"
8077      },
8078      "areaServed": {
8079        "@type": "Place",
8080        "name": "London and the Southeast"
8081      }
8082    },
8083    {
8084      "@context": "https://schema.org/",
8085      "@type": "Organization",
8086      "name": "Banham Security",
8087      "alternateName": "Banham",
8088      "url": "https://www.banham.co.uk/",
8089      "logo": "https://www.banham.co.uk/static/version1639663510/frontend/bh/bh/en_GB/images/banham-logo.svg",
8090      "address": {
8091        "@type": "PostalAddress",
8092        "addressLocality": "London, United Kingdom",
8093        "postalCode": "SW18 4EF",
8094        "streetAddress": "20 Thornsett Road, Earlsfield",
8095        "addressCountry": "GB"
8096      },
8097      "email": "[email protected]",
8098      "contactPoint": {
8099        "@type": "ContactPoint",
8100        "telephone": "+4402076225151",
8101        "contactType": "customer service",
8102        "areaServed": "GB",
8103        "availableLanguage": "en"
8104      },
8105      "sameAs": [
8106        "https://twitter.com/banhamsecurity",
8107        "https://www.facebook.com/Banham.Group/",
8108        "https://www.instagram.com/banhamgroup/",
8109        "https://www.pinterest.co.uk/banhamgroup/"
8110      ]
8111    }
8112  ],
8113  "graph": null
8114}    </script>
vendor: 1 bytes, line 8114
8114
8115<script>
8116        function initNewsletterForm() {
8117            return {
8118                errors: 0,
8119                hasCaptchaToken: 0,
8120                displayErrorMessage: false,
8121                errorMessages: [],
8122                setErrorMessages(messages) {
8123                    this.errorMessages = [messages]
8124                    this.displayErrorMessage = this.errorMessages.length
8125                },
8126                submitForm() {
8127                    // Do not rename $form, the variable is expected to be declared in the recaptcha output
8128                    const $form = document.querySelector('#newsletter-validate-detail');
8129                    
8130                    if (this.errors === 0) {
8131                        $form.submit();
8132                    }
8133                }
8134            }
8135        }
8136
8137        window.addEventListener('alpine:init', () => Alpine.data('initNewsletterForm', initNewsletterForm), {once: true})
8138    </script>
vendor: 1 bytes, line 8138
8138
8139<script>
8140document.addEventListener('alpine:init', () => {
8141    Alpine.store('footerResponsive', {
8142        isMobile: window.matchMedia('(max-width: 767px)').matches,
8143        openIndex: null,
8144        init() {
8145            const matchMedia = window.matchMedia('(max-width: 767px)');
8146            this.isMobile = matchMedia.matches;
8147
8148            const handleChange = (event) => {
8149                this.isMobile = event.matches;
8150                if (!this.isMobile) this.openIndex = null;
8151            };
8152
8153            if (typeof matchMedia.onchange !== 'object') {
8154                matchMedia.addListener(handleChange);
8155            } else {
8156                matchMedia.addEventListener('change', handleChange);
8157            }
8158        },
8159        toggle(index) {
8160            this.openIndex = this.openIndex === index ? null : index;
8161        },
8162        isOpen(index) {
8163            return this.openIndex === index;
8164        }
8165    });
8166
8167    // FIX: run store init manually (stores don’t auto-run init)
8168    Alpine.store('footerResponsive').init();
8169});
8170
8171document.addEventListener('DOMContentLoaded', function () {
8172    const el = document.querySelector('.pre-footer');
8173    if (el) {
8174        new Splide(el, {
8175            perPage: 1,
8176            type: 'loop',
8177            pagination: true,
8178            arrows: false,
8179            mediaQuery: 'min',
8180            autoplay: true, 
8181            interval: 3000, 
8182            breakpoints: {
8183                1024: { destroy: true },
8184            }            
8185        }).mount();
8186    }
8187});
8188</script>
vendor: 1 bytes, line 8188
8188
8189<script>
8190function initNewsletterFormModal() {
8191    const showPopup = 1;
8192    const closedCookieName = 'newsletter-modal-closed';
8193    const trigger = "on_load_delay";
8194    const waitForShowingTime = 40000; // ms
8195    const scrollThreshold = 80;
8196
8197    if (showPopup == 1) {
8198        window.cookie_consent_config['necessary'] = [].concat(
8199            window.cookie_consent_config['necessary'] || [],
8200            [closedCookieName]
8201        );
8202
8203        return {
8204            open: false,
8205            closedCookieName: closedCookieName,
8206
8207            firstname: '',
8208            lastname: '',
8209            email: '',
8210            errors: {},
8211
8212            validateField(field) {
8213                this.errors[field] = '';
8214
8215                if (field === 'firstname' && !this.firstname.trim()) {
8216                    this.errors.firstname = 'First\u0020Name\u0020is\u0020required.';
8217                }
8218                if (field === 'lastname' && !this.lastname.trim()) {
8219                    this.errors.lastname = 'Last\u0020Name\u0020is\u0020required.';
8220                }
8221                if (field === 'email') {
8222                    if (!this.email.trim()) {
8223                        this.errors.email = 'Email\u0020is\u0020required.';
8224                    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email)) {
8225                        this.errors.email = 'Please\u0020enter\u0020a\u0020valid\u0020email\u0020address.';
8226                    }
8227                }
8228            },
8229
8230            validateForm() {
8231                this.validateField('firstname');
8232                this.validateField('lastname');
8233                this.validateField('email');
8234                return Object.values(this.errors).every(v => v === '');
8235            },
8236
8237            submitForm() {
8238                const $form = document.querySelector('#newsletter-validate-modal');
8239                
8240                if (this.validateForm()) {
8241                    this.setCloseCookie();
8242                    $form.submit();
8243                }
8244            },
8245
8246            init() {
8247                if (!this.shouldShowModal()) return;
8248
8249                switch (trigger) {
8250                    case 'on_load_delay':
8251                        setTimeout(() => { this.open = true; }, waitForShowingTime);
8252                        break;
8253
8254                    case 'scroll_percent':
8255                        window.addEventListener('scroll', () => {
8256                            const percentScrolled = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
8257                            if (percentScrolled > scrollThreshold && !this.open) {
8258                                this.open = true;
8259                            }
8260                        }, { once: false });
8261                        break;
8262
8263                    case 'exit_intent':
8264                        document.addEventListener('mousemove', (e) => {
8265                            if (e.clientY <= 10 && !this.open && !hyva.getCookie(this.closedCookieName)) {
8266                                this.open = true;
8267                            }
8268                        });
8269                        break;
8270                }
8271            },
8272
8273            closeModal() {
8274                this.setCloseCookie();
8275            },
8276
8277            setCloseCookie() {
8278                hyva.setCookie(this.closedCookieName, true, 365);
8279                this.open = false;
8280            },
8281
8282            shouldShowModal() {
8283                const isInStoryblokPreview = window.location !== window.parent.location;
8284                const currentUrl = window.location.href;
8285                if(isInStoryblokPreview && !currentUrl.includes('newsletter-popup')) {
8286                    return false;
8287                }
8288                return !hyva.getCookie(this.closedCookieName);
8289            }
8290        }
8291    }
8292
8293    window.addEventListener('alpine:init', () => Alpine.data('initNewsletterFormModal', initNewsletterFormModal), { once: true });
8294}
8295</script>
vendor: 1 bytes, line 8295
8295
8296<script>
8297    window.enquiryTopic = "";
8298    window.enquiryTopicProduct = "";
8299    window.CRMForm = {enquiryTopic, enquiryTopicProduct};
8300
8301</script>
vendor: 1 bytes, line 8301
8301
8302<script type="text/javascript" async>
8303    var w = document.createElement("script");
8304    w.type = "text/javascript";
8305    w.src = "//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js";
8306    w.async = true;
8307    document.head.appendChild(w);
8308</script>
vendor: 1 bytes, line 8308
8308
8309<script type="text/javascript">
8310    (function(w,d,s,r,n){w.TrustpilotObject=n;w[n]=w[n]||function(){(w[n].q=w[n].q||[]).push(arguments)};
8311    a=d.createElement(s);a.async=1;a.src=r;a.type='text/java'+s;f=d.getElementsByTagName(s)[0];
8312    f.parentNode.insertBefore(a,f)})(window,document,'script', 'https://invitejs.trustpilot.com/tp.min.js', 'tp');
8313    tp('register','');
8314</script>
vendor: 1 bytes, line 8314
8314
8315<script type="text/javascript">
8316    function inIframe () {
8317        try {
8318            return window.self !== window.top;
8319        } catch (e) {
8320            return false;
8321        }
8322    }
8323
8324    function tryParseJson(str) {
8325        if (typeof str === 'string') {
8326            try {
8327                return JSON.parse(str);
8328            } catch (e) {
8329                return false;
8330            }
8331        }
8332        return false;
8333    }
8334
8335    if (inIframe()) {
8336        window.addEventListener('message', function(e) {
8337            var adminOrign = new URL(window.location).hostname;
8338            var eventOriginHostname = new URL(e.origin).hostname;
8339            if (!e.data || adminOrign !== eventOriginHostname) {
8340                return;
8341            }
8342            if (typeof TrustpilotPreview !== 'undefined') {
8343                if (typeof e.data === 'string' && e.data === 'submit') {
8344                    TrustpilotPreview.sendTrustboxes();
8345                } else {
8346                    jsonData = tryParseJson(e.data);
8347                    if (jsonData.trustbox) {
8348                        TrustpilotPreview.setSettings(jsonData.trustbox);
8349                    } else if (jsonData.customised) {
8350                        TrustpilotPreview.updateActive(jsonData.customised);
8351                    }
8352                }
8353            } else {
8354                var settings = tryParseJson(e.data);
8355                if (settings) {
8356                    var p = document.createElement("script");
8357                    p.type = "text/javascript";
8358                    p.onload = function () {
8359                        const iFrame = e.source.parent.document.getElementById('configuration_iframe').contentWindow;
8360                        TrustpilotPreview.init(['//ecommplugins-scripts.trustpilot.com/v2.1/css/preview.min.css'], settings, iFrame, e.source);
8361                    };
8362                    p.src = '//ecommplugins-scripts.trustpilot.com/v2.1/js/preview.min.js';
8363                    document.head.appendChild(p);
8364                }
8365            }
8366        });
8367    }
8368</script>
vendor: 1 bytes, line 8368
8368
8369<script type="text/javascript" async>
8370    const trustpilot_trustbox_settings = {"trustboxes":[]};
8371    if (trustpilot_trustbox_settings) {
8372        document.addEventListener('DOMContentLoaded', function() {
8373            tp('trustBox', trustpilot_trustbox_settings);
8374        });
8375    }
8376</script>
vendor: 1 bytes, line 8376
8376
8377<script>
8378    let SnapSlider = class {
8379        constructor(el, {
8380            labelSepparator = 'of',
8381            autoPager,
8382            groupPager
8383        } = {}) {
8384            this.el = el;
8385            this.track = this.el.querySelector("[data-track]");
8386            if (!this.track) {
8387                console.warn(
8388                    "No Slider track defined, reverting back to CSS slider.\nPlease create a wrapper for your slides with the attribute data-track",
8389                    this.el
8390                );
8391                return;
8392            }
8393            this.initialLoad = true;
8394            this.slides = [];
8395            this.inViewObserver;
8396            this.mutationObserver;
8397            this.resizeObserver;
8398            this.pager = this.el.querySelector("[data-pager]");
8399            this.navBtns = Array.from(
8400                this.el.querySelectorAll("[data-next], [data-prev]")
8401            );
8402            this.slideLabelSepparator = this.el.dataset.slideLabelSepparator || labelSepparator;
8403            this.useAutoPager = autoPager || this.el.hasAttribute("data-auto-pager") || false;
8404            this.useGroupPager = groupPager || this.el.hasAttribute("data-group-pager") || false;
8405            this.sliderLabel = this.el.hasAttribute("aria-label") && this.el.getAttribute("aria-label").toLowerCase().trim().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
8406            this.sliderId = this.el.id || this.sliderLabel || "slider";
8407            this.markerIdName = "data-target-id";
8408            this.pagerClasses = this.el.dataset.pagerClass || "snap-pager";
8409            this.markerClasses = this.el.dataset.markerClass || "snap-marker";
8410            this.init();
8411        }
8412        init() {
8413            this.setupSlides();
8414            this.setupNav();
8415            if (this.useAutoPager) {
8416                this.createPager();
8417            } else {
8418                this.setupPager();
8419            }
8420            this.setupObservers();
8421            this.setupMutationObserver();
8422            this.setupResizeObserver();
8423            this.el.addEventListener("click", this.eventHandler.bind(this));
8424            this.el.addEventListener("keydown", this.eventHandler.bind(this));
8425        }
8426        destroy() {
8427            this.inViewObserver?.disconnect();
8428            this.mutationObserver?.disconnect();
8429            this.resizeObserver?.disconnect();
8430            this.el.removeEventListener("click", this.eventHandler.bind(this));
8431            this.el.removeEventListener("keydown", this.eventHandler.bind(this));
8432        }
8433        roundUpIfGreaterThan(number, min = 8) {
8434            const decimalPart = number - Math.floor(number);
8435            return decimalPart >= min ? Math.ceil(number) : Math.floor(number);
8436        }
8437        getInViewItems() {
8438            const inViewSlides = this.track.querySelectorAll("[data-in-view]");
8439            const firstInViewSlide = inViewSlides[0] || null;
8440            const lastInViewSlide = inViewSlides[inViewSlides.length - 1] || null;
8441            const isAtStart = firstInViewSlide === this.slides[0];
8442            const isAtEnd = lastInViewSlide === this.slides[this.slides.length - 1];
8443            return {
8444                inViewSlides,
8445                totalInViewSlides: inViewSlides.length,
8446                firstInViewSlide,
8447                lastInViewSlide,
8448                isAtStart,
8449                isAtEnd,
8450                hasNoOverflow: isAtStart && isAtEnd
8451            };
8452        }
8453        groupPagerMarkers() {
8454            if (this.slides.length === 0 || !this.pager || !this.useGroupPager) return;
8455            const totalVisibleSlides = this.roundUpIfGreaterThan(
8456                this.track.offsetWidth / this.slides[0].offsetWidth
8457            );
8458            const markers = Array.from(this.pager.querySelectorAll("a, button"));
8459            markers.forEach((marker, index) => {
8460                marker.style.display = index % totalVisibleSlides === 0 ? null : "none";
8461            });
8462        }
8463        handleInView(entries) {
8464            entries.forEach((entry) => {
8465                const marker = this.pager && (this.pager.querySelector(`[href="#${entry.target.id}"]`) || this.pager.querySelector(
8466                    `[${this.markerIdName}="${entry.target.id}"]`
8467                ));
8468                entry.target.toggleAttribute("data-in-view", entry.isIntersecting);
8469                entry.target.toggleAttribute("inert", !entry.isIntersecting);
8470                marker?.setAttribute("aria-current", entry.isIntersecting);
8471                marker?.setAttribute("tabindex", entry.isIntersecting ? "0" : "-1");
8472            });
8473            const {
8474                isAtStart,
8475                isAtEnd,
8476                hasNoOverflow
8477            } = this.getInViewItems();
8478            this.navBtns.forEach((btn) => {
8479                if (btn.hasAttribute("data-next")) {
8480                    btn.style.visibility = hasNoOverflow ? "hidden" : null;
8481                    isAtEnd ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled");
8482                }
8483                if (btn.hasAttribute("data-prev")) {
8484                    btn.style.visibility = hasNoOverflow ? "hidden" : null;
8485                    isAtStart ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled");
8486                }
8487            });
8488            if (this.pager) {
8489                this.pager.style.visibility = hasNoOverflow ? "hidden" : null;
8490            }
8491            if (!this.initialLoad) {
8492                this.el.dispatchEvent(
8493                    new CustomEvent("slideChange", {
8494                        detail: this.getInViewItems()
8495                    })
8496                );
8497            } else {
8498                this.initialLoad = false;
8499            }
8500            if (document.activeElement.parentElement.hasAttribute("data-pager")) {
8501                const activeItems = this.pager.querySelectorAll('[tabindex="0"]');
8502                if (activeItems.length) {
8503                    activeItems[0].focus({ preventScroll: true });
8504                }
8505            }
8506        }
8507        getSlides() {
8508            if (!this.track) return [];
8509            return Array.from(this.track.children).filter(
8510                (child) => child.tagName.toLowerCase() !== "template" && child.tagName.toLowerCase() !== "style" && child.tagName.toLowerCase() !== "script"
8511            );
8512        }
8513        refreshSlides() {
8514            this.initialLoad = true;
8515            this.slides = this.getSlides();
8516            this.setupSlides();
8517            if (this.useAutoPager) {
8518                this.createPager();
8519            } else {
8520                this.setupPager();
8521            }
8522            this.groupPagerMarkers();
8523            this.setupObservers();
8524        }
8525        setupSlides() {
8526            this.slides = this.getSlides();
8527            this.slides.forEach((slide, index) => {
8528                const totalSlides = this.slides.length;
8529                const currentSlide = index + 1;
8530                const existingLabel = slide.getAttribute("aria-label") || "";
8531                const isImage = slide.tagName.toLowerCase() === "img" || slide.tagName.toLowerCase() === "picture";
8532                const slideLabelTag = isImage ? "alt" : "aria-label";
8533                const hasAutoLabel = existingLabel.startsWith(
8534                    `${currentSlide} ${this.slideLabelSepparator} `
8535                );
8536                if (!slide.hasAttribute("id")) {
8537                    slide.setAttribute(
8538                        "id",
8539                        `${this.sliderId}-item-${currentSlide}`
8540                    );
8541                }
8542                if (!slide.hasAttribute(slideLabelTag) || slide.getAttribute(slideLabelTag) === "" || hasAutoLabel) {
8543                    slide.setAttribute(
8544                        slideLabelTag,
8545                        `${currentSlide} ${this.slideLabelSepparator} ${totalSlides}`
8546                    );
8547                }
8548                if (slide.tagName.toLowerCase() === "div" && !slide.hasAttribute("role")) {
8549                    slide.setAttribute("role", "group");
8550                }
8551                if (this.pager && !isImage) {
8552                    slide.setAttribute("role", "tabpanel");
8553                }
8554                if (slide.getAttribute("role") === "group") {
8555                    slide.setAttribute("aria-roledescription", "item");
8556                }
8557            });
8558            if (!this.el.hasAttribute("role") && this.el.tagName !== "SECTION") {
8559                this.el.setAttribute("role", "region");
8560            }
8561            if (!this.el.hasAttribute("aria-roledescription")) {
8562                this.el.setAttribute("aria-roledescription", "carousel");
8563            }
8564            this.track.setAttribute("tabindex", 0);
8565            this.track.setAttribute("aria-live", "polite");
8566        }
8567        setupNav() {
8568            this.navBtns.forEach((btn) => {
8569                btn.setAttribute("disabled", "");
8570                btn.removeAttribute("hidden");
8571                btn.classList.remove("invisible");
8572                btn.style.visibility = null;
8573            });
8574        }
8575        createPager() {
8576            const newPager = document.createElement("nav");
8577            newPager.setAttribute("data-pager", "");
8578            newPager.setAttribute("role", "tablist");
8579            newPager.classList.add(...this.pagerClasses.split(" "));
8580            this.slides.forEach((slide, index) => {
8581                const marker = document.createElement("button");
8582                const slideId = slide.id || `${this.sliderId}-item-${index + 1}`;
8583                marker.setAttribute(this.markerIdName, slideId);
8584                marker.classList.add(...this.markerClasses.split(" "));
8585                this.setupPagerMarker(marker, index);
8586                newPager.appendChild(marker);
8587                if (slide.tagName.toLowerCase() !== "img" && slide.tagName.toLowerCase() !== "picture") {
8588                    slide.removeAttribute("aria-roledescription");
8589                    slide.setAttribute("role", "tabpanel");
8590                }
8591            });
8592            if (this.pager) {
8593                this.pager.setAttribute("role", "tablist");
8594                this.pager.replaceChildren(...newPager.children);
8595            } else {
8596                this.track.after(newPager);
8597                this.pager = this.el.querySelector("[data-pager]");
8598            }
8599        }
8600        setupPager() {
8601            if (!this.pager) return;
8602            this.pager.setAttribute("role", "tablist");
8603            const items = Array.from(this.pager.querySelectorAll("a, button"));
8604            items.forEach((marker, index) => this.setupPagerMarker(marker, index));
8605        }
8606        setupPagerMarker(marker, index) {
8607            const markerId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(this.markerIdName);
8608            const slideId = markerId || `${this.sliderId}-item-${index + 1}`;
8609            if (!markerId) {
8610                marker.setAttribute(this.markerIdName, slideId);
8611            }
8612            marker.setAttribute("role", "tab");
8613            marker.setAttribute("aria-controls", slideId);
8614            marker.setAttribute("aria-posinset", index + 1);
8615            marker.setAttribute("aria-setsize", this.slides.length);
8616            marker.setAttribute("tabindex", "-1");
8617            if (!marker.hasAttribute("aria-label")) {
8618                marker.setAttribute("aria-label", `Slide ${index + 1}`);
8619            }
8620        }
8621        setupObservers() {
8622            if (this.inViewObserver) {
8623                this.inViewObserver.disconnect();
8624            }
8625            this.inViewObserver = new IntersectionObserver(
8626                this.handleInView.bind(this), {
8627                    root: this.track,
8628                    threshold: 0.8
8629                }
8630            );
8631            this.slides.forEach((slide) => this.inViewObserver.observe(slide));
8632        }
8633        setupMutationObserver() {
8634            this.mutationObserver = new MutationObserver(
8635                this.refreshSlides.bind(this)
8636            );
8637            this.mutationObserver.observe(this.track, {
8638                childList: true,
8639                subtree: false
8640            });
8641        }
8642        setupResizeObserver() {
8643            this.resizeObserver = new ResizeObserver(
8644                this.groupPagerMarkers.bind(this)
8645            );
8646            this.resizeObserver.observe(this.el);
8647        }
8648        goToSlideDir(dir = "next") {
8649            const {
8650                firstInViewSlide,
8651                lastInViewSlide
8652            } = this.getInViewItems();
8653            const isPrev = dir === "prev";
8654            let targetSlide = isPrev ? firstInViewSlide?.previousElementSibling : lastInViewSlide?.nextElementSibling;
8655            if (!targetSlide) return;
8656            if (targetSlide.tagName.toLowerCase() === "template") {
8657                targetSlide = isPrev ? targetSlide?.previousElementSibling : targetSlide?.nextElementSibling;
8658            }
8659            targetSlide.scrollIntoView({ block: "nearest", inline: isPrev ? "end" : "start" });
8660        }
8661        pagerToSlide(event) {
8662            if (!event.target.closest("[data-pager]")) return;
8663            const marker = event.target.closest("a, button");
8664            if (!marker) return;
8665            event.preventDefault();
8666            const slideId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(this.markerIdName);
8667            const targetSlide = this.track.querySelector(`#${slideId}`);
8668            targetSlide?.scrollIntoView({ block: "nearest", inline: "start" });
8669        }
8670        eventHandler(event) {
8671            const target = event.target.closest(
8672                "[data-next], [data-prev], [data-pager]"
8673            );
8674            if (!target) return;
8675            if (event.type === "click") {
8676                if (target.hasAttribute("data-next")) {
8677                    this.goToSlideDir("next");
8678                } else if (target.hasAttribute("data-prev")) {
8679                    this.goToSlideDir("prev");
8680                } else if (target.closest("[data-pager]")) {
8681                    this.pagerToSlide(event);
8682                }
8683            }
8684            if (event.type === "keydown" && target.closest("[data-pager]")) {
8685                if (event.key === "ArrowRight") {
8686                    this.goToSlideDir("next");
8687                } else if (event.key === "ArrowLeft") {
8688                    this.goToSlideDir("prev");
8689                }
8690            }
8691        }
8692    };
8693
8694    (() => {
8695        function alpineSnapSlider(Alpine) {
8696            Alpine.directive("snap-slider", (el, {
8697                modifiers
8698            }, {
8699                cleanup
8700            }) => {
8701                const autoPager = modifiers.includes("auto-pager");
8702                const groupPager = modifiers.includes("group-pager");
8703                const slider = new SnapSlider(el, {
8704                    autoPager,
8705                    groupPager
8706                });
8707                cleanup(() => {
8708                    slider.destroy();
8709                });
8710            });
8711        }
8712
8713        document.addEventListener("alpine:init", () => {
8714            window.Alpine.plugin(alpineSnapSlider);
8715        });
8716    })();</script>
vendor: 1 bytes, line 8716
8716
8717<script>
8718    (() => {
8719        // src/dialog.js
8720        function dialog_default(Alpine) {
8721            Alpine.directive("htmldialog", fylgjaAlpineDialog);
8722
8723            function fylgjaAlpineDialog(el, {
8724                expression,
8725                modifiers
8726            }, {
8727                evaluateLater,
8728                cleanup
8729            }) {
8730                const evaluate = expression.length ? evaluateLater(expression) : () => {};
8731                const lockPageScroll = modifiers.includes("noscroll");
8732                const closeby = modifierValue(modifiers, "closeby", "any");
8733                el.style.display = null;
8734                el.hidden = false;
8735                el.style.length === 0 && el.removeAttribute("style");
8736                el.addEventListener("keydown", escapeDialog);
8737                el.addEventListener("click", backdropDialog);
8738                el.addEventListener("submit", methodDialog);
8739
8740                function scrollLock(use = true) {
8741                    document.body.style.overflow = use ? "hidden" : "";
8742                }
8743
8744                function methodDialog(event) {
8745                    if (event.target.getAttribute("method") === "dialog" || event.submitter && event.submitter.getAttribute("formmethod") === "dialog") {
8746                        evaluate();
8747                    }
8748                }
8749
8750                function escapeDialog(event) {
8751                    if (event.key !== "Escape")
8752                        return;
8753                    event.preventDefault();
8754                    if (closeby !== "any" && closeby !== "closerequest")
8755                        return;
8756                    evaluate();
8757                }
8758
8759                function backdropDialog(event) {
8760                    if (event.target !== el || closeby !== "any")
8761                        return;
8762                    const rect = el.getBoundingClientRect();
8763                    const isInDialog = rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width;
8764                    if (isInDialog)
8765                        return;
8766                    evaluate();
8767                }
8768                el._x_doShow = () => {
8769                    if (el.hasAttribute("open"))
8770                        return;
8771                    el.showModal();
8772                    scrollLock(lockPageScroll);
8773                };
8774                el._x_doHide = () => {
8775                    if (!el.hasAttribute("open"))
8776                        return;
8777                    el.close();
8778                    scrollLock(false);
8779                };
8780                cleanup(() => {
8781                    el.removeEventListener("keydown", escapeDialog);
8782                    el.removeEventListener("click", backdropDialog);
8783                    el.removeEventListener("submit", methodDialog);
8784                    scrollLock(false);
8785                });
8786            }
8787        }
8788
8789        function modifierValue(modifiers, key, fallback) {
8790            if (modifiers.indexOf(key) === -1)
8791                return fallback;
8792            const rawValue = modifiers[modifiers.indexOf(key) + 1];
8793            if (!rawValue)
8794                return fallback;
8795            if (key === "closeby") {
8796                const allowedValues = ["auto", "none", "closerequest", "any"];
8797                const options = allowedValues.join(", ");
8798                if (!allowedValues.includes(rawValue)) {
8799                    console.warn(
8800                        `"${rawValue}" is not one of the allowed values for closeby: ${options}`
8801                    );
8802                }
8803                return fallback;
8804            }
8805            return rawValue;
8806        }
8807
8808        // src/cdn.js
8809        document.addEventListener("alpine:init", () => {
8810            window.Alpine.plugin(dialog_default);
8811        });
8812    })();
8813</script>
vendor: 1 bytes, line 8813
8813
8814<script>
8815    (() => {
8816        function src_default(Alpine) {
8817            Alpine.directive("intersect", Alpine.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => {
8818                let evaluate = evaluateLater(expression);
8819                let options = {
8820                    rootMargin: getRootMargin(modifiers),
8821                    threshold: getThreshold(modifiers)
8822                };
8823                let observer = new IntersectionObserver((entries) => {
8824                    entries.forEach((entry) => {
8825                        if (entry.isIntersecting === (value === "leave"))
8826                            return;
8827                        evaluate();
8828                        modifiers.includes("once") && observer.disconnect();
8829                    });
8830                }, options);
8831                observer.observe(el);
8832                cleanup(() => {
8833                    observer.disconnect();
8834                });
8835            }));
8836        }
8837        function getThreshold(modifiers) {
8838            if (modifiers.includes("full"))
8839                return 0.99;
8840            if (modifiers.includes("half"))
8841                return 0.5;
8842            if (!modifiers.includes("threshold"))
8843                return 0;
8844            let threshold = modifiers[modifiers.indexOf("threshold") + 1];
8845            if (threshold === "100")
8846                return 1;
8847            if (threshold === "0")
8848                return 0;
8849            return Number(`.${threshold}`);
8850        }
8851        function getLengthValue(rawValue) {
8852            let match = rawValue.match(/^(-?[0-9]+)(px|%)?$/);
8853            return match ? match[1] + (match[2] || "px") : void 0;
8854        }
8855        function getRootMargin(modifiers) {
8856            const key = "margin";
8857            const fallback = "0px 0px 0px 0px";
8858            const index = modifiers.indexOf(key);
8859            if (index === -1)
8860                return fallback;
8861            let values = [];
8862            for (let i = 1; i < 5; i++) {
8863                values.push(getLengthValue(modifiers[index + i] || ""));
8864            }
8865            values = values.filter((v) => v !== void 0);
8866            return values.length ? values.join(" ").trim() : fallback;
8867        }
8868
8869        document.addEventListener("alpine:init", () => {
8870            window.Alpine.plugin(src_default);
8871        });
8872    })();</script>
vendor: 1 bytes, line 8872
8872
8873<script>
8874    for (const [selector, deferUntil] of Object.entries({".product-slider section[x-data]:not([x-data] [x-data])":"intersect",".product-info [x-data]:not([x-data] [x-data])":"intersect","#filters-content [x-data]:not([x-data] [x-data])":"intersect","#review_form":"intersect","section[x-data^=initRecentlyViewedProductsComponent]":"intersect","div[x-data^=initBundleOptions]":"intersect","#product_addtocart_form [x-data]:not([x-data] [x-data])":"intersect","#notice-cookie-block":"idle"})) {
8875        document.querySelectorAll(selector).forEach(el => el.setAttribute('x-defer', `${deferUntil}`));
8876    }</script>
vendor: 1 bytes, line 8876
8876
8877<script>
8878    (() => {
8879        const hasAlpine = new Promise(resolve => {
8880            window.addEventListener('alpine:initialized', resolve, {once: true, passive: true});
8881        });
8882
8883        const hasInteract = new Promise(resolve => {
8884            (events => {
8885                const onInteract = () => {
8886                    resolve();
8887                    events.forEach(type => window.removeEventListener(type, onInteract));
8888                }
8889                events.forEach(type => window.addEventListener(type, onInteract, {once: true, passive: true}))
8890            })(['touchstart', 'mouseover', 'wheel', 'scroll', 'keydown'])
8891        });
8892
8893        const onIntersect = (el) => {
8894            return new Promise(resolve => {
8895                const observer = new IntersectionObserver(entries => {
8896                    for (const entry of entries) {
8897                        if (entry.isIntersecting) {
8898                            observer.disconnect()
8899                            resolve();
8900                        }
8901                    }
8902                }, {});
8903                observer.observe(el);
8904            });
8905        }
8906
8907        function runComponent(el) {
8908            hasAlpine.then(() => {
8909                el.removeAttribute('x-ignore');
8910                queueMicrotask(() => Alpine.initTree(el));
8911            });
8912        }
8913
8914        function initDeferredComponents() {
8915            document.querySelectorAll('[x-data][x-defer]').forEach(el => {
8916                el.setAttribute('x-ignore', '');
8917                const deferUntil = (el.getAttribute('x-defer') || '').trim();
8918                switch (deferUntil) {
8919                    case 'interact':
8920                        hasInteract.then(() => runComponent(el));
8921                        break;
8922                    case 'intersect':
8923                        onIntersect(el).then(() => runComponent(el))
8924                        break;
8925                    case 'idle':
8926                        window.requestIdleCallback
8927                            ? window.requestIdleCallback(() => runComponent(el), {timeout: 4000})
8928                            : setTimeout(() => runComponent(el), 4000);
8929                        break;
8930                    case 'eager':
8931                        runComponent(el);
8932                        break;
8933                    default:
8934                        if (deferUntil.startsWith('event:') && deferUntil.length > 6) {
8935                            window.addEventListener(deferUntil.substring(6), () => runComponent(el), {once: true, passive: true});
8936                        }
8937                }
8938            });
8939        }
8940
8941        window.addEventListener('alpine:init', initDeferredComponents, {once: true, passive: true});
8942    })();</script>
vendor: 1 bytes, line 8942
8942
vendor: 4,405 bytes, lines 8943-9050
8943<script>
8944    (() => {
8945        // packages/collapse/src/index.js
8946        function src_default(Alpine) {
8947            Alpine.directive("collapse", collapse);
8948            collapse.inline = (el, {
8949                modifiers
8950            }) => {
8951                if (!modifiers.includes("min"))
8952                    return;
8953                el._x_doShow = () => {};
8954                el._x_doHide = () => {};
8955            };
8956
8957            function collapse(el, {
8958                modifiers
8959            }) {
8960                let duration = modifierValue(modifiers, "duration", 250) / 1e3;
8961                let floor = modifierValue(modifiers, "min", 0);
8962                let fullyHide = !modifiers.includes("min");
8963                if (!el._x_isShown)
8964                    el.style.height = `${floor}px`;
8965                if (!el._x_isShown && fullyHide)
8966                    el.hidden = true;
8967                if (!el._x_isShown)
8968                    el.style.overflow = "hidden";
8969                let setFunction = (el2, styles) => {
8970                    let revertFunction = Alpine.setStyles(el2, styles);
8971                    return styles.height ? () => {} : revertFunction;
8972                };
8973                let transitionStyles = {
8974                    transitionProperty: "height",
8975                    transitionDuration: `${duration}s`,
8976                    transitionTimingFunction: "cubic-bezier(0.4, 0.0, 0.2, 1)"
8977                };
8978                el._x_transition = {
8979                    in(before = () => {}, after = () => {}) {
8980                        if (fullyHide)
8981                            el.hidden = false;
8982                        if (fullyHide)
8983                            el.style.display = null;
8984                        let current = el.getBoundingClientRect().height;
8985                        el.style.height = "auto";
8986                        let full = el.getBoundingClientRect().height;
8987                        if (current === full) {
8988                            current = floor;
8989                        }
8990                        Alpine.transition(el, Alpine.setStyles, {
8991                            during: transitionStyles,
8992                            start: {
8993                                height: current + "px"
8994                            },
8995                            end: {
8996                                height: full + "px"
8997                            }
8998                        }, () => el._x_isShown = true, () => {
8999                            if (Math.abs(el.getBoundingClientRect().height - full) < 1) {
9000                                el.style.overflow = null;
9001                            }
9002                        });
9003                    },
9004                    out(before = () => {}, after = () => {}) {
9005                        let full = el.getBoundingClientRect().height;
9006                        Alpine.transition(el, setFunction, {
9007                            during: transitionStyles,
9008                            start: {
9009                                height: full + "px"
9010                            },
9011                            end: {
9012                                height: floor + "px"
9013                            }
9014                        }, () => el.style.overflow = "hidden", () => {
9015                            el._x_isShown = false;
9016                            if (el.style.height == `${floor}px` && fullyHide) {
9017                                el.style.display = "none";
9018                                el.hidden = true;
9019                            }
9020                        });
9021                    }
9022                };
9023            }
9024        }
9025
9026        function modifierValue(modifiers, key, fallback) {
9027            if (modifiers.indexOf(key) === -1)
9028                return fallback;
9029            const rawValue = modifiers[modifiers.indexOf(key) + 1];
9030            if (!rawValue)
9031                return fallback;
9032            if (key === "duration") {
9033                let match = rawValue.match(/([0-9]+)ms/);
9034                if (match)
9035                    return match[1];
9036            }
9037            if (key === "min") {
9038                let match = rawValue.match(/([0-9]+)px/);
9039                if (match)
9040                    return match[1];
9041            }
9042            return rawValue;
9043        }
9044
9045        // packages/collapse/builds/cdn.js
9046        document.addEventListener("alpine:init", () => {
9047            window.Alpine.plugin(src_default);
9048        });
9049    })();
9050</script>
vendor: 1 bytes, line 9050
9050
9051<script>
9052    function r(n,t){for(var i=0;i<t.length;i++){var r=t[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(n,r.key,r)}}function Jt(n,t,i){t&&r(n.prototype,t),i&&r(n,i),Object.defineProperty(n,"prototype",{writable:!1})}
9053    
vendor: 29,403 bytes, line 9053
9053var n,t;n=this,t=function(){"use strict";var v="(prefers-reduced-motion: reduce)",G=4,rn=5,r={CREATED:1,MOUNTED:2,IDLE:3,MOVING:G,SCROLLING:rn,DRAGGING:6,DESTROYED:7};function D(n){n.length=0}function o(n,t,i){return Array.prototype.slice.call(n,t,i)}function R(n){return n.bind.apply(n,[null].concat(o(arguments,1)))}function on(){}var p=setTimeout;function h(n){return requestAnimationFrame(n)}function u(n,t){return typeof t===n}function un(n){return!c(n)&&u("object",n)}var e=Array.isArray,x=R(u,"function"),C=R(u,"string"),en=R(u,"undefined");function c(n){return null===n}function m(n){try{return n instanceof(n.ownerDocument.defaultView||window).HTMLElement}catch(n){return!1}}function y(n){return e(n)?n:[n]}function g(n,t){y(n).forEach(t)}function b(n,t){return-1<n.indexOf(t)}function k(n,t){return n.push.apply(n,y(t)),n}function A(t,n,i){t&&g(n,function(n){n&&t.classList[i?"add":"remove"](n)})}function M(n,t){A(n,C(t)?t.split(" "):t,!0)}function L(n,t){g(t,n.appendChild.bind(n))}function O(n,i){g(n,function(n){var t=(i||n).parentNode;t&&t.insertBefore(n,i)})}function cn(n,t){return m(n)&&(n.msMatchesSelector||n.matches).call(n,t)}function S(n,t){n=n?o(n.children):[];return t?n.filter(function(n){return cn(n,t)}):n}function fn(n,t){return t?S(n,t)[0]:n.firstElementChild}var E=Object.keys;function w(t,i,n){t&&(n?E(t).reverse():E(t)).forEach(function(n){"__proto__"!==n&&i(t[n],n)})}function an(r){return o(arguments,1).forEach(function(i){w(i,function(n,t){r[t]=i[t]})}),r}function d(i){return o(arguments,1).forEach(function(n){w(n,function(n,t){e(n)?i[t]=n.slice():un(n)?i[t]=d({},un(i[t])?i[t]:{},n):i[t]=n})}),i}function sn(t,n){g(n||E(t),function(n){delete t[n]})}function P(n,i){g(n,function(t){g(i,function(n){t&&t.removeAttribute(n)})})}function I(i,t,r){un(t)?w(t,function(n,t){I(i,t,n)}):g(i,function(n){c(r)||""===r?P(n,t):n.setAttribute(t,String(r))})}function j(n,t,i){n=document.createElement(n);return t&&(C(t)?M:I)(n,t),i&&L(i,n),n}function _(n,t,i){if(en(i))return getComputedStyle(n)[t];c(i)||(n.style[t]=""+i)}function ln(n,t){_(n,"display",t)}function dn(n){n.setActive&&n.setActive()||n.focus({preventScroll:!0})}function z(n,t){return n.getAttribute(t)}function vn(n,t){return n&&n.classList.contains(t)}function N(n){return n.getBoundingClientRect()}function T(n){g(n,function(n){n&&n.parentNode&&n.parentNode.removeChild(n)})}function hn(n){return fn((new DOMParser).parseFromString(n,"text/html").body)}function F(n,t){n.preventDefault(),t&&(n.stopPropagation(),n.stopImmediatePropagation())}function pn(n,t){return n&&n.querySelector(t)}function gn(n,t){return t?o(n.querySelectorAll(t)):[]}function X(n,t){A(n,t,!1)}function mn(n){return n.timeStamp}function W(n){return C(n)?n:n?n+"px":""}var yn="splide",f="data-"+yn;function bn(n,t){if(!n)throw new Error("["+yn+"] "+(t||""))}var Y=Math.min,wn=Math.max,xn=Math.floor,kn=Math.ceil,U=Math.abs;function Sn(n,t,i){return U(n-t)<i}function En(n,t,i,r){var o=Y(t,i),t=wn(t,i);return r?o<n&&n<t:o<=n&&n<=t}function q(n,t,i){var r=Y(t,i),t=wn(t,i);return Y(wn(r,n),t)}function Ln(n){return(0<n)-(n<0)}function On(t,n){return g(n,function(n){t=t.replace("%s",""+n)}),t}function An(n){return n<10?"0"+n:""+n}var _n={};function zn(){var c=[];function i(n,i,r){g(n,function(t){t&&g(i,function(n){n.split(" ").forEach(function(n){n=n.split(".");r(t,n[0],n[1])})})})}return{bind:function(n,t,u,e){i(n,t,function(n,t,i){var r="addEventListener"in n,o=r?n.removeEventListener.bind(n,t,u,e):n.removeListener.bind(n,u);r?n.addEventListener(t,u,e):n.addListener(u),c.push([n,t,i,u,o])})},unbind:function(n,t,o){i(n,t,function(t,i,r){c=c.filter(function(n){return!!(n[0]!==t||n[1]!==i||n[2]!==r||o&&n[3]!==o)||(n[4](),!1)})})},dispatch:function(n,t,i){var r;return"function"==typeof CustomEvent?r=new CustomEvent(t,{bubbles:!0,detail:i}):(r=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!1,i),n.dispatchEvent(r),r},destroy:function(){c.forEach(function(n){n[4]()}),D(c)}}}var B="mounted",H="move",Dn="moved",Mn="click",Pn="active",In="inactive",Rn="visible",Cn="hidden",J="refresh",K="updated",jn="resize",Nn="resized",Tn="scroll",V="scrolled",a="destroy",Gn="navigation:mounted",Fn="autoplay:play",Xn="autoplay:pause",Wn="lazyload:loaded",Yn="sk",Un="sh";function Q(n){var i=n?n.event.bus:document.createDocumentFragment(),r=zn();return n&&n.event.on(a,r.destroy),an(r,{bus:i,on:function(n,t){r.bind(i,y(n).join(" "),function(n){t.apply(t,e(n.detail)?n.detail:[])})},off:R(r.unbind,i),emit:function(n){r.dispatch(i,n,o(arguments,1))}})}function qn(t,n,i,r){var o,u,e=Date.now,c=0,f=!0,a=0;function s(){if(!f){if(c=t?Y((e()-o)/t,1):1,i&&i(c),1<=c&&(n(),o=e(),r&&++a>=r))return l();u=h(s)}}function l(){f=!0}function d(){u&&cancelAnimationFrame(u),f=!(u=c=0)}return{start:function(n){n||d(),o=e()-(n?c*t:0),f=!1,u=h(s)},rewind:function(){o=e(),c=0,i&&i(c)},pause:l,cancel:d,set:function(n){t=n},isPaused:function(){return f}}}function s(n){var t=n;return{set:function(n){t=n},is:function(n){return b(y(n),t)}}}var n="Arrow",Bn=n+"Left",Hn=n+"Right",t=n+"Up",n=n+"Down",Jn="ttb",l={width:["height"],left:["top","right"],right:["bottom","left"],x:["y"],X:["Y"],Y:["X"],ArrowLeft:[t,Hn],ArrowRight:[n,Bn]};var Z="role",$="tabindex",i="aria-",Kn=i+"controls",Vn=i+"current",Qn=i+"selected",nn=i+"label",Zn=i+"labelledby",$n=i+"hidden",nt=i+"orientation",tt=i+"roledescription",it=i+"live",rt=i+"busy",ot=i+"atomic",ut=[Z,$,"disabled",Kn,Vn,nn,Zn,$n,nt,tt],i=yn+"__",et=yn,ct=i+"track",ft=i+"list",at=i+"slide",st=at+"--clone",lt=at+"__container",dt=i+"arrows",vt=i+"arrow",ht=vt+"--prev",pt=vt+"--next",gt=i+"pagination",mt=gt+"__page",yt=i+"progress"+"__bar",bt=i+"toggle",wt=i+"sr",tn="is-active",xt="is-prev",kt="is-next",St="is-visible",Et="is-loading",Lt="is-focus-in",Ot="is-overflow",At=[tn,St,xt,kt,Et,Lt,Ot];var _t="touchstart mousedown",zt="touchmove mousemove",Dt="touchend touchcancel mouseup click";var Mt="slide",Pt="loop",It="fade";function Rt(o,r,t,u){var e,n=Q(o),i=n.on,c=n.emit,f=n.bind,a=o.Components,s=o.root,l=o.options,d=l.isNavigation,v=l.updateOnMove,h=l.i18n,p=l.pagination,g=l.slideFocus,m=a.Direction.resolve,y=z(u,"style"),b=z(u,nn),w=-1<t,x=fn(u,"."+lt);function k(){var n=o.splides.map(function(n){n=n.splide.Components.Slides.getAt(r);return n?n.slide.id:""}).join(" ");I(u,nn,On(h.slideX,(w?t:r)+1)),I(u,Kn,n),I(u,Z,g?"button":""),g&&P(u,tt)}function S(){e||E()}function E(){var n,t,i;e||(n=o.index,(i=L())!==vn(u,tn)&&(A(u,tn,i),I(u,Vn,d&&i||""),c(i?Pn:In,O)),i=function(){if(o.is(It))return L();var n=N(a.Elements.track),t=N(u),i=m("left",!0),r=m("right",!0);return xn(n[i])<=kn(t[i])&&xn(t[r])<=kn(n[r])}(),t=!i&&(!L()||w),o.state.is([G,rn])||I(u,$n,t||""),I(gn(u,l.focusableNodes||""),$,t?-1:""),g&&I(u,$,t?-1:0),i!==vn(u,St)&&(A(u,St,i),c(i?Rn:Cn,O)),i||document.activeElement!==u||(t=a.Slides.getAt(o.index))&&dn(t.slide),A(u,xt,r===n-1),A(u,kt,r===n+1))}function L(){var n=o.index;return n===r||l.cloneStatus&&n===t}var O={index:r,slideIndex:t,slide:u,container:x,isClone:w,mount:function(){w||(u.id=s.id+"-slide"+An(r+1),I(u,Z,p?"tabpanel":"group"),I(u,tt,h.slide),I(u,nn,b||On(h.slideLabel,[r+1,o.length]))),f(u,"click",R(c,Mn,O)),f(u,"keydown",R(c,Yn,O)),i([Dn,Un,V],E),i(Gn,k),v&&i(H,S)},destroy:function(){e=!0,n.destroy(),X(u,At),P(u,ut),I(u,"style",y),I(u,nn,b||"")},update:E,style:function(n,t,i){_(i&&x||u,n,t)},isWithin:function(n,t){return n=U(n-r),(n=w||!l.rewind&&!o.is(Pt)?n:Y(n,o.length-n))<=t}};return O}var Ct=f+"-interval";var jt={passive:!1,capture:!0};var Nt={Spacebar:" ",Right:Hn,Left:Bn,Up:t,Down:n};function Tt(n){return n=C(n)?n:n.key,Nt[n]||n}var Gt="keydown";var Ft=f+"-lazy",Xt=Ft+"-srcset",Wt="["+Ft+"], ["+Xt+"]";var Yt=[" ","Enter"];var Ut=Object.freeze({__proto__:null,Media:function(r,n,o){var u=r.state,t=o.breakpoints||{},e=o.reducedMotion||{},i=zn(),c=[];function f(n){n&&i.destroy()}function a(n,t){t=matchMedia(t);i.bind(t,"change",s),c.push([n,t])}function s(){var n=u.is(7),t=o.direction,i=c.reduce(function(n,t){return d(n,t[1].matches?t[0]:{})},{});sn(o),l(i),o.destroy?r.destroy("completely"===o.destroy):n?(f(!0),r.mount()):t!==o.direction&&r.refresh()}function l(n,t,i){d(o,n),t&&d(Object.getPrototypeOf(o),n),!i&&u.is(1)||r.emit(K,o)}return{setup:function(){var i="min"===o.mediaQuery;E(t).sort(function(n,t){return i?+n-+t:+t-+n}).forEach(function(n){a(t[n],"("+(i?"min":"max")+"-width:"+n+"px)")}),a(e,v),s()},destroy:f,reduce:function(n){matchMedia(v).matches&&(n?d(o,e):sn(o,E(e)))},set:l}},Direction:function(n,t,o){return{resolve:function(n,t,i){var r="rtl"!==(i=i||o.direction)||t?i===Jn?0:-1:1;return l[n]&&l[n][r]||n.replace(/width|left|right/i,function(n,t){n=l[n.toLowerCase()][r]||n;return 0<t?n.charAt(0).toUpperCase()+n.slice(1):n})},orient:function(n){return n*("rtl"===o.direction?1:-1)}}},Elements:function(n,t,i){var r,o,u,e=Q(n),c=e.on,f=e.bind,a=n.root,s=i.i18n,l={},d=[],v=[],h=[];function p(){r=y("."+ct),o=fn(r,"."+ft),bn(r&&o,"A track/list element is missing."),k(d,S(o,"."+at+":not(."+st+")")),w({arrows:dt,pagination:gt,prev:ht,next:pt,bar:yt,toggle:bt},function(n,t){l[t]=y("."+n)}),an(l,{root:a,track:r,list:o,slides:d});var n=a.id||function(n){return""+n+An(_n[n]=(_n[n]||0)+1)}(yn),t=i.role;a.id=n,r.id=r.id||n+"-track",o.id=o.id||n+"-list",!z(a,Z)&&"SECTION"!==a.tagName&&t&&I(a,Z,t),I(a,tt,s.carousel),I(o,Z,"presentation"),m()}function g(n){var t=ut.concat("style");D(d),X(a,v),X(r,h),P([r,o],t),P(a,n?t:["style",tt])}function m(){X(a,v),X(r,h),v=b(et),h=b(ct),M(a,v),M(r,h),I(a,nn,i.label),I(a,Zn,i.labelledby)}function y(n){n=pn(a,n);return n&&function(n,t){if(x(n.closest))return n.closest(t);for(var i=n;i&&1===i.nodeType&&!cn(i,t);)i=i.parentElement;return i}(n,"."+et)===a?n:void 0}function b(n){return[n+"--"+i.type,n+"--"+i.direction,i.drag&&n+"--draggable",i.isNavigation&&n+"--nav",n===et&&tn]}return an(l,{setup:p,mount:function(){c(J,g),c(J,p),c(K,m),f(document,_t+" keydown",function(n){u="keydown"===n.type},{capture:!0}),f(a,"focusin",function(){A(a,Lt,!!u)})},destroy:g})},Slides:function(r,o,u){var n=Q(r),t=n.on,e=n.emit,c=n.bind,f=(n=o.Elements).slides,a=n.list,s=[];function i(){f.forEach(function(n,t){d(n,t,-1)})}function l(){h(function(n){n.destroy()}),D(s)}function d(n,t,i){t=Rt(r,t,i,n);t.mount(),s.push(t),s.sort(function(n,t){return n.index-t.index})}function v(n){return n?p(function(n){return!n.isClone}):s}function h(n,t){v(t).forEach(n)}function p(t){return s.filter(x(t)?t:function(n){return C(t)?cn(n.slide,t):b(y(t),n.index)})}return{mount:function(){i(),t(J,l),t(J,i)},destroy:l,update:function(){h(function(n){n.update()})},register:d,get:v,getIn:function(n){var t=o.Controller,i=t.toIndex(n),r=t.hasFocus()?1:u.perPage;return p(function(n){return En(n.index,i,i+r-1)})},getAt:function(n){return p(n)[0]},add:function(n,o){g(n,function(n){var t,i,r;m(n=C(n)?hn(n):n)&&((t=f[o])?O(n,t):L(a,n),M(n,u.classes.slide),t=n,i=R(e,jn),t=gn(t,"img"),(r=t.length)?t.forEach(function(n){c(n,"load error",function(){--r||i()})}):i())}),e(J)},remove:function(n){T(p(n).map(function(n){return n.slide})),e(J)},forEach:h,filter:p,style:function(t,i,r){h(function(n){n.style(t,i,r)})},getLength:function(n){return(n?f:s).length},isEnough:function(){return s.length>u.perPage}}},Layout:function(t,n,i){var r,o,u,e=(a=Q(t)).on,c=a.bind,f=a.emit,a=n.Slides,s=n.Direction.resolve,l=(n=n.Elements).root,d=n.track,v=n.list,h=a.getAt,p=a.style;function g(){r=i.direction===Jn,_(l,"maxWidth",W(i.width)),_(d,s("paddingLeft"),y(!1)),_(d,s("paddingRight"),y(!0)),m(!0)}function m(n){var t=N(l);!n&&o.width===t.width&&o.height===t.height||(_(d,"height",function(){var n="";r&&(bn(n=b(),"height or heightRatio is missing."),n="calc("+n+" - "+y(!1)+" - "+y(!0)+")");return n}()),p(s("marginRight"),W(i.gap)),p("width",i.autoWidth?null:W(i.fixedWidth)||(r?"":w())),p("height",W(i.fixedHeight)||(r?i.autoHeight?null:w():b()),!0),o=t,f(Nn),u!==(u=O())&&(A(l,Ot,u),f("overflow",u)))}function y(n){var t=i.padding,n=s(n?"right":"left");return t&&W(t[n]||(un(t)?0:t))||"0px"}function b(){return W(i.height||N(v).width*i.heightRatio)}function w(){var n=W(i.gap);return"calc((100%"+(n&&" + "+n)+")/"+(i.perPage||1)+(n&&" - "+n)+")"}function x(){return N(v)[s("width")]}function k(n,t){n=h(n||0);return n?N(n.slide)[s("width")]+(t?0:L()):0}function S(n,t){var i,n=h(n);return n?(n=N(n.slide)[s("right")],i=N(v)[s("left")],U(n-i)+(t?0:L())):0}function E(n){return S(t.length-1)-S(0)+k(0,n)}function L(){var n=h(0);return n&&parseFloat(_(n.slide,s("marginRight")))||0}function O(){return t.is(It)||E(!0)>x()}return{mount:function(){var n,t,i;g(),c(window,"resize load",(n=R(f,jn),i=qn(t||0,n,null,1),function(){i.isPaused()&&i.start()})),e([K,J],g),e(jn,m)},resize:m,listSize:x,slideSize:k,sliderSize:E,totalSize:S,getPadding:function(n){return parseFloat(_(d,s("padding"+(n?"Right":"Left"))))||0},isOverflow:O}},Clones:function(c,i,f){var t,r=Q(c),n=r.on,a=i.Elements,s=i.Slides,o=i.Direction.resolve,l=[];function u(){if(n(J,d),n([K,jn],v),t=h()){var o=t,u=s.get().slice(),e=u.length;if(e){for(;u.length<o;)k(u,u);k(u.slice(-o),u.slice(0,o)).forEach(function(n,t){var i=t<o,r=function(n,t){n=n.cloneNode(!0);return M(n,f.classes.clone),n.id=c.root.id+"-clone"+An(t+1),n}(n.slide,t);i?O(r,u[0].slide):L(a.list,r),k(l,r),s.register(r,t-o+(i?0:e),n.index)})}i.Layout.resize(!0)}}function d(){e(),u()}function e(){T(l),D(l),r.destroy()}function v(){var n=h();t!==n&&(t<n||!n)&&r.emit(J)}function h(){var n,t=f.clones;return c.is(Pt)?en(t)&&(t=(n=f[o("fixedWidth")]&&i.Layout.slideSize(0))&&kn(N(a.track)[o("width")]/n)||f[o("autoWidth")]&&c.length||2*f.perPage):t=0,t}return{mount:u,destroy:e}},Move:function(r,c,o){var e,n=Q(r),t=n.on,f=n.emit,a=r.state.set,u=(n=c.Layout).slideSize,i=n.getPadding,s=n.totalSize,l=n.listSize,d=n.sliderSize,v=(n=c.Direction).resolve,h=n.orient,p=(n=c.Elements).list,g=n.track;function m(){c.Controller.isBusy()||(c.Scroll.cancel(),y(r.index),c.Slides.update())}function y(n){b(S(n,!0))}function b(n,t){r.is(It)||(t=t?n:function(n){{var t,i;r.is(Pt)&&(t=k(n),i=t>c.Controller.getEnd(),(t<0||i)&&(n=w(n,i)))}return n}(n),_(p,"transform","translate"+v("X")+"("+t+"px)"),n!==t&&f(Un))}function w(n,t){var i=n-L(t),r=d();return n-=h(r*(kn(U(i)/r)||1))*(t?1:-1)}function x(){b(E(),!0),e.cancel()}function k(n){for(var t=c.Slides.get(),i=0,r=1/0,o=0;o<t.length;o++){var u=t[o].index,e=U(S(u,!0)-n);if(!(e<=r))break;r=e,i=u}return i}function S(n,t){var i=h(s(n-1)-(n=n,"center"===(i=o.focus)?(l()-u(n,!0))/2:+i*u(n)||0));return t?(n=i,n=o.trimSpace&&r.is(Mt)?q(n,0,h(d(!0)-l())):n):i}function E(){var n=v("left");return N(p)[n]-N(g)[n]+h(i(!1))}function L(n){return S(n?c.Controller.getEnd():0,!!o.trimSpace)}return{mount:function(){e=c.Transition,t([B,Nn,K,J],m)},move:function(n,t,i,r){var o,u;n!==t&&(o=i<n,u=h(w(E(),o)),o?0<=u:u<=p[v("scrollWidth")]-N(g)[v("width")])&&(x(),b(w(E(),i<n),!0)),a(G),f(H,t,i,n),e.start(t,function(){a(3),f(Dn,t,i,n),r&&r()})},jump:y,translate:b,shift:w,cancel:x,toIndex:k,toPosition:S,getPosition:E,getLimit:L,exceededLimit:function(n,t){t=en(t)?E():t;var i=!0!==n&&h(t)<h(L(!1)),n=!1!==n&&h(t)>h(L(!0));return i||n},reposition:m}},Controller:function(o,u,e){var c,f,a,s,n=Q(o),t=n.on,i=n.emit,l=u.Move,d=l.getPosition,r=l.getLimit,v=l.toPosition,h=(n=u.Slides).isEnough,p=n.getLength,g=e.omitEnd,m=o.is(Pt),y=o.is(Mt),b=R(L,!1),w=R(L,!0),x=e.start||0,k=x;function S(){f=p(!0),a=e.perMove,s=e.perPage,c=_();var n=q(x,0,g?c:f-1);n!==x&&(x=n,l.reposition())}function E(){c!==_()&&i("ei")}function L(n,t){var i=a||(P()?1:s),i=O(x+i*(n?-1:1),x,!(a||P()));return-1===i&&y&&!Sn(d(),r(!n),1)?n?0:c:t?i:A(i)}function O(n,t,i){var r;return h()||P()?((r=function(n){if(y&&"move"===e.trimSpace&&n!==x)for(var t=d();t===v(n,!0)&&En(n,0,o.length-1,!e.rewind);)n<x?--n:++n;return n}(n))!==n&&(t=n,n=r,i=!1),n<0||c<n?n=a||!En(0,n,t,!0)&&!En(c,t,n,!0)?m?i?n<0?-(f%s||s):f:n:e.rewind?n<0?c:0:-1:z(D(n)):i&&n!==t&&(n=z(D(t)+(n<t?-1:1)))):n=-1,n}function A(n){return m?(n+f)%f||0:n}function _(){for(var n=f-(P()||m&&a?1:s);g&&0<n--;)if(v(f-1,!0)!==v(n,!0)){n++;break}return q(n,0,f-1)}function z(n){return q(P()?n:s*n,0,c)}function D(n){return P()?Y(n,c):xn((c<=n?f-1:n)/s)}function M(n){n!==x&&(k=x,x=n)}function P(){return!en(e.focus)||e.isNavigation}function I(){return o.state.is([G,rn])&&!!e.waitForTransition}return{mount:function(){S(),t([K,J,"ei"],S),t(Nn,E)},go:function(n,t,i){var r;I()||-1<(r=A(n=function(n){var t=x;{var i,r;C(n)?(r=n.match(/([+\-<>])(\d+)?/)||[],i=r[1],r=r[2],"+"===i||"-"===i?t=O(x+ +(""+i+(+r||1)),x):">"===i?t=r?z(+r):b(!0):"<"===i&&(t=w(!0))):t=m?n:q(n,0,c)}return t}(n)))&&(t||r!==x)&&(M(r),l.move(n,r,k,i))},scroll:function(n,t,i,r){u.Scroll.scroll(n,t,i,function(){var n=A(l.toIndex(d()));M(g?Y(n,c):n),r&&r()})},getNext:b,getPrev:w,getAdjacent:L,getEnd:_,setIndex:M,getIndex:function(n){return n?k:x},toIndex:z,toPage:D,toDest:function(n){return n=l.toIndex(n),y?q(n,0,c):n},hasFocus:P,isBusy:I}},Arrows:function(o,n,t){var i,r,u=Q(o),e=u.on,c=u.bind,f=u.emit,a=t.classes,s=t.i18n,l=n.Elements,d=n.Controller,v=l.arrows,h=l.track,p=v,g=l.prev,m=l.next,y={};function b(){var n=t.arrows;!n||g&&m||(p=v||j("div",a.arrows),g=S(!0),m=S(!1),i=!0,L(p,[g,m]),v||O(p,h)),g&&m&&(an(y,{prev:g,next:m}),ln(p,n?"":"none"),M(p,r=dt+"--"+t.direction),n&&(e([B,Dn,J,V,"ei"],E),c(m,"click",R(k,">")),c(g,"click",R(k,"<")),E(),I([g,m],Kn,h.id),f("arrows:mounted",g,m))),e(K,w)}function w(){x(),b()}function x(){u.destroy(),X(p,r),i?(T(v?[g,m]:p),g=m=null):P([g,m],ut)}function k(n){d.go(n,!0)}function S(n){return hn('<button class="'+a.arrow+" "+(n?a.prev:a.next)+'" type="button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40" height="40" focusable="false"><path d="'+(t.arrowPath||"m15.5 0.932-4.3 4.38 14.5 14.6-14.5 14.5 4.3 4.4 14.6-14.6 4.4-4.3-4.4-4.4-14.6-14.6z")+'" />')}function E(){var n,t,i,r;g&&m&&(r=o.index,n=d.getPrev(),t=d.getNext(),i=-1<n&&r<n?s.last:s.prev,r=-1<t&&t<r?s.first:s.next,g.disabled=n<0,m.disabled=t<0,I(g,nn,i),I(m,nn,r),f("arrows:updated",g,m,n,t))}return{arrows:y,mount:b,destroy:x,update:E}},Autoplay:function(n,t,i){var r,o,u=Q(n),e=u.on,c=u.bind,f=u.emit,a=qn(i.interval,n.go.bind(n,">"),function(n){var t=l.bar;t&&_(t,"width",100*n+"%"),f("autoplay:playing",n)}),s=a.isPaused,l=t.Elements,d=(u=t.Elements).root,v=u.toggle,h=i.autoplay,p="pause"===h;function g(){s()&&t.Slides.isEnough()&&(a.start(!i.resetProgress),o=r=p=!1,b(),f(Fn))}function m(n){p=!!(n=void 0===n?!0:n),b(),s()||(a.pause(),f(Xn))}function y(){p||(r||o?m(!1):g())}function b(){v&&(A(v,tn,!p),I(v,nn,i.i18n[p?"play":"pause"]))}function w(n){n=t.Slides.getAt(n);a.set(n&&+z(n.slide,Ct)||i.interval)}return{mount:function(){h&&(i.pauseOnHover&&c(d,"mouseenter mouseleave",function(n){r="mouseenter"===n.type,y()}),i.pauseOnFocus&&c(d,"focusin focusout",function(n){o="focusin"===n.type,y()}),v&&c(v,"click",function(){p?g():m(!0)}),e([H,Tn,J],a.rewind),e(H,w),v&&I(v,Kn,l.track.id),p||g(),b())},destroy:a.cancel,play:g,pause:m,isPaused:s}},Cover:function(n,t,i){var r=Q(n).on;function o(i){t.Slides.forEach(function(n){var t=fn(n.container||n.slide,"img");t&&t.src&&u(i,t,n)})}function u(n,t,i){i.style("background",n?'center/cover no-repeat url("'+t.src+'")':"",!0),ln(t,n?"none":"")}return{mount:function(){i.cover&&(r(Wn,R(u,!0)),r([B,K,J],R(o,!0)))},destroy:R(o,!1)}},Scroll:function(n,c,u){var f,a,t=Q(n),i=t.on,s=t.emit,l=n.state.set,d=c.Move,v=d.getPosition,e=d.getLimit,h=d.exceededLimit,p=d.translate,g=n.is(Mt),m=1;function y(n,t,i,r,o){var u,e=v(),i=(x(),!i||g&&h()||(i=c.Layout.sliderSize(),u=Ln(n)*i*xn(U(n)/i)||0,n=d.toPosition(c.Controller.toDest(n%i))+u),Sn(e,n,1));m=1,t=i?0:t||wn(U(n-e)/1.5,800),a=r,f=qn(t,b,R(w,e,n,o),1),l(rn),s(Tn),f.start()}function b(){l(3),a&&a(),s(V)}function w(n,t,i,r){var o=v(),r=(n+(t-n)*(t=r,(n=u.easingFunc)?n(t):1-Math.pow(1-t,4))-o)*m;p(o+r),g&&!i&&h()&&(m*=.6,U(r)<10&&y(e(h(!0)),600,!1,a,!0))}function x(){f&&f.cancel()}function r(){f&&!f.isPaused()&&(x(),b())}return{mount:function(){i(H,x),i([K,J],r)},destroy:x,scroll:y,cancel:r}},Drag:function(e,o,c){var f,t,u,a,s,l,d,v,n=Q(e),i=n.on,h=n.emit,p=n.bind,g=n.unbind,m=e.state,y=o.Move,b=o.Scroll,w=o.Controller,x=o.Elements.track,k=o.Media.reduce,r=(n=o.Direction).resolve,S=n.orient,E=y.getPosition,L=y.exceededLimit,O=!1;function j(){var n=c.drag;C(!n),a="free"===n}function N(n){var t,i,r;l=!1,d||(t=R(n),i=n.target,r=c.noDrag,cn(i,"."+mt+", ."+vt)||r&&cn(i,r)||!t&&n.button||(w.isBusy()?F(n,!0):(v=t?x:window,s=m.is([G,rn]),u=null,p(v,zt,A,jt),p(v,Dt,_,jt),y.cancel(),b.cancel(),z(n))))}function A(n){var t,i,r,o,u;m.is(6)||(m.set(6),h("drag")),n.cancelable&&(s?(y.translate(f+D(n)/(O&&e.is(Mt)?5:1)),u=200<M(n),t=O!==(O=L()),(u||t)&&z(n),l=!0,h("dragging"),F(n)):U(D(u=n))>U(D(u,!0))&&(t=n,i=c.dragMinThreshold,r=un(i),o=r&&i.mouse||0,r=(r?i.touch:+i)||10,s=U(D(t))>(R(t)?r:o),F(n)))}function _(n){var t,i,r;m.is(6)&&(m.set(3),h("dragged")),s&&(i=function(n){return E()+Ln(n)*Y(U(n)*(c.flickPower||600),a?1/0:o.Layout.listSize()*(c.flickMaxPages||1))}(t=function(n){if(e.is(Pt)||!O){var t=M(n);if(t&&t<200)return D(n)/t}return 0}(t=n)),r=c.rewind&&c.rewindByDrag,k(!1),a?w.scroll(i,0,c.snap):e.is(It)?w.go(S(Ln(t))<0?r?"<":"-":r?">":"+"):e.is(Mt)&&O&&r?w.go(L(!0)?">":"<"):w.go(w.toDest(i),!0),k(!0),F(n)),g(v,zt,A),g(v,Dt,_),s=!1}function T(n){!d&&l&&F(n,!0)}function z(n){u=t,t=n,f=E()}function D(n,t){return I(n,t)-I(P(n),t)}function M(n){return mn(n)-mn(P(n))}function P(n){return t===n&&u||t}function I(n,t){return(R(n)?n.changedTouches[0]:n)["page"+r(t?"Y":"X")]}function R(n){return"undefined"!=typeof TouchEvent&&n instanceof TouchEvent}function C(n){d=n}return{mount:function(){p(x,zt,on,jt),p(x,Dt,on,jt),p(x,_t,N,jt),p(x,"click",T,{capture:!0}),p(x,"dragstart",F),i([B,K],j)},disable:C,isDragging:function(){return s}}},Keyboard:function(t,n,i){var r,o,u=Q(t),e=u.on,c=u.bind,f=u.unbind,a=t.root,s=n.Direction.resolve;function l(){var n=i.keyboard;n&&(r="global"===n?window:a,c(r,Gt,h))}function d(){f(r,Gt)}function v(){var n=o;o=!0,p(function(){o=n})}function h(n){o||((n=Tt(n))===s(Bn)?t.go("<"):n===s(Hn)&&t.go(">"))}return{mount:function(){l(),e(K,d),e(K,l),e(H,v)},destroy:d,disable:function(n){o=n}}},LazyLoad:function(i,n,o){var t=Q(i),r=t.on,u=t.off,e=t.bind,c=t.emit,f="sequential"===o.lazyLoad,a=[Dn,V],s=[];function l(){D(s),n.Slides.forEach(function(r){gn(r.slide,Wt).forEach(function(n){var t=z(n,Ft),i=z(n,Xt);t===n.src&&i===n.srcset||(t=o.classes.spinner,t=fn(i=n.parentElement,"."+t)||j("span",t,i),s.push([n,r,t]),n.src||ln(n,"none"))})}),(f?p:(u(a),r(a,d),d))()}function d(){(s=s.filter(function(n){var t=o.perPage*((o.preloadPages||1)+1)-1;return!n[1].isWithin(i.index,t)||v(n)})).length||u(a)}function v(n){var t=n[0];M(n[1].slide,Et),e(t,"load error",R(h,n)),I(t,"src",z(t,Ft)),I(t,"srcset",z(t,Xt)),P(t,Ft),P(t,Xt)}function h(n,t){var i=n[0],r=n[1];X(r.slide,Et),"error"!==t.type&&(T(n[2]),ln(i,""),c(Wn,i,r),c(jn)),f&&p()}function p(){s.length&&v(s.shift())}return{mount:function(){o.lazyLoad&&(l(),r(J,l))},destroy:R(D,s),check:d}},Pagination:function(l,n,d){var v,h,t=Q(l),p=t.on,g=t.emit,m=t.bind,y=n.Slides,b=n.Elements,w=n.Controller,x=w.hasFocus,r=w.getIndex,e=w.go,c=n.Direction.resolve,k=b.pagination,S=[];function E(){v&&(T(k?o(v.children):v),X(v,h),D(S),v=null),t.destroy()}function L(n){e(">"+n,!0)}function O(n,t){var i=S.length,r=Tt(t),o=A(),u=-1,o=(r===c(Hn,!1,o)?u=++n%i:r===c(Bn,!1,o)?u=(--n+i)%i:"Home"===r?u=0:"End"===r&&(u=i-1),S[u]);o&&(dn(o.button),e(">"+u),F(t,!0))}function A(){return d.paginationDirection||d.direction}function _(n){return S[w.toPage(n)]}function z(){var n,t=_(r(!0)),i=_(r());t&&(X(n=t.button,tn),P(n,Qn),I(n,$,-1)),i&&(M(n=i.button,tn),I(n,Qn,!0),I(n,$,"")),g("pagination:updated",{list:v,items:S},t,i)}return{items:S,mount:function n(){E(),p([K,J,"ei"],n);var t=d.pagination;if(k&&ln(k,t?"":"none"),t){p([H,Tn,V],z);var t=l.length,i=d.classes,r=d.i18n,o=d.perPage,u=x()?w.getEnd()+1:kn(t/o);M(v=k||j("ul",i.pagination,b.track.parentElement),h=gt+"--"+A()),I(v,Z,"tablist"),I(v,nn,r.select),I(v,nt,A()===Jn?"vertical":"");for(var e=0;e<u;e++){var c=j("li",null,v),f=j("button",{class:i.page,type:"button"},c),a=y.getIn(e).map(function(n){return n.slide.id}),s=!x()&&1<o?r.pageX:r.slideX;m(f,"click",R(L,e)),d.paginationKeyboard&&m(f,"keydown",R(O,e)),I(c,Z,"presentation"),I(f,Z,"tab"),I(f,Kn,a.join(" ")),I(f,nn,On(s,e+1)),I(f,$,-1),S.push({li:c,button:f,page:e})}z(),g("pagination:mounted",{list:v,items:S},_(l.index))}},destroy:E,getAt:_,update:z}},Sync:function(i,n,t){var r=t.isNavigation,o=t.slideFocus,u=[];function e(){var n,t;i.splides.forEach(function(n){n.isParent||(f(i,n.splide),f(n.splide,i))}),r&&(n=Q(i),(t=n.on)(Mn,s),t(Yn,l),t([B,K],a),u.push(n),n.emit(Gn,i.splides))}function c(){u.forEach(function(n){n.destroy()}),D(u)}function f(n,r){n=Q(n);n.on(H,function(n,t,i){r.go(r.is(Pt)?i:n)}),u.push(n)}function a(){I(n.Elements.list,nt,t.direction===Jn?"vertical":"")}function s(n){i.go(n.index)}function l(n,t){b(Yt,Tt(t))&&(s(n),F(t))}return{setup:R(n.Media.set,{slideFocus:en(o)?r:o},!0),mount:e,destroy:c,remount:function(){c(),e()}}},Wheel:function(e,c,f){var n=Q(e).bind,a=0;function t(n){var t,i,r,o,u;n.cancelable&&(t=(u=n.deltaY)<0,i=mn(n),r=f.wheelMinThreshold||0,o=f.wheelSleep||0,U(u)>r&&o<i-a&&(e.go(t?"<":">"),a=i),u=t,f.releaseWheel&&!e.state.is(G)&&-1===c.Controller.getAdjacent(u)||F(n))}return{mount:function(){f.wheel&&n(c.Elements.track,"wheel",t,jt)}}},Live:function(n,t,i){var r=Q(n).on,o=t.Elements.track,u=i.live&&!i.isNavigation,e=j("span",wt),c=qn(90,R(f,!1));function f(n){I(o,rt,n),n?(L(o,e),c.start()):(T(e),c.cancel())}function a(n){u&&I(o,it,n?"off":"polite")}return{mount:function(){u&&(a(!t.Autoplay.isPaused()),I(o,ot,!0),e.textContent="…",r(Fn,R(a,!0)),r(Xn,R(a,!1)),r([Dn,V],R(f,!0)))},disable:a,destroy:function(){P(o,[it,ot,rt]),T(e)}}}}),qt={type:"slide",role:"region",speed:400,perPage:1,cloneStatus:!0,arrows:!0,pagination:!0,paginationKeyboard:!0,interval:5e3,pauseOnHover:!0,pauseOnFocus:!0,resetProgress:!0,easing:"cubic-bezier(0.25, 1, 0.5, 1)",drag:!0,direction:"ltr",trimSpace:!0,focusableNodes:"a, button, textarea, input, select, iframe",live:!0,classes:{slide:at,clone:st,arrows:dt,arrow:vt,prev:ht,next:pt,pagination:gt,page:mt,spinner:i+"spinner"},i18n:{prev:"Previous slide",next:"Next slide",first:"Go to first slide",last:"Go to last slide",slideX:"Go to slide %s",pageX:"Go to page %s",play:"Start autoplay",pause:"Pause autoplay",carousel:"carousel",slide:"slide",select:"Select a slide to show",slideLabel:"%s of %s"},reducedMotion:{speed:0,rewindSpeed:0,autoplay:"pause"}};function Bt(n,t,i){var r=t.Slides;function o(){r.forEach(function(n){n.style("transform","translateX(-"+100*n.index+"%)")})}return{mount:function(){Q(n).on([B,J],o)},start:function(n,t){r.style("transition","opacity "+i.speed+"ms "+i.easing),p(t)},cancel:on}}function Ht(u,n,e){var c,f=n.Move,a=n.Controller,s=n.Scroll,t=n.Elements.list,l=R(_,t,"transition");function i(){l(""),s.cancel()}return{mount:function(){Q(u).bind(t,"transitionend",function(n){n.target===t&&c&&(i(),c())})},start:function(n,t){var i=f.toPosition(n,!0),r=f.getPosition(),o=function(n){var t=e.rewindSpeed;if(u.is(Mt)&&t){var i=a.getIndex(!0),r=a.getEnd();if(0===i&&r<=n||r<=i&&0===n)return t}return e.speed}(n);1<=U(i-r)&&1<=o?e.useScroll?s.scroll(i,o,!1,t):(l("transform "+o+"ms "+e.easing),f.translate(i,!0),c=t):(f.jump(n),t())},cancel:i}}t=function(){function i(n,t){this.event=Q(),this.Components={},this.state=s(1),this.splides=[],this.n={},this.t={};n=C(n)?pn(document,n):n;bn(n,n+" is invalid."),t=d({label:z(this.root=n,nn)||"",labelledby:z(n,Zn)||""},qt,i.defaults,t||{});try{d(t,JSON.parse(z(n,f)))}catch(n){bn(!1,"Invalid JSON")}this.n=Object.create(d({},t))}var n=i.prototype;return n.mount=function(n,t){var i=this,r=this.state,o=this.Components;return bn(r.is([1,7]),"Already mounted!"),r.set(1),this.i=o,this.r=t||this.r||(this.is(It)?Bt:Ht),this.t=n||this.t,w(an({},Ut,this.t,{Transition:this.r}),function(n,t){n=n(i,o,i.n);(o[t]=n).setup&&n.setup()}),w(o,function(n){n.mount&&n.mount()}),this.emit(B),M(this.root,"is-initialized"),r.set(3),this.emit("ready"),this},n.sync=function(n){return this.splides.push({splide:n}),n.splides.push({splide:this,isParent:!0}),this.state.is(3)&&(this.i.Sync.remount(),n.Components.Sync.remount()),this},n.go=function(n){return this.i.Controller.go(n),this},n.on=function(n,t){return this.event.on(n,t),this},n.off=function(n){return this.event.off(n),this},n.emit=function(n){var t;return(t=this.event).emit.apply(t,[n].concat(o(arguments,1))),this},n.add=function(n,t){return this.i.Slides.add(n,t),this},n.remove=function(n){return this.i.Slides.remove(n),this},n.is=function(n){return this.n.type===n},n.refresh=function(){return this.emit(J),this},n.destroy=function(t){void 0===t&&(t=!0);var n=this.event,i=this.state;return i.is(1)?Q(this).on("ready",this.destroy.bind(this,t)):(w(this.i,function(n){n.destroy&&n.destroy(t)},!0),n.emit(a),n.destroy(),t&&D(this.splides),i.set(7)),this},Jt(i,[{key:"options",get:function(){return this.n},set:function(n){this.i.Media.set(n,!0,!0)}},{key:"length",get:function(){return this.i.Slides.getLength(!0)}},{key:"index",get:function(){return this.i.Controller.getIndex()}}]),i}();return t.defaults={},t.STATES=r,t},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n="undefined"!=typeof globalThis?globalThis:n||self).Splide=t();
9054</script>
vendor: 1 bytes, line 9054
9054
9055<script>
9056    function initCustomSelect() {
9057        const selects = document.querySelectorAll("select");
9058        
9059        selects.forEach((selElmnt) => {
9060            // Check if already initialized or if wrapper already exists
9061            if (selElmnt.dataset.customSelectInit) return;
9062            if (!selElmnt.options.length || getComputedStyle(selElmnt).display === 'none') return;
9063            
9064            // Check if wrapper already exists to prevent double-wrapping
9065            if (selElmnt.parentNode && selElmnt.parentNode.classList.contains('custom-select-wrapper')) return;
9066            
9067            selElmnt.dataset.customSelectInit = true;
9068
9069            const wrapper = document.createElement("DIV");
9070            wrapper.setAttribute("class", "custom-select-wrapper");
9071            selElmnt.classList.forEach(cls => {
9072                wrapper.classList.add(cls);
9073            });
9074            selElmnt.parentNode.insertBefore(wrapper, selElmnt);
9075            
9076            const selected = document.createElement("DIV");
9077            selected.setAttribute("class", "select-selected");
9078            wrapper.appendChild(selected);
9079            
9080            const itemsBox = document.createElement("DIV");
9081            itemsBox.setAttribute("class", "select-items select-hide");
9082            wrapper.appendChild(itemsBox);
9083            wrapper.appendChild(selElmnt);
9084
9085            function updateDropdown() {
9086                selected.innerHTML = selElmnt.options[selElmnt.selectedIndex].innerHTML;
9087                itemsBox.innerHTML = '';
9088                
9089                for (let j = 0; j < selElmnt.length; j++) {
9090                    const item = document.createElement("DIV");
9091                    item.innerHTML = selElmnt.options[j].innerHTML;
9092                    
9093                    if (j === selElmnt.selectedIndex) {
9094                        item.setAttribute("class", "same-as-selected");
9095                    }
9096                    
9097                    item.addEventListener("click", function(e) {
9098                        e.stopPropagation();
9099                        selElmnt.selectedIndex = j;
9100                        selElmnt.dispatchEvent(new Event('change', { bubbles: true }));
9101                        updateDropdown();
9102                        selected.classList.remove("select-arrow-active");
9103                        itemsBox.classList.add("select-hide");
9104                    });
9105                    
9106                    itemsBox.appendChild(item);
9107                }
9108            }
9109
9110            updateDropdown();
9111            
9112            selected.addEventListener("click", function(e) {
9113                e.stopPropagation();
9114                closeAllSelects(selected);
9115                itemsBox.classList.toggle("select-hide");
9116                selected.classList.toggle("select-arrow-active");
9117            });
9118
9119            // Sync change
9120            selElmnt.addEventListener('change', () => {
9121                updateDropdown();
9122                selected.classList.remove('error');
9123                const errorMsg = wrapper.querySelector('.mage-error');
9124                if (errorMsg) errorMsg.remove();
9125            });
9126
9127            // Native invalid event (triggers Magento's validation message)
9128            selElmnt.addEventListener('invalid', () => {
9129                selected.classList.add('error');
9130
9131                // Only show message if it doesn’t exist already
9132                if (!wrapper.querySelector('.mage-error')) {
9133                    const msg = document.createElement('div');
9134                    msg.classList.add('mage-error');
9135                    msg.textContent = 'This is a required field.'; // same as Magento core
9136                    wrapper.appendChild(msg);
9137                }
9138            });
9139
9140            const observer = new MutationObserver(updateDropdown);
9141            observer.observe(selElmnt, { childList: true });
9142        });
9143
9144        function closeAllSelects(except) {
9145            document.querySelectorAll(".select-selected").forEach(sel => {
9146                if (sel !== except) {
9147                    sel.classList.remove("select-arrow-active");
9148                    sel.nextSibling.classList.add("select-hide");
9149                }
9150            });
9151        }
9152
9153        // Global click handler that only closes dropdowns when clicking outside
9154        if (!document._customSelectClickHandlerAdded) {
9155            document.addEventListener("click", function(e) {
9156                // Only close dropdowns if clicking outside of any custom-select-wrapper
9157                if (!e.target.closest('.custom-select-wrapper')) {
9158                    closeAllSelects();
9159                }
9160            });
9161            document._customSelectClickHandlerAdded = true;
9162        }
9163    }
9164
9165    // Debounce function to prevent multiple rapid calls
9166    let initTimeout;
9167    function debounceInit() {
9168        clearTimeout(initTimeout);
9169        initTimeout = setTimeout(initCustomSelect, 100);
9170    }
9171
9172    // Initial load on DOMContentLoaded
9173    if (document.readyState === 'loading') {
9174        document.addEventListener('DOMContentLoaded', initCustomSelect);
9175    } else {
9176        initCustomSelect();
9177    }
9178    
9179    // Watch for dynamic content changes
9180    if (typeof MutationObserver !== 'undefined') {
9181        const bodyObserver = new MutationObserver(debounceInit);
9182        if (document.readyState === 'loading') {
9183            document.addEventListener('DOMContentLoaded', () => {
9184                bodyObserver.observe(document.body, {
9185                    childList: true,
9186                    subtree: true
9187                });
9188            });
9189        } else {
9190            bodyObserver.observe(document.body, {
9191                childList: true,
9192                subtree: true
9193            });
9194        }
9195    }
9196
9197    // Hyvä Checkout specific events
9198    window.addEventListener('checkout:step:loaded', debounceInit);
9199    window.addEventListener('alpine:initialized', debounceInit);
9200    
9201    // Listen for private content loaded (customer data)
9202    window.addEventListener('private-content-loaded', debounceInit);
9203    
9204    // Re-initialize after AJAX updates
9205    document.addEventListener('ajaxComplete', debounceInit);
9206</script>
vendor: 1 bytes, line 9206
9206
9207<script>
9208    function createAjaxLoader() {
9209        const loader = document.createElement('div');
9210        loader.className = 'absolute inset-0 flex justify-center items-center loader';
9211        loader.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" stroke-linecap="round" class="w-full h-full p-2" role="img">
9212    <circle style="opacity: .3;" cx="12" cy="12" r="10"/>
9213    <path fill="none" stroke-width="2" d="M12,2 a10,10 0 0,1 10,10"/>
9214<title>Loading...</title></svg>
9215`;
9216        return loader;
9217    }
9218
9219    function addAjaxLoader(button, loader) {
9220        button.setAttribute('data-label', button.getAttribute('aria-label'));
9221        button.removeAttribute('aria-label');
9222        button.prepend(loader);
9223        button.classList.add('relative', '[&>:not(.loader)]:invisible');
9224        button.disabled = true;
9225    }
9226
9227    function removeAjaxLoader(button, loader) {
9228        button.setAttribute('aria-label', button.getAttribute('data-label'));
9229        button.removeAttribute('data-label');
9230        loader.remove();
9231        button.classList.remove('[&>:not(.loader)]:invisible');
9232        button.disabled = false;
9233    }
9234
9235    async function addAjaxCartForm(form, extraDelay = 500) {
9236        if (!form) return;
9237        event.preventDefault();
9238
9239        if (form.hasAttribute('enctype') || !form.reportValidity()) {
9240            return form.submit();
9241        }
9242
9243        const formData = new FormData(form);
9244        const button = form.querySelector('button:not([type=button], [type=reset])')
9245            ? form.querySelector('button:not([type=button], [type=reset])')
9246            : document.getElementById('product-addtocart-button');
9247        const loader = createAjaxLoader(button);
9248        const formUenc = hyva.getUenc();
9249        const postUrl = event.target.action.replace('%25uenc%25', formUenc);
9250
9251        let bodyUrl = new URLSearchParams(formData);
9252        bodyUrl.append("uenc", formUenc);
9253        addAjaxLoader(button, loader);
9254
9255        try {
9256            const response = await fetch(postUrl, {
9257                method: 'POST',
9258                body: bodyUrl.toString(),
9259                mode: "cors",
9260                credentials: "include",
9261                headers: {
9262                    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
9263                    'X-Requested-With': 'XMLHttpRequest'
9264                }
9265            });
9266
9267            if (!response.ok) {
9268                return form.submit();
9269            }
9270
9271            if (response.redirected) {
9272                return window.location.href = response.url;
9273            }
9274
9275            const responseData = await response.json();
9276            if (responseData.backUrl) {
9277                return window.location.href = responseData.backUrl;
9278            }
9279
9280            window.dispatchEvent(new CustomEvent("reload-customer-section-data"));
9281
9282                    } catch (err) {
9283            console.warn(err);
9284            window.dispatchEvent(new CustomEvent('product-addtocart-error'));
9285
9286            if (typeof window.dispatchMessages === "undefined") return;
9287            window.dispatchMessages([{
9288                text:'There\u0020was\u0020a\u0020problem\u0020adding\u0020your\u0020item\u0020to\u0020the\u0020cart.',
9289                type: 'error'
9290            }], 5000);
9291        } finally {
9292            setTimeout(() => removeAjaxLoader(button, loader), extraDelay);
9293        }
9294    }
9295
9296    function removeAjaxCartForm(form) {
9297        removeEventListener('submit', form);
9298    }
9299
9300    document.addEventListener('submit', function(event) {
9301        if (!event.target.matches('#product_addtocart_form, .product_addtocart_form')) return;
9302        addAjaxCartForm(event.target, 500);
9303    });
9304</script>
vendor: 1 bytes, line 9304
9304
9305<script>
9306
9307(_ => {
9308    document.addEventListener('DOMContentLoaded', event => {
9309        
9310        if (!Alpine.version.startsWith('2')) {
9311            return;
9312        }
9313
9314        const teleportDirective = (el, expression) => {
9315            let target = document.querySelector(expression)
9316            let clone = el.content.cloneNode(true).firstElementChild;
9317
9318            target.appendChild(clone);
9319            setTimeout(() => {
9320                target.querySelectorAll('[x-data]')
9321                    .forEach(el => Alpine.initializeComponent(el));
9322            }, 0)
9323        };
9324
9325        document.querySelectorAll('template').forEach(el => {
9326            if (!el.hasAttribute('x-teleport')) {
9327                return;
9328            }
9329
9330            teleportDirective(el, el.getAttribute('x-teleport'));
9331        });
9332
9333        document.querySelectorAll('[x-data]').forEach(el => {
9334            if (el.hasAttribute('x-init')) {
9335                return;
9336            }
9337
9338            setTimeout(() => {
9339                Alpine.initializeComponent(el);
9340            }, 0);
9341        });
9342    });
9343})()</script>
vendor: 1 bytes, line 9343
9343
9344<script type="module"
9345        src="https://www.banham.co.uk/static/version1790667712/frontend/BraveBison/default/en_GB/Hyva_Theme/js/alpine3.min.js"
9346        defer
9347        crossorigin
9348></script>
vendor: 1 bytes, line 9348
9348
9349<script>
9350    function dispatchMessages(messages, hideAfter) {
9351        const messagesEvent = new CustomEvent("messages-loaded", {
9352            detail: {
9353                messages: messages,
9354                hideAfter: hideAfter
9355            }
9356        });
9357        window.dispatchEvent(messagesEvent);
9358    }
9359
9360 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) {
9361        console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script");
9362    }
9363
9364    (function( hyva, undefined ) {
9365
9366        hyva.initFormKey = () => {
9367            const inputSelector = 'input[name="form_key"]',
9368                formKey = hyva.getFormKey();
9369
9370            Array.from(document.querySelectorAll(inputSelector)).map(function (input) {
9371                input.value = formKey
9372            });
9373        }
9374
9375        hyva.initMessages = () => {
9376            try {
9377                const messages = hyva.getCookie('mage-messages');
9378                window.mageMessages = messages ? JSON.parse(decodeURIComponent(messages).replace(/\+/g, ' ')) : [];
9379
9380                dispatchMessages(window.mageMessages);
9381
9382                 const skipSetDomain = true;
9383                hyva.setCookie('mage-messages','', -1, skipSetDomain);
9384
9385            } catch (error) {
9386                console.warn('Error parsing Cookie Messages:', error);
9387            }
9388        }
9389
9390        window.addEventListener('DOMContentLoaded', hyva.initFormKey);
9391        hyva.alpineInitialized(hyva.initMessages)
9392
9393    }( window.hyva = window.hyva || {} ));</script>
vendor: 1 bytes, line 9393
9393
9394<script>
9395    {
9396        const private_content_key = 'mage-cache-storage';
9397        const private_content_expire_key = 'mage-cache-timeout';
9398        const private_content_version_key = 'private_content_version';
9399        const section_data_ids_key = 'section_data_ids';
9400        const mage_cache_session_id_key = 'mage-cache-sessid';
9401        const last_visited_store_key = 'last_visited_store';
9402
9403        const ttl = 24800;
9404
9405 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) {
9406            console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script");
9407        }
9408
9409        function loadSectionData () {
9410            const browserStorage = hyva.getBrowserStorage();
9411            if (!browserStorage) {
9412                typeof window.dispatchMessages !== "undefined" && window.dispatchMessages(
9413                    [{
9414                        type: "warning",
9415                        text: "Please enable LocalStorage in your browser."
9416                    }]
9417                );
9418                return;
9419            }
9420            try {
9421                let isInvalid = false;
9422
9423 if (hyva.getCookie(last_visited_store_key) !== CURRENT_STORE_CODE) {
9424                    isInvalid = true;
9425                }
9426                hyva.setCookie(last_visited_store_key, CURRENT_STORE_CODE, false, false);
9427
9428 if (!hyva.getCookie(mage_cache_session_id_key)) {
9429                    isInvalid = true;
9430                    browserStorage.removeItem(private_content_key);
9431                    const skipSetDomain = true;
9432                    const days = false;
9433                    hyva.setCookie(mage_cache_session_id_key, true, days, skipSetDomain)
9434                }
9435
9436                const cookieVersion = hyva.getCookie(private_content_version_key);
9437                const storageVersion = browserStorage.getItem(private_content_version_key);
9438
9439                if (cookieVersion && !storageVersion || cookieVersion !== storageVersion) {
9440                    isInvalid = true;
9441                }
9442
9443                const privateContentExpires = browserStorage.getItem(private_content_expire_key);
9444                if (privateContentExpires && new Date(privateContentExpires) < new Date()) {
9445                    browserStorage.removeItem(private_content_key);
9446                }
9447
9448                if (isInvalid && cookieVersion) {
9449                    fetchPrivateContent([]);
9450                } else if (cookieVersion && storageVersion && cookieVersion === storageVersion) {
9451                    const privateContent = JSON.parse(browserStorage.getItem(private_content_key));
9452                    if (
9453                        privateContent &&
9454                        privateContentExpires &&
9455                        privateContent.cart &&
9456                        privateContent.customer
9457                    ) {
9458                        dispatchPrivateContent(privateContent);
9459                    } else {
9460                        fetchPrivateContent([]);
9461                    }
9462                } else {
9463                    if (document.getElementById('default-section-data')) {
9464                        const privateContent = JSON.parse(document.getElementById('default-section-data').innerText.trim());
9465                        dispatchPrivateContent(privateContent);
9466                    } else {
9467                        dispatchPrivateContent({});
9468                    }
9469                }
9470
9471            } catch (error) {
9472                console.warn('Error retrieving Private Content:', error);
9473            }
9474        }
9475
9476        hyva.alpineInitialized(loadSectionData)
9477        window.addEventListener('reload-customer-section-data', loadSectionData);
9478
9479 window.processSectionDataBeforeDispatch = window.processSectionDataBeforeDispatch || (data => data);
9480
9481        function dispatchPrivateContent(data) {
9482
9483            const privateContentEvent = new CustomEvent("private-content-loaded", {
9484                detail: {
9485                    data: window.processSectionDataBeforeDispatch(data)
9486                }
9487            });
9488            window.dispatchEvent(privateContentEvent);
9489        }
9490
9491 function fetchPrivateContent(sections) {
9492            fetch(`${BASE_URL}customer/section/load/?sections=${encodeURIComponent(sections.join(','))}`, {
9493                method: 'GET',
9494                headers: {
9495                    'Content-Type': 'application/json',
9496                    'X-Requested-With': 'XMLHttpRequest'
9497                }
9498            })
9499                .then(response => response.ok && response.json())
9500                .then(
9501                    data => {
9502                        if (data) {
9503                            try {
9504                                const browserStorage = hyva.getBrowserStorage();
9505
9506                                
9507                                const oldSectionData = JSON.parse(browserStorage.getItem(private_content_key) || '{}') || {};
9508
9509 if ((! data.cart || ! data.cart.cartId) && oldSectionData['checkout-data']) {
9510                                    delete oldSectionData['checkout-data'];
9511                                }
9512                                const newSectionData = Object.assign(oldSectionData, data);
9513
9514                                dispatchPrivateContent(newSectionData);
9515
9516                                
9517                                if (newSectionData.messages && newSectionData.messages.messages ) {
9518                                    newSectionData.messages.messages = [];
9519                                }
9520
9521                                browserStorage.setItem(private_content_key, JSON.stringify(newSectionData));
9522
9523                                const expiresAt = new Date(Date.now() + (ttl * 1000)).toISOString();
9524                                browserStorage.setItem(private_content_expire_key, expiresAt);
9525
9526                                const newCookieVersion = hyva.getCookie(private_content_version_key);
9527                                browserStorage.setItem(private_content_version_key, newCookieVersion);
9528
9529                                
9530                                
9531                                hyva.setCookie(
9532                                    section_data_ids_key,
9533                                    JSON.stringify(
9534                                        Object.keys(data).reduce((sectionDataIds, sectionKey) => {
9535                                            sectionDataIds[sectionKey] = data[sectionKey]['data_id'];
9536                                            return sectionDataIds;
9537                                        }, {})
9538                                    ),
9539                                    false,
9540                                    true
9541                                );
9542                            } catch (error) {
9543                                console.warn("Couldn't store privateContent", error);
9544                            }
9545                        }
9546                    }
9547                );
9548        }
9549    }</script>
vendor: 1 bytes, line 9549
9549
9550<script>
9551    (() => {
9552        document.addEventListener('submit', event => event.target.action = event.target.action.replace('%25uenc%25', hyva.getUenc()));
9553    })()</script>
vendor: 1 bytes, line 9553
9553
9554<script>
9555    (events => {
9556        const dispatchUserInteractionEvent = () => {
9557            events.forEach(type => window.removeEventListener(type, dispatchUserInteractionEvent))
9558            window.dispatchEvent(new Event('init-external-scripts'))
9559        };
9560        events.forEach(type => window.addEventListener(type, dispatchUserInteractionEvent, {once: true, passive: true}))
9561    })(['touchstart', 'mousemove', 'wheel', 'scroll', 'keydown']);</script>
vendor: 1 bytes, line 9561
9561
9562<script>
9563    function initConfigurableOptions(productId, optionConfig) {
9564
9565        function findPathParam(key) {
9566                        const baseUrl = (BASE_URL.substring(0, 2) === '//' ? 'http:' : '') + BASE_URL;
9567            const baseUrlParts = (new URL(baseUrl)).pathname.replace(/\/$/, '').split('/');
9568            const pathParts = window.location.pathname.split('/').slice(baseUrlParts.length + 3);
9569            for (let i = 0; i < pathParts.length; i += 2) {
9570                if (pathParts[i] === key && pathParts.length > i) {
9571                    return pathParts[i + 1];
9572                }
9573            }
9574        }
9575
9576        return {
9577            optionConfig,
9578            productId,
9579            itemId: (new URLSearchParams(window.location.search)).get('id') || findPathParam('id'),
9580            allowedAttributeOptions: [],
9581            selectedValues: [],
9582            init() {
9583                this.findAllowedAttributeOptions();
9584                this.$nextTick(() => {
9585                    if (typeof this.optionConfig.defaultValues === 'object') {
9586                        for (const [attributeId, value] of Object.entries(this.optionConfig.defaultValues)) {
9587                            this.changeOption(attributeId, value + '');
9588                        }
9589                    }
9590                    this.preselectQuerystringItems();
9591                    this.preselectLocationHashItems();
9592                });
9593            },
9594            productIndex: 0,
9595            productIndexForPrice: 0,
9596            optionIsActive(attributeId, optionId) {
9597                                return !!this.getAllowedAttributeOptions(attributeId).find(
9598                    option => option.id === optionId
9599                )
9600            },
9601            optionIsEnabled(attributeId, optionId) {
9602                                for (const productId in this.optionConfig.index) {
9603                    if (this.optionConfig.index[productId][attributeId] === optionId) {
9604                        return true;
9605                    }
9606                }
9607                return false;
9608            },
9609            findSimpleIndex() {
9610                                this.productIndex = this.calculateSimpleIndexForPartialSelection(this.selectedValues);
9611                this.productIndexForPrice = this.findCheapestProductForPartialSelection(this.selectedValues);
9612            },
9613            calculateSimpleIndexForPartialSelection(selectedValues) {
9614                if (selectedValues.length === 0) return 0;
9615                return this.findProductIdsForPartialSelection(selectedValues)[0];
9616            },
9617            calculateSimpleIndexForFullSelection(selectedValues) {
9618                if (! this.isFullSelection(selectedValues)) return false;
9619
9620                const productIndexes = this.optionConfig.index;
9621                return Object.keys(productIndexes).find(productIndex => {
9622                    const productCandidateOptions = productIndexes[productIndex];
9623
9624                    for (const productOption in productCandidateOptions) {
9625                        if (
9626                            !selectedValues[productOption] ||
9627                            selectedValues[productOption] !== productCandidateOptions[productOption]
9628                        ) {
9629                            return false;
9630                        }
9631                    }
9632                    return productIndex;
9633                });
9634            },
9635            findAllowedAttributeOptions() {
9636                                this.allowedAttributeOptions = this.calculateAllowedAttributeOptions(this.selectedValues);
9637            },
9638            calculateAllowedAttributeOptions(selectedValues) {
9639                const allAttributes = this.optionConfig.attributes;
9640                const allAttributesSorted = Object.values(allAttributes).sort((a,b) => {
9641                    return a.position - b.position
9642                });
9643
9644                const newAllowedAttributeOptions = [];
9645
9646                allAttributesSorted.forEach(attribute => {
9647                    const selectionWithoutAttr = Object.assign({}, this.removeAttrFromSelection(selectedValues, attribute.id));
9648                    const availableIndexes = this.calculateAvailableProductIndexes(selectionWithoutAttr);
9649                    newAllowedAttributeOptions[attribute.id] = allAttributes[attribute.id].options.filter(option => {
9650                        return !!option.products.find(product => {
9651                            return availableIndexes.includes(product);
9652                        })
9653                    });
9654                });
9655                return newAllowedAttributeOptions;
9656            },
9657            calculateAvailableProductIndexes(selectedOptions) {
9658                if (Object.keys(selectedOptions).length === 0) {
9659                                        if (Object.values(this.optionConfig.salable || {}).length) {
9660                                                return [].concat.apply([], [].concat.apply([], Object.values(this.optionConfig.salable).map(Object.values))).filter((x, i, a) => a.indexOf(x) === i)
9661                    }
9662                                        return Object.keys(this.optionConfig.index);
9663                }
9664
9665                                const selectedIds = Object.keys(selectedOptions);
9666                if (Object.values(this.optionConfig.salable || {}).length) {
9667                                        const selectedOptionIndexes = selectedIds.map(attrId => {
9668                        const optionValue = selectedOptions[attrId];
9669                        return this.optionConfig.salable[attrId] && this.optionConfig.salable[attrId][optionValue] || []
9670                    })
9671                                        return selectedOptionIndexes.reduce((acc, optionIndexes) => {
9672                        return acc.filter(index => optionIndexes.includes(index));
9673                    });
9674                } else {
9675                                        const productIndexes = this.optionConfig.index;
9676                    return Object.keys(productIndexes).filter(index => {
9677                                                for (const attrId of selectedIds) {
9678                            if (productIndexes[index][attrId] !== `${selectedOptions[attrId]}`) return false
9679                        }
9680                        return true
9681                    });
9682                }
9683            },
9684            findAttributeByOptionId(optionId) {
9685                for (const attributeId in this.optionConfig.attributes) {
9686                    const attributeOptions = this.optionConfig.attributes[attributeId].options || [];
9687                    if (attributeOptions.find(option => option.id === optionId)) {
9688                        return attributeId;
9689                    }
9690                }
9691            },
9692            getAllowedAttributeOptions(attributeId) {
9693                return this.allowedAttributeOptions[attributeId] || []
9694            },
9695            getAllAttributeOptions(attributeId) {
9696                return (
9697                    this.optionConfig.attributes[attributeId] &&
9698                    this.optionConfig.attributes[attributeId].options
9699                ) || []
9700            },
9701            getProductIdsForOption(option) {
9702                const attributeId = this.findAttributeByOptionId(option.id);
9703                const allOptions = this.optionConfig.attributes[attributeId];
9704                const opt = (allOptions && allOptions.options || []).find(o => o.id === option.id);
9705                return opt && opt.products
9706                    ? opt.products
9707                    : [];
9708            },
9709            findProductIdsForPartialSelection(optionSelection) {
9710                const candidateProducts = Object.values(optionSelection).reduce((candidates, optionId) => {
9711                    const newCandidates = this.getProductIdsForOption({id: optionId});
9712                    return candidates === null
9713                        ? newCandidates
9714                        : candidates.filter(productId => newCandidates.includes(productId));
9715                }, null);
9716                return candidateProducts || [];
9717            },
9718            findCheapestProductForPartialSelection(optionSelection) {
9719                const candidateProducts = this.findProductIdsForPartialSelection(optionSelection);
9720                return candidateProducts.reduce((cheapest, simpleIdx) => {
9721                    // in the first iteration we start with simpleIdx as the currently cheapest product
9722                    if (! this.optionConfig.optionPrices[cheapest]) return simpleIdx;
9723                    const knownCheapestPrice = this.optionConfig.optionPrices[cheapest].finalPrice.amount;
9724                    return knownCheapestPrice > this.optionConfig.optionPrices[simpleIdx].finalPrice.amount
9725                        ? simpleIdx
9726                        : cheapest;
9727                }, 0)
9728            },
9729            findProductIdToUseForOptionPrice(option) {
9730                // try to find a product for a complete selection
9731                const attributeId = this.findAttributeByOptionId(option.id);
9732                const optionSelection = Object.assign({}, this.selectedValues, {[attributeId]: option.id});
9733                const matchingSimpleIndex = this.calculateSimpleIndexForFullSelection(optionSelection);
9734                // if there is no complete selection, use the cheapest product for the option
9735                return matchingSimpleIndex || this.findCheapestProductForPartialSelection(optionSelection);
9736            },
9737            getAttributeOptionLabel(option) {
9738                const optionProduct = this.findProductIdToUseForOptionPrice(option);
9739
9740                if ((! optionProduct) || (optionProduct === this.productIndexForPrice)) {
9741                    return option.label;
9742                }
9743
9744                const currentPrice = this.getOptionPriceAdjustmentBasePrice();
9745
9746                if (this.optionConfig.optionPrices[optionProduct]) {
9747                    const optionPrice = this.optionConfig.optionPrices[optionProduct].finalPrice.amount;
9748                    if (optionPrice !== currentPrice){
9749                        return option.label + ' ' + hyva.formatPrice(optionPrice - currentPrice, true);
9750                    }
9751                }
9752                return option.label;
9753            },
9754            getOptionPriceAdjustmentBasePrice() {
9755                if (this.optionConfig.optionPrices[this.productIndexForPrice]) {
9756                    return this.optionConfig.optionPrices[this.productIndexForPrice].finalPrice.amount
9757                }
9758                return this.optionConfig.prices.finalPrice.amount; // default price if no option selection
9759            },
9760            clearOptionIfActive(optionId, value) {
9761                if (this.selectedValues[optionId] === value) {
9762                    this.blurLabel()
9763                    this.changeOption(optionId, '')
9764                }
9765            },
9766            removeAttrFromSelection(selectedValues, attributeId) {
9767                                attributeId = parseInt(attributeId);
9768                return selectedValues.reduce((newSelection, val, attr) => {
9769                    if (attr !== attributeId) {
9770                        newSelection[attr] = val;
9771                    }
9772                    return newSelection;
9773                }, []);
9774            },
9775            changeOption(attributeId, value) {
9776                if (value === '') {
9777                    this.selectedValues = this.removeAttrFromSelection(this.selectedValues, attributeId)
9778                } else if (value && this.getAllowedAttributeOptions(attributeId).find(option => option.id === value)) {
9779                                        this.selectedValues[attributeId] = value;
9780                }
9781                this.findSimpleIndex();
9782                this.findAllowedAttributeOptions();
9783                this.updatePrices();
9784                this.updateGallery();
9785
9786                const candidates = this.findProductIdsForPartialSelection(this.selectedValues);
9787
9788                                window.dispatchEvent(
9789                    new CustomEvent(
9790                        'configurable-selection-changed',
9791                        {
9792                            detail: {
9793                                productId: this.productId,
9794                                optionId: attributeId,
9795                                value: value,
9796                                productIndex: this.productIndex,
9797                                selectedValues: this.selectedValues,
9798                                candidates: candidates,
9799                                skuCandidates: Object.values(candidates).map(id =>
9799 this.optionConfig.sku?.[id] ?? null).filter(Boolean),
9800                            }
9801                        }
9802                    )
9803                );
9804            },
9805            calculateIsMinimalPrice() {
9806                return ! this.isFullSelection(this.selectedValues);
9807            },
9808            isFullSelection(selectedValues) {
9809                return Object.values(selectedValues).length === Object.keys(this.optionConfig.attributes).length;
9810            },
9811            updatePrices() {
9812                const value = this.optionConfig.optionPrices[this.productIndexForPrice] || this.optionConfig.prices;
9813                window.dispatchEvent(
9814                    new CustomEvent(
9815                        "update-prices-" + this.productId,
9816                        {
9817                            detail: Object.assign(
9818                                value,
9819                                { isMinimalPrice: this.calculateIsMinimalPrice() }
9820                            )
9821                        }
9822                    )
9823                );
9824            },
9825            updateGallery () {
9826                if (this.productIndex) {
9827                    const images = this.optionConfig.images[this.productIndex];
9828                    images && window.dispatchEvent(new CustomEvent(
9829                        "update-gallery",
9830                        { detail: this.sortImagesByPosition(images) }
9831                    ));
9832                } else {
9833                    window.dispatchEvent(new Event("reset-gallery"));
9834                }
9835            },
9836            sortImagesByPosition(images) {
9837                return images.sort((x, y) => {
9838                    return x.position === y.position ? 0 : (parseInt(x.position) > parseInt(y.position) ? 1 : -1)
9839                });
9840            },
9841            onGetCartData(data) {
9842                            },
9843            preselectCartItems(data) {
9844                // pre-select options based on cart data for current (quote) itemId
9845                const cart = data && data.cart;
9846                if (cart && cart.items) {
9847                    const cartItem = cart.items.find((item) => {
9848                        return (
9849                            item.item_id === this.itemId
9850                            && item.product_id === this.productId
9851                        )
9852                    });
9853                    if (cartItem && cartItem.options && cartItem.options.length) {
9854                        cartItem.options.map(option => {
9855                            this.changeOption(option.option_id, option.option_value);
9856                        })
9857                    }
9858                }
9859            },
9860            preselectQuerystringItems() {
9861                // pre-select option like ?size=167
9862                const urlQueryParams = new URLSearchParams(window.location.search.replace('?',''));
9863                this.preselectItemsBasedOnLocation(attribute => urlQueryParams.get(attribute.code));
9864            },
9865            preselectLocationHashItems() {
9866                // pre-select option like #144=167
9867                const urlHashParams = new URLSearchParams(window.location.hash.replace('#',''));
9868                this.preselectItemsBasedOnLocation(attribute => urlHashParams.get(attribute.id));
9869            },
9870            preselectItemsBasedOnLocation(getLocationValue) {
9871                Object.values(this.optionConfig.attributes).map(attribute => {
9872                    const v = getLocationValue(attribute);
9873                    v && this.changeOption(attribute.id, v)
9874                });
9875            }
9876        }
9877    }
9878</script>
vendor: 1 bytes, line 9878
9878
9879<script>
9880    function initSwatchOptions(swatchConfig) {
9881        return {
9882            swatchConfig,
9883            getAttributeSwatchData(attributeId) {
9884                const swatchConfig = Object.assign({}, this.swatchConfig[attributeId]);
9885                swatchConfig['details'] = JSON.parse(swatchConfig['additional_data']);
9886
9887                return swatchConfig;
9888            },
9889            mapSwatchTypeNumberToTypeCode(typeNumber) {
9890                switch ("" + typeNumber) {
9891                    case "1":
9892                        return "color"
9893                    case "2":
9894                        return "image"
9895                    case "3":
9896                        return "empty"
9897                    case "0":
9898                    default:
9899                        return "text"
9900                }
9901            },
9902            getTypeOfFirstOption(attributeId) {
9903                for (const optionId in this.swatchConfig[attributeId]) {
9904                    const option = this.swatchConfig[attributeId][optionId];
9905                    if (typeof option.type !== 'undefined') {
9906                        return this.mapSwatchTypeNumberToTypeCode(option.type);
9907                    }
9908                }
9909            },
9910            getVisualSwatchType(attributeId, targetOptionId) {
9911                // If a type configuration is present for the given option id, use it
9912                const config = this.swatchConfig[attributeId];
9913                if (config[targetOptionId] && typeof config[targetOptionId].type !== 'undefined') {
9914                    return this.mapSwatchTypeNumberToTypeCode(config[targetOptionId].type);
9915                }
9916
9917                // Otherwise - if no config is present for the target option - use the type of the first option
9918                // with a type property from the attribute, thus assuming its the same type as the target option.
9919                // (This edge case condition can occur on single swatch products if some options are not salable)
9920                return this.getTypeOfFirstOption(attributeId);
9921            },
9922            getSwatchType(attributeId, optionId) {
9923                // Deserialize the attribute details the first time they are used
9924                if (this.swatchConfig[attributeId] && ! this.swatchConfig[attributeId].details) {
9925                    this.swatchConfig[attributeId] = this.getAttributeSwatchData(attributeId);
9926                }
9927                const type =  this.swatchConfig[attributeId] &&
9928                    this.swatchConfig[attributeId].details &&
9929                    this.swatchConfig[attributeId].details.swatch_input_type ||
9930                    "empty";
9931                return type === 'visual' ? this.getVisualSwatchType(attributeId, optionId) : type;
9932            },
9933            isTextSwatch(attributeId, optionId) {
9934                return this.getSwatchType(attributeId, optionId) === 'text';
9935            },
9936            isVisualSwatch(attributeId, optionId) {
9937                const type = this.getSwatchType(attributeId, optionId);
9938
9939                return ['image', 'color'].includes(type);
9940            },
9941            getSwatchBackgroundStyle(attributeId, optionId) {
9942                const config = this.getSwatchConfig(attributeId, optionId);
9943                const type = this.getSwatchType(attributeId, optionId);
9944
9945                if (type === "color") {
9946                        return 'background-color:' + config.value;
9947                } else if (type === "image") {
9948                        return "background: #fff url('" + config.value + "') no-repeat center";
9949                } else {
9950                    return '';
9951                }
9952            },
9953            getSwatchText(attributeId, optionId) {
9954                const config = this.getSwatchConfig(attributeId, optionId);
9955                return config.label || config.value || this.getOptionLabelFromOptionConfig(attributeId, optionId);
9956            },
9957            getOptionLabelFromOptionConfig(attributeId, optionId) {
9958                // Fallback if no value is present in swatchConfig data
9959                // Reference issue https://gitlab.hyva.io/hyva-themes/magento2-default-theme/-/issues/190
9960                const option = this.getAllAttributeOptions(attributeId).filter(option => option.id === optionId);
9961                return option && option[0] && option[0].label ||'';
9962            },
9963            getSwatchConfig(attributeId, optionId) {
9964                return this.swatchConfig[attributeId] && this.swatchConfig[attributeId][optionId]
9965                    ? this.swatchConfig[attributeId][optionId]
9966                    : false;
9967            },
9968            activeTooltipItem: false,
9969            tooltipPositionElement: false,
9970            isTooltipVisible() {
9971                return this.activeTooltipItem &&
9972                    this.getSwatchConfig(
9973                        this.activeTooltipItem.attribute,
9974                        this.activeTooltipItem.item
9975                    );
9976            },
9977            isFirstItemCol() {
9978                return this.activeTooltipItem.index === 0;
9979            },
9980            getTooltipImageStyle(attributeId, optionId) {
9981                const config = this.getSwatchConfig(attributeId, optionId);
9982                const type = this.getSwatchType(attributeId, optionId);
9983
9984                if (type === "color") {
9985                    return 'background-color:' + config.value + '; width: 110px; height: 90px;';
9986                } else if (type === "image") {
9987                    return "background: #ffffff url('" + config.thumb +
9988                        "') center center no-repeat; width: 110px; height: 90px;";
9989                } else {
9990                    return 'display:none';
9991                }
9992            },
9993            getTooltipPosition() {
9994                return this.tooltipPositionElement ?
9995                    `top: ${this.tooltipPositionElement.offsetTop}px;` +
9996                    `left: ${
9997                        this.tooltipPositionElement.offsetLeft - (
9998                            this.tooltipPositionElement.closest('.snap') &&
9999                            this.tooltipPositionElement.closest('.snap').scrollLeft ||
10000                            0
10001                        )
10002                    }px;` : ''
10003            },
10004            getTooltipLabel() {
10005                return this.getSwatchConfig(this.activeTooltipItem.attribute, this.activeTooltipItem.item).label
10006            },
10007            focusedLabel: false,
10008            focusLabel(optionId) {
10009                this.focusedLabel = optionId;
10010            },
10011            blurLabel() {
10012                this.focusedLabel = false;
10013            }
10014        }
10015    }
10016</script>
vendor: 1 bytes, line 10016
10016
10017<script>
10018    'use strict';
10019
10020    const grecaptchaV2LoadCallbacks = [];
10021
10022    function executeRecaptchaLoadCallbacks () {
10023        while (window.grecaptcha && grecaptchaV2LoadCallbacks.length > 0) {
10024            const callback = grecaptchaV2LoadCallbacks.pop();
10025            typeof callback === 'string' ? window[callback]() : callback();
10026        }
10027    }
10028
10029    (function() {
10030        const loadRecaptchaScript = (event) => {
10031
10032            if (window.grecaptcha || !event.target.form) {
10033                return;
10034            }
10035
10036            const url = 'https://www.google.com/recaptcha/api.js?onload=executeRecaptchaLoadCallbacks';
10037            const siteKey = '6LfHDCMrAAAAACnDJl581eICSW3VnauItgp_hR2S';
10038            const script = document.createElement('script');
10039            script.type = 'text/javascript';
10040            script.src = siteKey ? `${url}&render=${siteKey}` : `${url}&render=explicit`;
10041            script.async = true;
10042            document.head.appendChild(script);
10043
10044            script.addEventListener('load', () => {
10045                Array.from(document.querySelectorAll('button[data-recaptcha-btn]:disabled')).forEach(btn => btn.removeAttribute('disabled'));
10046            });
10047        }
10048
10049        window.forceLoadRecaptchaScript = (form) => {
10050            loadRecaptchaScript({target: {form: form || 'dummy'}});
10051            executeRecaptchaLoadCallbacks();
10052        };
10053
10054        document.body.addEventListener('input', loadRecaptchaScript, { once: true });
10055        document.body.addEventListener('focus', loadRecaptchaScript, { once: true });
10056
10057    }());
10058
10059</script>
vendor: 1 bytes, line 10059
10059
10060<script>
10061    (function (w, d, s, l, i) {
10062        w[l] = w[l] || []; w[l].push({
10063            'gtm.start':
10064                new Date().getTime(), event: 'gtm.js'
10065        }); var f = d.getElementsByTagName(s)[0],
10066            j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
10067                'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
10068    })(window, document, 'script', 'dataLayer', 'GTM\u002D5VC2G8L');
10069</script>
vendor: 1 bytes, line 10069
10069
10070<script>
10071    'use strict';
10072
10073    function initAmInitConfigurableSwatchOptions() {
10074        const productId = this.$el.dataset.productId ?? this.$el.closest('form')?.querySelector('input[name="product"]').value;
10075        const component = window['initConfigurableSwatchOptions'] ?? window['initConfigurableSwatchOptions_' + productId]
10076        const originInitConfigurableSwatchOptions = component.call(this);
10077
10078        return {
10079            ...originInitConfigurableSwatchOptions,
10080            init() {
10081                if (this.showSwatches !== undefined) {
10082                    this.$watch('showSwatches', value => {
10083                        if (value) {
10084                            this.dispatchConfigurableShowEvent();
10085                        }
10086                    });
10087                } else {
10088                    this.$nextTick(() => {
10089                        this.dispatchConfigurableShowEvent();
10090                    });
10091                }
10092
10093                this.findAllowedAttributeOptions();
10094                this.$nextTick(() => {
10095                    if (typeof this.optionConfig.defaultValues === 'object') {
10096                        for (const [attributeId, value] of Object.entries(this.optionConfig.defaultValues)) {
10097                            this.changeOption(attributeId, value + '');
10098                        }
10099                    }
10100                });
10101            },
10102
10103            dispatchConfigurableShowEvent() {
10104                window.dispatchEvent(new CustomEvent('configurable-show-swatches', {
10105                    detail: {
10106                        productId: this.productId,
10107                        element: this.$el
10108                    }
10109                }));
10110            }
10111        }
10112    }
10113
10114    window.addEventListener('alpine:init', () => {
10115        Alpine.data('initAmInitConfigurableSwatchOptions', initAmInitConfigurableSwatchOptions);
10116    }, {once: true});</script>
vendor: 1 bytes, line 10116
10116
10117<script type="text/json" id="default-section-data">
10118    {"messages":[],"customer":[],"compare-products":[],"last-ordered-items":[],"requisition":[],"cart":[],"directory-data":{"GB":{"name":"United Kingdom"},"data_id":1790927930},"captcha":[],"wishlist":{"items":[]},"company":[],"company_authorization":[],"customer-companies":[],"negotiable_quote":[],"instant-purchase":[],"loggedAsCustomer":[],"multiplewishlist":[],"purchase_order":[],"persistent":[],"review":[],"payments":[],"amasty-storepickup-data":[],"apptrian_metapixelapi_matching_section":[],"webforms":[],"hyva_checkout":[],"chatData":[],"recently_viewed_product":[],"recently_compared_product":[],"product_data_storage":[],"paypal-billing-agreement":[],"paypal-buyer-country":[]}</script>
vendor: 1 bytes, line 10118
10118
10119<script>
10120    'use strict';
10121
10122    function attributeIcon() {
10123        return {
10124            labelledById: '',
10125
10126            init() {
10127                const timestamp = Date.now();
10128                const randomNum = Math.floor(Math.random() * 1000);
10129                this.labelledById = `amshopby-option-id-${timestamp}-${randomNum}`;
10130            }
10131        }
10132    }
10133    window.addEventListener(
10134        'alpine:init',
10135        () => Alpine.data('attributeIcon',attributeIcon),
10136        {once: true}
10137    );</script>
vendor: 1 bytes, line 10137
10137
10138<script>
10139document.addEventListener('alpine:init', () => {
10140    Alpine.data('newsletterForm', () => ({
10141        firstname: '',
10142        lastname: '',
10143        email: '',
10144        errors: {},
10145
10146        validateField(field) {
10147            this.errors[field] = '';
10148
10149            if (field === 'firstname' && !this.firstname.trim()) {
10150                this.errors.firstname = 'First\u0020Name\u0020is\u0020required.';
10151            }
10152
10153            if (field === 'lastname' && !this.lastname.trim()) {
10154                this.errors.lastname = 'Last\u0020Name\u0020is\u0020required.';
10155            }
10156
10157            if (field === 'email') {
10158                if (!this.email.trim()) {
10159                    this.errors.email = 'Email\u0020is\u0020required.';
10160                } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email)) {
10161                    this.errors.email = 'Please\u0020enter\u0020a\u0020valid\u0020email\u0020address.';
10162                }
10163            }
10164        },
10165
10166        validateForm() {
10167            this.validateField('firstname');
10168            this.validateField('lastname');
10169            this.validateField('email');
10170            return Object.values(this.errors).every(error => error === '');
10171        },
10172
10173        submitForm() {
10174            const form = document.querySelector('#newsletter-validate-detail');
10175            
10176            if (this.validateForm()) {
10177                form.submit();
10178            }
10179        }
10180    }));
10181});
10182</script>
vendor: 1 bytes, line 10182
10182
10183<script type="text/x-magento-init">
10184    {
10185        ".popup-newsletter": {
10186            "newsletterPopup": {
10187
10188                "delay":"40",
10189                "closing":"5"
10190            }
10191        }
10192    }</script>
vendor: 1 bytes, line 10192
10192
10193<script type="text/x-magento-init">{"*":
10194            {"Magento_Persistent/js/remember-me-config": {
10195            "config": {"persistenceConfig":{"isRememberMeCheckboxVisible":true,"isRememberMeCheckboxChecked":true}}
10196            }}}</script>
10196
10197</body>
10198</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.