PageSourceSearch

https://shop.runningcompany.com/shop/

html runningcompany.com collected 2026-09-26 05:06:53 UTC 277,182 bytes, 6,191 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3
4<head>
vendor: 75 bytes, lines 4-7
4
5  
6  
7  <script async src="https://www.googletagmanager.com/gtag/js?id=
7G-7S01FXEE6H
vendor: 12 bytes, line 7
7"></script>
8<script>
vendor: 129 bytes, lines 9-12
9window.dataLayer = window.dataLayer || [];
10function gtag() { dataLayer.push(arguments);}
11gtag("js", new Date());
12gtag("config", "
12G-7S01FXEE6H
vendor: 4 bytes, line 12
12");
13</script>
13
14
15
16
17  <meta charset="utf-8" />
18  <title>Shop</title>
19  <meta name="viewport" content="width=device-width, initial-scale=1" />
20  <meta name="keywords" content="" />
21  <meta name="description" content="" />
22  <!-- Icons -->
23  <meta name="msapplication-TileColor" content="#1bb8de" />
24  <meta name="msapplication-TileImage" content="/assets/branding/shop.runningcompany.com/ms-icon-144x144.png" />
25  <meta name="theme-color" content="#8dc63f" />
26  <meta property="og:title" content="Shop Naperville Running" />  
27  <meta property="og:image" content="https://shop.runningcompany.com/assets/branding/shop.runningcompany.com/logo.png" />
28  <meta property="og:description" content="" />
29  <link rel="canonical" href="https://shop.runningcompany.com/shop" />
30  <link rel="shortcut icon" id="appFavicon" href="/assets/branding/shop.runningcompany.com/favicon.ico" />
31  <link rel="apple-touch-icon" id="appFaviconApple57" sizes="57x57" href="/assets/branding/shop.runningcompany.com/apple-icon-57x57.png" />
32  <link rel="apple-touch-icon" id="appFaviconApple60" sizes="60x60" href="/assets/branding/shop.runningcompany.com/apple-icon-60x60.png" />
33  <link rel="apple-touch-icon" id="appFaviconApple72" sizes="72x72" href="/assets/branding/shop.runningcompany.com/apple-icon-72x72.png" />
34  <link rel="apple-touch-icon" id="appFaviconApple76" sizes="76x76" href="/assets/branding/shop.runningcompany.com/apple-icon-76x76.png" />
35  <link rel="apple-touch-icon" id="appFaviconApple114" sizes="114x114" href="/assets/branding/shop.runningcompany.com/apple-icon-114x114.png" />
36  <link rel="apple-touch-icon" id="appFaviconApple120" sizes="120x120" href="/assets/branding/shop.runningcompany.com/apple-icon-120x120.png" />
37  <link rel="apple-touch-icon" id="appFaviconApple144" sizes="144x144" href="/assets/branding/shop.runningcompany.com/apple-icon-144x144.png" />
38  <link rel="apple-touch-icon" id="appFaviconApple152" sizes="152x152" href="/assets/branding/shop.runningcompany.com/apple-icon-152x152.png" />
39  <link rel="apple-touch-icon" id="appFaviconApple180" sizes="180x180" href="/assets/branding/shop.runningcompany.com/apple-icon-180x180.png" />
40  <link rel="icon" type="image/png" id="appFavicon192" sizes="192x192" href="/assets/branding/shop.runningcompany.com/android-icon-192x192.png" />
41  <link rel="icon" type="image/png" id="appFavicon32" sizes="32x32" href="/assets/branding/shop.runningcompany.com/favicon-32x32.png" />
42  <link rel="icon" type="image/png" id="appFavicon96" sizes="96x96" href="/assets/branding/shop.runningcompany.com/favicon-96x96.png" />
43  <link rel="icon" type="image/png" id="appFavicon16" sizes="16x16" href="/assets/branding/shop.runningcompany.com/favicon-16x16.png" />
44  <!-- Font Preloading - Optimized for Performance -->
45  <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
46  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
47  <link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700;800&display=swap">
48  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700;800&display=swap" media="print" onload="this.media='all'">
49  <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700;800&display=swap"></noscript>
50  <!-- Styles -->
51  <link href="/assets/styles/font-variables.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
52  <style>:root { --font-primary: "Nunito", "Open Sans", "Helvetica Neue", sans-serif; }</style>
53  <link href="/assets/admin/styles/spectrum.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
54  <link href="/assets/styles/bootstrap.css?v=1.2.0" rel="stylesheet" type="text/css" media="all"/>
55  <link href="/assets/styles/themify-icons.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
56  <link href="/assets/styles/flexslider.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
57  <link href="/assets/styles/theme.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
58  <link href="/assets/styles/custom.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
59  <link href="/assets/styles/runfree.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
60  <link href="/assets/styles/modal.css?v=1.2.0" rel="stylesheet" type="text/css" />
61	<link href="/assets/styles/datetimepicker.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
62  <link href="/assets/styles/font-awesome.min.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
63  <link rel="stylesheet" href="/assets/styles/tooltips.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
64  <link href="/assets/styles/runfreefont.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
65  <link href="/assets/styles/search-overlay.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
66  <link href="/assets/branding/shop.runningcompany.com/branding.css?v=1.2.0" rel="stylesheet" type="text/css" media="all" />
67  
67<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
67
68  
68<script>
69    // Universal tracking helper - supports both GTM and direct gtag
70    window.dataLayer = window.dataLayer || [];
71    function trackEvent(eventName, eventData) {
72      // Clear previous ecommerce object (GTM best practice)
73      dataLayer.push({ ecommerce: null });
74
75      // Map UA field names to GA4 schema (keep both for store GTM compatibility)
76      if (eventData && eventData.items) {
77        eventData.items = eventData.items.map(function(item) {
78          var mapped = {
79            item_id: item.item_id || item.id,
80            item_name: item.item_name || item.name,
81            item_brand: item.item_brand || item.brand,
82            item_category: item.item_category || item.category,
83            item_variant: item.item_variant || item.variant,
84            item_list_name: item.item_list_name || item.list_name,
85            index: item.index != null ? item.index : item.list_position,
86            quantity: item.quantity,
87            price: item.price,
88            id: item.id,
89            name: item.name,
90            brand: item.brand,
91            category: item.category,
92            variant: item.variant,
93            list_name: item.list_name,
94            list_position: item.list_position
95          };
96          if (item.affiliation) mapped.affiliation = item.affiliation;
97          return mapped;
98        });
99      }
100
101      // Map legacy UA event names to GA4 equivalents
102      var ga4EventName = eventName;
103      if (eventName === 'checkout_progress') {
104        ga4EventName = 'add_shipping_info';
105      }
106
107      // GTM format: push object with event property (sends both legacy and GA4 names)
108      var gtmData = { event: eventName };
109      if (eventData) {
110        if (eventData.items) gtmData.ecommerce = eventData;
111        for (var key in eventData) {
112          if (eventData.hasOwnProperty(key)) gtmData[key] = eventData[key];
113        }
114      }
115      dataLayer.push(gtmData);
116
117      // Also push GA4 event name if different (for GTM GA4 triggers)
118      if (ga4EventName !== eventName) {
119        dataLayer.push({ ecommerce: null });
120        var ga4GtmData = { event: ga4EventName };
121        if (eventData) {
122          if (eventData.items) ga4GtmData.ecommerce = eventData;
123          for (var key in eventData) {
124            if (eventData.hasOwnProperty(key)) ga4GtmData[key] = eventData[key];
125          }
126        }
127        dataLayer.push(ga4GtmData);
128      }
129
130      // Direct gtag format (for stores using GA4 directly) - always use GA4 event name
131      if (typeof gtag === 'function') {
132        gtag('event', ga4EventName, eventData);
133      }
134    }
135  </script>
135
136  
137  <style>
138    :root {
139      --primary: #8dc63f;
140      --primaryOpaque: rgba(141,198,63,0.1);
141      --secondary: #fefffe;
142      --white: #FFF;
143      --almostblack: #252525;
144      --grey: #eff1f5;
145      --red: #ff104b;
146      --shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.08);
147      --bigShadow: 0px 12px 23px 0px rgba(0, 0, 0, .1);
148      --transition: 0.5s;
149      --even: #FCFCFC;
150      --siteLogo: url(/assets/branding/shop.runningcompany.com/logo.png);
151      --input: #F5F6FA;
152      --border: #f5f6fa;
153      --inputfocus: #e7ebf1;
154      --glass: rgba(250, 250, 250, 0.7);
155      --navutility: #f5f8fb;
156      --menu: #434c5e;
157      --filterhr: #d2d8e5;
158      --bggrey: #f5f6fa;
159      --thumbloader: linear-gradient(90deg, #eef1f5 0px, #fbfbfd 40px, #eef1f5 80px);
160      --skeleton-one: #eff1f5;
161      --skeleton-two: #F5F6FA;
162      --disappearing-header: linear-gradient(to bottom, rgba(245, 246, 250, 1) 0%, rgba(245, 246, 250, 0) 100%);
163      --disappearing-footer: linear-gradient(to bottom, rgba(245, 246, 250, 0) 0%, rgba(245, 246, 250, 1) 100%);
164    }
165  </style>
166  <link href="/assets/styles/round.css" rel="stylesheet" type="text/css" media="all" />
167  
167<script>
168    var logoCard = '/assets/branding/shop.runningcompany.com/logo.png';
169    var logoUrl = '/';
170  </script>
170
171  
172  
172<script>var cdnOn = false;</script>
vendor: 1 bytes, line 172
172
173<script type="text/javascript">var _learnq;</script>
173<script type="text/javascript">window.blueshift = null;</script>
173
174  
174<script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","@id":"https://www.runningcompany.com/#organization","name":"Naperville Running","url":"https://www.runningcompany.com/","logo":"https://www.runningcompany.com/logo.png","sameAs":["https://shop.runningcompany.com"]}</script>
174
175  <!-- End Header Script -->
176</head>
177
178<body class="scroll-assist">
179  
180  
181  <!-- Cart Template //-->
182  <li id="CartTemplate" class="cartItem template">
183    <div class="productImage" style="background-image: url('{{product.url}}')"></div>
184    <div class="rel">
185      <div class="productName">{{product.name}}</div>
186      <div class="productPrice">
187        {{product.quantity}} at ${{product.cost}} - {{product.options}}
188      </div>
189      <div class="remove" data-index="{{index}}"></div>
190    </div>
191  </li>
192
193  <div class="nav-container">
194    <nav>
195      <div class="nav-bar">
196        <div class="module left">
197          <img id="StoreLogo" class="logo logo-dark" alt="Naperville Running" src="/assets/branding/shop.runningcompany.com/logo.png" />
198        </div>
199        
200        <!-- Mobile toggle (hamburger) -->
201        <div class="module right widget-handle mobile-toggle visible-sm visible-xs">
202          <i class="icon-Main-Menu mobilemenu"></i>
203        </div>
204        
205        <!-- Cart icon - visible on mobile only -->
206        <div id="MobileCartMenu" class="module right widget-handle visible-sm visible-xs ecomtrue" style="width: 65px; padding: 0; border-left: 2px solid var(--border); text-align: center;">
207          <a href="/cart" style="text-decoration: none; position: relative; display: block; height: 69px; filter: brightness(100%);">
208            <i class="icon-ti-Cart" style="line-height: 69px !important; font-size: 24px; display: inline-block; vertical-align: middle;"></i>
209            <span id="MobileCartItemCount" class="label number"></span>
210          </a>
211        </div>
212        
213        <div class="module-group right pt0 pb0">
214
215          <!-- Account Pod -->
216          <div id="AccountMenu" class="module right widget-handle hidden-sm hidden-xs">
217            <ul class="menu">
218              <li class="has-dropdown-account" style="border-top: unset;"><i class="icon-Profile"></i>
219                <span class="title">My Account</span>
220                <ul style="margin-top: -7px; margin-right: -20px;"><li><a href="/login"><i class="icon-Log-In dropdown-icon"></i> Login</a></li><li><a href="/signup"><i class="icon-Signup dropdown-icon"></i> Signup</i></a></li></ul>
221              </li>
222            </ul>
223          </div>
224
225          <!-- Cart Pod -->
226          <div id="CartMenuSize" class="module widget-handle cart-widget-handle right ecomtrue hidden-sm hidden-xs">
227            <div class="cart max" data-url="/cart">
228              <i class="icon-ti-Cart"></i>
229              <span id="CartItemCount" class="label number"></span>
230              <span class="title">Shopping Cart</span>
231            </div>
232            <div id="CartMenu" class="function">
233              <div class="widget" style="padding: 16px;">
234                <h6 class="title">Shopping Cart</h6>
235                <hr />
236                <ul id="CartInfo" class="cart-overview"></ul>
237                <div class="cart-controls mt16">
238                  <a class="btn btn-sm btn-filled" href="/cart">View Cart</a>
239                  <div class="list-inline pull-right">
240                    <span class="cart-total">Total: </span>
241                    <span id="CartTotal" class="number"></span>
242                  </div>
243                </div>
244              </div>
245            </div>
246          </div>
247
248          <!-- Search Pod - Overlay Trigger -->
249          <div id="SearchOverlayTrigger" class="module widget-handle search-widget-handle right ecomtrue hidden-sm hidden-xs" style="cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;">
250            <div class="search max">
251              <i class="icon-aisearch" style="pointer-events: none;"></i>
252              <span class="title" style="pointer-events: none;">Search Site</span>
253            </div>
254          </div>
255
256          <!-- Menu Pod  -->
257          <div id="TheMenu" class="module left pt0 pb16">
258            <ul id="MainMenu" class="menu"><li class="has-dropdown"><a href="#">Shop by Category</a><ul class="mega-menu"><li><ul id="HeaderCategories"></ul></li></ul></li><li id="GiftCardCart"><a href="/giftcard">Gift Cards</a></li><li style="display:none"></li></ul>
259          </div>
260
261        </div>
262        <!-- End Modal Group -->
263
264      </div>
265    </nav>
266  </div>
267  
268  <!-- Search Overlay Component -->
269  <!-- RunFree Search Overlay - Modular Component -->
270<div id="SearchOverlay" class="search-overlay" role="dialog" aria-modal="true" aria-label="Search Products" aria-hidden="true">
271  <div class="search-overlay-header">
272    <div class="search-logo">
273      <img id="SearchStoreLogo" alt="" src="" />
274    </div>
275    <div class="search-input-container">
276      <i class="icon-aisearch search-icon" aria-hidden="true"></i>
277      <input 
278        type="search" 
279        id="SearchOverlayInput" 
280        class="search-overlay-input" 
281        placeholder="Search for Products, Brands..." 
282        autocomplete="off"
283        spellcheck="false"
284        aria-label="Search for products, brands, or categories"
285        aria-expanded="false"
286        aria-controls="SearchProductPreviews SearchSuggestions"
287        aria-describedby="SearchOverlayDescription"
288      />
289      <span id="SearchOverlayDescription" class="sr-only">Type to search. Use arrow keys to navigate results. Press enter to view all results.</span>
290      <button 
291        class="icon-Broswer-Close clear-search x" 
292        id="ClearSearchInput" 
293        style="display: none;"
294        aria-label="Clear search"
295        type="button"
296      ></button>
297    </div>
298    <button class="search-cancel mb0" id="SearchOverlayCancel">Cancel</button>
299  </div>
300
301  <div class="search-overlay-content">
302    <!-- Left: Suggestions -->
303    <div class="search-suggestions">
304      <!-- Popular Searches -->
305      <div class="suggestions-section" id="PopularSearches" role="region" aria-label="Popular searches">
306        <h4 class="suggestions-title">Popular Searches</h4>
307        <ul id="PopularSearchesList" class="suggestions-list" role="list" aria-live="polite">
308          <!-- Loading skeleton -->
309          <li class="suggestion-skeleton" aria-hidden="true"><span></span></li>
310          <li class="suggestion-skeleton" aria-hidden="true"><span></span></li>
311          <li class="suggestion-skeleton" aria-hidden="true"><span></span></li>
312        </ul>
313      </div>
314      
315      <!-- Top Searched Brands -->
316      <div class="suggestions-section" id="TopBrands" role="region" aria-label="Top brands">
317        <h4 class="suggestions-title">Top Brands</h4>
318        <ul id="TopBrandsList" class="suggestions-list" role="list" aria-live="polite">
319          <!-- Loading skeleton -->
320          <li class="suggestion-skeleton"><span></span></li>
321          <li class="suggestion-skeleton"><span></span></li>
322          <li class="suggestion-skeleton"><span></span></li>
323        </ul>
324      </div>
325      
326      <!-- Top Searched Categories -->
327      <div class="suggestions-section" id="TopCategories" role="region" aria-label="Top categories">
328        <h4 class="suggestions-title">Top Categories</h4>
329        <ul id="TopCategoriesList" class="suggestions-list" role="list" aria-live="polite">
330          <!-- Loading skeleton -->
331          <li class="suggestion-skeleton"><span></span></li>
332          <li class="suggestion-skeleton"><span></span></li>
333          <li class="suggestion-skeleton"><span></span></li>
334        </ul>
335      </div>
336      
337      <!-- Dynamic Search Suggestions (shown when typing) -->
338      <div class="suggestions-section" id="SearchSuggestions" style="display: none;">
339        <h4 class="suggestions-title">Top Suggestions</h4>
340        <ul id="SuggestionsList" class="suggestions-list">
341          <!-- Dynamic suggestions populated here -->
342        </ul>
343      </div>
344    </div>
345
346    <!-- Right: Product Previews -->
347    <div class="search-products">
348      <div class="search-loading-bar" id="SearchLoadingBar">
349        <div class="search-loading-bar-progress"></div>
350      </div>
351      <div class="search-products-fade"></div>
352      <div id="SearchProductPreviews" class="product-previews-grid">
353        <!-- Dynamic product tiles populated here -->
354      </div>
355      <div id="SearchSearching" class="search-searching" style="display: none;">
356        <h3>Searching...</h3>
357      </div>
358      <div id="SearchEmptyState" class="search-empty-state" style="display: none;">
359        <div class="icon-aisearch empty-icon"></div>
360        <p id="SearchEmptyStateText">Start Typing to Search</p>
361        <div class="recent-searches-inline mt8" id="RecentSearches" style="display: none;" role="region" aria-label="Recent searches">
362          <div class="recent-searches-container">
363            <span class="recent-searches-label">Your Recent Searches:</span>
364            <span id="RecentSearchesList" class="recent-searches-links" role="list">
365              <!-- Dynamic recent searches -->
366            </span>
367          </div>
368        </div>
369      </div>
370      <div id="SearchNoResults" class="search-no-results" style="display: none;">
371        <div class="sad-search"></div>
372        <p>Hmmm... We didn't find any matches</p>
373        <span>Modify your search and try again</span>
374      </div>
375    </div>
376  </div>
377
378  <!-- Search All Button -->
379  <div class="search-overlay-footer">
380    <button id="SearchAllButton" class="search-all-button">
381      <div>Search All Products</div>
382    </button>
383  </div>
384</div>
385
386<!-- Product Preview Template -->
387<div id="SearchProductTemplate" class="search-product-tile product clickable template" data-url="{{url}}" style="display: none;">
388  <div class="search-product-image image" style="background-image: url('{{product.url}}')">
389    <span class="search-sale-badge{{onsale}}">SALE</span>
390  </div>
391  <div class="colorswatches" data-product-name="{{product.name}}" data-site-id="{{siteId}}" data-total-colors="{{totalColors}}"></div>
392  <div class="search-product-info">
393    <div class="search-product-name">{{product.name}}</div>
394    <div class="search-product-brand">{{product.brandName}}</div>
395    <div class="search-product-price">{{product.price}}</div>
396  </div>
397</div>
398
399<!-- Color Swatches Component -->
400<script src="/assets/scripts/shared/colorSwatches.js"></script>
400
401
402  
403  <div class="main-container"></div>
404  
405  <!-- Search Overlay Script -->
406  
406<script src="/assets/scripts/search-overlay.js?v=1.2.0"></script>
406
407  
407<script>
408    // Initialize search overlay triggers - use immediate execution to avoid race conditions
409    (function() {
410      function attachSearchTriggers() {
411        var trigger = document.getElementById('SearchOverlayTrigger');
412        
413        if (trigger && typeof SearchOverlay !== 'undefined') {
414          // Remove any existing listener first
415          trigger.replaceWith(trigger.cloneNode(true));
416          trigger = document.getElementById('SearchOverlayTrigger');
417          
418          trigger.addEventListener('click', function(e) {
419            e.preventDefault();
420            e.stopPropagation();
421            SearchOverlay.open();
422          });
423        }
424      }
425      
426      // Attach immediately if DOM is ready, otherwise wait
427      if (document.readyState === 'loading') {
428        document.addEventListener('DOMContentLoaded', attachSearchTriggers);
429      } else {
430        attachSearchTriggers();
431      }
432    })();
433      
434    // Sync mobile cart count with desktop cart count - run after DOM is ready
435    (function() {
436      function syncMobileCart() {
437        var desktopCount = document.getElementById('CartItemCount');
438        var mobileCount = document.getElementById('MobileCartItemCount');
439        if (desktopCount && mobileCount) {
440          mobileCount.textContent = desktopCount.textContent;
441          mobileCount.className = desktopCount.className;
442        }
443      }
444      
445      function initCartSync() {
446        syncMobileCart();
447        
448        var observer = new MutationObserver(syncMobileCart);
449        var desktopCount = document.getElementById('CartItemCount');
450        if (desktopCount) {
451          observer.observe(desktopCount, { childList: true, characterData: true, subtree: true });
452        }
453      }
454      
455      if (document.readyState === 'loading') {
456        document.addEventListener('DOMContentLoaded', initCartSync);
457      } else {
458        initCartSync();
459      }
460    })();
461  </script>
461<section class="page-title page-title-4 image-bg overlay hideshopheaders">
462  <div class="background-image-holder">
463    <img alt="Background Image testing" class="background-image" src="/branding/shop.runningcompany.com/running1.jpg" />
464  </div>
465  <div class="headeroverlay"></div>
466  <div class="container wide">
467    <div class="row">
468      <div class="col-md-7">
469        <h2 class="uppercase mb0 text-shadow">Shop Naperville Running</h2>
470        <p class="lead mb0 text-shadow"></p>
471      </div>
472      <div class="col-md-5 text-right">
473        <ol class="breadcrumb breadcrumb-2 text-shadow">
474          <li><a href="/">Shop</a></li>
475          <li id="CategoryName" class="active"></li>
476        </ol> 
477      </div>
478    </div> 
479  </div>
480</section>
481<div class="threshold hidden">Free Shipping<span class="freeterms hidden"> on orders totaling more than $<span id="Threshold" class="freeamount"></span></span></div>
482<section class="pt24 pt-xs-0 bggrey">
483  <div class="container wide mb8">
484    <div class="row">
485      <div class="col-md-9 col-md-push-3">
486        <div id="BrandingImage" class="col-md-12 mb16" style="display: none">
487          <div class="row">
488            <div class="page-title brandingimage image-bg">
489              <img id="BrandImage" alt="Background Image" class="background-image" />
490            </div>
491          </div>
492        </div>
493
494        <div class="row">
495          <div class="col-sm-12 mb24 mb-sm-0">
496            <div class="row search-page-container pl0 mb-sm-8 initializing">
497              <div class="paging-container">
498                <div class="paging-labels">
499                  <div id="PagingTotalsNone" class="col-md-9 col-sm-12 pageTotals"><span class="input-lh">&nbsp;</span></div>
500                  <div id="PagingTotals" class="col-md-9 col-sm-12 pageTotals"><span class="input-lh"><span id="SearchTotal"></span> Results</span></div>
501                </div>
502                <div id="MobileFilterButton" class="col-xs-6 visible-sm visible-xs pl0 pr1">
503                  <button id="OpenMobileFilters" class="btn" style="width: 100%; margin-bottom: 0;">
504                    Filters <span id="FilterBadge" class="filter-badge" style="display: none;"></span> <div class="filtericon"></div>
505                  </button>
506                </div>
507                <div id="SortArea" class="col-md-3 col-sm-6 col-xs-6 page-select-container widget mb0 pl1 pr0">
508                  <div class="select-option sortby filter-content mb-sm-0 mb0">
509                    <i class="ti-angle-down"></i>
510                    <select id="SortBy">
511                      <option selected value="brandName ASC">Sort By...</option>
512                      <option value="relevance ASC">Relevance</option>
513                      <option value="brandName ASC">Brand</option> 
514                      <option value="name ASC">Product Name</option>
515                      <option value="cost DESC">Highest Price</option>
516                      <option value="cost ASC">Lowest Price</option> 
517                      <option value="isFeatured DESC">Featured</option>
518                    </select>
519                  </div> 
520                </div>
521              </div> 
522            </div>
523          </div>
524        </div>
525
526        <div id="ProductList" class="grid responsive-product-grid initializing">
527          
528          <div id="InitialLoader" style="display: contents;">
529            <div class="product skeleton-loader">
530              <div class="thumb-loading"></div>
531              <div class="title-loading"></div>
532              <div class="brand-loading"></div>
533            </div>
534            <div class="product skeleton-loader">
535              <div class="thumb-loading"></div>
536              <div class="title-loading"></div>
537              <div class="brand-loading"></div>
538            </div>
539            <div class="product skeleton-loader">
540              <div class="thumb-loading"></div>
541              <div class="title-loading"></div>
542              <div class="brand-loading"></div>
543            </div>
544            <div class="product skeleton-loader">
545              <div class="thumb-loading"></div>
546              <div class="title-loading"></div>
547              <div class="brand-loading"></div>
548            </div>
549            <div class="product skeleton-loader">
550              <div class="thumb-loading"></div>
551              <div class="title-loading"></div>
552              <div class="brand-loading"></div>
553            </div>
554            <div class="product skeleton-loader">
555              <div class="thumb-loading"></div>
556              <div class="title-loading"></div>
557              <div class="brand-loading"></div>
558            </div>
559            <div class="product skeleton-loader">
560              <div class="thumb-loading"></div>
561              <div class="title-loading"></div>
562              <div class="brand-loading"></div>
563            </div>
564            <div class="product skeleton-loader">
565              <div class="thumb-loading"></div>
566              <div class="title-loading"></div>
567              <div class="brand-loading"></div>
568            </div>
569            <div class="product skeleton-loader">
570              <div class="thumb-loading"></div>
571              <div class="title-loading"></div>
572              <div class="brand-loading"></div>
573            </div>
574            <div class="product skeleton-loader">
575              <div class="thumb-loading"></div>
576              <div class="title-loading"></div>
577              <div class="brand-loading"></div>
578            </div>
579            <div class="product skeleton-loader">
580              <div class="thumb-loading"></div>
581              <div class="title-loading"></div>
582              <div class="brand-loading"></div>
583            </div>
584            <div class="product skeleton-loader">
585              <div class="thumb-loading"></div>
586              <div class="title-loading"></div>
587              <div class="brand-loading"></div>
588            </div>
589          </div>
590        </div>
591
592        <!--end of row-->
593        <div class="paging col-sm-9 pl0 pr0"><div class="pages"></div></div>
594        <div id="PagingArea" class="pageCount col-sm-3 mt8 mb-xs-32"><span>Page <span id="SearchCurrentPage">1</span> of <span id="SearchTotalPages"></span></div>
595        
596      </div>
597      <!--end of nine col-->
598      <div id="SearchFilterArea" class="col-md-3 col-md-pull-9 pt-xs-24">
599        <div class="mobile-filter-group">
600          <div id="PillBoxArea" class="widget mb-sm-16" style="display: none;">
601            <ul id="PillBox" class="pillbox"></ul>
602            <div id="ClearFilterButton" class="clearfilters mt8 mt-sm-0" style="display: none;"><i class="fa fa-rotate-right red"></i>
603              Clear Filters</div>
604          </div>
605          <!--end of widget-->
606          <div id="FiltersArea">
607          <div class="filter-container visible-sm visible-xs">
608            <i id="FiltersExpand" class="filteropener toggleright"></i>
609            <div class="filtertoggletitle shopfilters mb0">Filter & Sort</div>
610          </div>
611          <div id="FiltersList">
612
613          <div id="BrandArea" class="widget">
614            <div class="filter-container">
615                <i id="BrandsExpand" class="ti-angle-down toggleright"></i>
616                <div class="title shopfilters"> Brand</div>
617            </div>
618            <hr />
619            <div class="filter-content">
620              <input id="BrandSearchInput" class="mb16" type="text" placeholder="Search Brands..." />
621              <div id="BrandCheckboxList" class="mt-sm-0 mb-sm-8"></div>
622              <div id="BrandShowMore" class="show-more-container mb-sm-16" style="display:none;">
623                <a href="javascript:void(0);" class="show-more-link">Show <span id="BrandShowMoreCount"></span> more</a>
624              </div>
625            </div>
626          </div>
627          <!--end of widget-->
628
629          <div id="CategoryArea" class="widget">
630            <div class="filter-container">
631              <i id="CategoriesExpand" class="ti-angle-down toggleright"></i>
632              <div class="title shopfilters">Categories</div>
633            </div>
634            <hr />
635            <div id="CategoryList" class="filter-content mt-sm-0 mb-sm-8" style="display:none">
636              <input id="CategorySearchInput" class="mb16" type="text" placeholder="Search Categories..." />
637              <div id="CategoryLinkList"></div>
638              <div id="CategoryShowMore" class="show-more-container mb-sm-16" style="display:none;">
639                <a href="javascript:void(0);" class="show-more-link">Show <span id="CategoryShowMoreCount"></span> more</a>
640              </div>
641            </div>
642          </div>
643
644          <div id="CollectionArea" class="widget">
645            <div class="filter-container">
646                <i id="CollectionsExpand" class="ti-angle-down toggleright"></i>
647                <div class="title shopfilters">Collections</div>
648            </div>
649            <hr />
650            <div class="filter-content">
651              <input id="CollectionSearchInput" class="mb16" type="text" placeholder="Search Collections..." />
652              <div id="CollectionCheckboxList" class="mt-sm-0 mb-sm-8"></div>
653              <div id="CollectionShowMore" class="show-more-container mb-sm-16" style="display:none;">
654                <a href="javascript:void(0);" class="show-more-link">Show <span id="CollectionShowMoreCount"></span> more</a>
655              </div>
656            </div>
657          </div>
658          <!--end of widget-->
659
660          <div id="SizeArea" class="widget">
661            <div class="filter-container">
662              <i id="SizesExpand" class="ti-angle-down toggleright"></i>
663              <div class="title shopfilters">Sizes</div>
664            </div>
665            <hr />
666            <div class="filter-content">
667              <input id="SizeSearchInput" class="mb16" type="text" placeholder="Search Sizes..." />
668              <div id="SizeCheckboxList" class="mt-sm-0 mb-sm-8"></div>
669              <div id="SizeShowMore" class="show-more-container mb-sm-16" style="display:none;">
670                <a href="javascript:void(0);" class="show-more-link">Show <span id="SizeShowMoreCount"></span> more</a>
671              </div>
672            </div>
673          </div>
674
675          <div id="WidthArea" class="widget bridaloff">
676            <div class="filter-container">
677              <i id="WidthsExpand" class="ti-angle-down toggleright"></i>
678              <div class="title shopfilters">Styles</div>
679            </div>
680            <hr />
681            <div class="filter-content">
682              <input id="WidthSearchInput" class="mb16" type="text" placeholder="Search Styles..." />
683              <div id="WidthCheckboxList" class="mt-sm-0 mb-sm-8"></div>
684              <div id="WidthShowMore" class="show-more-container mb-sm-16" style="display:none;">
685                <a href="javascript:void(0);" class="show-more-link">Show <span id="WidthShowMoreCount"></span> more</a>
686              </div>
687            </div>
688          </div>
689
690          <div id="PriceArea" class="widget">
691            <div class="filter-container">
692              <i id="PriceExpand" class="ti-angle-down toggleright"></i>
693              <div class="title shopfilters">Price</div>
694            </div>
695            <hr />
696            <div class="filter-content">
697              <div id="PriceCheckboxList" class="mt-sm-0 mb-sm-24"></div>
698              <div class="mt-sm-0 mb-sm-16">
699                <div class="price-filter-grid">
700                  <input type="text" id="PriceMin" data-filter="price-min" placeholder="Min" class="mb0" />
701                  <span class="price-dash">-</span>
702                  <input type="text" id="PriceMax" data-filter="price-max" placeholder="Max" class="mb0" />
703                  <button id="ApplyCustomPrice" data-filter="apply-price" class="btn btn-sm mb0">Apply</button>
704                </div>
705              </div>
706            </div>
707          </div>
708
709          <div id="GenderArea" class="widget">
710            <div class="filter-container">
711              <i id="GenderExpand" class="ti-angle-down toggleright"></i>
712              <div class="title shopfilters">Gender</div>
713            </div>
714            <hr />
715            <div class="filter-content">
716              <div id="GenderCheckboxList" class="mt-sm-0 mb-sm-24">
717                <div class="input-checkbox">
718                  <input type="checkbox" id="GenderMens" name="gender-filter" value="M" />
719                  <label for="GenderMens" class="runfreecheck"></label>
720                  <span class="checkboxlabel">Mens</span>
721                </div>
722                <div class="input-checkbox">
723                  <input type="checkbox" id="GenderWomens" name="gender-filter" value="W" />
724                  <label for="GenderWomens" class="runfreecheck"></label>
725                  <span class="checkboxlabel">Womens</span>
726                </div>
727                <div class="input-checkbox">
728                  <input type="checkbox" id="GenderUnisex" name="gender-filter" value="U" />
729                  <label for="GenderUnisex" class="runfreecheck"></label>
730                  <span class="checkboxlabel">Unisex</span>
731                </div>
732                <div class="input-checkbox">
733                  <input type="checkbox" id="GenderKids" name="gender-filter" value="K" />
734                  <label for="GenderKids" class="runfreecheck"></label>
735                  <span class="checkboxlabel">Kids</span>
736                </div>
737              </div>
738            </div>
739          </div>
740
741          <div id="ColorArea" class="widget">
742            <div class="filter-container">
743              <i id="ColorExpand" class="ti-angle-down toggleright"></i>
744              <div class="title shopfilters">Color</div>
745            </div>
746            <hr />
747            <div class="filter-content">
748              <div id="ColorCheckboxList" class="mt-sm-0 mb-sm-8"></div>
749              <div id="ColorShowMore" class="show-more-container mb-sm-16" style="display:none;">
750                <a href="javascript:void(0);" class="show-more-link">Show <span id="ColorShowMoreCount"></span> more</a>
751              </div>
752            </div>
753          </div>
754          <!--end of widget-->
755
756          <div id="ShippingArea" class="widget" style="display:none">
757            <div class="filter-container">
758              <i id="ShippingExpand" class="ti-angle-down toggleright"></i>
759              <div class="title shopfilters">Options</div>
760            </div>
761            <hr />
762            <div id="ShippingList" class="filter-content  mt-sm-0 mb-sm-8">
763              <div class="input-checkbox" style="display:none;"  >
764                <input id="ShipToMe" data-filter="ship-to-me" type="checkbox" name="agree" />
765                <label for="ShipToMe" class="runfreecheck"></label>
766                <span class="checkboxlabel">Ship To Me</span>
767              </div>
768              <div style="display:none;" class="input-checkbox" >
769                <input id="PickupInStore" data-filter="pickup-in-store" type="checkbox" name="agree" />
770                <label for="PickupInStore" class="runfreecheck"></label>
771                <span class="checkboxlabel">Pickup In-Store</span>
772              </div>
773              <div class="input-checkbox" >
774                <input id="OnSale" data-filter="on-sale" type="checkbox" name="agree" />
775                <label for="OnSale" class="runfreecheck"></label>
776                <span class="checkboxlabel">Sale Products</span>
777              </div>
778            </div>
779          </div>
780        </div>
781        </div>
782        </div>
783        <!--end of widget-->
784        <div id="ReturnPolicy" class="widget mb8">
785          <div class="filter-container">
786            <i id="ReturnExpand" class="ti-angle-down toggleright"></i>
787          <div class="title">Return Policy</div>
788        </div>
789          <hr/>
790          <p id="miniReturn">We want you to be 100% satisfied with your purchase. If you're not happy with the product, please contact us before 30 days and we'll make sure you're taken care of. </p>
791        </div>
792
793        <!--end of widget-->
794        <div id="PopularArea" class="widget" style="display:none">
795          <div class="filter-container">
796            <i id="PopularExpand" class="ti-angle-down toggleright"></i>
797            <div class="title">Featured Items</div>
798          </div>
799          <hr />
800          <div id="PopularList" class="cart-overview"></div>
801        </div>
802        <!--end of widget-->
803      </div>
804      <!--end of sidebar-->
805    </div>
806    <!--end of container row-->
807  </div>
808  <!--end of container-->
809</section>
810
811<!-- Mobile Filter Panel -->
812<div id="MobileFilterOverlay" class="mobile-filter-overlay"></div>
813<div id="MobileFilterPanel" class="mobile-filter-panel">
814  <div class="mobile-filter-header">
815    <h3 class="mobile-filter-title">Filters</h3>
816    <button id="CloseMobileFilters" class="mobile-filter-close">
817      <i class="icon-x"></i>
818    </button>
819  </div>
820  <div id="MobilePillBoxArea" class="mobile-pill-box-area" style="display: none;">
821    <ul id="MobilePillBox" class="pillbox"></ul>
822    <div id="MobileClearFilterButton" class="clearfilters mt8 mt-sm-0" style="display: none;"><i class="fa fa-rotate-right red"></i>
823      Clear Filters</div>
824  </div>
825  <div id="MobileFilterContent" class="mobile-filter-content">
826    <!-- Filters will be cloned here -->
827  </div>
828  <div class="mobile-filter-footer">
829    <button id="ApplyMobileFilters" class="btn btn-primary mb0 ml0">
830      View&nbsp;<span id="MobileFilterCount"></span>&nbsp;Products
831    </button>
832  </div>
833</div>
834
835<!-- Templates -->
836<div id="CardLoader" style="display: none;">
837  <div class="cardloader" id="loading">
838    <div class="thumb-loading"></div>
839    <div class="title-loading"></div>
840    <div class="brand-loading"></div>
841    <div class="loadtext">Loading...</div>
842  </div>
843  <div class="cardloader" id="loading">
844    <div class="thumb-loading"></div>
845    <div class="title-loading"></div>
846    <div class="brand-loading"></div>
847    <div class="loadtext">Loading...</div>
848  </div>
849  <div class="cardloader" id="loading">
850    <div class="thumb-loading"></div>
851    <div class="title-loading"></div>
852    <div class="brand-loading"></div>
853    <div class="loadtext">Loading...</div>
854  </div>
855  <div class="cardloader" id="loading">
856    <div class="thumb-loading"></div>
857    <div class="title-loading"></div>
858    <div class="brand-loading"></div>
859    <div class="loadtext">Loading...</div>
860  </div>
861  <div class="cardloader" id="loading">
862    <div class="thumb-loading"></div>
863    <div class="title-loading"></div>
864    <div class="brand-loading"></div>
865    <div class="loadtext">Loading...</div>
866  </div>
867  <div class="cardloader" id="loading">
868    <div class="thumb-loading"></div>
869    <div class="title-loading"></div>
870    <div class="brand-loading"></div>
871    <div class="loadtext">Loading...</div>
872  </div>
873  <div class="cardloader" id="loading">
874    <div class="thumb-loading"></div>
875    <div class="title-loading"></div>
876    <div class="brand-loading"></div>
877    <div class="loadtext">Loading...</div>
878  </div>
879  <div class="cardloader" id="loading">
880    <div class="thumb-loading"></div>
881    <div class="title-loading"></div>
882    <div class="brand-loading"></div>
883    <div class="loadtext">Loading...</div>
884  </div>
885  <div class="cardloader" id="loading">
886    <div class="thumb-loading"></div>
887    <div class="title-loading"></div>
888    <div class="brand-loading"></div>
889    <div class="loadtext">Loading...</div>
890  </div>
891    <div class="cardloader" id="loading">
892    <div class="thumb-loading"></div>
893    <div class="title-loading"></div>
894    <div class="brand-loading"></div>
895    <div class="loadtext">Loading...</div>
896  </div>
897  <div class="cardloader" id="loading">
898    <div class="thumb-loading"></div>
899    <div class="title-loading"></div>
900    <div class="brand-loading"></div>
901    <div class="loadtext">Loading...</div>
902  </div>
903  <div class="cardloader" id="loading">
904    <div class="thumb-loading"></div>
905    <div class="title-loading"></div>
906    <div class="brand-loading"></div>
907    <div class="loadtext">Loading...</div>
908  </div>
909</div>
910
911<style>
912  @keyframes fadeInUp {
913  from {
914    opacity: 0;
915    transform: translateY(60px);
916  }
917  to {
918    opacity: 1;
919    transform: translateY(0);
920  }
921}
922#SearchFilterArea {
923  opacity: 1;
924  /** animation: fadeInUp 0.9s cubic-bezier(0.22, 0.61, 0.36, 1) forwards; **/
925}
926
927/* Generic Filter Styles */
928#BrandCheckboxList,
929#SizeCheckboxList,
930#WidthCheckboxList,
931#PriceCheckboxList,
932#GenderCheckboxList {
933  margin-top: 0;
934  margin-bottom: 8px;
935}
936
937/* Hide native checkbox inputs - custom styling via .runfreecheck label */
938.input-checkbox input[type="checkbox"] {
939  position: absolute;
940  opacity: 0;
941  pointer-events: none;
942}
943
944/* Add left margin to align checkboxes with section headers */
945.input-checkbox {
946  margin-left: 17px;
947}
948
949.show-more-container {
950  margin-top: 8px;
951}
952
953.show-more-link,
954.show-more-link span {
955  color: var(--almostblack )!important;
956  text-decoration: underline !important;
957  font-size: 15px !important;
958  font-weight: 600 !important;
959}
960
961.show-more-link:hover,
962.show-more-link:hover span {
963  color: var(--primary)!important;
964  filter: unset;
965}
966
967.show-more-link:active {
968  filter: brightness(75%);
969  transform: translateY(1px)!important;
970  transition: 0.3s;
971}
972
973/* Price filter grid */
974.price-filter-grid {
975  display: grid;
976  gap: 8px;
977  align-items: center;
978  margin-bottom: 8px;
979  grid-template-columns: 70px 5px 70px 100px;
980}
981
982.price-dash {
983  color: var(--almostblack);
984  margin-bottom: 4px;
985  text-align: center;
986}
987
988/* Wrap Apply button to new line on tablet and below when sidebar is narrower */
989@media (max-width: 1200px) {
990  .price-filter-grid {
991    grid-template-columns: 70px 5px 70px;
992  }
993  
994  .price-filter-grid #ApplyCustomPrice {
995    grid-column: 1 / -1;
996    width: 100%;
997  }
998}
999
1000/* Color filter circles */
1001.color-circle {
1002  width: 24px;
1003  height: 24px;
1004  border-radius: 50%;
1005  display: inline-block;
1006  margin-right: 8px;
1007  border: 2px solid #e0e0e0;
1008  vertical-align: middle;
1009  position: relative;
1010  top: -1px;
1011}
1012
1013.input-checkbox .color-circle {
1014  margin-left: 8px;
1015}
1016
1017/* Make filter containers clickable */
1018.filter-container {
1019  cursor: pointer;
1020  user-select: none;
1021}
1022
1023.filter-container:hover .ti-angle-down.toggleright {
1024  color: var(--almostblack);
1025}
1026
1027/* Category Filter Styles */
1028.category-item {
1029  display: block;
1030  margin-bottom: 8px;
1031}
1032
1033.category-toggle {
1034  cursor: pointer;
1035  font-size: 12px;
1036  margin-right: 10px;
1037  vertical-align: middle;
1038  color: var(--filterhr);
1039  font-weight: 100;
1040  transition: 0.3s;
1041}
1042
1043.category-toggle:hover {
1044  color: var(--almostblack);
1045  transition: 0.3s;
1046}
1047
1048.category-toggle:active {
1049  filter: brightness(75%);
1050  transform: translateY(1px);
1051  transition: 0.3s;
1052}
1053
1054.category-link {
1055  color: var(--menu);
1056  text-decoration: none;
1057}
1058
1059.category-link.selected {
1060  font-weight: 700;
1061  color: var(--primary)!important;
1062  transition: 0.3s;
1063}
1064
1065.category-link:hover {
1066  color: var(--primary);
1067  text-decoration: underline;
1068  filter: unset;
1069  transition: 0.3s;
1070}
1071
1072.category-link:active {
1073  filter: brightness(80%);
1074  transition: 0.3s;
1075}
1076
1077.category-spacer {
1078  display: inline-block;
1079  width: 20px;
1080}
1081
1082.category-children {
1083  display: none;
1084  margin-left: 30px;
1085  margin-top: 5px;
1086}
1087
1088.category-child-item {
1089  margin-bottom: 5px;
1090}
1091
1092/* Prevent body scroll when mobile filter is open - iOS fix */
1093body.mobile-filter-open {
1094  overflow: hidden !important;
1095  position: fixed;
1096  width: 100%;
1097  height: 100%;
1098  touch-action: none;
1099  -webkit-overflow-scrolling: none;
1100}
1101
1102/* Mobile Filter Panel Styles */
1103.mobile-filter-overlay {
1104  display: none;
1105  position: fixed;
1106  top: 0;
1107  left: 0;
1108  right: 0;
1109  bottom: 0;
1110  width: 100%;
1111  height: 100%;
1112  background: var(--bggrey);
1113  z-index: 9998;
1114  opacity: 0;
1115  transition: opacity 0.3s ease;
1116}
1117
1118.mobile-filter-overlay.active {
1119  display: block;
1120  opacity: 1;
1121}
1122
1123.mobile-filter-panel {
1124  position: fixed;
1125  top: 0;
1126  left: 0;
1127  right: 0;
1128  bottom: 0;
1129  width: 100%;
1130  background: var(--white);
1131  z-index: 9999;
1132  display: flex;
1133  flex-direction: column;
1134  transform: translateX(-100%);
1135  transform-origin: left center;
1136  will-change: transform;
1137  overflow: hidden;
1138}
1139
1140.mobile-filter-panel.active {
1141  animation: slideInFromLeft 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
1142}
1143
1144.count {
1145  display: none !important;
1146}
1147
1148@keyframes slideInFromLeft {
1149  0% {
1150    transform: translateX(-100%) scaleX(0.95);
1151  }
1152  50% {
1153    transform: translateX(0) scaleX(1.03);
1154  }
1155  65% {
1156    transform: translateX(0) scaleX(0.98);
1157  }
1158  80% {
1159    transform: translateX(0) scaleX(1.01);
1160  }
1161  100% {
1162    transform: translateX(0) scaleX(1);
1163  }
1164}
1165
1166.mobile-filter-header {
1167  position: sticky;
1168  top: 0;
1169  background: var(--bggrey);
1170  padding: 15px 20px 15px 20px;
1171  border-bottom: 1px solid var(--border);
1172  display: flex;
1173  justify-content: space-between;
1174  align-items: center;
1175  z-index: 10;
1176}
1177
1178.mobile-pill-box-area {
1179  position: sticky;
1180  top: 69px;
1181  background: white;
1182  padding: 12px 20px;
1183  border-bottom: 1px solid var(--border);
1184  z-index: 9;
1185}
1186
1187.mobile-pill-box-area .pillbox {
1188  margin-bottom: 0;
1189}
1190
1191.mobile-pill-box-area .clearfilters {
1192  margin-top: 8px;
1193}
1194
1195.mobile-filter-title {
1196  margin: 0;
1197  font-size: 20px;
1198  font-weight: 700;
1199  color: var(--almostblack);
1200}
1201
1202.mobile-filter-close {
1203  background: none;
1204  border: none;
1205  font-size: 25px;
1206  color: var(--almostblack);
1207  cursor: pointer;
1208  padding: 0;
1209  width: 32px;
1210  height: 32px;
1211  font-weight: 800;
1212  display: flex;
1213  align-items: center;
1214  justify-content: center;
1215  margin-bottom: 0px;
1216}
1217
1218.mobile-filter-close:hover {
1219  color: var(--primary);
1220}
1221
1222.mobile-filter-content {
1223  flex: 1;
1224  overflow-y: auto;
1225  overflow-x: hidden;
1226  padding: 20px;
1227  -webkit-overflow-scrolling: touch;
1228}
1229
1230.mobile-filter-footer {
1231  position: sticky;
1232  bottom: 0;
1233  background: var(--bggrey);
1234  padding: 16px 20px;
1235  border-top: 1px solid var(--border);
1236  z-index: 10;
1237  text-align: center;
1238}
1239
1240#ApplyMobileFilters {
1241  width: 225px;
1242  height: auto;
1243  margin: 0 auto;
1244  position: relative;
1245  cursor: pointer;
1246  transition: all 0.2s ease;
1247  display: inline;
1248  align-items: center;
1249  justify-content: center;
1250  font-family: inherit;
1251  margin-bottom: 0px;
1252  border: 2px solid transparent;
1253  border-radius: 12px;
1254  padding: 3px 20px;
1255  font-size: 16px;
1256  font-weight: 700;
1257  color: #ffffff;
1258  overflow: visible;
1259  -webkit-tap-highlight-color: transparent;
1260  touch-action: manipulation;
1261  /* Rainbow gradient background with multiple layers */
1262  background: 
1263    linear-gradient(#121213, #121213) padding-box,
1264    linear-gradient(#121213 50%, rgba(18, 18, 19, 0.6) 80%, rgba(18, 18, 19, 0)) border-box,
1265    linear-gradient(90deg, 
1266    #0fb865,
1267    #3285ff,
1268    #f94543,
1269    #fabd10
1270    ) border-box;
1271  background-size: 200%;
1272  background-clip: padding-box, border-box, border-box;
1273  background-origin: border-box;
1274  animation: rainbow 2s linear infinite;
1275}
1276
1277#ApplyMobileFilters::before {
1278  content: '';
1279  position: absolute;
1280  bottom: -30%;
1281  left: 50%;
1282  z-index: 0;
1283  height: 30%;
1284  width: 90%;
1285  transform: translateX(-50%);
1286  background: linear-gradient(90deg, 
1287    #0fb865,
1288    #3285ff,
1289    #f94543,
1290    #fabd10
1291  );
1292  filter: blur(20px);
1293  opacity: 0.8;
1294  animation: rainbow 2s linear infinite;
1295}
1296
1297#ApplyMobileFilters  span,
1298#ApplyMobileFilters  i,
1299#ApplyMobileFilters  div {
1300  position: relative;
1301  z-index: 1;
1302}
1303
1304#ApplyMobileFilters:hover {
1305  transform: scale(1.02);
1306}
1307
1308#ApplyMobileFilters:active {
1309  transform: translateY(2px);
1310}
1311
1312#MobileFilterCount {
1313  font-weight: 700;
1314}
1315
1316/**
1317#ApplyMobileFilters {
1318  color: #fff;
1319  background-color: var(--primary);
1320  border-color: var(--primary);
1321}
1322
1323#ApplyMobileFilters:focus {
1324  color: #fff;
1325  background-color: var(--primary);
1326  border-color: var(--primary);
1327}
1328
1329#ApplyMobileFilters span {
1330  font-weight: 800;
1331}
1332  **/
1333
1334#OpenMobileFilters {
1335  background-color: var(--white);
1336  border-color: var(--white);
1337  height: 50px;
1338  border-radius: 0px;
1339  color: var(--almostblack);
1340  margin-left:0px;
1341  outline: white;
1342  font-size: 14px;
1343  font-weight: 700;
1344  text-align: left;
1345  animation: fadeIn 1.75s ease forwards;
1346}
1347
1348#OpenMobileFilters:hover {
1349  filter: brightness(90%);
1350}
1351
1352#OpenMobileFilters:active {
1353  box-shadow: unset;
1354}
1355
1356#OpenMobileFilters span {
1357  font-size: 14px;
1358}
1359
1360.filter-badge {
1361    display: inline-block;
1362    min-width: 18px;
1363    height: 18px;
1364    padding: 3px 3px;
1365    font-size: 11px !important;
1366    font-weight: 700;
1367    line-height: 12px;
1368    color: var(--white);
1369    text-align: center;
1370    white-space: nowrap;
1371    vertical-align: middle;
1372    background-color: var(--almostblack);
1373    border-radius: 18px;
1374    margin-left: 4px;
1375    margin-top: -1px;
1376}
1377
1378/* Button Loading Spinner Styles */
1379#ApplyMobileFilters.loading {
1380  position: relative !important;
1381  pointer-events: none;
1382}
1383
1384#ApplyMobileFilters.loading::before {
1385  content: "";
1386  position: absolute;
1387  right: 18px;
1388  top: 50%;
1389  transform: translateY(-50%);
1390  width: 16px;
1391  height: 16px;
1392  border: 2px solid rgba(255, 255, 255, 0.3);
1393  border-top-color: white;
1394  border-radius: 50%;
1395  animation: buttonSpinner 0.8s linear infinite;
1396}
1397
1398@keyframes buttonSpinner {
1399  to {
1400    transform: translateY(-50%) rotate(360deg);
1401  }
1402}
1403
1404.filtericon {
1405  width: 20px;
1406  height: 20px;
1407  margin-bottom: 0px;
1408  margin-top: 8px;
1409  margin-right: -7px;
1410  background-image: url(/assets/images/filters.svg);
1411  background-size: 20px;
1412  background-repeat: no-repeat;
1413  float: right;
1414}
1415
1416
1417/* Hide desktop filter area on mobile when panel is used */
1418@media (max-width: 975px) {
1419  .mobile-filter-group {
1420    display: none !important;
1421  }
1422  
1423  /* Ensure Sort By stays visible on mobile */
1424  #SortArea {
1425    display: block !important;
1426  }
1427  
1428  /* Mobile filter/sort button row */
1429  #MobileFilterButton,
1430  #SortArea {
1431    margin-bottom: 0px;
1432  }
1433  
1434  .pr1 {
1435    padding-right: 1px;
1436  }
1437  
1438  .pl1 {
1439    padding-left: 1px;
1440  }
1441
1442  
1443  /* Hide paging labels initially to prevent layout shift */
1444  .paging-labels {
1445    position: absolute;
1446    visibility: hidden;
1447  }
1448  
1449  /* Show paging labels after they've been repositioned */
1450  .paging-labels.positioned {
1451    position: static;
1452    visibility: visible;
1453  }
1454}
1455
1456/* Hide SSR products until initialization is complete */
1457#ProductList.initializing .product:not(.skeleton-loader) {
1458  display: none !important;
1459}
1460/* Style skeleton loaders */
1461.skeleton-loader {
1462  pointer-events: none;
1463  background: var(--white);
1464}
1465/* Reserve space for paging/sort to prevent layout jump - desktop only */
1466@media (min-width: 768px) {
1467  .search-page-container {
1468    min-height: 48px;
1469  }
1470  /* Collapse during initialization to match skeleton position */
1471  .search-page-container.initializing {
1472    min-height: 0 !important;
1473    height: 0;
1474    overflow: hidden;
1475  }
1476}
1477/* Also collapse the parent container's margin during initialization */
1478.col-sm-12:has(.search-page-container.initializing) {
1479  margin-bottom: 64px !important;
1480}
1481/* Hide paging/sort areas during initialization to prevent layout jump */
1482.search-page-container.initializing .paging-labels,
1483.search-page-container.initializing #SortArea {
1484  opacity: 0;
1485  visibility: hidden;
1486}
1487/* Fade in paging/sort areas after initialization */
1488.search-page-container:not(.initializing) .paging-labels,
1489.search-page-container:not(.initializing) #SortArea {
1490  animation: fadeIn 1s ease forwards;
1491}
1492@keyframes fadeIn {
1493  from {
1494    opacity: 0;
1495  }
1496  to {
1497    opacity: 1;
1498  }
1499}
1500</style>
1501
1502<!-- Wishlist Login Modal -->
1503<div id="WishlistLoginModal" class="modal box">
1504  <div class="close"></div>
1505  <div class="modal-header">
1506    <div class="wishlist-color-modal mb24"></div>
1507    <div>
1508        <div class="title mt0 text-left">Save to Wishlist</div>
1509        <div class="subtitle mt0 mb8">Please login or sign up to save items to your wishlist</div>
1510    </div>
1511  </div>
1512  <div class="grid two" style="gap: 12px; margin-top: 24px;">
1513    <a href="/login" class="button hollow" style="text-decoration: none; color: white; text-align: center;" onclick="modal.close();">Login</a>
1514    <a href="/signup" class="button" style="text-decoration: none; color: white; text-align: center;" onclick="modal.close();">Sign Up</a>
1515  </div>
1516</div>
1517
1518<!-- Repeater Templates -->
1519<div id="RowTemplate" class="product template clickable" style="display:none">
1520  <span class="salelabel"><span class="salelabel-text">SALE</span></span>
1521  <span class="releaselabel"></span>
1522  <button class="wishlist-toggle inactive" data-product-id="" aria-label="Add to wishlist">
1523    <div class="btn__effect">
1524      <svg class="heart-stroke" viewBox="20 18 29 28" aria-hidden="true" focusable="false"><path d="M28.3 21.1a4.3 4.3 0 0 1 4.1 2.6 2.5 2.5 0 0 0 2.3 1.7c1 0 1.7-.6 2.2-1.7a3.7 3.7 0 0 1 3.7-2.6c2.7 0 5.2 2.7 5.3 5.8.2 4-5.4 11.2-9.3 15a2.8 2.8 0 0 1-2 1 3.4 3.4 0 0 1-2.2-1c-9.6-10-9.4-13.2-9.3-15 0-1 .6-5.8 5.2-5.8m0-3c-5.3 0-7.9 4.3-8.2 8.5-.2 3.2.4 7.2 10.2 17.4a6.3 6.3 0 0 0 4.3 1.9 5.7 5.7 0 0 0 4.1-1.9c1.1-1 10.6-10.7 10.3-17.3-.2-4.6-4-8.6-8.4-8.6a7.6 7.6 0 0 0-6 2.7 8.1 8.1 0 0 0-6.2-2.7z"></path></svg>
1525      <svg class="heart-full" viewBox="0 0 19.2 18.5" aria-hidden="true" focusable="false"><path d="M9.66 18.48a4.23 4.23 0 0 1-2.89-1.22C.29 10.44-.12 7.79.02 5.67.21 2.87 1.95.03 5.42.01c1.61-.07 3.16.57 4.25 1.76A5.07 5.07 0 0 1 13.6 0c2.88 0 5.43 2.66 5.59 5.74.2 4.37-6.09 10.79-6.8 11.5-.71.77-1.7 1.21-2.74 1.23z"></path></svg>
1526      <svg class="broken-heart" xmlns="http://www.w3.org/2000/svg" width="32" height="12" viewBox="5.707 17 32 12"><g fill="var(--red)"><path class="broken-heart--left" d="M21.865 28.735V18.703a3.562 3.562 0 0 0-2.567-1.476c-2.916.017-3.378 2.403-3.538 4.756-.118 1.781.227 4.006 4.672 7.737a2.544 2.544 0 0 0 1.428 1.025l-.008-.008.013-.002z"/><path class="broken-heart--right" d="M27.868 22.045c-.135-2.588-1.277-4.823-3.697-4.823a3.258 3.258 0 0 0-2.302 1.487l-.004-.003v10.035a2.215 2.215 0 0 0 1.289-1.033c.598-.596 4.882-5.99 4.714-9.663z"/></g><path class="broken-heart--crack" fill="none" stroke="#FFF" stroke-miterlimit="10" d="M21.865 18.205v10.573"/></svg>
1527      <div class="effect-group">
1528        <span class="effect"></span>
1529        <span class="effect"></span>
1530        <span class="effect"></span>
1531        <span class="effect"></span>
1532        <span class="effect"></span>
1533      </div>
1534    </div>
1535  </button>
1536  <div class="image"></div>
1537  <div class="colorswatches" data-product-name="" data-site-id="" data-total-colors=""></div>
1538  <div class="name"></div>
1539  <div class="brand uppercase"></div>
1540  <div class="price"></div>
1541  <a href="" rel="cononical" aria-label=""></a>
1542</div> 
1543
1544<div id="PopularTemplate" class="template popular grid split clicker featured" style="display:none">
1545  <div class="image mini" style="background-image: url('{{product.url}}')"></div>
1546  <div class="description">
1547    <span class="name">{{product.name}}</span>
1548    <span class="price">${{product.price}}</span>
1549    <a href="{{url}}"></a>
1550  </div>
1551</div>
1552
1553<script>
1554// Apply stagger animation to products dynamically
1555document.addEventListener('DOMContentLoaded', function() {
1556  // Apply stagger animation to SSR products
1557  document.querySelectorAll('.product').forEach((el, i) => el.style.setProperty('--i', i + 1));
1558  
1559  // Check if we have filters in the URL that will cause JS filtering
1560  const urlParams = new URLSearchParams(window.location.search);
1561  const hasFilters = urlParams.has('category') || urlParams.has('brand') || 
1562                     urlParams.has('size') || urlParams.has('width') ||
1563                     urlParams.has('search') || urlParams.has('q') ||
1564                     urlParams.has('c') || urlParams.has('sale');
1565  
1566  // If no filters, reveal products immediately
1567  // If filters exist, keep initializing state until JS filtering completes
1568  if (!hasFilters) {
1569    $('#ProductList').removeClass('initializing');
1570    $('#InitialLoader').remove();
1571    $('.search-page-container').removeClass('initializing');
1572  }
1573  
1574  // Attach click handlers
1575  $('.clickable').off('click').on('click', page.goto);
1576  
1577  // Load color swatches and wishlist asynchronously after products are visible
1578  // This prevents blocking the animation
1579  setTimeout(function() {
1580    // Initialize color swatches
1581    colorSwatches.init('#ProductList');
1582    colorSwatches.load();
1583    
1584    // Re-render swatches after layout is complete to get accurate container widths
1585    setTimeout(function() {
1586      colorSwatches.load(true); // Force refresh with correct widths
1587    }, 500);
1588    
1589    // Attach wishlist toggle handlers directly to SSR products
1590    // Must be attached before .clickable handlers fire
1591    // Attach wishlist toggle handlers
1592    $('.wishlist-toggle').off('click').on('click', page.toggleWishlist);
1593    
1594    // Update wishlist button states asynchronously
1595    if (page && page.updateWishlistButtons) {
1596      if (wishlist && wishlist.isLoaded) {
1597        page.updateWishlistButtons();
1598      } else {
1599        // Wait for wishlist to load in background
1600        var checkWishlist = setInterval(function() {
1601          if (wishlist && wishlist.isLoaded) {
1602            clearInterval(checkWishlist);
1603            page.updateWishlistButtons();
1604          }
1605        }, 50); 
1606        // Stop checking after 5 seconds
1607        setTimeout(function() {
1608          clearInterval(checkWishlist);
1609        }, 5000);
1610      }
1611    }
1612  }, 0);
1613});
1614</script>
1614
1615
1616<script src="/assets/scripts/shared/colorSwatches.js"></script>
vendor: 2 bytes, line 1616
1616
1617<script src="/assets/scripts/productRelease.js"></script>
vendor: 2 bytes, line 1617
1617
1618<script src="/assets/scripts/collection.js"></script>
1618
1619
1620<script language="javascript" type="text/javascript">
1621  var threshold = Number('100');
1622  var isAutoSale = 'false'=='true';
1623  var flatRate = Number('8');
1624  var shipType = 'flat';
1625  var inStoreAllowed = 'true';
1626  var defaultSort = 'isFeatured DESC';
1627  var brandImage = '';
1628  var proSizes = '[{"size":"0","productCount":24},{"size":"1","productCount":25},{"size":"1.5","productCount":28},{"size":"2","productCount":18},{"size":"2.5","productCount":27},{"size":"3","productCount":18},{"size":"3.5","productCount":45},{"size":"4","productCount":44},{"size":"4.5","productCount":138},{"size":"5","productCount":243},{"size":"5.5","productCount":827},{"size":"6","productCount":306},{"size":"6.5","productCount":996},{"size":"7","productCount":514},{"size":"7.5","productCount":1769},{"size":"8","productCount":1373},{"size":"8.5","productCount":1875},{"size":"9","productCount":1414},{"size":"9.5","productCount":1976},{"size":"10","productCount":1426},{"size":"10.5","productCount":1889},{"size":"11","productCount":568},{"size":"11.5","productCount":1386},{"size":"12","productCount":456},{"size":"12.5","productCount":845},{"size":"13","productCount":709},{"size":"13.5","productCount":26},{"size":"14","productCount":271},{"size":"15","productCount":540},{"size":"16","productCount":35},{"size":"17","productCount":4},{"size":"18","productCount":3},{"size":"01","productCount":1},{"size":"02","productCount":2},{"size":"02.5","productCount":1},{"size":"03","productCount":1},{"size":"03.5","productCount":1},{"size":"04","productCount":7},{"size":"04.5","productCount":2},{"size":"05","productCount":13},{"size":"05.5","productCount":6},{"size":"06","productCount":34},{"size":"06.5","productCount":72},{"size":"07","productCount":135},{"size":"07.5","productCount":139},{"size":"08","productCount":177},{"size":"08.5","productCount":229},{"size":"09","productCount":273},{"size":"09.5","productCount":267},{"size":"36","productCount":6},{"size":"37","productCount":9},{"size":"38","productCount":11},{"size":"39","productCount":12},{"size":"40","productCount":9},{"size":"41","productCount":16},{"size":"42","productCount":6},{"size":"43","productCount":5},{"size":"44","productCount":6},{"size":"45","productCount":6},{"size":"46","productCount":5}]';
1629  var proWidths = '[{"sizeAppend":"2A","width":"2A","productCount":26},{"sizeAppend":"2E","width":"2E","productCount":123},{"sizeAppend":"4E","width":"4E","productCount":49},{"sizeAppend":"6E","width":"6E","productCount":6},{"sizeAppend":"B","width":"B","productCount":526},{"sizeAppend":"D","width":"D","productCount":763},{"sizeAppend":"EE","width":"EE","productCount":183},{"sizeAppend":"EEEE","width":"EEEE","productCount":22},{"sizeAppend":"L","width":"L","productCount":24},{"sizeAppend":"MD","width":"MD","productCount":55},{"sizeAppend":"S","width":"S","productCount":24},{"sizeAppend":"W","width":"W","productCount":19},{"sizeAppend":"WIDE","width":"WIDE","productCount":7},{"sizeAppend":"XL","width":"XL","productCount":24},{"sizeAppend":"N","width":"N","productCount":9},{"sizeAppend":"R","width":"R","productCount":7}]';
1630  var forcing = false; 
1631
1632  // Known brand names for extraction from search queries
1633  const KNOWN_BRANDS = [
1634    'brooks', 'nike', 'adidas', 'asics', 'saucony', 'hoka', 'new balance',
1635    'mizuno', 'altra', 'on', 'salomon', 'merrell', 'inov-8', 'topo athletic',
1636    'newton', 'karhu', 'under armour', 'reebok', 'puma', 'skechers',
1637    'la sportiva', 'diadora', 'oofos', 'balega', 'feetures', 'darn tough',
1638    'smartwool', 'swiftwick', 'bombas', 'thorlo', 'injinji', 'stance',
1639    'garmin', 'polar', 'coros', 'suunto', 'gu', 'maurten', 'tailwind',
1640    'nuun', 'skratch', 'hammer', 'clif', 'honey stinger', 'nathan',
1641    'amphipod', 'camelbak', 'ultimate direction', 'osprey', 'orange mud',
1642    'flipbelt', 'spibelt', 'lululemon', 'athleta', 'patagonia', 'rabbit'
1643  ];
1644
1645  // Import synonym maps from search-overlay for consistent search behavior
1646  // This is a simplified version - only includes the most common terms
1647const SEARCH_SYNONYMS = {
1648    // Footwear types
1649    'shoe': ['shoes', 'sneaker', 'sneakers'],
1650    'shoes': ['shoe', 'sneaker', 'sneakers'],
1651    'sneaker': ['sneakers', 'shoe', 'shoes'],
1652    'sneakers': ['sneaker', 'shoe', 'shoes'],
1653    'racing flat': ['racing flats', 'flat', 'flats', 'racer', 'racers'],
1654    'spike': ['spikes', 'track spike', 'track spikes'],
1655    
1656    // Shoe characteristics (from your categories)
1657    'neutral': ['cushioned', 'cushion', 'mens neutral', 'wmns neutral'],
1658    'stability': ['support', 'supportive', 'motion control', 'mens stability', 'wmns stability'],
1659    'motion control': ['stability', 'support', 'mens motion control', 'wmns motion control'],
1660    'cushion': ['cushioned', 'neutral', 'plush', 'soft'],
1661    'cushioned': ['cushion', 'neutral', 'plush', 'soft'],
1662    'minimal': ['minimalist', 'barefoot', 'zero drop'],
1663    'minimalist': ['minimal', 'barefoot', 'zero drop'],
1664    'maximal': ['maximalist', 'max cushion', 'ultra cushion'],
1665    'maximalist': ['maximal', 'max cushion', 'ultra cushion'],
1666    'responsive': ['bouncy', 'springy', 'energetic'],
1667    'lightweight': ['light', 'fast', 'racing'],
1668    'waterproof': ['water resistant', 'gore-tex', 'gtx'],
1669    'racing': ['race', 'fast', 'mens racing', 'wmns racing'],
1670    'trail': ['trails', 'hiking', 'mens trail', 'wmns trail'],
1671    'sandals': ['sandal', 'mens sandals', 'wmns sandals'],
1672    
1673    // Gender terms (from your categories)
1674    'mens': ["men's", 'men', 'male', 'mns', 'm'],
1675    'men': ["men's", 'mens', 'male', 'mns', 'm'],
1676    'wmns': ["women's", 'womens', 'women', 'female', 'w'],
1677    'womens': ["women's", 'wmns', 'women', 'female', 'ladies', 'w'],
1678    'women': ["women's", 'womens', 'wmns', 'female', 'ladies', 'w'],
1679    'ladies': ["women's", 'women', 'womens', 'wmns', 'female', 'w'],
1680    'mns': ["men's", 'mens', 'men', 'male', 'm'],
1681    'm': ["men's", 'mens', 'men', 'male', 'mns'],
1682    'w': ["women's", 'womens', 'women', 'female', 'wmns'],
1683    'kids': ['youth', 'children', 'junior', 'boys', 'girls'],
1684    'youth': ['kids', 'children', 'junior'],
1685    
1686    // Apparel types (from your categories)
1687    'sock': ['socks', 'hosiery'],
1688    'socks': ['sock', 'hosiery'],
1689    'short': ['shorts', '4" short', '5" short', '7" short', '9" short', 'split short'],
1690    'shorts': ['short', 'mens short', 'wmns short', 'long short'],
1691    'shirt': ['shirts', 'top', 'tops', 'tee', 'tees'],
1692    'shirts': ['shirt', 'top', 'tops', 'tee', 'tees'],
1693    'top': ['tops', 'shirt', 'shirts', 'tee', 'tees'],
1694    'tops': ['top', 'shirt', 'shirts', 'tee', 'tees', 'ss tops', 'ls tops'],
1695    'tee': ['tees', 'shirt', 'shirts', 't-shirt'],
1696    'tees': ['tee', 'shirt', 'shirts', 't-shirts'],
1697    'pant': ['pants', 'trouser', 'trousers', 'tight', 'tights', 'mens pant', 'wmns pant'],
1698    'pants': ['pant', 'trouser', 'trousers', 'tight', 'tights'],
1699    'tight': ['tights', 'legging', 'leggings', 'pant', 'pants', 'mens tight', 'wmns tight'],
1700    'tights': ['tight', 'legging', 'leggings', 'pant', 'pants'],
1701    'legging': ['leggings', 'tight', 'tights'],
1702    'leggings': ['legging', 'tight', 'tights'],
1703    'capri': ['capris', 'mens capri', 'wmns capri'],
1704    'jacket': ['jackets', 'coat', 'coats', 'outerwear'],
1705    'jackets': ['jacket', 'coat', 'coats', 'outerwear'],
1706    'outerwear': ['jacket', 'jackets', 'coat', 'coats', 'mens outerwear', 'wmns outerwear'],
1707    'zip': ['zipline', '1/2 zip', 'half zip', 'mens 1/2 zip', 'wmns 1/2 zip'],
1708    'bra': ['bras', 'sports bra', 'run bra', 'wmns bra'],
1709    'tank': ['tanks', 'singlet', 'mens tank', 'wmns tank'],
1710    'vest': ['vests', 'hydration vest', 'running vest'],
1711    'base layer': ['base layers', 'baselayer', 'thermal'],
1712    'arm sleeve': ['arm sleeves', 'sleeves'],
1713    'calf sleeve': ['calf sleeves', 'compression sleeve'],
1714    'long sleeve': ['ls', 'long sleeves', 'mens ls tops', 'wmns ls tops'],
1715    'short sleeve': ['ss', 'short sleeves', 'mens ss tops', 'wmns ss tops'],
1716    'skirt': ['skirts', 'wmns skirt', 'running skirt'],
1717    'dress': ['dresses'],
1718    'underwear': ['undergarments', 'mens underwear', 'wmns underwear'],
1719    '2 in 1': ['2-n-1', 'mens 2 in 1', 'wmns 2-n-1'],
1720    
1721    // Accessories (from your categories)
1722    'glove': ['gloves', 'mitt', 'mitts'],
1723    'gloves': ['glove', 'mitt', 'mitts'],
1724    'hat': ['hats', 'cap', 'caps', 'beanie', 'headwear'],
1725    'cap': ['caps', 'hat', 'hats'],
1726    'visor': ['visors'],
1727    'headband': ['headbands', 'sweatband'],
1728    'buff': ['buffs', 'neck gaiter', 'gaiter'],
1729    'watch': ['watches', 'gps', 'fitness tracker', 'smartwatch', 'electronics'],
1730    'belt': ['belts', 'running belt', 'waist pack'],
1731    'pack': ['packs', 'hydration pack', 'vest', 'backpack', 'bags'],
1732    'bag': ['bags', 'backpack', 'duffel', 'pack'],
1733    'bottle': ['bottles', 'water bottle', 'flask', 'hydration'],
1734    'light': ['lights', 'headlamp', 'flashlight'],
1735    'reflective': ['reflective gear', 'visibility', 'hi-vis'],
1736    'sunglasses': ['glasses', 'shades', 'eyewear'],
1737    'eyewear': ['sunglasses', 'glasses', 'shades'],
1738    'insole': ['insoles', 'insert', 'inserts', 'footbed', 'shoe accessories'],
1739    'insoles': ['insole', 'insert', 'inserts', 'footbed'],
1740    'collar': ['collars', 'dog collar'],
1741    'stroller': ['strollers', 'jogging stroller'],
1742    'book': ['books', 'magazines', 'books/magazines'],
1743    'injury prevention': ['recovery', 'massage', 'foam roller'],
1744    
1745    // Activity types (running specific)
1746    'run': ['running', 'runner', 'runners', 'jog', 'jogging'],
1747    'running': ['run', 'runner', 'runners', 'jog', 'jogging'],
1748    'jog': ['jogging', 'jogger', 'run', 'running'],
1749    'jogging': ['jog', 'jogger', 'run', 'running'],
1750    'walk': ['walking', 'walker'],
1751    'walking': ['walk', 'walker'],
1752    'hike': ['hiking', 'hiker', 'trail'],
1753    'hiking': ['hike', 'hiker', 'trail'],
1754    'trail': ['trails', 'hiking', 'hike', 'off-road', 'mountain', 'mens trail', 'wmns trail'],
1755    'ultra': ['ultramarathon', 'ultrarunning', 'ultra running'],
1756    'marathon': ['marathons', 'long distance', 'distance'],
1757    'half marathon': ['half', 'half marathons', '13.1'],
1758    '5k': ['5km', 'five k'],
1759    '10k': ['10km', 'ten k'],
1760    'track': ['racing', 'race', 'tempo'],
1761    'race': ['racing', 'track', 'tempo', 'speed'],
1762    'tempo': ['threshold', 'tempo run'],
1763    'interval': ['intervals', 'speed work', 'track work'],
1764    'recovery': ['recover', 'rest', 'easy', 'massage'],
1765    'training': ['train', 'trainer', 'workout', 'mens training', 'wmns training'],
1766    'lifestyle': ['casual', 'everyday', 'wmns lifestyle'],
1767    'tri': ['triathlon', 'wmns tri top'],
1768    
1769    // Common terms
1770    'sport': ['sports', 'athletic'],
1771    'sports': ['sport', 'athletic'],
1772    'athletic': ['athletics', 'sport', 'sports'],
1773    'training': ['train', 'trainer', 'workout'],
1774    'workout': ['training', 'exercise', 'fitness'],
1775    'gear': ['equipment', 'accessories'],
1776    'compression': ['compress', 'tight', 'support', 'wmns compression'],
1777    'breathable': ['moisture wicking', 'wicking', 'ventilated'],
1778    'nutrition': ['fuel', 'energy', 'hydration', 'gu', 'gels'],
1779    'hydration': ['water', 'fluid', 'drink', 'nutrition', 'bottle'],
1780    'gel': ['gels', 'energy gel', 'gu'],
1781    'chew': ['chews', 'energy chew', 'blocks'],
1782    'clearance': ['sale', 'discount', 'closeout'],
1783    'apparel': ['clothing', 'clothes', 'mens apparel', 'womens apparel', 'kids apparel'],
1784    'footwear': ['shoes', 'shoe', 'mens footwear', 'womens footwear', 'kids footwear', 'unisex footwear'],
1785    
1786    // Brand names (from your database)
1787    'hoka': ['hoka one one'],
1788    'nb': ['new balance'],
1789    'newbalance': ['new balance', 'nb'],
1790    'on': ['on running', 'on cloud'],
1791    
1792    // Common brand misspellings - Running Shoe Brands
1793    'nike': ['nke', 'nikey', 'nyke', 'nikee'],
1794    'adidas': ['addidas', 'adiddas', 'addias', 'adidias', 'adiddis'],
1795    'balance': ['balence', 'ballance', 'balanse'],
1796    'new balance': ['newbalance', 'new ballance', 'new balence', 'newbalence'],
1797    'brooks': ['brook', 'broks', 'brookes', 'brookz', 'brroks'],
1798    'asics': ['asic', 'asix', 'asicks', 'acics', 'assics', 'asiks'],
1799    'saucony': ['sauconey', 'sacony', 'sauconny', 'saucany', 'socony', 'saucon'],
1800    'mizuno': ['mizino', 'mizumo', 'mizzuno', 'mizunno', 'misuno'],
1801    'altra': ['altrah', 'altera', 'alltra', 'alttra'],
1802    'salomon': ['salmon', 'salamon', 'salamon', 'soloman', 'solamon'],
1803    'hoka': ['hooka', 'hokka', 'hocka', 'hokah', 'hoko'],
1804    'merrell': ['merell', 'merrel', 'merel', 'merrill', 'merill'],
1805    'skechers': ['sketchers', 'skecher', 'sketcher', 'skeechers', 'skethers'],
1806    'puma': ['pumma', 'pooma', 'pumah'],
1807    'reebok': ['rebok', 'reebok', 'rebock', 'reebook'],
1808    'under armour': ['under armor', 'underarmour', 'underarmor', 'ua'],
1809    'oofos': ['oofoos', 'oofo', 'oofus', 'ooofos'],
1810    'topo athletic': ['topo', 'toppo', 'topo atheltic'],
1811    'inov-8': ['inov8', 'inov', 'innovate', 'innov8'],
1812    'karhu': ['karho', 'karuh', 'karoo'],
1813    'newton': ['newten', 'neuton'],
1814    'diadora': ['diadoria', 'diodora', 'diadorra'],
1815    'la sportiva': ['lasportiva', 'la sportive', 'sportiva'],
1816    'norda': ['norda', 'nordah'],
1817    
1818    // Common product misspellings - Brooks
1819    'ghost': ['ghot', 'gost', 'ghoast', 'goast'],
1820    'adrenaline': ['adrenalin', 'adreneline', 'addrenaline', 'adrenalene', 'andenaline'],
1821    'glycerin': ['glycerine', 'glicerin', 'glyceran', 'glyserin', 'glycren'],
1822    'cascadia': ['cascada', 'cascadea', 'cascaddia', 'cascaida'],
1823    'levitate': ['levitae', 'levitat', 'levatate', 'levitte'],
1824    'hyperion': ['hypereon', 'hyperian', 'hyerion', 'hyperyon'],
1825    
1826    // Common product misspellings - Nike
1827    'pegasus': ['pegusus', 'pegeses', 'pegasas', 'pegsus', 'pegisis', 'pegusas'],
1828    'vomero': ['vomaro', 'vommero', 'vomorro', 'vomera'],
1829    'vaporfly': ['vapourfly', 'vaporflye', 'vaperfly', 'vaporflie'],
1830    'alphafly': ['alphaflye', 'alfafly', 'alphaflie', 'alpahfly'],
1831    'invincible': ['invincable', 'invicible', 'invinsible', 'invincble'],
1832    'infinity': ['infiniti', 'infnity', 'infinty', 'infitity'],
1833    
1834    // Common product misspellings - Hoka
1835    'bondi': ['bondie', 'bondy', 'bondii', 'bandi', 'bondee'],
1836    'clifton': ['cliffton', 'cliften', 'clifften', 'cliftton', 'cliftonn'],
1837    'speedgoat': ['speed goat', 'speedgot', 'speedgoaat', 'speegoat'],
1838    'rincon': ['rinconn', 'ricon', 'rinkin', 'rickon'],
1839    'arahi': ['arhi', 'arhai', 'arhi', 'ahrai'],
1840    'mach': ['mac', 'match', 'maach'],
1841    'gaviota': ['gaviotta', 'gavioat', 'gaviots', 'gavioota'],
1842    'kawana': ['kawanna', 'kowona', 'kawona', 'kawanna'],
1843    
1844    // Common product misspellings - ASICS
1845    'kayano': ['kayanno', 'kayanna', 'kyano', 'kayno', 'kaiano'],
1846    'nimbus': ['nimbes', 'nimbis', 'nimbuus', 'nimbes'],
1847    'cumulus': ['cumulis', 'cumulous', 'cumulas', 'cummulus'],
1848    'novablast': ['nova blast', 'novablst', 'novvablast'],
1849    'metaspeed': ['meta speed', 'metaspede', 'metasped'],
1850    
1851    // Common product misspellings - Saucony
1852    'kinvara': ['kinvarra', 'kinvera', 'kinvarra', 'kinvar', 'kinvra'],
1853    'triumph': ['truimph', 'triump', 'triumf', 'triuph', 'trumph'],
1854    'endorphin': ['endorfin', 'endorphan', 'endophin', 'endorphine'],
1855    'peregrine': ['peragrine', 'perregrine', 'perergrine', 'perigrine'],
1856    'hurricane': ['hurrican', 'huricane', 'hurricaine', 'huricain'],
1857    
1858    // Common product misspellings - New Balance
1859    'fuelcell': ['fuel cell', 'fuelcel', 'fuellcell', 'fuelsel'],
1860    'fresh foam': ['freshfoam', 'fresh fome', 'freshfome'],
1861    
1862    // Common product misspellings - Altra
1863    'escalante': ['escalant', 'escallante', 'escalente', 'escalanty'],
1864    'torin': ['torrin', 'toren', 'torinn', 'torren'],
1865    'lone peak': ['lonepeak', 'lone peek', 'lonepeek'],
1866    'timp': ['timmp', 'tymp', 'tem'],
1867    'paradigm': ['paradigim', 'peradigm', 'paradime', 'paradgm'],
1868    'olympus': ['olypmus', 'olympis', 'olumpus', 'olympas'],
1869    
1870    // Common product misspellings - On Running
1871    'cloudrunner': ['cloud runner', 'cloudruner', 'cloudrunnr'],
1872    'cloudflow': ['cloud flow', 'cloudfloe', 'cloudflo'],
1873    'cloudmonster': ['cloud monster', 'cloudmonstr', 'cloudmoster'],
1874    'cloudsurfer': ['cloud surfer', 'cloudsurfer', 'cloudsurffer'],
1875    
1876    // Common product misspellings - Mizuno
1877    'wave rider': ['waverider', 'wave ridder', 'waveridder'],
1878    'wave inspire': ['waveinspire', 'wave insipre', 'wave inspir'],
1879    
1880    // Common product misspellings - Salomon
1881    'speedcross': ['speed cross', 'speedcros', 'speedcross'],
1882    
1883    // Sock brand misspellings
1884    'feetures': ['features', 'feeture', 'featurs', 'feeturs', 'feechers'],
1885    'balega': ['balaga', 'balego', 'baleca', 'belega', 'bellega'],
1886    'darn tough': ['darntough', 'darn tuff', 'darntuff', 'darn tuf'],
1887    'smartwool': ['smart wool', 'smartwhool', 'smartwol', 'smartwoool'],
1888    'swiftwick': ['swiftwhick', 'swiftwik', 'swiftwhik', 'swift wick'],
1889    'injinji': ['injini', 'injinji', 'injiji', 'injenji', 'injinjii'],
1890    'thorlo': ['thorlow', 'thorloo', 'tharlo', 'thorlos'],
1891    'bombas': ['bomba', 'bombass', 'bombis', 'bomas'],
1892    
1893    // Watch/tech brand misspellings
1894    'garmin': ['garmen', 'garmim', 'garman', 'gramin', 'garmon'],
1895    'polar': ['poler', 'pollar', 'polor'],
1896    'coros': ['corros', 'coras', 'corros', 'koros'],
1897    'suunto': ['sunto', 'suunto', 'sunnto', 'suunton', 'sunnto'],
1898    'whoop': ['woop', 'whooop', 'whopp'],
1899    'wahoo': ['wahho', 'waho', 'waahoo', 'wahoe'],
1900    
1901    // Nutrition brand misspellings
1902    'maurten': ['morten', 'maurteen', 'marten', 'maurtenn', 'maurtun'],
1903    'nuun': ['nun', 'noon', 'nunn', 'nune'],
1904    'tailwind': ['tailwing', 'tailwinnd', 'tail wind', 'talwind'],
1905    'skratch': ['scratch', 'skrach', 'scrach', 'skratch'],
1906    'gu': ['guu', 'goo'],
1907    'clif': ['cliff', 'clif', 'clifff'],
1908    'honey stinger': ['honeystinger', 'honey stiner', 'hony stinger'],
1909    'huma': ['humma', 'humas', 'huuma'],
1910    'ucan': ['youcan', 'u can', 'uucan'],
1911    
1912    // Hydration/accessory brand misspellings
1913    'nathan': ['nathen', 'nathann', 'nathon'],
1914    'amphipod': ['amphipod', 'amfipod', 'amphapod', 'amphypod'],
1915    'camelbak': ['camelback', 'camelbac', 'cammelback', 'camelbakk'],
1916    'ultimate direction': ['ultimatedirection', 'ultimate directon', 'ud'],
1917    'flipbelt': ['flip belt', 'flipblt', 'flibelt'],
1918    'spibelt': ['spy belt', 'spi belt', 'spybelt'],
1919    'osprey': ['ospry', 'osprery', 'ossprey'],
1920    
1921    // Apparel brand misspellings
1922    'lululemon': ['lulu lemon', 'lulemon', 'lulullemon', 'lulumon'],
1923    'athleta': ['athletia', 'atheleta', 'athlete', 'atheleta'],
1924    'patagonia': ['patogonia', 'patigonia', 'patagona', 'patgonia'],
1925    'oiselle': ['oisele', 'oisselle', 'oisell', 'oisele'],
1926    'janji': ['janji', 'janjii', 'janjy', 'janji'],
1927    'vuori': ['vuoori', 'vouri', 'vuorii', 'voori'],
1928    'rhone': ['rhon', 'rone', 'rhonne'],
1929    
1930    // Eyewear brand misspellings
1931    'goodr': ['gooder', 'goodrr', 'good r', 'goodar'],
1932    'oakley': ['oakly', 'okley', 'oakely', 'oaklee'],
1933    'tifosi': ['tifossi', 'tiffosi', 'tifos', 'tifosy'],
1934  };
1935
1936  /**
1937   * Extract quoted strings from search query
1938   * Returns object with quoted phrases and cleaned query
1939   * Example: 'nike "wave inspire 16" shoes' => { quotedPhrases: ['wave inspire 16'], cleanedQuery: 'nike shoes' }
1940   * @param {string} query - The search query
1941   * @returns {Object} - { quotedPhrases: string[], cleanedQuery: string }
1942   */
1943  function extractQuotedStrings(query) {
1944    const quotedPhrases = [];
1945    let cleanedQuery = query?.toString() || '';
1946    
1947    const quotePattern = /"([^"]*)"|'([^']*)'|"([^"]*)"|'([^']*)'/g;
1948    let match;
1949    
1950    while ((match = quotePattern.exec(query)) !== null) {
1951      // Extract the matched text from whichever group captured it
1952      const quotedText = (match[1] || match[2] || match[3] || match[4] || '').trim();
1953      if (quotedText.length > 0) {
1954        quotedPhrases.push(quotedText);
1955        // Remove the quoted phrase from the query (including quotes)
1956        cleanedQuery = cleanedQuery.replace(match[0], ' ').trim();
1957      }
1958    }
1959    
1960    // Clean up multiple spaces
1961    try {
1962      cleanedQuery = cleanedQuery.replace(/\s+/g, ' ').trim();
1963    } catch (e) {
1964
1965    }
1966    
1967    return {
1968      quotedPhrases,
1969      cleanedQuery
1970    };
1971  }
1972
1973  // Extract brand names from search query
1974  function extractBrandsFromQuery(query, allBrands) {
1975    const normalized = query.toLowerCase().trim();
1976    const words = normalized.split(/\s+/);
1977    const detectedBrands = [];
1978    const wordsToKeep = []; 
1979    
1980    // Build a brand map from allBrands array
1981    const brandMap = {};
1982    if (allBrands && allBrands.length > 0) {
1983      allBrands.forEach(brand => {
1984        brandMap[brand.name.toLowerCase()] = brand.brandId;
1985      });
1986    }
1987    
1988    // Check each word (and combinations) against known brands
1989    let i = 0;
1990    while (i < words.length) {
1991      let matchFound = false;
1992      let skipWords = 0;
1993      
1994      // Try 3-word combinations
1995      if (i + 2 < words.length) {
1996        const threeWord = `${words[i]} ${words[i+1]} ${words[i+2]}`;
1997        if (KNOWN_BRANDS.includes(threeWord)) {
1998          const brandId = brandMap[threeWord]; // May be undefined if brands not loaded yet
1999          detectedBrands.push({ id: brandId, name: threeWord });
2000          skipWords = 3;
2001          matchFound = true;
2002        }
2003      }
2004      
2005      // Try 2-word combinations
2006      if (!matchFound && i + 1 < words.length) {
2007        const twoWord = `${words[i]} ${words[i+1]}`;
2008        if (KNOWN_BRANDS.includes(twoWord)) {
2009          const brandId = brandMap[twoWord]; // May be undefined if brands not loaded yet
2010          detectedBrands.push({ id: brandId, name: twoWord });
2011          skipWords = 2;
2012          matchFound = true;
2013        }
2014      }
2015      
2016      // Try single word
2017      if (!matchFound) {
2018        const word = words[i];
2019        if (KNOWN_BRANDS.includes(word)) {
2020          const brandId = brandMap[word]; // May be undefined if brands not loaded yet
2021          detectedBrands.push({ id: brandId, name: word });
2022          skipWords = 1;
2023          matchFound = true;
2024        }
2025      }
2026      
2027      if (matchFound) {
2028        i += skipWords;
2029      } else {
2030        wordsToKeep.push(words[i]);
2031        i++;
2032      }
2033    }
2034    
2035    return {
2036      detectedBrands,
2037      cleanedQuery: wordsToKeep.join(' ')
2038    };
2039  }
2040
2041  // Function to expand search terms with synonyms (matching search-overlay logic)
2042  function expandSearchTermsWithSynonyms(searchTerms) {
2043    // IMPORTANT: Start with the full original phrase to ensure phrase matching
2044    // Example: ["inspire", "15"] becomes ["inspire 15", "inspire", "15", ...]
2045    const allTerms = [searchTerms.join(' ')]; // Full phrase as first term
2046    
2047    searchTerms.forEach(term => {
2048      const normalized = term.toLowerCase().trim();
2049      
2050      // Add original term only if not already present (avoid duplicates)
2051      if (!allTerms.includes(normalized)) {
2052        allTerms.push(normalized);
2053      }
2054      
2055      // Add ALL synonyms if they exist (matching search-overlay behavior)
2056      if (SEARCH_SYNONYMS[normalized]) {
2057        SEARCH_SYNONYMS[normalized].forEach(syn => {
2058          if (!allTerms.includes(syn)) {
2059            allTerms.push(syn);
2060          }
2061        });
2062      }
2063    });
2064    
2065    return allTerms;
2066  }
2067
2068  var page = {
2069    category: null,
2070    lastSearch: "", 
2071    categories: [],
2072    brands: [],
2073    collections: [],
2074    products: [],
2075    popular: [],
2076    brandsCalled: false,
2077    doAfterCatLoad: false,
2078    doAfterBrandLoad: false,
2079    parentSelected: -1,
2080    isInitial: false,
2081    forceBrand: "",
2082    forceBrandId: -1,
2083    forceCategory: "",
2084    forceCategoryId: -1,
2085    terms: {
2086      instore: 0,
2087      shipable: 0,
2088      brand: {
2089        label: "",
2090        id: -1
2091      },
2092      categories: {
2093        label: "",
2094        id: -1
2095      },
2096      filters: [],  
2097      filter: "",
2098      sizes: [],
2099      widths: [],
2100      prices: []
2101    },
2102    /**
2103     * Extract gender keywords from query and return query with gender codes
2104     * NOTE: We don't remove gender keywords from the query - they still help with matching
2105     * @param {string} query - The search query
2106     * @returns {Object} - { cleanedQuery: string, genders: string[] }
2107     */ 
2108    extractGenderFromQuery: function(query) {
2109      // Gender keyword patterns mapped to gender codes
2110      const genderPatterns = {
2111        'M': [ 
2112          /\b(men'?s?|male|mns?|boys?)\b/gi
2113        ],
2114        'W': [
2115          /\b(women'?s?|womens?|wmns|female|ladies|girls?)\b/gi
2116        ],
2117        'U': [ 
2118          /\bunisex\b/gi
2119        ],
2120        'K': [
2121          /\b(kids?|youth|children|child)\b/gi
2122        ]
2123      };
2124
2125      const detectedGenders = new Set();
2126
2127      // Check each gender pattern but DON'T remove from query
2128      for (const [genderCode, patterns] of Object.entries(genderPatterns)) {
2129        for (const pattern of patterns) {
2130          if (pattern.test(query)) {
2131            detectedGenders.add(genderCode);
2132          }
2133        }
2134      }
2135
2136      return {
2137        cleanedQuery: query, // Keep original query intact
2138        genders: Array.from(detectedGenders)
2139      };
2140    },
2141    /**
2142     * Extract color keywords from query and return detected colors
2143     * @param {string} query - The search query
2144     * @returns {Object} - { cleanedQuery: string, colors: string[] }
2145     */ 
2146    extractColorFromQuery: function(query) {
2147      // Color keyword patterns mapped to color names (matching colorDefinitions)
2148      const colorPatterns = {
2149        'Red': /\b(red|crimson|scarlet|maroon|burgundy)\b/gi,
2150        'Orange': /\b(orange|tangerine|coral)\b/gi,
2151        'Yellow': /\b(yellow|gold|golden|mustard|lemon)\b/gi,
2152        'Green': /\b(green|olive|lime|mint|teal|emerald|forest)\b/gi,
2153        'Blue': /\b(blue|navy|aqua|cyan|cobalt|royal|indigo|turquoise)\b/gi,
2154        'Purple': /\b(purple|violet|lavender|plum|magenta)\b/gi,
2155        'Pink': /\b(pink|rose|salmon|fuchsia|blush)\b/gi,
2156        'Beige': /\b(beige|tan|khaki|cream|nude|sand)\b/gi,
2157        'Brown': /\b(brown|chocolate|coffee|mocha|caramel|chestnut)\b/gi,
2158        'Black': /\b(black|onyx|charcoal|ebony)\b/gi,
2159        'Gray': /\b(gray|grey|silver|slate|graphite|ash)\b/gi,
2160        'White': /\b(white|ivory|pearl|snow|cream)\b/gi
2161      };
2162
2163      const detectedColors = new Set();
2164      let cleanedQuery = query;
2165
2166      // Check each color pattern and remove from query
2167      for (const [colorName, pattern] of Object.entries(colorPatterns)) {
2168        if (pattern.test(query)) {
2169          detectedColors.add(colorName);
2170          // Remove the color keyword from query to avoid redundant search
2171          cleanedQuery = cleanedQuery.replace(pattern, ' ');
2172        }
2173      }
2174
2175      // Normalize whitespace
2176      cleanedQuery = cleanedQuery.trim().replace(/\s+/g, ' ');
2177
2178      return {
2179        cleanedQuery: cleanedQuery,
2180        colors: Array.from(detectedColors)
2181      };
2182    },
2183    init: function () {
2184        $("#PagingTotalsNone").hide();
2185      if (document.referrer) {
2186        var url = document.referrer; 
2187        var ref = url.match(/:\/\/(.[^/]+)/)[1];
2188        if (ref!=window.location.hostname) {
2189          page.terms = { brand: { label: "", id: -1 }, brands: [], collections: [], categories: { label: "", id: -1 }, filter: "", filters: [], quotedFilters: [], sizes: [], widths: [], prices: [], colors: [], genders: [], page: 1 };
2190          context.set("storeTerms", page.terms);
2191        }
2192      } else {
2193        //page.terms = { brand: { label: "", id: -1 }, categories: { label: "", id: -1 }, filter: "", filters: [], sizes: [], widths: [] };
2194        //context.set("storeTerms", page.terms);
2195      }
2196      
2197      // Bug #4 fix: If navigating to /shop with NO filters (clean URL), clear saved filters
2198      // This ensures clicking "Shop" in nav resets to a fresh browse experience
2199      var isCleanShopUrl = (window.location.pathname === '/shop' || window.location.pathname === '/shop/') && 
2200                           window.location.hash.length === 0 && 
2201                           window.location.search.length === 0;
2202      if (isCleanShopUrl) {
2203        page.terms = { brand: { label: "", id: -1 }, brands: [], collections: [], categories: { label: "", id: -1 }, filter: "", filters: [], quotedFilters: [], sizes: [], widths: [], prices: [], colors: [], genders: [], page: 1 };
2204        context.set("storeTerms", page.terms);
2205      }
2206      
2207      if (window.location.pathname.length>1) {
2208        var parts = window.location.pathname.substr(1).split('/');
2209        if (parts[0]=="brand") {
2210          forcing = true;
2211          if (isNaN(parts[1])) page.forceBrand = parts[1].split('%20').join(' ');
2212          else page.forceBrandId = Number(parts[1]);
2213        }
2214        if (parts[0]=="category") {
2215          forcing = true;
2216          if (isNaN(parts[1])) page.forceCategory = parts[parts.length-1].split('%20').join(' ');
2217          else page.forceCategoryId = Number(parts[1]);
2218        }
2219      } 
2220      products.searchId = ""; //moment().unix();
2221      if (!products.filter) products.filter = {};
2222      products.filter.grouped = false; // Show ungrouped variant counts to match brand filter counts
2223      
2224      // Check if there's a search query in the URL
2225      const urlParams = new URLSearchParams(window.location.search);
2226      const hasSearchParam = urlParams.has('search') || urlParams.has('q');
2227      const hasSortParam = urlParams.has('sort');
2228      const saleParamValue = (urlParams.get('sale') || '').trim().toLowerCase();
2229      const hasSaleParam = saleParamValue === '1' || saleParamValue === 'true' || saleParamValue === 'yes';
2230      
2231      // Set default sort based on context
2232      if (defaultSort && defaultSort !== '') { 
2233        var sortBy = defaultSort.split(" ");
2234        if (sortBy.length == 2) {
2235          products.filter.sort = sortBy[0];
2236          products.filter.sortType = sortBy[1];
2237        }
2238        $('#SortBy').val(defaultSort);
2239      } else if (hasSearchParam && !hasSortParam) {
2240        // When searching without explicit sort, default to relevance
2241        products.filter.sort = "relevance";
2242        products.filter.sortType = "ASC";
2243        $('#SortBy').val("relevance ASC");
2244      } else {
2245        products.filter.sort = "brandName, name";
2246      }
2247      page.events();
2248      
2249      // Initialize color filter
2250      page.initColors();
2251      
2252      // Load wishlist for logged-in users
2253      if (user && user.data && user.data.memberId && typeof wishlist !== 'undefined' && !wishlist.isLoaded) {
2254        wishlist.load();
2255      }
2256      
2257      brand.filter.size = 1000; 
2258      brand.get(); // Load brands for filter
2259      
2260      collection.filter.size = 1000;
2261      collection.get(); // Load collections for filter
2262      
2263      // Load sizes and widths for filters 
2264      page.sizesLoaded(page.parseValueList(proSizes));
2265      page.widthsLoaded(page.parseValueList(proWidths));
2266      
2267      // Initialize price filter checkboxes (will show 0 counts until products load)
2268      page.initializePriceFilters();
2269      
2270      // Check for query string params BEFORE restoring storeTerms - they should override saved filters
2271      if (window.location.search.length > 0) {
2272        if (urlParams.has('brand') || urlParams.has('category') || urlParams.has('search') || urlParams.has('q') || hasSaleParam) {
2273          forcing = true; // Set forcing early so storeTerms are not restored
2274          page.isInitial = false; // Ensure API call is made since server-rendered products may not match filters
2275        }
2276      }
2277      
2278      var lastFilter = context.get("storeTerms");
2279      if (lastFilter&&!forcing&&((lastFilter.filters&&lastFilter.filters.length>0) || lastFilter.categories.id>-1 || (lastFilter.brands&&lastFilter.brands.length>0))) {
2280        page.terms = lastFilter; 
2281        // Migrate old brand structure to new brands array if needed
2282        if (!page.terms.brands) {
2283          page.terms.brands = [];
2284          if (page.terms.brand && page.terms.brand.id !== -1) {
2285            page.terms.brands.push({
2286              id: page.terms.brand.id,
2287              label: page.terms.brand.label
2288            });
2289          }
2290        }
2291        // Ensure the old singular brand object is cleared if brands array is empty
2292        if (page.terms.brands.length === 0) {
2293          page.terms.brand = { label: "", id: -1 };
2294        }
2295        // Ensure colors array exists
2296        if (!page.terms.colors) {
2297          page.terms.colors = [];
2298        }
2299        // Ensure quotedFilters array exists (migration from old saved terms)
2300        if (!page.terms.quotedFilters) {
2301          page.terms.quotedFilters = [];
2302        }
2303        page.isInitial = false;
2304      }
2305      if (inStoreAllowed) $("#ShippingArea").show();
2306      
2307      // Bug #3 fix: Handle query string params (?search=ghost or ?q=ghost) directly
2308      // Process them the same way as urlParamsChanged, but keep original URL
2309      if (window.location.search.length > 0) {
2310        // Handle search param from query string (support both 'search' and 'q' params)
2311        var searchParam = urlParams.get('search') || urlParams.get('q');
2312        if (searchParam && searchParam.trim().length > 0) {
2313          var searchValue = decodeURIComponent(searchParam.trim());
2314          
2315          // FIRST: Extract quoted strings before any other processing
2316          // Example: 'nike "wave inspire 16" shoes' => quotedPhrases: ['wave inspire 16'], cleanedQuery: 'nike shoes'
2317          var quoteResult = extractQuotedStrings(searchValue);
2318          var quotedPhrases = quoteResult.quotedPhrases;
2319          var cleanedSearch = quoteResult.cleanedQuery;
2320          
2321          // Check if the entire search is quoted (no remaining text after quote extraction)
2322          var isFullyQuoted = quotedPhrases && quotedPhrases.length > 0 && (!cleanedSearch || cleanedSearch.trim().length === 0);
2323          
2324          // Clear old filters for a fresh search (same as hashChanged does)
2325          page.terms.filters = [];
2326          page.terms.quotedFilters = []; // Track which filters came from quoted searches
2327          page.terms.genders = [];
2328          page.terms.brands = [];
2329          page.terms.collections = [];
2330          page.terms.sizes = [];
2331          page.terms.widths = [];
2332          page.terms.prices = [];
2333          page.terms.colors = [];
2334          
2335          if (isFullyQuoted) {
2336            // Fully quoted search - use ONLY the quoted phrase(s), no brand/gender/color extraction
2337            quotedPhrases.forEach(function(phrase) {
2338              if (phrase && phrase.trim().length > 0 && !page.terms.filters.includes(phrase)) {
2339                page.terms.filters.push(phrase);
2340                page.terms.quotedFilters.push(phrase); // Mark as quoted
2341              }
2342            });
2343          } else {
2344            // Normal search or mixed quoted+unquoted - process brands/genders/colors
2345            
2346            // Add quoted phrases to filters first (if any) and mark them as quoted
2347            if (quotedPhrases && quotedPhrases.length > 0) {
2348              quotedPhrases.forEach(function(phrase) {
2349                if (phrase && phrase.trim().length > 0 && !page.terms.filters.includes(phrase)) {
2350                  page.terms.filters.push(phrase);
2351                  page.terms.quotedFilters.push(phrase); // Mark as quoted
2352                }
2353              });
2354            }
2355          
2356            // Extract gender from the remaining search query (after quotes removed)
2357            var genderExtraction = page.extractGenderFromQuery(cleanedSearch);
2358            cleanedSearch = cleanedSearch;
2359            if (genderExtraction.genders && genderExtraction.genders.length > 0) {
2360              if (!page.terms.genders) page.terms.genders = [];
2361              var genderLabels = { 'M': 'Mens', 'W': 'Womens', 'U': 'Unisex', 'K': 'Kids' };
2362              genderExtraction.genders.forEach(function(g) {
2363                if (!page.terms.genders.includes(g)) {
2364                  page.terms.genders.push(g);
2365                }
2366              });
2367              // Remove gender keywords from search
2368              cleanedSearch = searchValue.replace(/\b(men'?s?|women'?s?|womens?|wmns|male|female|ladies|boys?|girls?|kids?|youth|children|child|unisex|mns?)\b/gi, ' ');
2369              cleanedSearch = cleanedSearch.trim().replace(/\s+/g, ' ');
2370            }
2371             
2372            // Extract colors from the search query (e.g., "red shoes" → apply red color filter)
2373            var colorExtraction = page.extractColorFromQuery(cleanedSearch);
2374            if (colorExtraction.colors && colorExtraction.colors.length > 0) {
2375              if (!page.terms.colors) page.terms.colors = [];
2376              if (!page.terms.filters) page.terms.filters = [];
2377              colorExtraction.colors.forEach(function(colorName) {
2378                if (!page.terms.colors.some(function(c) { return c.name === colorName; })) {
2379                  var colorDef = page.colorDefinitions ? page.colorDefinitions.find(function(c) { return c.name === colorName; }) : null;
2380                  page.terms.colors.push({ 
2381                    name: colorName, 
2382                    hex: colorDef ? colorDef.hex : '#888888' 
2383                  });
2384                  // Add color to filters array so it's actually searched
2385                  var colorLower = colorName.toLowerCase();
2386                  if (!page.terms.filters.includes(colorLower)) {
2387                    page.terms.filters.push(colorLower);
2388                  }
2389                  // Check the corresponding color checkbox
2390                  $('#ColorCheckboxList input[value="' + colorName + '"]').prop("checked", true);
2391                  $('#MobileFilterContent #ColorCheckboxList input[value="' + colorName + '"]').prop("checked", true);
2392                }
2393              });
2394              // Use the cleaned query (with color removed) for the search f
2394ilter
2395              cleanedSearch = colorExtraction.cleanedQuery;
2396            }
2397            
2398            // Extract brands from the search term before adding to filters
2399            // Note: page.brands may not be loaded yet at this point, but we still extract
2400            // based on KNOWN_BRANDS and the brands will be applied once page.brands loads
2401            if (cleanedSearch && cleanedSearch.length > 0) {
2402              var brandExtraction = extractBrandsFromQuery(cleanedSearch, page.brands || []);
2403              
2404              // If brands were detected, store their names for later mapping
2405              // We can't add IDs yet because page.brands isn't loaded
2406              if (brandExtraction.detectedBrands && brandExtraction.detectedBrands.length > 0) {
2407                if (!page.pendingBrandNames) page.pendingBrandNames = [];
2408                brandExtraction.detectedBrands.forEach(function(brand) {
2409                  // If we got an ID (brands were already loaded), add to page.terms.brands
2410                  if (brand.id) {
2411                    if (!page.terms.brands) page.terms.brands = [];
2412                    if (!page.terms.brands.some(b => b.id === brand.id)) {
2413                      page.terms.brands.push({
2414                        id: brand.id,
2415                        label: brand.name
2416                      });
2417                    }
2418                  } else { 
2419                    // Store brand name for later mapping when brands load
2420                    if (!page.pendingBrandNames.includes(brand.name)) {
2421                      page.pendingBrandNames.push(brand.name);
2422                    }
2423                  }
2424                });
2425              }
2426              
2427              // Add only the cleaned query (without brand names) to filters
2428              var finalSearchTerm = brandExtraction.cleanedQuery.trim();
2429              if (finalSearchTerm.length > 0 && !page.terms.filters.includes(finalSearchTerm)) {
2430                page.terms.filters.push(finalSearchTerm);
2431              }
2432            }
2433          } // End of else block for non-fully-quoted searches
2434          
2435          // Mark that we've already processed the search param to prevent urlParamsChanged from re-processing
2436          page.searchParamProcessed = true;
2437          
2438          // Trigger pills rendering - but if brands need to load, brandsLoaded will handle it
2439          if (page.brands && page.brands.length > 0) {
2440            // Brands already loaded, safe to render pills now
2441            page.pills();
2442          }
2443          // If brands aren't loaded yet, brandsLoaded will call page.pills() when ready
2444          
2445          forcing = true;
2446        }
2447        
2448        // Handle brand param from query string
2449        if (urlParams.has('brand') && urlParams.get('brand').trim().length > 0) {
2450          var brandValue = urlParams.get('brand').trim();
2451          var brandId = parseInt(brandValue);
2452          if (!isNaN(brandId)) {
2453            page.forceBrandId = brandId;
2454          } else {
2455            page.forceBrand = decodeURIComponent(brandValue).split('%20').join(' ');
2456          }
2457          forcing = true;
2458        }
2459        
2460        // Handle category param from query string
2461        if (urlParams.has('category') && urlParams.get('category').trim().length > 0) {
2462          var categoryValue = urlParams.get('category').trim();
2463          var categoryId = parseInt(categoryValue);
2464          if (!isNaN(categoryId)) {
2465            page.forceCategoryId = categoryId;
2466          } else {
2467            page.forceCategory = decodeURIComponent(categoryValue).split('%20').join(' ');
2468          }
2469          forcing = true;
2470        }
2471      }
2472      
2473      if (window.location.search.length > 0) {
2474        page.urlParamsChanged();
2475      } else if (forcing) {
2476        // If we processed query params, trigger search
2477        // But if forceBrand is set (either name or ID), wait for brandsLoaded to add it to page.terms.brands
2478        // Similarly for forceCategory - wait for categoriesLoaded to resolve
2479        if (page.forceBrand != "" || page.forceBrandId > 0 || 
2480            page.forceCategory != "" || page.forceCategoryId > 0) {
2481          // Don't call pills() yet - brandsLoaded/categoriesLoaded will handle it
2482        } else {
2483          //page.pills();
2484        }
2485      } else {
2486        // No query params and no forcing - load default products
2487        if (!lastFilter || !lastFilter.filters || lastFilter.filters.length === 0) {
2488          //page.pills();
2489        }
2490      }
2491      if (shipType == 'flat' && flatRate <= 0) {
2492        $(".threshold").removeClass("hidden");
2493      } else {
2494        if (threshold != null && threshold >= 0) {
2495          $(".threshold").removeClass("hidden");
2496          if (threshold > 0) {
2497            $(".freeterms").removeClass("hidden");
2498            $("#Threshold").html(threshold.toFixed(2));
2499          }
2500        }
2501      }
2502      if (typeof products.popular === 'function') {
2503        products.popular();
2504      }
2505      page.resizeFilters();
2506
2507      let totalPages = Number($("#SearchTotalPages").html());
2508      let paging = "";
2509      for (var i=1; i<=totalPages && i<=10; i++) {
2510        paging += '<div class="page'+((i==1)?" current":"")+'" data-page="'+i+'">'+i+'</div>';
2511      } 
2512      $(".pages").html(paging);
2513      $(".page").click(page.page);
2514      if (brandImage && brandImage.trim()!='' && brandImage.indexOf("NoImage.svg") == -1) {
2515        $("#BrandImage").prop("src", brandImage);
2516        $("#BrandingImage").show();
2517      }
2518      if (totalPages<1) $("#PagingArea").hide(); 
2519      page.sizesLoaded(page.parseValueList(proSizes));
2520      page.widthsLoaded(page.parseValueList(proWidths));
2521      page.initializePriceFilters();
2522      // page.pillsChanged();
2523    },
2524    parseValueList: (value) => {
2525      if (value === null || value === undefined) return [];
2526      if (Array.isArray(value)) return value;
2527      if (typeof value !== 'string') return [value];
2528      const trimmed = value.trim();
2529      if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
2530          try {
2531              return JSON.parse(trimmed);
2532          } catch (e) {}
2533      }
2534      return trimmed.split(',').map(v => v.trim()).filter(v => v.length > 0);
2535    },
2536    resizeFilters: function() {
2537      const width = $(window).width();
2538      if (width < 992 && !page.mobile) {
2539        page.mobile = true;
2540        $(".mobile-filter-group").detach().insertBefore('#ProductList');
2541        $(".paging-labels").detach().insertBefore('#ProductList');
2542        // Add 'positioned' class to show paging labels after moving
2543        setTimeout(() => $(".paging-labels").addClass('positioned'), 10);
2544        // Don't move SortArea on mobile - it stays next to Filters button
2545        // $(".page-select-container").detach().insertAfter('#BrandArea');
2546        $(".mobile-filter-group .widget").addClass('min-view-area');
2547        page.toggleFilters({}, true);
2548      } else if (width >= 992 && page.mobile) {
2549        page.mobile = false;
2550        $(".mobile-filter-group").detach().insertBefore('#ReturnPolicy');
2551        $(".search-widget").detach().insertBefore('#PillBoxArea');
2552        $(".paging-labels").detach().insertBefore('.page-select-container');
2553        $(".paging-labels").removeClass('positioned');
2554        $(".search-widget").removeClass('min-view');
2555        $(".paging-container").removeClass('min-view');
2556        $(".search-page-container").removeClass('min-view');
2557        $(".mobile-filter-group .widget").removeClass('min-view-area');
2558      }
2559    },
2560    events: function () {
2561      context.addListener("categories", page.categoriesLoaded);
2562      context.addListener("brands", page.brandsLoaded);
2563      context.addListener("collections", page.collectionsLoaded);
2564      context.addListener("popular", page.popularLoaded);
2565      // context.addListener("products"+products.searchId, page.productsLoaded);
2566      context.addListener("sizes", page.sizesLoaded);
2567      context.addListener("widths", page.widthsLoaded);
2568      context.addListener("wishlist", page.updateWishlistButtons);
2569      
2570      // Check if categories are already loaded in context and trigger callback
2571      const existingCategories = context.get("categories");
2572      if (existingCategories && existingCategories.length > 0) {
2573        page.categoriesLoaded(existingCategories);
2574      }
2575      
2576      $('#FiltersExpand').click(page.toggleFilters);
2577      $('#PillBoxExpand').click(page.togglePills);
2578      $('#CategoryArea .filter-container').click(page.toggleCategories);
2579      $('#SortArea .filter-container').click(page.toggleSort);
2580	    $('#BrandArea .filter-container').click(page.toggleBrands);
2581      $('#CollectionArea .filter-container').click(page.toggleCollections);
2582      $('#SizeArea .filter-container').click(page.toggleSizes);
2583      $('#WidthArea .filter-container').click(page.toggleWidths);
2584      $('#PriceArea .filter-container').click(page.togglePrice);
2585      $('#ColorArea .filter-container').click(page.toggleColor);
2586      $('#ShippingArea .filter-container').click(page.togglePickup);
2587      $('#ReturnPolicy .filter-container').click(page.toggleReturn);
2588      $('#PopularArea .filter-container').click(page.togglePopular);
2589      $(".checker").click(function(e) {
2590        if ($(e.currentTarget).hasClass("selected")) $(e.currentTarget).removeClass("selected");
2591        else $(e.currentTarget).addClass("selected");
2592      });
2593      $("#ClearFilterButton").click(page.clear);
2594      $("#SortBy").change(page.sort);
2595      
2596      // Setup options checkboxes to sync between desktop and mobile
2597      $("input[data-filter='pickup-in-store']").off('change').on('change', function() {
2598        const isChecked = $(this).is(':checked');
2599        $("input[data-filter='pickup-in-store']").prop('checked', isChecked);
2600        page.pillsChanged(true);
2601      });
2602      
2603      $("input[data-filter='on-sale']").off('change').on('change', function() {
2604        const isChecked = $(this).is(':checked');
2605        $("input[data-filter='on-sale']").prop('checked', isChecked);
2606        page.pillsChanged(true);
2607      });
2608      
2609      $("input[data-filter='ship-to-me']").off('change').on('change', function() {
2610        const isChecked = $(this).is(':checked');
2611        $("input[data-filter='ship-to-me']").prop('checked', isChecked);
2612        page.pillsChanged(true);
2613      });
2614      
2615      // Listen for popstate (browser back/forward) to handle URL changes
2616      $(window).on('popstate', page.urlParamsChanged);
2617      
2618      // Trigger urlParamsChanged on initial page load if query params exist
2619      if (window.location.search) {
2620        page.urlParamsChanged();
2621      }
2622
2623      $(window).resize(function(event) {
2624        page.resizeFilters(); 
2625      });
2626      $("nav").find("a").click((e) => {
2627        page.terms = { brand: { label: "", id: -1 }, brands: [], collections: [], categories: { label: "", id: -1 }, filter: "", filters: [], quotedFilters: [], sizes: [], widths: [], colors: [], page: 1 };
2628        context.set("storeTerms", page.terms);
2629      });
2630      
2631      // Mobile filter panel handlers
2632      $("#OpenMobileFilters").click(page.openMobileFilters);
2633      $("#CloseMobileFilters").click(page.closeMobileFilters);
2634      $("#MobileFilterOverlay").click(page.closeMobileFilters);
2635      $("#ApplyMobileFilters").click(page.applyMobileFilters);
2636      
2637      // Initialize filter counts on page load
2638      setTimeout(function() {
2639        page.updateFilterCounts();
2640      }, 500);
2641    },
2642    mobileFiltersCloned: false,
2643    openMobileFilters: function() {
2644      // Clone filters to mobile panel on first open
2645      if (!page.mobileFiltersCloned) {
2646        // Clone just the FiltersList content (not the accordion wrapper or Sort By)
2647        const filtersClone = $("#FiltersList").clone();
2648        filtersClone.show(); // Make sure it's visible
2649        filtersClone.find('.filter-container').removeClass('closed');
2650        filtersClone.find('.toggleright').removeClass('ti-angle-up').addClass('ti-angle-down');
2651        // Remove any Sort By elements that might have been cloned
2652        filtersClone.find('#SortArea, #SortBy').remove();
2653        
2654        // Prefix input/select IDs with "mobile-" and update label "for" attributes to match
2655        filtersClone.find('input[id], select[id]').each(function() {
2656          const oldId = $(this).attr('id');
2657          if (oldId) {
2658            const newId = 'mobile-' + oldId;
2659            $(this).attr('id', newId);
2660            // Update any labels that reference this input
2661            filtersClone.find('label[for="' + oldId + '"]').attr('for', newId);
2662          }
2663        });
2664        
2665        $("#MobileFilterContent").html(filtersClone);
2666        page.mobileFiltersCloned = true;
2667        
2668        // Re-attach event handlers for cloned filters
2669        $("#MobileFilterContent .filter-container").each(function() {
2670          const parentId = $(this).parent().attr('id');
2671          if (parentId === 'CategoryArea') {
2672            $(this).off('click').on('click', function(e) {
2673              // Only toggle if clicking the header itself, not children
2674              if ($(e.target).closest('.category-link, .category-toggle, .checkboxlabel, input').length === 0) {
2675                page.toggleCategories.call(this, e);
2676              }
2677            });
2678          } else if (parentId === 'BrandArea') {
2679            $(this).off('click').on('click', function(e) {
2680              if ($(e.target).closest('.checkboxlabel, input, a').length === 0) {
2681                page.toggleBrands.call(this, e);
2682              }
2683            });
2684          } else if (parentId === 'CollectionArea') {
2685            $(this).off('click').on('click', function(e) {
2686              if ($(e.target).closest('.checkboxlabel, input, a').length === 0) {
2687                page.toggleCollections.call(this, e);
2688              }
2689            });
2690          } else if (parentId === 'SizeArea') {
2691            $(this).off('click').on('click', function(e) {
2692              if ($(e.target).closest('.checkboxlabel, input, a').length === 0) {
2693                page.toggleSizes.call(this, e);
2694              }
2695            });
2696          } else if (parentId === 'WidthArea') {
2697            $(this).off('click').on('click', function(e) {
2698              if ($(e.target).closest('.checkboxlabel, input, a').length === 0) {
2699                page.toggleWidths.call(this, e);
2700              }
2701            });
2702          } else if (parentId === 'PriceArea') {
2703            $(this).off('click').on('click', function(e) {
2704              if ($(e.target).closest('input').length === 0) {
2705                page.togglePrice.call(this, e);
2706              }
2707            });
2708          } else if (parentId === 'ColorArea') {
2709            $(this).off('click').on('click', function(e) {
2710              if ($(e.target).closest('.checkboxlabel, input, a').length === 0) {
2711                page.toggleColor.call(this, e);
2712              }
2713            });
2714          } else if (parentId === 'ShippingArea') {
2715            $(this).off('click').on('click', function(e) {
2716              if ($(e.target).closest('.checkboxlabel, input').length === 0) {
2717                page.togglePickup.call(this, e);
2718              }
2719            });
2720          } else if (parentId === 'PopularArea') {
2721            $(this).off('click').on('click', function(e) {
2722              if ($(e.target).closest('.checkboxlabel, input').length === 0) {
2723                page.togglePopular.call(this, e);
2724              }
2725            });
2726          }
2727        });
2728        
2729        // Re-attach checkbox handlers
2730        $("#MobileFilterContent input[type='checkbox']").off("change").on("change", function() {
2731          const name = $(this).attr('name');
2732          const value = $(this).val();
2733          
2734          if (name === 'brand-filter') {
2735            const brandId = parseInt(value);
2736            const brandLabel = $(this).siblings('.checkboxlabel').text().replace(/\s*\(\d+\)/, '').trim();
2737            const isChecked = $(this).is(":checked");
2738            
2739            if (isChecked) {
2740              if (!page.terms.brands.some(b => b.id === brandId)) {
2741                page.terms.brands.push({ id: brandId, label: brandLabel });
2742              }
2743              page.addPill(brandId, brandLabel, "brand");
2744            } else {
2745              page.terms.brands = page.terms.brands.filter(b => b.id !== brandId);
2746              page.pills();
2747            }
2748            
2749            products.filter.brands = page.terms.brands.map(b => b.id);
2750            page.pillsChanged();
2751            // Sync desktop checkbox to match mobile
2752            $("#FiltersList input[name='brand-filter'][value='" + value + "']").prop('checked', isChecked);
2753          } else if (name === 'size-filter') {
2754            const size = value;
2755            const isChecked = $(this).is(":checked");
2756            
2757            if (isChecked) {
2758              if (!page.terms.sizes.includes(size)) {
2759                page.terms.sizes.push(size);
2760              }
2761              page.addPill(size, size, "size");
2762            } else {
2763              page.terms.sizes = page.terms.sizes.filter(s => s !== size);
2764              page.pills();
2765            }
2766            
2767            products.filter.sizes = page.terms.sizes;
2768            page.pillsChanged();
2769            // Sync desktop checkbox to match mobile
2770            $("#FiltersList #SizeCheckboxList input[value='" + size + "']").prop("checked", isChecked);
2771          } else if (name === 'width-filter') {
2772            const width = value;
2773            const isChecked = $(this).is(":checked");
2774            
2775            if (isChecked) {
2776              if (!page.terms.widths.includes(width)) {
2777                page.terms.widths.push(width);
2778              }
2779              page.addPill(width, width, "width");
2780            } else {
2781              page.terms.widths = page.terms.widths.filter(w => w !== width);
2782              page.pills();
2783            }
2784            
2785            products.filter.widths = page.terms.widths;
2786            page.pillsChanged();
2787            // Sync desktop checkbox to match mobile
2788            $("#FiltersList #WidthCheckboxList input[value='" + width + "']").prop("checked", isChecked);
2789          } else if (name === 'color-filter') {
2790            const colorName = value;
2791            const isChecked = $(this).is(":checked");
2792            
2793            if (isChecked) {
2794              // Trigger NLP-based AI search for the color using lowercase (this handles pill creation)
2795              page.addSearch(colorName.toLowerCase(), null, 'filter');
2796            } else {
2797              // Remove the filter when unchecked
2798              page.terms.filters = page.terms.filters.filter(f => f.toLowerCase() !== colorName.toLowerCase());
2799              page.pills();
2800              page.pillsChanged();
2801            }
2802            
2803            // Sync desktop checkbox to match mobile
2804            $("#FiltersList #ColorCheckboxList input[value='" + colorName + "']").prop('checked', isChecked);
2805          } else if (name === 'collection-filter') {
2806            const collectionId = parseInt(value);
2807            const collectionTitle = $(this).data("collection-title");
2808            const isChecked = $(this).is(":checked");
2809            
2810            if (isChecked) {
2811              // Add to collections array if not already there
2812              if (!page.terms.collections.some(c => c.id === collectionId)) {
2813                page.terms.collections.push({ id: collectionId, label: collectionTitle });
2814              }
2815              page.addPill(collectionId, collectionTitle, "collection");
2816              // Check the corresponding checkbox in the other panel
2817              $("#FiltersList #CollectionCheckboxList input[value='" + collectionId + "']").prop("checked", true);
2818            } else {
2819              // Remove from collections array
2820              page.terms.collections = page.terms.collections.filter(c => c.id !== collectionId);
2821              page.pills();
2822              // Uncheck the corresponding checkbox in the other panel
2823              $("#FiltersList #CollectionCheckboxList input[value='" + collectionId + "']").prop("checked", false);
2824            }
2825            
2826            // Set single collection filter (backend expects singular 'collection' parameter)
2827            products.filter.collection = page.terms.collections.length > 0 ? page.terms.collections[0].id : -1;
2828            page.pillsChanged();
2829          } else if (name === 'gender-filter') {
2830            const genderValue = value;
2831            const genderLabels = { 'M': 'Mens', 'W': 'Womens', 'U': 'Unisex', 'K': 'Kids' };
2832            const isChecked = $(this).is(':checked');
2833            
2834            if (isChecked) {
2835              if (!page.terms.genders) page.terms.genders = [];
2836              if (!page.terms.genders.includes(genderValue)) {
2837                page.terms.genders.push(genderValue);
2838                page.addPill(genderValue, genderLabels[genderValue], 'gender');
2839              }
2840              // Sync desktop checkbox
2841              $('#FiltersList #GenderCheckboxList input[value="' + genderValue + '"]').prop('checked', true);
2842            } else {
2843              if (page.terms.genders) {
2844                const idx = page.terms.genders.indexOf(genderValue);
2845                if (idx !== -1) page.terms.genders.splice(idx, 1);
2846              }
2847              page.pills();
2848              // Sync desktop checkbox
2849              $('#FiltersList #GenderCheckboxList input[value="' + genderValue + '"]').prop('checked', false);
2850            }
2851            
2852            products.filter.genders = page.terms.genders || [];
2853            page.pillsChanged();
2854          } else if (name === 'shipping-options' || name === 'sale-option') {
2855            // Handle shipping and sale checkboxes - these don't create pills
2856            page.pills();
2857          }
2858        });
2859        
2860        // Re-attach brand search input handler (ID is prefixed with "mobile-")
2861        $("#MobileFilterContent #mobile-BrandSearchInput").off("input").on("input", function() {
2862          page.filterBrandCheckboxes($(this).val());
2863        });
2864        
2865        $("#MobileFilterContent #mobile-CollectionSearchInput").off("input").on("input", function() {
2866          page.filterCollectionCheckboxes($(this).val());
2867        });
2868        
2869        $("#MobileFilterContent #mobile-SizeSearchInput").off("input").on("input", function() {
2870          page.filterSizeCheckboxes($(this).val());
2871        });
2872        
2873        $("#MobileFilterContent #mobile-WidthSearchInput").off("input").on("input", function() {
2874          page.filterWidthCheckboxes($(this).val());
2875        });
2876        
2877        $("#MobileFilterContent #mobile-CategorySearchInput").off("input").on("input", function() {
2878          page.filterCategoryLinks($(this).val());
2879        });
2880        
2881        // Re-attach show more handlers
2882        $("#MobileFilterContent #BrandArea #BrandShowMore a").off('click').on('click', function(e) {
2883          e.preventDefault();
2884          page.showAllBrands();
2885        });
2886        $("#MobileFilterContent #CategoryArea #CategoryShowMore a").off('click').on('click', function(e) {
2887          e.preventDefault();
2888          page.showAllCategories();
2889        });
2890        $("#MobileFilterContent #CollectionArea #CollectionShowMore a").off('click').on('click', function(e) {
2891          e.preventDefault();
2892          page.showAllCollections();
2893        });
2894        $("#MobileFilterContent #SizeArea #SizeShowMore a").off('click').on('click', function(e) {
2895          e.preventDefault();
2896          page.expandAllSizes();
2897        });
2898        $("#MobileFilterContent #WidthArea #WidthShowMore a").off('click').on('click', function(e) {
2899          e.preventDefault();
2900          page.expandAllWidths();
2901        });
2902        $("#MobileFilterContent #ColorArea #ColorShowMore a").off('click').on('click', function(e) {
2903          e.preventDefault();
2904          page.showAllColors(this);
2905        });
2906        
2907        // Re-attach category link handlers
2908        $("#MobileFilterContent .category-toggle").off('click').on('click', page.toggleCategoryChildren);
2909        
2910        $("#MobileFilterContent .category-link").off('click').on('click', function(e) {
2911          e.stopPropagation();
2912          e.preventDefault();
2913          const categoryId = parseInt($(this).data('category-id'));
2914          const categoryLabel = $(this).text().replace(/\s*\(\d+\)/, '').trim();
2915          
2916          // Remove selected class from all category links
2917          $("#MobileFilterContent .category-link").removeClass("selected");
2918          $("#FiltersList .category-link").removeClass("selected");
2919          
2920          // Add selected class to clicked link and its desktop counterpart
2921          $(this).addClass("selected");
2922          $("#FiltersList .category-link[data-category-id='" + categoryId + "']").addClass("selected");
2923          
2924          // Update filter state
2925          page.terms.categories.id = categoryId;
2926          page.terms.categories.label = categoryLabel;
2927          page.addPill(categoryId, categoryLabel, "category");
2928          
2929          products.filter.category = page.terms.categories.id;
2930          
2931          return false;
2932        });
2933        
2934        // Re-attach price input handlers for mobile
2935        const updateApplyButtonOpacity = function($container) {
2936          const hasMin = $container.find("input[data-filter='price-min']").val().trim() !== '';
2937          const hasMax = $container.find("input[data-filter='price-max']").val().trim() !== '';
2938          $container.find("button[data-filter='apply-price']").css('opacity', (hasMin || hasMax) ? '1' : '0.5');
2939        };
2940        
2941        $("#MobileFilterContent input[data-filter='price-min'], #MobileFilterContent input[data-filter='price-max']").off('input blur focus').on('input', function() {
2942          const $container = $("#MobileFilterContent");
2943          updateApplyButtonOpacity($container);
2944        }).on('blur', function() {
2945          let val = $(this).val().replace(/[^0-9.]/g, '');
2946          if (val) {
2947            $(this).val('$' + val);
2948          }
2949        }).on('focus', function() {
2950          let val = $(this).val().replace('$', '');
2951          $(this).val(val);
2952          // Select all text so user can replace by typing (Bug #2 fix)
2953          $(this).select();
2954        });
2955        
2956        $("#MobileFilterContent button[data-filter='apply-price']").off('click').on('click', function() {
2957          const $container = $("#MobileFilterContent");
2958          const min = parseFloat($container.find('#PriceMin').val().replace('$', ''));
2959          const max = parseFloat($container.find('#PriceMax').val().replace('$', ''));
2960          
2961          if (!isNaN(min) && !isNaN(max) && min <= max) {
2962            const customValue = min + '-' + max;
2963            const customLabel = '$' + min + ' - $' + max;
2964            
2965            // Uncheck all price checkboxes in both panels
2966            $('#PriceCheckboxList input[type="checkbox"], #MobileFilterContent .filter-content input[type="radio"][name="priceRange"]').prop('checked', false);
2967            
2968            // Replace prices array with only this custom range
2969            page.terms.prices = [customValue];
2970            
2971            // Add pill
2972            page.addPill(customValue, customLabel, 'price');
2973            
2974            // Update filter
2975            products.filter.prices = page.terms.prices;
2976            // page.pillsChanged();
2977            
2978            // Clear inputs in both panels
2979            $("input[data-filter='price-min']").val('');
2980            $("input[data-filter='price-max']").val('');
2981            updateApplyButtonOpacity($('#FiltersList'));
2982            updateApplyButtonOpacity($('#MobileFilterContent'));
2983          } else {
2984            alert('Please enter valid min and max prices (min must be less than or equal to max)');
2985          }
2986        });
2987      }
2988      
2989      // Sync checkboxes from desktop to mobile to reflect current filter state
2990      $("#FiltersList input[type='checkbox']").each(function() {
2991        const name = $(this).attr('name');
2992        const value = $(this).val();
2993        const isChecked = $(this).is(':checked');
2994        const $mobileCheckbox = $("#MobileFilterContent input[name='" + name + "'][value='" + value + "']");
2995        $mobileCheckbox.prop('checked', isChecked);
2996      });
2997      
2998      // Sync pills from desktop to mobile
2999      page.syncMobilePills();
3000      
3001      // Update product count before opening
3002      page.updateMobileProductCount();
3003      
3004      // Expand all filter sections in mobile panel
3005      $('#MobileFilterContent .filter-content').show();
3006      
3007      // Re-attach ALL show more handlers every time (to ensure they work even if data loads late)
3008      $("#MobileFilterContent #BrandArea #BrandShowMore a").off('click').on('click', function(e) {
3009        e.preventDefault();
3010        page.showAllBrands();
3011      });
3012      $("#MobileFilterContent #CategoryArea #CategoryShowMore a").off('click').on('click', function(e) {
3013        e.preventDefault();
3014        page.showAllCategories();
3015      });
3016      $("#MobileFilterContent #CollectionArea #CollectionShowMore a").off('click').on('click', function(e) {
3017        e.preventDefault();
3018        page.showAllCollections();
3019      });
3020      $("#MobileFilterContent #SizeArea #SizeShowMore a").off('click').on('click', function(e) {
3021        e.preventDefault();
3022        page.expandAllSizes();
3023      });
3024      $("#MobileFilterContent #WidthArea #WidthShowMore a").off('click').on('click', function(e) {
3025        e.preventDefault();
3026        page.expandAllWidths();
3027      });
3028      $("#MobileFilterContent #ColorArea #ColorShowMore a").off('click').on('click', function(e) {
3029        e.preventDefault();
3030        page.showAllColors(this);
3031      });
3032      
3033      // Prevent body scroll - iOS fix
3034      $('body').addClass('mobile-filter-open');
3035      
3036      // Show overlay and panel
3037      $('#MobileFilterOverlay').addClass('active');
3038      $('#MobileFilterPanel').addClass('active');
3039      
3040      // Fix flexbox layout issue - ensure filter content is positioned correctly
3041      $('.mobile-filter-content').css({ position: 'relative', top: '0' });
3042      $('.mobile-filter-content').scrollTop(0);
3043    },
3044    closeMobileFilters: function() {
3045      // Restore body scroll
3046      $('body').removeClass('mobile-filter-open');
3047      
3048      // Hide overlay and panel
3049      $('#MobileFilterOverlay').removeClass('active');
3050      $('#MobileFilterPanel').removeClass('active');
3051    },
3052    applyMobileFilters: function() {
3053      // Trigger filter search
3054      page.pills();
3055      
3056      // Close panel
3057      page.closeMobileFilters();
3058    },
3059    syncCheckboxes: function(name, value) {
3060      // Determine if checkbox should be checked based on current filter state
3061      let isChecked = false;
3062      
3063      if (name === 'brand-filter') {
3064        isChecked = page.terms.brands.some(b => b.id === parseInt(value));
3065      } else if (name === 'size-filter') {
3066        isChecked = page.terms.sizes.includes(value);
3067      } else if (name === 'width-filter') {
3068        isChecked = page.terms.widths.includes(value);
3069      }
3070      
3071      // Update both desktop and mobile checkboxes to match filter state
3072      const $mobileCheckbox = $(`#MobileFilterContent input[name="${name}"][value="${value}"]`);
3073      const $desktopCheckbox = $(`#FiltersList input[name="${name}"][value="${value}"]`);
3074      $desktopCheckbox.prop('checked', isChecked);
3075      $mobileCheckbox.prop('checked', isChecked);
3076    },
3077    updateMobileProductCount: function() {
3078      // Use the displayed product count from SearchTotal (handles both filtered and unfiltered states)
3079      const displayedCount = $("#SearchTotal").text().trim();
3080      const count = displayedCount ? parseInt(displayedCount, 10) : 0;
3081      $("#MobileFilterCount").text(count);
3082    },
3083    syncMobilePills: function() {
3084      // Clone pills from desktop to mobile
3085      const desktopPills = $("#PillBox").html();
3086      $("#MobilePillBox").html(desktopPills);
3087      
3088      // Show/hide mobile pill box area based on whether there are pills
3089      if (desktopPills && desktopPills.trim().length > 0) {
3090        $("#MobilePillBoxArea").show();
3091        $("#MobileClearFilterButton").show();
3092      } else {
3093        $("#MobilePillBoxArea").hide();
3094        $("#MobileClearFilterButton").hide();
3095      }
3096      
3097      // Re-attach click handlers to mobile pills
3098      $("#MobilePillBox .pill").off('click').on('click', page.removeSearch);
3099      
3100      // Attach clear button handler
3101      $("#MobileClearFilterButton").off('click').on('click', function() {
3102        page.clear();
3103        page.closeMobileFilters();
3104      });
3105    }, 
3106    allSizes: [],
3107    currentFilteredSizes: null,
3108    sizesShowingAll: false,
3109    sizesLoaded: function(data) {
3110      // Store all sizes for show more functionality
3111      page.allSizes = data;
3112      
3113      // Setup show more functionality
3114      $("#SizeShowMore a").off("click").on("click", function(e) {
3115        e.preventDefault();
3116        page.expandAllSizes();
3117      });
3118      
3119      page.renderSizeCheckboxes();
3120    },
3121    renderSizeCheckboxes: function(sizes, showAll = false) {
3122      sizes = sizes || page.allSizes;
3123      page.sizesShowingAll = showAll;
3124      const sizesToShow = showAll ? sizes : sizes.slice(0, 5);
3125      const remainingCount = sizes.length - sizesToShow.length;
3126      
3127      let html = '';
3128      for (let i = 0; i < sizesToShow.length; i++) {
3129        const sizeData = sizesToShow[i];
3130        const size = sizeData.size !== undefined ? Number(sizeData.size).toFixed(1).replace('.0', '') : sizeData;
3131        const sizeStr = size.toString();
3132        const isChecked = page.terms.sizes.includes(sizeStr) ? 'checked' : '';
3133        
3134        html += `
3135          <div class="input-checkbox">
3136            <input id="size-${i}" type="checkbox" name="size-filter" value="${sizeStr}" ${isChecked} data-size="${sizeStr}" />
3137            <label for="size-${i}" class="runfreecheck"></label>
3138            <span class="checkboxlabel">${size}</span>
3139          </div>
3140        `;
3141      }
3142      
3143      // Update both desktop and mobile (if mobile panel is open)
3144      $("#FiltersList #SizeCheckboxList").html(html);
3145      $("#MobileFilterContent #SizeCheckboxList").html(html);
3146      
3147      // Toggle button text (both desktop and mobile)
3148      if (showAll) {
3149        $("#FiltersList #SizeShowMore a").html('Show less');
3150        $("#MobileFilterContent #SizeArea #SizeShowMore a").html('Show Less');
3151        $("#SizeShowMore").show();
3152      } else if (remainingCount > 0) {
3153        $("#SizeShowMoreCount").text(remainingCount);
3154        $("#FiltersList #SizeShowMore a").html(`Show <span>${remainingCount}</span> more`);
3155        $("#MobileFilterContent #SizeArea #SizeShowMoreCount").text(remainingCount);
3156        $("#MobileFilterContent #SizeArea #SizeShowMore a").html(`Show <span>${remainingCount}</span> More`);
3157        $("#SizeShowMore").show();
3158        $("#MobileFilterContent #SizeArea #SizeShowMore").show();
3159      } else {
3160        $("#SizeShowMore").hide();
3161        $("#MobileFilterContent #SizeArea #SizeShowMore").hide();
3162      }
3163      
3164      // Show size area if we have sizes
3165      if (page.allSizes.length > 0) {
3166        $("#SizeArea").show();
3167      }
3168      
3169      // Attach change handlers to both desktop and mobile checkboxes
3170      $("#FiltersList #SizeCheckboxList input[type='checkbox'], #MobileFilterContent #SizeArea input[type='checkbox']").off("change").on("change", function() {
3171        const size = $(this).val();
3172        
3173        if ($(this).is(":checked")) {
3174          if (!page.terms.sizes.includes(size)) {
3175            page.terms.sizes.push(size);
3176          }
3177          page.addPill(size, size, "size");
3178          // Check the corresponding checkbox in the other panel
3179          $("#FiltersList #SizeCheckboxList input[value='" + size + "']").prop("checked", true);
3180          $("#MobileFilterContent #SizeCheckboxList input[value='" + size + "']").prop("checked", true);
3181        } else {
3182          const index = page.terms.sizes.indexOf(size);
3183          if (index > -1) {
3184            page.terms.sizes.splice(index, 1);
3185          }
3186          products.filter.sizes = page.terms.sizes;
3187          page.pills();
3188          // Uncheck the corresponding checkbox in the other panel
3189          $("#FiltersList #SizeCheckboxList input[value='" + size + "']").prop("checked", false);
3190          $("#MobileFilterContent #SizeCheckboxList input[value='" + size + "']").prop("checked", false);
3191        }
3192        
3193        products.filter.sizes = page.terms.sizes;
3194        // page.pillsChanged();
3195      });
3196    },
3197    expandAllSizes: function() {
3198      const desktopText = $("#FiltersList #SizeArea #SizeShowMore a").text().trim();
3199      const mobileText = $("#MobileFilterContent #SizeArea #SizeShowMore a").text().trim();
3200      const isShowingAll = desktopText === 'Show less' || mobileText === 'Show Less';
3201      const currentData = page.currentFilteredSizes || page.allSizes;
3202      page.renderSizeCheckboxes(currentData, !isShowingAll);
3203    },
3204    toggleFilters: function(data, close) {
3205      if ($('#FiltersList').is(":visible") || close) {
3206        $('#FiltersArea').addClass('closed');
3207        $('#FiltersExpand').addClass('closed');
3208        $('#FiltersList').hide();
3209        $('#FiltersArea .select-option .ti-angle-down').hide();
3210      } else {
3211		    $('#FiltersArea').removeClass('closed')
3212        $('#FiltersExpand').removeClass('closed');
3213        $('#FiltersList').show();
3214        $('#FiltersArea .select-option .ti-angle-down').show();
3215      }
3216    },
3217    toggleSort: function(data, close) {
3218      if ($('#SortBy').is(":visible") || close) {
3219        $('#SortArea').addClass('closed');
3220        $('#SortExpand').addClass('closed');
3221        $('#SortBy').hide();
3222        $('#SortArea .select-option .ti-angle-down').hide();
3223      } else {
3224        $('#SortArea').removeClass('closed');
3225        $('#SortExpand').removeClass('closed');
3226        $('#SortBy').show();
3227        $('#SortArea .select-option .ti-angle-down').show();
3228      }
3229    },
3230     toggleBrands: function(data, close) {
3231      const $container = $(this).closest('#BrandArea');
3232      const $content = $container.find('.filter-content');
3233      const $icon = $container.find('.toggleright');
3234      
3235      if ($content.is(":visible") || close) {
3236        $container.addClass('closed');
3237        $icon.addClass('closed');
3238        $content.hide();
3239      } else {
3240        $container.removeClass('closed');
3241        $icon.removeClass('closed');
3242        $content.show();
3243      }
3244    },
3245    toggleCollections: function(data, close) {
3246      const $container = $(this).closest('#CollectionArea');
3247      const $content = $container.find('.filter-content');
3248      const $icon = $container.find('.toggleright');
3249      
3250      if ($content.is(":visible") || close) {
3251        $container.addClass('closed');
3252        $icon.addClass('closed');
3253        $content.hide();
3254      } else {
3255        $container.removeClass('closed');
3256        $icon.removeClass('closed');
3257        $content.show();
3258      }
3259    },
3260    toggleCategories: function(data, close) {
3261      const $container = $(this).closest('#CategoryArea');
3262      const $content = $container.find('#CategoryList');
3263      const $icon = $container.find('.toggleright');
3264      
3265      if ($content.is(":visible") || close) {
3266        $container.addClass('closed');
3267        $icon.addClass('closed');
3268        $content.hide();
3269      } else {
3270        $container.removeClass('closed');
3271        $icon.removeClass('closed');
3272        $content.show();
3273      }
3274    },
3275    toggleSizes: function(data, close) {
3276      const $container = $(this).closest('#SizeArea');
3277      const $content = $container.find('.filter-content');
3278      const $icon = $container.find('.toggleright');
3279      
3280      if ($content.is(":visible") || close) {
3281        $container.addClass('closed');
3282        $icon.addClass('closed');
3283        $content.hide();
3284      } else {
3285        $container.removeClass('closed');
3286        $icon.removeClass('closed');
3287        $content.show();
3288      }
3289    },
3290    toggleWidths: function(data, close) {
3291      const $container = $(this).closest('#WidthArea');
3292      const $content = $container.find('.filter-content');
3293      const $icon = $container.find('.toggleright');
3294      
3295      if ($content.is(":visible") || close) {
3296        $container.addClass('closed');
3297        $icon.addClass('closed');
3298        $content.hide();
3299      } else {
3300        $container.removeClass('closed');
3301        $icon.removeClass('closed');
3302        $content.show();
3303      }
3304    },
3305    togglePrice: function(data, close) {
3306      const $container = $(this).closest('#PriceArea');
3307      const $content = $container.find('.filter-content');
3308      const $icon = $container.find('.toggleright');
3309      
3310      if ($content.is(":visible") || close) {
3311        $container.addClass('closed');
3312        $icon.addClass('closed');
3313        $content.hide();
3314      } else {
3315        $container.removeClass('closed');
3316        $icon.removeClass('closed');
3317        $content.show();
3318      }
3319    },
3320    toggleColor: function(data, close) {
3321      const $container = $(this).closest('#ColorArea');
3322      const $content = $container.find('.filter-content');
3323      const $icon = $container.find('.toggleright');
3324      
3325      if ($content.is(":visible") || close) {
3326        $container.addClass('closed');
3327        $icon.addClass('closed');
3328        $content.hide();
3329      } else {
3330        $container.removeClass('closed');
3331        $icon.removeClass('closed');
3332        $content.show();
3333      }
3334    },
3335    togglePickup: function(data, close) {
3336      const $container = $(this).closest('#ShippingArea');
3337      const $content = $container.find('#ShippingList');
3338      const $icon = $container.find('.toggleright');
3339      
3340      if ($content.is(":visible") || close) {
3341        $container.addClass('closed');
3342        $icon.addClass('closed');
3343        $content.hide();
3344      } else {
3345        $container.removeClass('closed');
3346        $icon.removeClass('closed');
3347        $content.show();
3348      }
3349    },
3350    toggleReturn: function(data, close) {
3351      const $container = $(this).closest('#ReturnPolicy');
3352      const $content = $container.find('#miniReturn');
3353      const $icon = $container.find('.toggleright');
3354      
3355      if ($content.is(":visible") || close) {
3356        $container.addClass('closed');
3357        $icon.addClass('closed');
3358        $content.hide();
3359      } else {
3360        $container.removeClass('closed');
3361        $icon.removeClass('closed');
3362        $content.show();
3363      }
3364    },
3365    togglePopular: function(data, close) {
3366      const $container = $(this).closest('#PopularArea');
3367      const $content = $container.find('#PopularList');
3368      const $icon = $container.find('.toggleright');
3369      
3370      if ($content.is(":visible") || close) {
3371        $container.addClass('closed');
3372        $icon.addClass('closed');
3373        $content.hide();
3374      } else {
3375        $container.removeClass('closed');
3376        $icon.removeClass('closed');
3377        $content.show();
3378      }
3379    },
3380    allWidths: [],
3381    currentFilteredWidths: null,
3382    widthsShowingAll: false,
3383    widthsLoaded: function(data) {
3384      // Transform data to include sizeAppend as width property if needed
3385      page.allWidths = data.map(item => {
3386        if (typeof item === 'object' && item.sizeAppend !== undefined) {
3387          return {
3388            width: item.sizeAppend,
3389            productCount: item.productCount || 0
3390          };
3391        }
3392        return {
3393          width: item.toString(),
3394          productCount: 0
3395        };
3396      });
3397      
3398      // Setup show more functionality
3399      $("#WidthShowMore a").off("click").on("click", function(e) {
3400        e.preventDefault();
3401        page.expandAllWidths();
3402      });
3403      
3404      page.renderWidthCheckboxes();
3405    },
3406    renderWidthCheckboxes: function(widths, showAll = false) {
3407      widths = widths || page.allWidths;
3408      page.widthsShowingAll = showAll;
3409      const widthsToShow = showAll ? widths : widths.slice(0, 5);
3410      const remainingCount = widths.length - widthsToShow.length;
3411      
3412      let html = '';
3413      for (let i = 0; i < widthsToShow.length; i++) {
3414        const widthData = widthsToShow[i];
3415        const width = widthData.width;
3416        const isChecked = page.terms.widths.includes(width) ? 'checked' : '';
3417        
3418        html += `
3419          <div class="input-checkbox">
3420            <input id="width-${i}" type="checkbox" name="width-filter" value="${width}" ${isChecked} data-width="${width}" />
3421            <label for="width-${i}" class="runfreecheck"></label>
3422            <span class="checkboxlabel">${width}</span>
3423          </div>
3424        `;
3425      }
3426      
3427      // Update both desktop and mobile (if mobile panel is open)
3428      $("#FiltersList #WidthCheckboxList").html(html);
3429      $("#MobileFilterContent #WidthCheckboxList").html(html);
3430      
3431      // Toggle button text (both desktop and mobile)
3432      if (showAll) {
3433        $("#FiltersList #WidthShowMore a").html('Show less');
3434        $("#MobileFilterContent #WidthArea #WidthShowMore a").html('Show Less');
3435        $("#WidthShowMore").show();
3436        $("#MobileFilterContent #WidthArea #WidthShowMore").show();
3437      } else if (remainingCount > 0) {
3438        $("#WidthShowMoreCount").text(remainingCount);
3439        $("#FiltersList #WidthShowMore a").html(`Show <span>${remainingCount}</span> more`);
3440        $("#MobileFilterContent #WidthArea #WidthShowMoreCount").text(remainingCount);
3441        $("#MobileFilterContent #WidthArea #WidthShowMore a").html(`Show <span>${remainingCount}</span> More`);
3442        $("#WidthShowMore").show();
3443        $("#MobileFilterContent #WidthArea #WidthShowMore").show();
3444      } else {
3445        $("#WidthShowMore").hide();
3446        $("#MobileFilterContent #WidthArea #WidthShowMore").hide();
3447      }
3448      
3449      // Show width area if we have widths
3450      if (page.allWidths.length > 0) {
3451        $("#WidthArea").show();
3452      }
3453      
3454      // Attach change handlers to both desktop and mobile checkboxes
3455      $("#FiltersList #WidthCheckboxList input[type='checkbox'], #MobileFilterContent #WidthArea input[type='checkbox']").off("change").on("change", function() {
3456        const width = $(this).val();
3457        
3458        if ($(this).is(":checked")) {
3459          if (!page.terms.widths.includes(width)) {
3460            page.terms.widths.push(width);
3461          }
3462          page.addPill(width, width, "width");
3463          // Check the corresponding checkbox in the other panel
3464          $("#FiltersList #WidthCheckboxList input[value='" + width + "']").prop("checked", true);
3465          $("#MobileFilterContent #WidthCheckboxList input[value='" + width + "']").prop("checked", true);
3466        } else {
3467          const index = page.terms.widths.indexOf(width);
3468          if (index > -1) {
3469            page.terms.widths.splice(index, 1);
3470          }
3471          products.filter.widths = page.terms.widths;
3472          page.pills();
3473          // Uncheck the corresponding checkbox in the other panel
3474          $("#FiltersList #WidthCheckboxList input[value='" + width + "']").prop("checked", false);
3475          $("#MobileFilterContent #WidthCheckboxList input[value='" + width + "']").prop("checked", false);
3476        }
3477        
3478        products.filter.widths = page.terms.widths;
3479       // page.pillsChanged();
3480      });
3481    },
3482    expandAllWidths: function() {
3483      const desktopText = $("#FiltersList #WidthArea #WidthShowMore a").text().trim();
3484      const mobileText = $("#MobileFilterContent #WidthArea #WidthShowMore a").text().trim();
3485      const isShowingAll = desktopText === 'Show less' || mobileText === 'Show Less';
3486      const currentData = page.currentFilteredWidths || page.allWidths;
3487      page.renderWidthCheckboxes(currentData, !isShowingAll);
3488    },
3489    initializePriceFilters: function() {
3490      const priceRanges = [
3491        { label: '$0 - $49.99', min: 0, max: 49.99, value: '0-49.99' },
3492        { label: '$50 - $99.99', min: 50, max: 99.99, value: '50-99.99' },
3493        { label: '$100 - $199.99', min: 100, max: 199.99, value: '100-199.99' },
3494        { label: '$200 - $499.99', min: 200, max: 499.99, value: '200-499.99' },
3495        { label: '$500 - $999.99', min: 500, max: 999.99, value: '500-999.99' }
3496      ];
3497      
3498      // Store price ranges for later use
3499      page.priceRanges = priceRanges;
3500      
3501      // Render price ranges without counts
3502      let html = '';
3503      for (let i = 0; i < priceRanges.length; i++) {
3504        const range = priceRanges[i];
3505        const isChecked = (page.terms.prices && page.terms.prices.indexOf(range.value) !== -1) ? 'checked' : '';
3506        
3507        html += `
3508          <div class="input-checkbox">
3509            <input type="checkbox" value="${range.value}" ${isChecked} id="price_${i}" />
3510            <label for="price_${i}" class="runfreecheck"></label>
3511            <span class="checkboxlabel">${range.label}</span>
3512          </div>
3513        `;
3514      }
3515      
3516      $('#FiltersList #PriceCheckboxList, #MobileFilterContent #PriceArea .filter-content > div:first').html(html);
3517      
3518      // Setup click handlers on labels to toggle checkboxes
3519      $('#FiltersList #PriceCheckboxList .checkboxlabel, #MobileFilterContent #PriceArea .checkboxlabel').on('click', function() {
3520        const checkbox = $(this).siblings('input[type="checkbox"]');
3521        checkbox.prop('checked', !checkbox.prop('checked')).trigger('change');
3522      });
3523      
3524      // Setup change handlers for checkboxes (both desktop and mobile)
3525      $('#FiltersList #PriceCheckboxList input[type="checkbox"], #MobileFilterContent #PriceArea input[type="checkbox"]').on('change', function() {
3526        const priceRange = $(this).val();
3527        if ($(this).is(':checked')) {
3528          // Uncheck all other price checkboxes in both desktop and mobile
3529          $('#FiltersList #PriceCheckboxList input[type="checkbox"], #MobileFilterContent #PriceArea input[type="checkbox"]').not(this).prop('checked', false);
3530          
3531          // Check this checkbox in both panels
3532          $('#FiltersList #PriceCheckboxList input[value="' + priceRange + '"], #MobileFilterContent #PriceArea input[value="' + priceRange + '"]').prop('checked', true);
3533          
3534          // Clear existing prices and add only this one
3535          page.terms.prices = [priceRange];
3536          page.addPill(priceRange, priceRange, 'price');
3537        } else {
3538          // Clear prices array
3539          page.terms.prices = [];
3540          page.pills();
3541          // Uncheck in both panels
3542          $('#FiltersList #PriceCheckboxList input[value="' + priceRange + '"], #MobileFilterContent #PriceCheckboxList input[value="' + priceRange + '"]').prop('checked', false);
3543        }
3544        
3545        products.filter.prices = page.terms.prices;
3546        // page.pillsChanged();
3547      
3548      });
3549      
3550      // Setup custom price range handler
3551      const updateApplyButtonOpacity = function($container) {
3552        const hasMin = $container.find('#PriceMin').val().trim() !== '';
3553        const hasMax = $container.find('#PriceMax').val().trim() !== '';
3554        $container.find('#ApplyCustomPrice').css('opacity', (hasMin || hasMax) ? '1' : '0.5');
3555      };
3556      
3557      // Setup gender checkbox handlers
3558      $('#FiltersList #GenderCheckboxList input[type="checkbox"], #MobileFilterContent #GenderArea input[type="checkbox"]').on('change', function() {
3559        const genderValue = $(this).val();
3560        const genderLabels = {
3561          'M': 'Mens',
3562          'W': 'Womens',
3563          'U': 'Unisex',
3564          'K': 'Kids'
3565        };
3566        
3567        if ($(this).is(':checked')) {
3568          // Add to genders array
3569          if (!page.terms.genders) page.terms.genders = [];
3570          if (!page.terms.genders.includes(genderValue)) {
3571            page.terms.genders.push(genderValue);
3572            page.addPill(genderValue, genderLabels[genderValue], 'gender');
3573          }
3574          // Check in both panels
3575          $('#FiltersList #GenderCheckboxList input[value="' + genderValue + '"], #MobileFilterContent #GenderArea input[value="' + genderValue + '"]').prop('checked', true);
3576        } else {
3577          // Remove from genders array
3578          if (page.terms.genders) {
3579            const index = page.terms.genders.indexOf(genderValue);
3580            if (index !== -1) {
3581              page.terms.genders.splice(index, 1);
3582            }
3583          }
3584          // Uncheck in both panels
3585          $('#FiltersList #GenderCheckboxList input[value="' + genderValue + '"], #MobileFilterContent #GenderArea input[value="' + genderValue + '"]').prop('checked', false);
3586          // Remove pill
3587          page.pills();
3588        }
3589        
3590        products.filter.genders = page.terms.genders || [];
3591        page.pillsChanged();
3592      });
3593      
3594      // Add $ formatting to price inputs
3595      const formatPriceInput = function(input) {
3596        let val = $(input).val().replace(/[^0-9.]/g, '');
3597        if (val) {
3598          $(input).val('$' + val);
3599        }
3600      };
3601      
3602      // Setup handlers for both desktop and mobile price inputs
3603      $("input[data-filter='price-min'], input[data-filter='price-max']").off('input blur focus').on('input', function() {
3604        const $container = $(this).closest('#FiltersList, #MobileFilterContent');
3605        updateApplyButtonOpacity($container);
3606      }).on('blur', function() {
3607        formatPriceInput(this);
3608      }).on('focus', function() {
3609        let val = $(this).val().replace('$', '');
3610        $(this).val(val);
3611        // Select all text so user can replace by typing (Bug #2 fix)
3612        $(this).select();
3613      });
3614      
3615      $("button[data-filter='apply-price']").off('click').on('click', function() {
3616        const $container = $(this).closest('#FiltersList, #MobileFilterContent');
3617        const min = parseFloat($container.find("input[data-filter='price-min']").val().replace('$', ''));
3618        const max = parseFloat($container.find("input[data-filter='price-max']").val().replace('$', ''));
3619        
3620        if (!isNaN(min) && !isNaN(max) && min <= max) {
3621          const customValue = min + '-' + max;
3622          const customLabel = '$' + min + ' - $' + max;
3623          
3624          // Uncheck all price checkboxes in both panels
3625          $('#FiltersList #PriceCheckboxList input[type="checkbox"], #MobileFilterContent #PriceArea input[type="checkbox"]').prop('checked', false);
3626          
3627          // Replace prices array with only this custom range
3628          page.terms.prices = [customValue];
3629          
3630          // Add pill
3631          page.addPill(customValue, customLabel, 'price');
3632          
3633          // Update filter
3634          products.filter.prices = page.terms.prices;
3635          // page.pillsChanged();
3636          
3637          // Clear inputs in both panels
3638          $("input[data-filter='price-min']").val('');
3639          $("input[data-filter='price-max']").val('');
3640          updateApplyButtonOpacity($('#FiltersList'));
3641          updateApplyButtonOpacity($('#MobileFilterContent'));
3642        } else {
3643          alert('Please enter valid min and max prices (min must be less than or equal to max)');
3644        }
3645      });
3646    },
3647    urlParamsChanged: function () {
3648      const urlParams = new URLSearchParams(window.location.search);
3649      var filters = [];
3650      
3651      // Check if URL contains a search parameter
3652      const hasSearchParam = urlParams.has('search') || urlParams.has('q');
3653      const saleParamValue = (urlParams.get('sale') || '').trim().toLowerCase();
3654      const hasSaleParam = saleParamValue === '1' || saleParamValue === 'true' || saleParamValue === 'yes';
3655      
3656      // If new search from URL and we haven't already processed it, clear ALL old filters for a clean search
3657      if (hasSearchParam && !page.searchParamProcessed) {
3658        page.terms.filters = [];
3659        page.terms.genders = [];
3660        page.terms.brands = [];
3661        page.terms.collections = [];
3662        page.terms.sizes = [];
3663        page.terms.widths = [];
3664        page.terms.prices = [];
3665        page.terms.colors = [];
3666        
3667        // Also clear UI checkboxes and pills to prevent them from being re-added
3668        $("#BrandCheckboxList input[type='checkbox']").prop("checked", false);
3669        $("#MobileFilterContent #BrandCheckboxList input[type='checkbox']").prop("checked", false);
3670        $("#SizeCheckboxList input[type='checkbox']").prop("checked", false);
3671        $("#MobileFilterContent #SizeCheckboxList input[type='checkbox']").prop("checked", false);
3672        $("#WidthCheckboxList input[type='checkbox']").prop("checked", false);
3673        $("#MobileFilterContent #WidthCheckboxList input[type='checkbox']").prop("checked", false);
3674        $("#PriceCheckboxList input[type='checkbox']").prop("checked", false);
3675        $("#MobileFilterContent #PriceCheckboxList input[type='checkbox']").prop("checked", false);
3676        $("#GenderCheckboxList input[type='checkbox']").prop("checked", false);
3677        $("#MobileFilterContent #GenderArea input[type='checkbox']").prop("checked", false);
3678        $("#CollectionCheckboxList input[type='checkbox']").prop("checked", false);
3679        $("#MobileFilterContent #CollectionCheckboxList input[type='checkbox']").prop("checked", false);
3680        $("#ColorCheckboxList input[type='checkbox']").prop("checked", false);
3681        $("#MobileFilterContent #ColorCheckboxList input[type='checkbox']").prop("checked", false);
3682        $("input[data-filter='ship-to-me']").prop("checked", false);
3683        $("input[data-filter='pickup-in-store']").prop("checked", false);
3684        $("input[data-filter='on-sale']").prop("checked", false);
3685        
3686        // Clear pill box (pills will be regenerated from the new search)
3687        $("#PillBox").html("");
3688      }
3689      
3690      // Process brand filter
3691      if (urlParams.has('brand')) {
3692        const brandValue = urlParams.get('brand');
3693        if (brandValue) {
3694          const brandParam = brandValue.trim();
3695          if (true) {
3696            if (true) {
3697              const brandId = parseInt(brandParam);
3698              if (page.brands.length > 0) {
3699                var details = brand.details(brandId);
3700                if (!page.terms.brands.some(b => b.id === brandId)) {
3701                  page.terms.brands.push({ id: brandId, label: details.name });
3702                }
3703                page.addSearch(details.name, brandId, "brand", false);
3704              } else {
3705                page.doAfterBrandLoad = true;
3706              }
3707            }
3708          }
3709        }
3710      }
3711      
3712      // Process category filter
3713      if (urlParams.has('category')) {
3714        const categoryValue = urlParams.get('category');
3715        if (categoryValue) {
3716          const categoryParam = categoryValue.trim();
3717          if (true) {
3718            if (true) {
3719              page.terms.categories.id = categoryParam;
3720              if (page.categories.length > 0) {
3721                var details = category.details(page.terms.categories.id);
3722                var label = details.name;
3723                if (details.label && details.label.trim().length>0) label = details.label;
3724                page.addSearch(label, page.terms.categories.id, "category", false);
3725              } else {
3726                page.doAfterCatLoad = true;
3727              }
3728            }
3729          }
3730        }
3731      }
3732      
3733      // Process search filter
3734      if (urlParams.has('search') || urlParams.has('q')) {
3735        const rawSearch = urlParams.get('search') || urlParams.get('q');
3736        if (rawSearch && !page.searchParamProcessed) {
3737          // Only process if not already handled during initial page load
3738          if (true) {
3739            if (true) {
3740                const searchValue = decodeURIComponent(rawSearch.trim());
3741                
3742                // Extract gender from the search query (silently for API filtering)
3743                const genderExtraction = page.extractGenderFromQuery(searchValue);
3744                
3745                // Store genders for API call and create pills to show active gender filters
3746                if (genderExtraction.genders && genderExtraction.genders.length > 0) {
3747                  if (!page.terms.genders) page.terms.genders = [];
3748                  const genderLabels = { 'M': 'Mens', 'W': 'Womens', 'U': 'Unisex', 'K': 'Kids' };
3749                  genderExtraction.genders.forEach(g => {
3750                    if (!page.terms.genders.includes(g)) {
3751                      page.terms.genders.push(g);
3752                      // Create pill for the gender filter
3753                      page.addPill(g, genderLabels[g], 'gender', false);
3754                    }
3755                  });
3756                }
3757                
3758                // Remove gender keywords from search since they're now in the genders filter
3759                // This prevents "Mens Ghost 12" from becoming a literal phrase search
3760                let cleanedSearch = searchValue;
3761                if (genderExtraction.genders && genderExtraction.genders.length > 0) {
3762                  // Remove gender keywords like Mens, Womens, Men, Women, etc.
3763                  cleanedSearch = searchValue.replace(/\b(men'?s?|women'?s?|womens?|wmns|male|female|ladies|boys?|girls?|kids?|youth|children|child|unisex|mns?)\b/gi, ' ');
3764                  cleanedSearch = cleanedSearch.trim().replace(/\s+/g, ' '); // Normalize whitespace
3765                }
3766                
3767                // Extract colors from the search query (e.g., "red shoes" → apply red color filter)
3768                const colorExtraction = page.extractColorFromQuery(cleanedSearch);
3769                
3770                // Store colors for filtering and create pills to show active color filters
3771                if (colorExtraction.colors && colorExtraction.colors.length > 0) {
3772                  if (!page.terms.colors) page.terms.colors = [];
3773                  if (!page.terms.filters) page.terms.filters = [];
3774                  colorExtraction.colors.forEach(colorName => {
3775                    if (!page.terms.colors.some(c => c.name === colorName)) {
3776                      const colorDef = page.colorDefinitions?.find(c => c.name === colorName);
3777                      page.terms.colors.push({ 
3778                        name: colorName, 
3779                        hex: colorDef?.hex || '#888888' 
3780                      });
3781                      // Add color to filters array so it's actually searched
3782                      const colorLower = colorName.toLowerCase();
3783                      if (!page.terms.filters.includes(colorLower)) {
3784                        page.terms.filters.push(colorLower);
3785                      }
3786                      // Check the corresponding color checkbox
3787                      $(`#ColorCheckboxList input[value="${colorName}"]`).prop("checked", true);
3788                      $(`#MobileFilterContent #ColorCheckboxList input[value="${colorName}"]`).prop("checked", true);
3789                    }
3790                  });
3791                  // Use the cleaned query (with color removed) for the search filter
3792                  cleanedSearch = colorExtraction.cleanedQuery;
3793                }
3794                
3795                // Extract brands from the search term before adding to filters
3796                if (cleanedSearch && cleanedSearch.length > 0) {
3797                  const brandExtraction = extractBrandsFromQuery(cleanedSearch, page.brands || []);
3798                  
3799                  // If brands were detected, store their names for later mapping
3800                  if (brandExtraction.detectedBrands && brandExtraction.detectedBrands.length > 0) {
3801                    if (!page.pendingBrandNames) page.pendingBrandNames = [];
3802                    brandExtraction.detectedBrands.forEach(brand => {
3803                      // If we got an ID (brands were already loaded), add to page.terms.brands
3804                      if (brand.id) {
3805                        if (!page.terms.brands) page.terms.brands = [];
3806                        if (!page.terms.brands.some(b => b.id === brand.id)) {
3807                          page.terms.brands.push({
3808                            id: brand.id,
3809                            label: brand.name
3810                          });
3811                        }
3812                      } else {
3813                        // Store brand name for later mapping when brands load
3814                        if (!page.pendingBrandNames.includes(brand.name)) {
3815                          page.pendingBrandNames.push(brand.name);
3816                        }
3817                      }
3818                    });
3819                  }
3820                  
3821                  // Add only the cleaned query (without brand names) to filters
3822                  if (!page.terms.filters) page.terms.filters = [];
3823                  const finalSearchTerm = brandExtraction.cleanedQuery.trim();
3824                  if (finalSearchTerm.length > 0 && !page.terms.filters.includes(finalSearchTerm)) {
3825                    page.terms.filters.push(finalSearchTerm);
3826                  }
3827                }
3828            }
3829          }
3830        }
3831      }
3832      
3833      // Process sort filter
3834      if (urlParams.has('sort')) {
3835        const rawSort = urlParams.get('sort');
3836        if (rawSort) {
3837          const sortValue = decodeURIComponent(rawSort.trim());
3838          const sortParts = sortValue.split(/\s+/);
3839          if (sortParts.length === 2) {
3840            products.filter.sort = sortParts[0];
3841            products.filter.sortType = sortParts[1];
3842            $('#SortBy').val(sortValue);
3843          }
3844        }
3845      }
3846
3847      if (hasSaleParam) {
3848        $('input[data-filter="on-sale"]').prop('checked', true);
3849        $('#MobileFilterContent input[data-filter="on-sale"]').prop('checked', true);
3850      }
3851      
3852      // page.pills();
3853    }, 
3854    brandsLoaded: function (e) {
3855      page.brands = e;
3856      
3857      // Ensure brands array exists in page.terms
3858      if (!page.terms.brands) {
3859        page.terms.brands = [];
3860        // Migrate old brand structure if exists
3861        if (page.terms.brand && page.terms.brand.id !== -1) {
3862          page.terms.brands.push({
3863            id: page.terms.brand.id,
3864            label: page.terms.brand.label
3865          });
3866        }
3867      }
3868      
3869      // Process any pending brand names that were detected during URL parsing
3870      // before the brands list was loaded
3871      if (page.pendingBrandNames && page.pendingBrandNames.length > 0) {
3872        page.pendingBrandNames.forEach(brandName => {
3873          // Find the brand by name (case-insensitive)
3874          const brand = page.brands.find(b => b.name.toLowerCase() === brandName.toLowerCase());
3875          if (brand && !page.terms.brands.some(b => b.id === brand.brandId)) {
3876            page.terms.brands.push({
3877              id: brand.brandId,
3878              label: brand.name
3879            });
3880          }
3881        });
3882        // Clear pending brand names
3883        page.pendingBrandNames = [];
3884      }
3885      
3886      // Sort brands by product count (descending)
3887      page.brands.sort((a, b) => (b.total || b.productCount || 0) - (a.total || a.productCount || 0));
3888      
3889      // Initialize allBrands temporarily with database counts
3890      // These will be updated with accurate API counts shortly
3891      page.allBrands = page.brands
3892        .map(brand => ({
3893          brandId: brand.brandId,
3894          name: brand.name,
3895          productCount: brand.total || brand.productCount || 0,
3896          isHidden: brand.isHidden || brand.hidden || false
3897        }))
3898        .filter(brand => brand.productCount > 0 && !brand.isHidden)
3899        .sort((a, b) => b.productCount - a.productCount);
3900      
3901      // Immediately update with accurate counts from the products API
3902      page.updateFilterCounts();
3903      
3904      // Handle forced brand selection
3905      if (page.brands.length > 0) {
3906        for (var i = 0; i < page.brands.length; i++) { 
3907          if (page.forceBrandId > 0) { 
3908            if (page.forceBrandId == page.brands[i].brandId) { 
3909              const brandId = page.brands[i].brandId;
3910              const brandName = page.brands[i].name;
3911              if (!page.terms.brands.some(b => b.id === brandId)) {
3912                page.terms.brands.push({ id: brandId, label: brandName });
3913              }
3914            }
3915          } else {
3916            if (page.forceBrand != "" && (page.brands[i].name.toLowerCase() == page.forceBrand.toLowerCase() || page.brands[i].name.split(' ').join('').toLowerCase() == page.forceBrand.split(' ').join(''))) {
3917              const brandId = page.brands[i].brandId;
3918              const brandName = page.brands[i].name;
3919              page.forceBrandId = brandId; // Set the ID so filters are applied
3920              if (!page.terms.brands.some(b => b.id === brandId)) {
3921                page.terms.brands.push({ id: brandId, label: brandName });
3922              }
3923            }
3924          }
3925        }
3926      }
3927      
3928      // Render brand checkboxes
3929      page.renderBrandCheckboxes();
3930      
3931      // Setup search functionality
3932      $("#BrandSearchInput").off("input").on("input", function() {
3933        page.filterBrandCheckboxes($(this).val());
3934      });
3935      
3936      $("#SizeSearchInput").off("input").on("input", function() {
3937        page.filterSizeCheckboxes($(this).val());
3938      });
3939      
3940      $("#WidthSearchInput").off("input").on("input", function() {
3941        page.filterWidthCheckboxes($(this).val());
3942      });
3943      
3944      // Setup show more functionality
3945      $("#BrandShowMore a").off("click").on("click", function(e) {
3946        e.preventDefault();
3947        page.showAllBrands();
3948      });
3949      
3950      if (page.doAfterBrandLoad) {
3951        page.urlParamsChanged();
3952        // After processing URL params with loaded brands, render pills
3953        page.pills();
3954      } else {
3955        if (page.forceBrand != "" || page.forceBrandId > 0) {
3956          // Reset search state since we now have the brand ID resolved
3957          page.isSearching = false; 
3958          page.pills();
3959        }
3960        else if (page.forceCategory != "" || page.forceCategoryId > 0) { 
3961          // Category is forced but brand is not - let categoriesLoaded handle it
3962          // Don't call pills() here to avoid duplicate searches
3963        } else {
3964          // No forced brand or category - call pills() for default product load
3965          page.pills();
3966        }
3967      }
3968    },
3969    collectionsLoaded: function (e) {
3970      page.collections = e;
3971      
3972      // Ensure collections array exists in page.terms
3973      if (!page.terms.collections) {
3974        page.terms.collections = [];
3975      }
3976      
3977      // Hide Collections filter if there are no collections
3978      if (!page.collections || page.collections.length === 0) {
3979        $("#CollectionArea").hide();
3980        return;
3981      }
3982      
3983      // Show Collections filter if it was hidden
3984      $("#CollectionArea").show();
3985      
3986      // Sort collections alphabetically by title
3987      page.collections.sort((a, b) => (a.title || '').localeCompare(b.title || ''));
3988      
3989      // Store all collections with their data (no counts needed)
3990      page.allCollections = page.collections
3991        .map(coll => ({
3992          collectionId: coll.collectionId,
3993          title: coll.title
3994        }))
3995        .filter(coll => coll.collectionId);
3995 // Just filter out any invalid entries
3996      
3997      // Render collection checkboxes
3998      page.renderCollectionCheckboxes();
3999      
4000      // Setup search functionality
4001      $("#CollectionSearchInput").off("input").on("input", function() {
4002        page.filterCollectionCheckboxes($(this).val());
4003      });
4004      
4005      // Setup show more functionality for desktop
4006      $("#CollectionShowMore a").off("click").on("click", function(e) {
4007        e.preventDefault();
4008        page.showAllCollections();
4009      });
4010      
4011      // Setup show more for mobile if it exists (may be cloned later)
4012      if ($("#MobileFilterContent #CollectionArea").length > 0) {
4013        $("#MobileFilterContent #CollectionArea #CollectionShowMore a").off('click').on('click', function(e) {
4014          e.preventDefault();
4015          page.showAllCollections();
4016        });
4017      }
4018    },
4019    renderBrandCheckboxes: function(brands, showAll) {
4020      brands = brands || page.allBrands;
4021      const showCount = showAll ? brands.length : 5;
4022      const displayBrands = brands.slice(0, showCount);
4023      const remainingCount = brands.length - showCount;
4024      
4025      let html = '';
4026      for (let i = 0; i < displayBrands.length; i++) {
4027        const brand = displayBrands[i];
4028        const isChecked = page.terms.brands.some(b => b.id === brand.brandId) ? 'checked' : '';
4029        
4030        html += `
4031          <div class="input-checkbox">
4032            <input id="brand-${brand.brandId}" type="checkbox" name="brand-filter" value="${brand.brandId}" ${isChecked} data-brand-name="${brand.name}" />
4033            <label for="brand-${brand.brandId}" class="runfreecheck"></label>
4034            <span class="checkboxlabel">${brand.name} <span class="count" style="display:none">(${brand.productCount})</span></span>
4035          </div>
4036        `;
4037      }
4038      
4039      $("#BrandCheckboxList").html(html);
4040      // Also update mobile panel if it exists
4041      $("#MobileFilterContent #BrandCheckboxList").html(html);
4042      
4043      // Toggle button text (both desktop and mobile)
4044      if (showAll) {
4045        $("#FiltersList #BrandShowMore a").html('Show less');
4046        $("#MobileFilterContent #BrandArea #BrandShowMore a").html('Show Less');
4047        $("#BrandShowMore").show();
4048        $("#MobileFilterContent #BrandArea #BrandShowMore").show();
4049      } else if (remainingCount > 0) {
4050        $("#BrandShowMoreCount").text(remainingCount);
4051        $("#FiltersList #BrandShowMore a").html(`Show <span>${remainingCount}</span> more`);
4052        $("#MobileFilterContent #BrandArea #BrandShowMoreCount").text(remainingCount);
4053        $("#MobileFilterContent #BrandArea #BrandShowMore a").html(`Show <span>${remainingCount}</span> More`);
4054        $("#BrandShowMore").show();
4055        $("#MobileFilterContent #BrandArea #BrandShowMore").show();
4056      } else {
4057        $("#BrandShowMore").hide();
4058        $("#MobileFilterContent #BrandArea #BrandShowMore").hide();
4059      }
4060      
4061      // Attach change handlers to both desktop and mobile checkboxes
4062      $("#FiltersList #BrandCheckboxList input[type='checkbox'], #MobileFilterContent #BrandArea input[type='checkbox']").off("change").on("change", function() {
4063        const brandId = parseInt($(this).val());
4064        const brandName = $(this).data("brand-name");
4065        
4066        if ($(this).is(":checked")) {
4067          // Add to brands array if not already there
4068          if (!page.terms.brands.some(b => b.id === brandId)) {
4069            page.terms.brands.push({ id: brandId, label: brandName });
4070          }
4071          page.addPill(brandId, brandName, "brand");
4072          // Check the corresponding checkbox in the other panel
4073          $("#FiltersList #BrandCheckboxList input[value='" + brandId + "']").prop("checked", true);
4074          $("#MobileFilterContent #BrandArea input[value='" + brandId + "']").prop("checked", true);
4075        } else {
4076          // Remove from brands array
4077          page.terms.brands = page.terms.brands.filter(b => b.id !== brandId);
4078          page.pills();
4079          // Uncheck the corresponding checkbox in the other panel
4080          $("#FiltersList #BrandCheckboxList input[value='" + brandId + "']").prop("checked", false);
4081          $("#MobileFilterContent #BrandArea input[value='" + brandId + "']").prop("checked", false);
4082        }
4083        
4084        products.filter.brands = page.terms.brands.map(b => b.id);
4085        page.pillsChanged();
4086      });
4087    },
4088    filterBrandCheckboxes: function(searchTerm) {
4089      if (!searchTerm || searchTerm.trim() === '') {
4090        page.renderBrandCheckboxes();
4091        return;
4092      }
4093      
4094      const filtered = page.allBrands.filter(brand => 
4095        brand.name.toLowerCase().includes(searchTerm.toLowerCase())
4096      );
4097      
4098      page.renderBrandCheckboxes(filtered, true);
4099    },
4100    filterSizeCheckboxes: function(searchTerm) {
4101      if (!searchTerm || searchTerm.trim() === '') {
4102        page.currentFilteredSizes = null;
4103        page.renderSizeCheckboxes();
4104        return;
4105      }
4106      
4107      const filtered = page.allSizes.filter(sizeData => {
4108        const size = sizeData.size !== undefined ? Number(sizeData.size).toFixed(1).replace('.0', '') : sizeData;
4109        return size.toString().toLowerCase().includes(searchTerm.toLowerCase());
4110      });
4111      
4112      page.currentFilteredSizes = filtered;
4113      page.renderSizeCheckboxes(filtered, true);
4114    },
4115    filterWidthCheckboxes: function(searchTerm) {
4116      if (!searchTerm || searchTerm.trim() === '') {
4117        page.currentFilteredWidths = null;
4118        page.renderWidthCheckboxes();
4119        return;
4120      }
4121      
4122      const filtered = page.allWidths.filter(widthData => 
4123        widthData.width.toLowerCase().includes(searchTerm.toLowerCase())
4124      );
4125      
4126      page.currentFilteredWidths = filtered;
4127      page.renderWidthCheckboxes(filtered, true);
4128    },
4129    showAllBrands: function() {
4130      const desktopText = $("#FiltersList #BrandShowMore a").text().trim();
4131      const mobileText = $("#MobileFilterContent #BrandShowMore a").text().trim();
4132      const isShowingAll = desktopText === 'Show less' || mobileText === 'Show Less';
4133      page.renderBrandCheckboxes(page.allBrands, !isShowingAll);
4134    },
4135    renderCollectionCheckboxes: function(collections, showAll) {
4136      collections = collections || page.allCollections;
4137      const showCount = showAll ? collections.length : 5;
4138      const displayCollections = collections.slice(0, showCount);
4139      const remainingCount = collections.length - showCount;
4140      
4141      let html = '';
4142      for (let i = 0; i < displayCollections.length; i++) {
4143        const collection = displayCollections[i];
4144        const isChecked = page.terms.collections.some(c => c.id === collection.collectionId) ? 'checked' : '';
4145        
4146        html += `
4147          <div class="input-checkbox">
4148            <input id="collection-${collection.collectionId}" type="checkbox" name="collection-filter" value="${collection.collectionId}" ${isChecked} data-collection-title="${collection.title}" />
4149            <label for="collection-${collection.collectionId}" class="runfreecheck"></label>
4150            <span class="checkboxlabel">${collection.title}</span>
4151          </div>
4152        `;
4153      }
4154      
4155      $("#CollectionCheckboxList").html(html);
4156      // Also update mobile panel if it exists
4157      $("#MobileFilterContent #CollectionCheckboxList").html(html);
4158      
4159      // Toggle button text (both desktop and mobile)
4160      if (showAll) {
4161        $("#FiltersList #CollectionShowMore a").html('Show less');
4162        $("#MobileFilterContent #CollectionArea #CollectionShowMore a").html('Show Less');
4163        $("#CollectionShowMore").show();
4164        $("#MobileFilterContent #CollectionArea #CollectionShowMore").show();
4165      } else if (remainingCount > 0) {
4166        $("#CollectionShowMoreCount").text(remainingCount);
4167        $("#FiltersList #CollectionShowMore a").html(`Show <span>${remainingCount}</span> more`);
4168        $("#MobileFilterContent #CollectionArea #CollectionShowMoreCount").text(remainingCount);
4169        $("#MobileFilterContent #CollectionArea #CollectionShowMore a").html(`Show <span>${remainingCount}</span> More`);
4170        $("#CollectionShowMore").show();
4171        $("#MobileFilterContent #CollectionArea #CollectionShowMore").show();
4172      } else {
4173        $("#CollectionShowMore").hide();
4174        $("#MobileFilterContent #CollectionArea #CollectionShowMore").hide();
4175      }
4176      
4177      // Attach change handlers to both desktop and mobile checkboxes
4178      $("#FiltersList #CollectionCheckboxList input[type='checkbox'], #MobileFilterContent #CollectionArea input[type='checkbox']").off("
4178change").on("change", function() {
4179        const collectionId = parseInt($(this).val());
4180        const collectionTitle = $(this).data("collection-title");
4181        
4182        if ($(this).is(":checked")) {
4183          // Add to collections array if not already there
4184          if (!page.terms.collections.some(c => c.id === collectionId)) {
4185            page.terms.collections.push({ id: collectionId, label: collectionTitle });
4186          }
4187          page.addPill(collectionId, collectionTitle, "collection");
4188          // Check the corresponding checkbox in the other panel
4189          $("#FiltersList #CollectionCheckboxList input[value='" + collectionId + "']").prop("checked", true);
4190          $("#MobileFilterContent #CollectionArea input[value='" + collectionId + "']").prop("checked", true);
4191        } else {
4192          // Remove from collections array
4193          page.terms.collections = page.terms.collections.filter(c => c.id !== collectionId);
4194          page.pills();
4195          // Uncheck the corresponding checkbox in the other panel
4196          $("#FiltersList #CollectionCheckboxList input[value='" + collectionId + "']").prop("checked", false);
4197          $("#MobileFilterContent #CollectionArea input[value='" + collectionId + "']").prop("checked", false);
4198        }
4199        
4200        // Set single collection filter (backend expects singular 'collection' parameter)
4201        products.filter.collection = page.terms.collections.length > 0 ? page.terms.collections[0].id : -1;
4202        
4203        // page.pillsChanged();
4204      });
4205    },
4206    filterCollectionCheckboxes: function(searchTerm) {
4207      if (!searchTerm || searchTerm.trim() === '') {
4208        page.renderCollectionCheckboxes();
4209        return;
4210      }
4211      
4212      const filtered = page.allCollections.filter(collection => 
4213        collection.title.toLowerCase().includes(searchTerm.toLowerCase())
4214      );
4215      
4216      page.renderCollectionCheckboxes(filtered, true);
4217    },
4218    showAllCollections: function() {
4219      const desktopText = $("#FiltersList #CollectionArea #CollectionShowMore a").text().trim();
4220      const mobileText = $("#MobileFilterContent #CollectionArea #CollectionShowMore a").text().trim();
4221      const isShowingAll = desktopText === 'Show less' || mobileText === 'Show Less';
4222      page.renderCollectionCheckboxes(page.allCollections, !isShowingAll);
4223    },
4224    updateFilterCounts: function() {
4225      // Combined function to update both brand counts and option counts with a single API call
4226      // Check if there are any non-brand filters applied
4227      const hasNonBrandFilters = (
4228        (products.filter.sizes && products.filter.sizes.length > 0) ||
4229        (products.filter.widths && products.filter.widths.length > 0) ||
4230        (products.filter.prices && products.filter.prices.length > 0) ||
4231        (page.terms.filters && page.terms.filters.length > 0) || // Color/NLP filters
4232        products.filter.instore ||
4233        products.filter.onsale ||
4234        products.filter.shipable ||
4235        (products.filter.category && products.filter.category !== -1) ||
4236        (products.filter.collection && products.filter.collection !== -1) ||
4237        (products.filter.search && products.filter.search !== "")
4238      );
4239      
4240      // If ONLY brand filters are applied (no other filters), use the original brand totals
4241      // from page.brands which contains accurate unstacked variant counts from the backend
4242      if (!hasNonBrandFilters) {
4243        page.allBrands = page.brands
4244          .map(brand => ({
4245            brandId: brand.brandId,
4246            name: brand.name,
4247            productCount: brand.total || brand.productCount || 0,
4248            isHidden: brand.isHidden || brand.hidden || false
4249          }))
4250          .filter(brand => brand.productCount > 0 && !brand.isHidden)
4251          .sort((a, b) => b.productCount - a.productCount);
4252        page.renderBrandCheckboxes();
4253        
4254        // Still need to update option counts even if only brands are filtered
4255        page.updateOptionCountsOnly();
4256        return;
4257      }
4258      
4259      // Make ONE API call that removes both brand and option filters
4260      // Then use client-side filtering to compute both brand and option counts
4261      const countingFilter = JSON.parse(JSON.stringify(products.filter));
4262      countingFilter.size = 10000; // Get all products
4263      countingFilter.page = 1;
4264      countingFilter.grouped = true; // Use grouped products to match display count
4265      
4266      // Remove both brand filters AND option filters to get the superset
4267      delete countingFilter.brands;
4268      delete countingFilter.instore;
4269      delete countingFilter.onsale;
4270      delete countingFilter.shipable;
4271      delete countingFilter.prices;
4272      
4273      // NOTE: The backend stored procedure (up_SearchProducts_UI) should handle filter logic as follows:
4274      // - Different filter TYPES are ANDed together: (gender filter) AND (search terms) AND (price filter) AND (size filter)
4275      // - Multiple values within SAME filter type are ORed: (price>=50 AND price<=99.99) OR (price>=100 AND price<=159.99)
4276      // - Search terms within the same query are ANDed: 'Mens Ghost 12' means (Mens) AND (Ghost) AND (12)
4277      // This ensures precise filtering while allowing multiple options within each category
4278      
4279      service.call("products-search", countingFilter, function(e) {
4280        if (!e.data || e.data.length === 0) {
4281          // Set all counts to 0 if no products
4282          page.allBrands = [];
4283          page.renderBrandCheckboxes();
4284          $("#ShipToMe").parent().find('.checkboxlabel').html('Ship To Me <span class="count">(0)</span>');
4285          $("#PickupInStore").parent().find('.checkboxlabel').html('Pickup In-Store <span class="count">(0)</span>');
4286          $("#OnSale").parent().find('.checkboxlabel').html('Sale Products <span class="count">(0)</span>');
4287          page.updatePriceRangeCounts([]);
4288          return;
4289        }
4290        
4291        // Apply client-side color filtering if colors are selected
4292        let allProducts = e.data;
4293        if (page.selectedColorFilters && page.selectedColorFilters.length > 0) {
4294          allProducts = e.data.filter(product => 
4295            page.productMatchesColorFilter(product.color, page.selectedColorFilters)
4296          );
4297        }
4298        
4299        // ===== BRAND COUNTS =====
4300        // Filter products by active option filters (instore, onsale, shipable, prices)
4301        let productsForBrandCounts = allProducts;
4302        
4303        // Apply option filters client-side
4304        if (products.filter.instore) {
4305          productsForBrandCounts = productsForBrandCounts.filter(p => p.stock > 0);
4306        }
4307        if (products.filter.onsale) {
4308          productsForBrandCounts = productsForBrandCounts.filter(p => 
4309            p.isOnSale === true || p.isOnSale === 1 || p.onsale === true || p.onsale === 1
4310          );
4311        }
4312        if (products.filter.shipable) {
4313          productsForBrandCounts = productsForBrandCounts.filter(p => 
4314            !p.isInStorePickupOnly && !p.inStorePickupOnly && 
4315            !p.isInStorePurchaseOnly && !p.inStorePurchaseOnly
4316          );
4317        }
4318        if (page.terms.prices && page.terms.prices.length > 0) {
4319          productsForBrandCounts = productsForBrandCounts.filter(p => {
4320            const price = parseFloat(p.price || p.cost || 0);
4321            return page.terms.prices.some(priceRange => {
4322              const range = page.priceRanges.find(r => r.value === priceRange);
4323              return range && price >= range.min && price <= range.max;
4324            });
4325          });
4326        }
4327        
4328        // Count unique products per brand
4329        const brandCounts = {};
4330        const seenBrandProducts = new Set();
4331        productsForBrandCounts.forEach(product => {
4332          const productKey = `${product.name}|${product.color}`;
4333          if (!seenBrandProducts.has(productKey)) {
4334            seenBrandProducts.add(productKey);
4335            const brandId = product.brandId;
4336            if (brandId) {
4337              brandCounts[brandId] = (brandCounts[brandId] || 0) + 1;
4338            }
4339          }
4340        });
4341        
4342        // Update allBrands with new counts
4343        page.allBrands = page.brands
4344          .map(brand => ({
4345            brandId: brand.brandId,
4346            name: brand.name,
4347            productCount: brandCounts[brand.brandId] || 0,
4348            isHidden: brand.isHidden || brand.hidden || false
4349          }))
4350          .filter(brand =>
4350 brand.productCount > 0 && !brand.isHidden)
4351          .sort((a, b) => b.productCount - a.productCount);
4352        
4353        page.renderBrandCheckboxes();
4354        
4355        // ===== OPTION COUNTS =====
4356        // Filter products by active brand filters
4357        let productsForOptionCounts = allProducts;
4358        
4359        if (products.filter.brands && products.filter.brands.length > 0) {
4360          productsForOptionCounts = productsForOptionCounts.filter(p => 
4361            products.filter.brands.includes(p.brandId)
4362          );
4363        }
4364        
4365        // Count unique products for each option
4366        const seenOptionProducts = new Set();
4367        let shipableCount = 0;
4368        let instoreCount = 0;
4369        let onsaleCount = 0;
4370        
4371        productsForOptionCounts.forEach(product => {
4372          const productKey = `${product.name}|${product.color}`;
4373          if (seenOptionProducts.has(productKey)) return;
4374          seenOptionProducts.add(productKey);
4375          
4376          if (!product.isInStorePickupOnly && !product.inStorePickupOnly && 
4377              !product.isInStorePurchaseOnly && !product.inStorePurchaseOnly) {
4378            shipableCount++;
4379          }
4380          
4381          if (product.stock > 0) {
4382            instoreCount++;
4383          }
4384          
4385          if (product.isOnSale === true || product.isOnSale === 1 || product.onsale === true || product.onsale === 1) {
4386            onsaleCount++;
4387          }
4388        });
4389        
4390        // Update option labels
4391        $("#ShipToMe").parent().find('.checkboxlabel').html(`Ship To Me <span class="count">(${shipableCount})</span>`);
4392        $("#PickupInStore").parent().find('.checkboxlabel').html(`Pickup In-Store <span class="count">(${instoreCount})</span>`);
4393        $("#OnSale").parent().find('.checkboxlabel').html(`Sale Products <span class="count">(${onsaleCount})</span>`);
4394        
4395        // Update price range counts
4396        page.updatePriceRangeCounts(productsForOptionCounts);
4397      });
4398    },
4399    updateOptionCountsOnly: function() {
4400      // Separate function for when we only need to update option counts (not brand counts)
4401      // This is called when only brand filters are active
4402      const countingFilter = JSON.parse(JSON.stringify(products.filter));
4403      countingFilter.size = 10000;
4404      countingFilter.page = 1;
4405      countingFilter.grouped = true;
4406      delete countingFilter.instore;
4407      delete countingFilter.onsale;
4408      delete countingFilter.shipable;
4409      delete countingFilter.prices;
4410      
4411      service.call("products-search", countingFilter, function(e) {
4412        if (!e.data || e.data.length === 0) {
4413          $("#ShipToMe").parent().find('.checkboxlabel').html('Ship To Me <span class="count">(0)</span>');
4414          $("#PickupInStore").parent().find('.checkboxlabel').html('Pickup In-Store <span class="count">(0)</span>');
4415          $("#OnSale").parent().find('.checkboxlabel').html('Sale Products <span class="count">(0)</span>');
4416          page.updatePriceRangeCounts([]);
4417          return;
4418        }
4419        
4420        let productsForCounting = e.data;
4421        if (page.selectedColorFilters && page.selectedColorFilters.length > 0) {
4422          productsForCounting = e.data.filter(product => 
4423            page.productMatchesColorFilter(product.color, page.selectedColorFilters)
4424          );
4425        }
4426        
4427        const seenProducts = new Set();
4428        let shipableCount = 0;
4429        let instoreCount = 0;
4430        let onsaleCount = 0;
4431        
4432        productsForCounting.forEach(product => {
4433          const productKey = `${product.name}|${product.color}`;
4434          if (seenProducts.has(productKey)) return;
4435          seenProducts.add(productKey);
4436          
4437          if (!product.isInStorePickupOnly && !product.inStorePickupOnly && 
4438              !product.isInStorePurchaseOnly && !product.inStorePurchaseOnly) {
4439            shipableCount++;
4440          }
4441          if (product.stock > 0) {
4442            instoreCount++;
4443          }
4444          if (product.isOnSale === true || product.isOnSale === 1 || product.onsale === true || product.onsale === 1) {
4445            onsaleCount++;
4446          }
4447        });
4448        
4449        $("#ShipToMe").parent().find('.checkboxlabel').html(`Ship To Me <span class="count">(${shipableCount})</span>`);
4450        $("#PickupInStore").parent().find('.checkboxlabel').html(`Pickup In-Store <span class="count">(${instoreCount})</span>`);
4451        $("#OnSale").parent().find('.checkboxlabel').html(`Sale Products <span class="count">(${onsaleCount})</span>`);
4452        
4453        page.updatePriceRangeCounts(productsForCounting);
4454      });
4455    },
4456    updatePriceRangeCounts: function(products) {
4457      // If no price ranges defined yet, skip
4458      if (!page.priceRanges) {
4459        return;
4460      }
4461      
4462      // Count products in each price range
4463      const rangeCounts = page.priceRanges.map(range => {
4464        let count = 0;
4465        products.forEach(product => {
4466          const price = parseFloat(product.price || product.cost || 0);
4467          if (price >= range.min && price <= range.max) {
4468            count++;
4469          }
4470        });
4471        return { value: range.value, label: range.label, count: count };
4472      });
4473      
4474      // Hide/show price ranges based on whether products exist in that range (no counts displayed)
4475      rangeCounts.forEach(rangeCount => {
4476        const $desktopContainer = $(`#FiltersList #PriceCheckboxList input[value="${rangeCount.value}"]`).parent();
4477        const $mobileContainer = $(`#MobileFilterContent #PriceArea input[value="${rangeCount.value}"]`).parent();
4478        
4479        // Hide/show based on count (unless it's currently checked)
4480        const isChecked = $desktopContainer.find('input').prop('checked');
4481        if (rangeCount.count === 0 && !isChecked) {
4482          $desktopContainer.hide();
4483          $mobileContainer.hide();
4484        } else {
4485          $desktopContainer.show();
4486          $mobileContainer.show();
4487        }
4488      });
4489    },
4490    // Color filter functions
4491    allColors: [],
4492    /**
4493     * Check if a product's color matches any of the selected color filters
4494     * @param {string} productColor - The product's color field (e.g., "Red/Black", "Navy Blue")
4495     * @param {string[]} selectedColors - Array of selected color names (e.g., ["Red", "Blue"])
4496     * @returns {boolean} - True if product matches any selected color
4497     */
4498    productMatchesColorFilter: function(productColor, selectedColors) {
4499      if (!selectedColors || selectedColors.length === 0) return true; // No filter = all match
4500      if (!productColor) return false; // No color = doesn't match any filter
4501      
4502      const productColorLower = productColor.toLowerCase();
4503      
4504      // Color keyword patterns for flexible matching (same as extractColorFromQuery)
4505      const colorPatterns = {
4506        'red': /\b(red|crimson|scarlet|maroon|burgundy)\b/i,
4507        'orange': /\b(orange|tangerine|coral)\b/i,
4508        'yellow': /\b(yellow|gold|golden|mustard|lemon)\b/i,
4509        'green': /\b(green|olive|lime|mint|teal|emerald|forest)\b/i,
4510        'blue': /\b(blue|navy|aqua|cyan|cobalt|royal|indigo|turquoise)\b/i,
4511        'purple': /\b(purple|violet|lavender|plum|magenta)\b/i,
4512        'pink': /\b(pink|rose|salmon|fuchsia|blush)\b/i,
4513        'beige': /\b(beige|tan|khaki|cream|nude|sand)\b/i,
4514        'brown': /\b(brown|chocolate|coffee|mocha|caramel|chestnut)\b/i,
4515        'black': /\b(black|onyx|charcoal|ebony)\b/i,
4516        'gray': /\b(gray|grey|silver|slate|graphite|ash)\b/i,
4517        'white': /\b(white|ivory|pearl|snow)\b/i
4518      };
4519      
4520      // Check if product matches ANY of the selected colors
4521      for (const color of selectedColors) {
4522        const colorLower = color.toLowerCase();
4523        const pattern = colorPatterns[colorLower];
4524        if (pattern && pattern.test(productColorLower)) {
4525          return true;
4526        }
4527        // Fallback: simple substring match
4528        if (productColorLower.includes(colorLower)) {
4529          return true;
4530        }
4531      }
4532      return false;
4533    },
4534    initColors: function() {
4535      // Initialize colors with hex values (from Backcountry.com)
4536      const colorDefinitions = [
4537        { name: 'Red', hex: '#DC143C' },
4538        { name: 'Orange', hex: '#FF8C00' },
4539        { name: 'Yellow', hex: '#FFD700' },
4540        { name: 'Green', hex: '#228B22' },
4541        { name: 'Blue', hex: '#4169E1' },
4542        { name: 'Purple', hex: '#800080' },
4543        { name: 'Pink', hex: '#FF69B4' },
4544        { name: 'Beige', hex: '#F5DEB3' },
4545        { name: 'Brown', hex: '#8B4513' },
4546        { name: 'Black', hex: '#000000' },
4547        { name: 'Gray', hex: '#808080' },
4548        { name: 'White', hex: '#FFFFFF' }
4549      ];
4550      
4551      // Ensure colors array exists in page.terms
4552      if (!page.terms.colors) {
4553        page.terms.colors = [];
4554      }
4555      
4556      // Store color definitions
4557      page.colorDefinitions = colorDefinitions;
4558      
4559      // For now, initialize with mock counts (will be replaced with real data later)
4560      page.allColors = colorDefinitions.map(color => ({
4561        name: color.name,
4562        hex: color.hex
4563      }));
4564      
4565      page.renderColorCheckboxes();
4566    },
4567    renderColorCheckboxes: function(colors, showAll) {
4568      colors = colors || page.allColors;
4569      const showCount = showAll ? colors.length : 6;
4570      const displayColors = colors.slice(0, showCount);
4571      const remainingCount = colors.length - showCount;
4572      
4573      let html = '';
4574      for (let i = 0; i < displayColors.length; i++) {
4575        const color = displayColors[i];
4576        const isChecked = page.terms.colors.some(c => c.name === color.name) ? 'checked' : '';
4577        const borderColor = color.name === 'White' ? '#e0e0e0' : color.hex;
4578        
4579        html += `
4580          <div class="input-checkbox">
4581            <input id="color-${color.name}" type="checkbox" name="color-filter" value="${color.name}" ${isChecked} data-color-hex="${color.hex}" />
4582            <label for="color-${color.name}" class="runfreecheck"></label>
4583            <span class="color-circle" style="background-color: ${color.hex}; border-color: ${borderColor};"></span>
4584            <span class="checkboxlabel">${color.name}</span>
4585          </div>
4586        `;
4587      }
4588      
4589      $("#ColorCheckboxList").html(html);
4590      $("#MobileFilterContent #ColorCheckboxList").html(html);
4591      
4592      // Attach change handlers to DESKTOP checkboxes only (mobile handled by general mobile handler)
4593      $("#FiltersList #ColorCheckboxList input[type='checkbox']").off("change").on("change", function() {
4594        const colorName = $(this).val();
4595        if (!colorName) return; // Guard against null/undefined values
4596        
4597        const isChecked = $(this).is(":checked");
4598        const colorLabel = $(this).siblings('.checkboxlabel').text().trim();
4599        
4600        if (isChecked) {
4601          // Trigger NLP-based AI search for the color using lowercase (this handles pill creation)
4602          page.addSearch(colorName.toLowerCase(), null, 'filter');
4603        } else {
4604          // Remove the filter when unchecked
4605          page.terms.filters = page.terms.filters.filter(f => f.toLowerCase() !== colorName.toLowerCase());
4606          page.pills();
4607          // page.pillsChanged();
4608        }
4609        
4610        // Sync checkbox state between desktop and mobile
4611        $("#FiltersList #ColorCheckboxList input[value='" + colorName + "'], #MobileFilterContent #ColorCheckboxList input[value='" + colorName + "']").prop("checked", isChecked);
4612      });
4613      
4614      // Toggle button text
4615      if (showAll) {
4616        $("#FiltersList #ColorShowMore a").html('Show less');
4617        $("#MobileFilterContent #ColorArea #ColorShowMore a").html('Show Less');
4618        $("#ColorShowMore").show();
4619        $("#MobileFilterContent #ColorArea #ColorShowMore").show();
4620      } else if (remainingCount > 0) {
4621        $("#ColorShowMoreCount").text(remainingCount);
4622        $("#FiltersList #ColorShowMore a").html(`Show <span>${remainingCount}</span> more`);
4623        $("#MobileFilterContent #ColorArea #ColorShowMoreCount").text(remainingCount);
4624        $("#MobileFilterContent #ColorArea #ColorShowMore a").html(`Show <span>${remainingCount}</span> More`);
4625        $("#ColorShowMore").show();
4626        $("#MobileFilterContent #ColorArea #ColorShowMore").show();
4627      } else {
4628        $("#ColorShowMore").hide();
4629        $("#MobileFilterContent #ColorArea #ColorShowMore").hide();
4630      }
4631      
4632      // Re-attach show more click handler after rendering
4633      $("#ColorShowMore a, #MobileFilterContent #ColorArea #ColorShowMore a").off("click").on("click", function(e) {
4634        e.preventDefault();
4635        page.showAllColors(this);
4636      });
4637    },
4638    showAllColors: function(clickedElement) {
4639      // Check if we're currently showing all colors by looking at any show more link text
4640      const linkText = $(clickedElement || "#ColorShowMore a").text().trim();
4641      const isShowingAll = linkText.toLowerCase().includes('less');
4642      page.renderColorCheckboxes(page.allColors, !isShowingAll);
4643    },
4644    addPill: function (id, name, type, doSearch = true) {
4645      page.addSearch(name, id, type, doSearch);
4646    },
4647    pillCategory: function (e) {
4648      var id = $(e.currentTarget).data("id");
4649      var details = category.details(id); 
4650      var label = details.name;
4651      if (details.label && details.label.trim().length>0) label = details.label.trim();
4652      page.addPill(id, label, "category");
4653    },
4654    pillBrand: function (e) {
4655      var id = $(e.currentTarget).val();
4656      var details = brand.details(id);
4657      if (id > 0) {
4658        page.addPill(id, details.name, "brand");
4659      }
4660      $("#BrandList").val("-1");
4661    },
4662
4663    sort: function (e) {
4664      var sortBy = $("#SortBy").val().split(" ");
4665      if (sortBy.length == 2) {
4666        products.filter.page = 1;
4667        if (page.terms.page) page.terms.page = 1;
4668        products.filter.sort = sortBy[0];
4669        products.filter.sortType = sortBy[1];
4670      }
4671      page.pillsChanged(true);
4672    },
4673    lastPillCount: 0,
4674    lastPillSignature: "",
4675    searchDebounceTimer: null,
4676    pillsChanged: (force = false) => {
4677      var pillSignature = $("#PillBox .pill").map(function() { return $(this).data("id") + ":" + $(this).data("type"); }).get().join("|");
4678      console.log("Pills changed, preparing to execute search... "+ $("#PillBox .pill").length+" pills active. "+force+" force flag.");
4679      
4680      if (force || page.lastPillCount!=$("#PillBox .pill").length || page.lastPillSignature!=pillSignature || $("#PillBox .pill").length==0) {
4681        console.log("Pill count changed from "+page.lastPillCount+" to "+$("#PillBox .pill").length);
4682        page.lastPillCount = $("#PillBox .pill").length;
4683        page.lastPillSignature = pillSignature;
4684
4685        if (page.searchDebounceTimer) clearTimeout(page.searchDebounceTimer);
4686      
4687        page.searchDebounceTimer = setTimeout(() => {
4688          page.executeSearch();
4689        }, 100);
4690      } else {
4691        console.log("Pill count unchanged at "+page.lastPillCount);
4692      }
4693    },
4694    executeSearch: function() {
4695      // debugger;
4696        $(".paging").hide();
4697        $(".pages").html("");
4698        $("#BrandingImage").hide();
4699        $("#ProductList").html($("#CardLoader").html());
4700        $("#SearchFilterArea").addClass("disabled");
4701        const urlParams = new URLSearchParams(window.location.search);
4702        if (urlParams.has('c')) {
4703          page.forceCategoryId = -1;
4704          page.forceCategory = '';
4705          page.forceBrandId = -1;
4706          page.forceBrand = '';
4707        }
4708
4709      products.filter.brand = -1;
4710      products.filter.category = -1;
4711      delete products.filter.search; // Remove old search field - use searchVariations instead
4712      delete products.filter.searchVariations; // Will be set later if needed
4713      products.filter.instore = $("input[data-filter='pickup-in-store']").first().is(":checked") || null;
4714      products.filter.onsale = $("input[data-filter='on-sale']").first().is(":checked") || null;
4715      products.filter.shipable = $("input[data-filter='ship-to-me']").first().is(":checked") || null;
4716
4717      if (!products.filter.sizes) products.filter.sizes = [];
4718      if (!products.filter.widths) products.filter.widths = [];
4719      if (!products.filter.prices) products.filter.prices = [];
4720      if (!products.filter.brands) products.filter.brands = [];
4721      if (page.forceCategoryId) products.filter.category = page.forceCategoryId;
4722
4723      // Set sizes and widths from page.terms
4724      products.filter.sizes = page.terms.sizes || [];
4725      products.filter.widths = page.terms.widths || [];
4726      
4727      // Initialize brands from page.terms.brands (populated during URL parsing)
4728      if (page.terms.brands && page.terms.brands.length > 0) {
4729        products.filter.brands = page.terms.brands.map(b => b.id);
4730      }
4731      
4732      // Set genders from page.terms if available (extracted from URL hash)
4733      if (page.terms.genders && page.terms.genders.length > 0) {
4734        products.filter.genders = page.terms.genders;
4735      }
4736
4737      // Track selected colors for client-side filtering (colors from colorDefinitions)
4738      const colorNames = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'beige', 'brown', 'black', 'gray', 'white'];
4739      page.selectedColorFilters = [];
4740      
4741      // Collect search terms for brand extraction and synonym expansion
4742      const searchTerms = [];
4743      
4744      // Track if we have any quoted phrases from the original search
4745      const quotedPhrasesFromSearch = [];
4746
4747      // Only read from #PillBox (desktop) to avoid duplicates since #MobilePillBox has same pills
4748      $("#PillBox .pill").each(function (i, e) {
4749        var id = $(e).data("id");
4750        var type = $(e).data("type");
4751        var isQuoted = $(e).data("quoted") === true; // Check if this pill came from a quoted search
4752        
4753        if (type == "brand") { 
4754          if (!products.filter.brands.includes(id)) {
4755            products.filter.brands.push(id);
4756          }
4757        }
4758        if (type == "collection") {
4759          // Set single collection (backend only supports one collection at a time)
4760          products.filter.collection = id;
4761        }
4762        if (type == "category") products.filter.category = id;
4763        if (type == "filter") {
4764          // Check if this filter is a color - if so, track for client-side filtering ONLY
4765          const idLower = id.toString().toLowerCase();
4766          if (colorNames.includes(idLower)) {
4767            // Add to selectedColorFilters if not already present (avoid duplicates)
4768            if (!page.selectedColorFilters.includes(idLower)) {
4769              page.selectedColorFilters.push(idLower);
4770            }
4771            // Don't add colors to search - they're filtered client-side by product.color field
4772          } else if (isQuoted) {
4773            // This is a quoted search phrase - add directly to quotedPhrasesFromSearch without any processing
4774            if (!quotedPhrasesFromSearch.includes(id)) {
4775              quotedPhrasesFromSearch.push(id);
4776            }
4777          } else {
4778            // Non-color, non-quoted filters (like general search terms) - extract quotes first, then process
4779            const quoteResult = extractQuotedStrings(id);
4780            // Add quoted phrases to be used directly in searchVariations
4781            if (quoteResult.quotedPhrases && quoteResult.quotedPhrases.length > 0) {
4782              quoteResult.quotedPhrases.forEach(phrase => {
4783                if (!quotedPhrasesFromSearch.includes(phrase)) {
4784                  quotedPhrasesFromSearch.push(phrase);
4785                }
4786              });
4787            }
4788            // Add remaining text (without quotes) for normal processing
4789            if (quoteResult.cleanedQuery && quoteResult.cleanedQuery.trim().length > 0) {
4790              searchTerms.push(quoteResult.cleanedQuery);
4791            }
4792          }
4793        } 
4794      });
4795      
4796      // Check if we only have quoted phrases (no other search terms)
4797      const hasOnlyQuotedPhrases = quotedPhrasesFromSearch.length > 0 && searchTerms.length === 0;
4798      
4799      // Extract brands from search terms before synonym expansion (skip if fully quoted)
4800      if (searchTerms.length > 0 && !hasOnlyQuotedPhrases) {
4801        const searchQuery = searchTerms.join(' ');
4802        const brandResult = extractBrandsFromQuery(searchQuery, page.brands);
4803        
4804        console.log('Brand extraction result:', {
4805          originalQuery: searchQuery,
4806          detectedBrands: brandResult.detectedBrands,
4807          cleanedQuery: brandResult.cleanedQuery,
4808          currentBrands: products.filter.brands
4809        });
4810        
4811        // Add detected brands to BOTH page.terms.brands (for pills) and products.filter.brands (for API)
4812        if (brandResult.detectedBrands.length > 0) {
4813          if (!page.terms.brands) page.terms.brands = [];
4814          
4815          brandResult.detectedBrands.forEach(brand => {
4816            // Add to page.terms.brands if not already there (for pill display)
4817            if (!page.terms.brands.some(b => b.id === brand.id)) {
4818              page.terms.brands.push({
4819                id: brand.id,
4820                label: brand.name
4821              });
4822            }
4823            // Add to products.filter.brands for API call
4824            if (!products.filter.brands.includes(brand.id)) {
4825              products.filter.brands.push(brand.id);
4826            }
4827          });
4828          
4829          // Re-render pills to show the new brands
4830          let pillHtml = "";
4831          if (page.terms.brands && page.terms.brands.length > 0) {
4832            for (let i = 0; i < page.terms.brands.length; i++) {
4833              pillHtml += '<div class="btn btn-sm pill" data-id="' + page.terms.brands[i].id + '" data-type="brand"><i class="fa fa-close"></i> ' + page.terms.brands[i].label + '</div>';
4834            }
4835          }
4836          // Prepend brand pills to existing pills
4837          $("#PillBox").prepend(pillHtml);
4838          $("#MobilePillBox").prepend(pillHtml);
4839          
4840          // Remove the search terms that contained brand names from page.terms.filters
4841          // so they don't show as separate search pills
4842          page.terms.filters = page.terms.filters.filter(f => f.toLowerCase() !== searchQuery.toLowerCase());
4843        }
4844        
4845        // Expand remaining search terms (without brand names) with synonyms
4846        if (brandResult.cleanedQuery && brandResult.cleanedQuery.trim().length > 0) {
4847          const cleanedQuery = brandResult.cleanedQuery.trim();
4848          const words = cleanedQuery.split(/\s+/);
4849
4850          // Build search variations with synonym expansion for better matching
4851          // Example: "shirts" -> ["shirts", "shirt", "top", "tops", "tee", "tees"]
4852          const synonymExpandedVariations = expandSearchTermsWithSynonyms(words);
4853
4854          // Start with quoted phrases (highest priority - kept as complete phrases)
4855          let searchVariations = [];
4856          if (quotedPhrasesFromSearch && quotedPhrasesFromSearch.length > 0) {
4857            quotedPhrasesFromSearch.forEach(phrase => {
4858              if (phrase && phrase.trim().length > 0) {
4859                searchVariations.push(phrase.trim().toLowerCase());
4860              }
4861            });
4862          }
4863          
4864          // Then add synonym-expanded variations from remaining text
4865          searchVariations.push(...synonymExpandedVariations);
4866
4867          products.filter.searchVariations = searchVariations;
4868          
4869          console.log('Final search variations:', { quotedPhrases: quotedPhrasesFromSearch, synonymExpanded: synonymExpandedVariations, combined: searchVariations });
4870          
4871          // Update page.terms.filters with only the cleaned terms (without brand names)
4872          page.terms.filters = page.terms.filters.filter(f => f.toLowerCase() !== searchQuery.toLowerCase());
4873          if (!page.terms.filters.includes(cleanedQuery)) {
4874            page.terms.filters.push(cleanedQuery);
4875          }
4876        } else if (quotedPhrasesFromSearch && quotedPhrasesFromSearch.length > 0) {
4877          // If we only have quoted phrases (no other search terms), use them directly
4878          products.filter.searchVariations = quotedPhrasesFromSearch.map(p => p.trim().toLowerCase());
4879          console.log('Search variations (quoted only):', products.filter.searchVariations);
4880        } else {
4881          delete products.filter.searchVariations;
4882        }
4883      } else if (hasOnlyQuotedPhrases) {
4884        // Fully quoted search - use ONLY the quoted phrases, no brand/synonym expansion
4885        products.filter.searchVariations = quotedPhrasesFromSearch.map(p => p.trim().toLowerCase());
4886        console.log('Fully quoted search - exact phrases only:', products.filter.searchVariations);
4887      } else {
4888        delete products.filter.searchVariations;
4889      }
4890      
4891      delete products.filter.search;
4891 // Remove old search field
4892
4893      $(".pill").off("click", page.removeSearch);
4894      $(".pill").on("click", page.removeSearch);
4895
4896      if ($("#PillBox").html().length>0 || products.filter.sizes.length>0 || products.filter.widths.length>0 || products.filter.prices.length>0) {
4897        if (!page.filtersClosed) {
4898          $("#ClearFilterButton").show();
4899          $("#PillBoxArea").show();
4900        }
4901      } else {
4902        $("#ClearFilterButton").hide();
4903        $("#PillBoxArea").hide();
4904      }
4905      context.set("storeTerms", page.terms);
4906      try {
4907        // Facebook Pixel tracking - use searchVariations if available, otherwise empty
4908        const searchString = products.filter.searchVariations ? products.filter.searchVariations.join(' ') : '';
4909        if (searchString.length>0) fbq('track', 'Search', {search_string: searchString}); 
4910      } catch (e) {}
4911      if (!page.isInitial) {
4912        // Only add loading state when we're actually going to make an API call
4913        $("#FiltersList").addClass("filter-loading");
4914        $("#MobileFilterContent").addClass("filter-loading");
4915        
4916        // Show loading state on mobile "View X Products" button
4917        const $applyButton = $("#ApplyMobileFilters");
4918        if ($applyButton.length) {
4919          $applyButton.addClass('loading').html('Filtering...');
4920        }
4921        
4922        if (page.terms.page != null) products.filter.page = page.terms.page;
4923        
4924        // Gender extraction is already handled during synonym expansion
4925        // searchVariations are individual terms, not phrases with gender keywords
4926        
4927        // Debug: Log search parameters before API call
4928        console.log('Products filter before API call:', {
4929          brands: products.filter.brands,
4930          searchVariations: products.filter.searchVariations,
4931          fullFilter: products.filter
4932        });
4933        
4934        // When color filters are active, request ALL products for client-side filtering
4935        if (page.selectedColorFilters && page.selectedColorFilters.length > 0) {
4936          products.filter.size = 10000; // Request all products
4937        }
4938        
4939		    service.call("products-search", products.filter, function(response) {
4940          page.productsLoaded(response);
4941          page.isSearching = false; // Reset flag after search completes
4942        });
4943      } else {
4944        page.isInitial = false;
4945        page.isSearching = false; // Reset flag
4946      }
4947    },
4948    updateHash: function() {
4949      const url = new URL(window.location);
4950      url.searchParams.set('c', '1');
4951      window.history.pushState({}, '', url);
4952    },
4953    clear: function () {
4954      page.updateHash();
4955      $("#PillBox").html("");
4956      $(".searchItem").removeClass("selected");
4957      $("#BrandCheckboxList input[type='checkbox']").prop("checked", false);
4958      $("#MobileFilterContent #BrandCheckboxList input[type='checkbox']").prop("checked", false);
4959      $(".category-link").removeClass("selected");
4960      $("#PriceCheckboxList input[type='checkbox']").prop("checked", false);
4961      $("#ShipToMe, #PickupInStore, #OnSale").prop("checked", false);
4962      products.filter.sizes = [];
4963      products.filter.widths = [];
4964      products.filter.prices = [];
4965      products.filter.brands = [];
4966      products.filter.instore = null;
4967      products.filter.onsale = null;
4968      products.filter.shipable = null;
4969      page.forceCategoryId = -1;
4970      // Reset BOTH old and new brand structures to ensure clean state
4971      page.terms = {
4972        brand: { label: "", id: -1 },
4973        brands: [],
4974        collections: [],
4975        categories: { label: "", id: -1 },
4976        filter: "",
4977        filters: [],
4978        sizes: [],
4979        widths: [],
4980        prices: [],
4981        colors: [],
4982        genders: [],
4983        instore: 0,
4984        shipable: 0
4985      };
4986      context.set("storeTerms", page.terms);
4987      window.location = "/shop";
4988      // page.pillsChanged();
4989    },
4990    removeSearch: function (e) {
4991      // page.updateHash();
4992      var id = $(e.currentTarget).data("id");
4993      var type = $(e.currentTarget).data("type");
4994      if (type == "brand") {
4995        // Remove the specific brand from the array
4996        const brandIdToRemove = parseInt(id);
4997        page.terms.brands = page.terms.brands.filter(b => b.id !== brandIdToRemove);
4998        products.filter.brands = page.terms.brands.map(b => b.id);
4999        // Also reset the old singular brand object if this was the only brand
5000        if (page.terms.brands.length === 0) {
5001          page.terms.brand = { label: "", id: -1 };
5002        }
5003        // Uncheck the specific brand checkbox in both desktop and mobile
5004        $("#FiltersList #BrandCheckboxList input[type='checkbox'][value='" + id + "']").prop("checked", false);
5005        $("#MobileFilterContent #BrandCheckboxList input[type='checkbox'][value='" + id + "']").prop("checked", false);
5006      } else if (type == "collection") {
5007        // Remove the specific collection from the array
5008        const collectionIdToRemove = parseInt(id);
5009        page.terms.collections = page.terms.collections.filter(c => c.id !== collectionIdToRemove);
5010        products.filter.collections = page.terms.collections.map(c => c.id);
5011        // Uncheck the specific collection checkbox in both desktop and mobile
5012        $("#FiltersList #CollectionCheckboxList input[type='checkbox'][value='" + id + "']").prop("checked", false);
5013        $("#MobileFilterContent #CollectionCheckboxList input[type='checkbox'][value='" + id + "']").prop("checked", false);
5014      } else if (type == "category") {
5015        page.terms.categories = { label: "", id: -1 };
5016        // Remove selected class from category links
5017        $(".category-link").removeClass("selected"); 
5018      } else if (type == "size") {
5019        var index = page.terms.sizes.indexOf(id.toString());
5020        if (index !== -1) {
5021          page.terms.sizes.splice(index, 1);
5022        }
5023        products.filter.sizes = page.terms.sizes;
5024        // Uncheck the size checkbox in both desktop and mobile
5025        $("#FiltersList #SizeCheckboxList input[value='" + id + "']").prop("checked", false);
5026        $("#MobileFilterContent #SizeCheckboxList input[value='" + id + "']").prop("checked", false);
5027      } else if (type == "width") {
5028        var index = page.terms.widths.indexOf(id.toString());
5029        if (index !== -1) {
5030          page.terms.widths.splice(index, 1);
5031        }
5032        products.filter.widths = page.terms.widths;
5033        // Uncheck the width checkbox in both desktop and mobile
5034        $("#FiltersList #WidthCheckboxList input[value='" + id + "']").prop("checked", false);
5035        $("#MobileFilterContent #WidthCheckboxList input[value='" + id + "']").prop("checked", false);
5036      } else if (type == "price") {
5037        var index = page.terms.prices.indexOf(id.toString());
5038        if (index !== -1) {
5039          page.terms.prices.splice(index, 1);
5040        }
5041        products.filter.prices = page.terms.prices;
5042        // Uncheck the price checkbox in both desktop and mobile
5043        $("#FiltersList #PriceCheckboxList input[value='" + id + "']").prop("checked", false);
5044        $("#MobileFilterContent #PriceCheckboxList input[value='" + id + "']").prop("checked", false);
5045      } else if (type == "gender") {
5046        var index = page.terms.genders.indexOf(id.toString());
5047        if (index !== -1) {
5048          page.terms.genders.splice(index, 1);
5049        }
5050        products.filter.genders = page.terms.genders;
5051        // Uncheck the gender checkbox in both desktop and mobile
5052        $("#FiltersList #GenderCheckboxList input[value='" + id + "']").prop("checked", false);
5053        $("#MobileFilterContent #GenderArea input[value='" + id + "']").prop("checked", false);
5054      } else if (type == "option") {
5055        // Uncheck the option checkbox
5056        if (id === "shipable") {
5057          $("#ShipToMe").prop("checked", false);
5058        } else if (id === "instore") {
5059          $("#PickupInStore").prop("checked", false);
5060        } else if (id === "onsale") {
5061          $("#OnSale").prop("checked", false);
5062        }
5063      } else {
5064        var index = page.terms.filters.indexOf(id.toString());
5065        if (index !== -1) page.terms.filters.splice(index, 1);
5066        
5067        // Check if this is a color filter and uncheck the color checkbox
5068        const colorNames = ['black', 'blue', 'green', 'brown', 'white', 'gray', 'red', 'purple', 'pink', 'orange', 'beige', 'yellow'];
5069        if (colorNames.includes(id.toLowerCase())) {
5070          // Find the color with this name (case-insensitive) and uncheck it
5071          $("#FiltersList #ColorCheckboxList input[type='checkbox']").each(function() {
5072            if ($(this).val().toLowerCase() === id.toLowerCase()) {
5073              $(this).prop("checked", false);
5074            }
5075          });
5076          $("#MobileFilterContent #ColorCheckboxList input[type='checkbox']").each(function() {
5077            if ($(this).val().toLowerCase() === id.toLowerCase()) {
5078              $(this).prop("checked", false);
5079            }
5080          });
5081        }
5082      }
5083      
5084      // Regenerate all pills from page.terms (this removes the clicked pill and keeps everything in sync)
5085      page.pills();
5086      
5087      // Check if all filters have been cleared - if so, redirect to clear URL
5088      const hasAnyFilters = 
5089        (page.terms.brands && page.terms.brands.length > 0) ||
5090        (page.terms.collections && page.terms.collections.length > 0) ||
5091        (page.terms.categories && page.terms.categories.id !== -1) ||
5092        (page.terms.sizes && page.terms.sizes.length > 0) ||
5093        (page.terms.widths && page.terms.widths.length > 0) ||
5094        (page.terms.prices && page.terms.prices.length > 0) ||
5095        (page.terms.genders && page.terms.genders.length > 0) ||
5096        (page.terms.filters && page.terms.filters.length > 0) ||
5097        products.filter.instore ||
5098        products.filter.onsale ||
5099        products.filter.shipable;
5100      
5101      if (!hasAnyFilters) {
5102        // All filters cleared - redirect to clean shop page
5103        window.location = "/shop?c=1";
5104        return;
5105      }
5106      
5107      // Reload products with updated filters
5108      page.pillsChanged();
5109    },
5110    updateFilterBadge: function() {
5111      let count = 0;
5112      
5113      // Count brands
5114      if (page.terms.brands && page.terms.brands.length > 0) {
5115        count += page.terms.brands.length;
5116      }
5117      
5118      // Count category
5119      if (page.terms.categories && page.terms.categories.id != -1) {
5120        count += 1;
5121      }
5122      
5123      // Count sizes
5124      if (page.terms.sizes && page.terms.sizes.length > 0) {
5125        count += page.terms.sizes.length;
5126      }
5127      
5128      // Count widths
5129      if (page.terms.widths && page.terms.widths.length > 0) {
5130        count += page.terms.widths.length;
5131      }
5132      
5133      // Count prices
5134      if (page.terms.prices && page.terms.prices.length > 0) {
5135        count += page.terms.prices.length;
5136      }
5137      
5138      // Count options
5139      if ($("input[data-filter='ship-to-me']").first().is(":checked")) {
5140        count += 1;
5141      }
5142      if ($("input[data-filter='pickup-in-store']").first().is(":checked")) {
5143        count += 1;
5144      }
5145      if ($("input[data-filter='on-sale']").first().is(":checked")) {
5146        count += 1;
5147      }
5148      
5149      // Count additional filters (excluding brands and categories already counted)
5150      if (page.terms.filters && page.terms.filters.length > 0) {
5151        const oldBrandLabel = (page.terms.brand && page.terms.brand.label) ? page.terms.brand.label.toLowerCase() : '';
5152        const categoryLabel = (page.terms.categories && page.terms.categories.label) ? page.terms.categories.label.toLowerCase() : '';
5153        for (var i = 0; i < page.terms.filters.length; i++) {
5154          const term = page.terms.filters[i];
5155          if (term.toLowerCase()!=oldBrandLabel && term.toLowerCase()!=categoryLabel) {
5156            count += 1;
5157          }
5158        }
5159      }
5160      
5161      // Update badge
5162      const badge = $("#FilterBadge");
5163      if (count > 0) {
5164        badge.text(count).show();
5165      } else {
5166        badge.hide();
5167      }
5168    },
5169    pills: function () {
5170      products.filter.page = 1;
5171      products.filter.size = 36;
5172      var html = "";
5173      // Show all brand pills
5174      if (page.terms.brands && page.terms.brands.length > 0) {
5175        for (let i = 0; i < page.terms.brands.length; i++) {
5176          html += '<div class="btn btn-sm pill" data-id="' + page.terms.brands[i].id + '" data-type="brand"><i class="fa fa-close"></i> ' + page.terms.brands[i].label + '</div>';
5177        }
5178      }
5179      // Show all collection pills
5180      if (page.terms.collections && page.terms.collections.length > 0) {
5181        for (let i = 0; i < page.terms.collections.length; i++) {
5182          html += '<div class="btn btn-sm pill" data-id="' + page.terms.collections[i].id + '" data-type="collection"><i class="fa fa-close"></i> ' + page.terms.collections[i].label + '</div>';
5183        }
5184      }
5185      if (page.terms.categories && page.terms.categories.id != -1) {
5186        html += '<div class="btn btn-sm pill" data-id="' + page.terms.categories.id + '" data-type="category"><i class="fa fa-close"></i> ' + page.terms.categories.label + '</div>';
5187        $(".subCat"+page.terms.categories.id).show();
5188      }
5189      if (page.terms.sizes && page.terms.sizes.length > 0) {
5190        for (var i = 0; i < page.terms.sizes.length; i++) {
5191          var size = page.terms.sizes[i];
5192          html += '<div class="btn btn-sm pill" data-id="' + size + '" data-type="size"><i class="fa fa-close"></i> ' + size + '</div>';
5193        }
5194      }
5195      if (page.terms.widths && page.terms.widths.length > 0) {
5196        for (var i = 0; i < page.terms.widths.length; i++) {
5197          var width = page.terms.widths[i];
5198          html += '<div class="btn btn-sm pill" data-id="' + width + '" data-type="width"><i class="fa fa-close"></i> ' + width + '</div>';
5199        }
5200      }
5201      if (page.terms.prices && page.terms.prices.length > 0) {
5202        for (var i = 0; i < page.terms.prices.length; i++) {
5203          var price = page.terms.prices[i];
5204          var displayPrice = price.includes('-') ? '$' + price.replace('-', '-$') : '$' + price;
5205          html += '<div class="btn btn-sm pill" data-id="' + price + '" data-type="price"><i class="fa fa-close"></i> ' + displayPrice + '</div>';
5206        }
5207      }
5208      if (page.terms.genders && page.terms.genders.length > 0) {
5209        const genderLabels = { 'M': 'Mens', 'W': 'Womens', 'U': 'Unisex', 'K': 'Kids' };
5210        for (var i = 0; i < page.terms.genders.length; i++) {
5211          var gender = page.terms.genders[i];
5212          var displayGender = genderLabels[gender] || gender;
5213          html += '<div class="btn btn-sm pill" data-id="' + gender + '" data-type="gender"><i class="fa fa-close"></i> ' + displayGender + '</div>';
5214        }
5215      }
5216      // Show pills for options
5217      if ($("input[data-filter='ship-to-me']").first().is(":checked")) {
5218        html += '<div class="btn btn-sm pill" data-id="shipable" data-type="option"><i class="fa fa-close"></i> Ship To Me</div>';
5219      }
5220      if ($("input[data-filter='pickup-in-store']").first().is(":checked")) {
5221        html += '<div class="btn btn-sm pill" data-id="instore" data-type="option"><i class="fa fa-close"></i> Pickup In-Store</div>';
5222      }
5223      if ($("input[data-filter='on-sale']").first().is(":checked")) {
5224        html += '<div class="btn btn-sm pill" data-id="onsale" data-type="option"><i class="fa fa-close"></i> On Sale</div>';
5225      }
5226      if (page.terms.filters && page.terms.filters.length > 0) {
5227        for (var i = 0; i < page.terms.filters.length; i++) {
5228          var term = page.terms.filters[i];
5229          const oldBrandLabel = (page.terms.brand && page.terms.brand.label) ? page.terms.brand.label.toLowerCase() : '';
5230          const categoryLabel = (page.terms.categories && page.terms.categories.label) ? page.terms.categories.label.toLowerCase() : '';
5231          if (term.toLowerCase()!=oldBrandLabel && term.toLowerCase()!=categoryLabel) {
5232            // Check if this filter came from a quoted search
5233            const isQuoted = page.terms.quotedFilters && page.terms.quotedFilters.includes(term);
5234            const quotedAttr = isQuoted ? ' data-quoted="true"' : '';
5235            html += '<div class="btn btn-sm pill" data-id="' + page.terms.filters[i].split('"').join('') + '" data-type="filter"' + quotedAttr + '><i class="fa fa-close"></i> ' + term + '</div>';
5236          }
5237        }
5238      }
5239      $("#PillBox").html(html);
5240      $("#MobilePillBox").html(html);
5241      
5242      // Re-attach click handlers to pills after updating HTML (both desktop and mobile)
5243      $("#PillBox .pill").off("click", page.removeSearch);
5244      $("#PillBox .pill").on("click", page.removeSearch);
5245      $("#MobilePillBox .pill").off("click", page.removeSearch);
5246      $("#MobilePillBox .pill").on("click", page.removeSearch);
5247      
5248      // Show/hide mobile pill box area based on whether there are pills
5249      if (html && html.trim().length > 0) {
5250        $("#MobilePillBoxArea").show();
5251      } else {
5252        $("#MobilePillBoxArea").hide();
5253      }
5254      
5255      page.updateFilterBadge();
5256      page.pillsChanged();
5257    },
5258    addSearch: function (label, id, from, doSearch = true) {
5259      page.lastSearch = label;
5260      if (from == "filter") {
5261        if (typeof products.searchView === 'function') {
5262          products.searchView(label);
5263        }
5264        if (!page.findBrand(label)) {
5265          page.findCategory(label);
5266        }
5267      } else if (from == "brand") {
5268        page.terms.brand = {
5269          label: label,
5270          id: id
5271        }
5272        // Only navigate to brand page if we're on a forced brand page and switching to a SINGLE different brand
5273        // Don't navigate if we're in multi-brand mode (already have brands selected via checkboxes)
5274        const hasMultipleBrands = page.terms.brands && page.terms.brands.length > 0;
5275        if (!hasMultipleBrands && page.forceBrandId !=null && page.forceBrandId!=-1 && id!=page.forceBrandId) {
5276          doSearch = false;
5277          var url = label.trim().toLowerCase().replace(/\W/g, '-');     
5278          while (url.indexOf("--")>=0) url = url.split('--').join('-'); 
5279          window.location = "/brand/"+id+"/"+url;
5280        }
5281      } else if (from == "category") {
5282        page.terms.categories = {
5283          label: label,
5284          id: id
5285        }
5286        // Only navigate to category page if we're switching to a SINGLE different category
5287        // Don't navigate if we're in multi-filter mode
5288        const hasMultipleCategories = page.terms.categories && page.terms.categories.length > 0;
5289        if (!hasMultipleCategories && page.forceCategoryId!=null && page.forceCategoryId!=-1 && id!=page.forceCategoryId) {
5290          doSearch = false;
5291          var url = label.trim().toLowerCase().replace(/\W/g, '-');     
5292          while (url.indexOf("--")>=0) url = url.split('--').join('-'); 
5293          window.location = "/category/"+id+"/"+url;
5294        }
5295      } else if (from == "size") {
5296        // Size is already added to page.terms.sizes array in the checkbox handler
5297        // Just trigger the pills refresh
5298      } else if (from == "width") {
5299        // Width is already added to page.terms.widths array in the checkbox handler
5300        // Just trigger the pills refresh
5301      } else if (from == "price") {
5302        // Price is already added to page.terms.prices array in the checkbox handler
5303        // Just trigger the pills refresh
5304      } else if (from == "collection") {
5305        // Collection is already added to page.terms.collections array in the checkbox handler
5306        // Just trigger the pills refresh
5307      } else if (from == "gender") {
5308        // Gender is already added to page.terms.genders array in the checkbox handler
5309        // Just trigger the pills refresh
5310      }
5311      if (doSearch) {
5312        console.log("Adding search term from "+from+": "+label);
5313        page.terms.page = 1;
5314        page.pills();
5315      } 
5316    },
5317    findCategory: function(searchFor) {
5318      var found = false;
5319      searchFor = searchFor.trim().toLowerCase();
5320      if (!page.terms.filters) page.terms.filters = [];
5321      if (searchFor.length>0) {
5322        for (var i = 0; i < page.categories.length; i++) {
5323          const category = page.categories[i];
5324          const categoryName = category.name ? category.name.toLowerCase() : '';
5325          const categoryLabel = category.label ? category.label.toLowerCase() : '';
5326          
5327          if (categoryName === searchFor || categoryLabel === searchFor) {
5328            page.terms.categories.label = category.label || category.name;
5329            page.terms.categories.id = category.categoryId;  
5330            found = true;
5331            break; 
5332          }
5333        } 
5334      }
5335      if (!found) {
5336        if (searchFor.length > 0 && !page.IsInArray(searchFor, page.terms.filters)) {
5337          page.terms.filters[page.terms.filters.length] = searchFor;
5338        }
5339      }
5340      return found;
5341    },
5342    IsInArray: function(str, arr) {
5343      str = str.trim().toLowerCase();
5344      for (var i=0; i<arr.length; i++) {
5345        let item = arr[i].trim().toLowerCase();
5346        if (item==str) return true;
5347      }
5348      return false;
5349    },
5350    findBrand: function (searchFor) {
5351      var found = false;
5352      searchFor = searchFor.trim().toLowerCase();
5353      if (!page.terms.filters) page.terms.filters = [];
5354      for (var i = 0; i < page.brands.length; i++) {
5355        if (page.brands[i].name.toLowerCase()==searchFor) {
5356          page.terms.brand = {
5357            label: page.brands[i].name,
5358            id: page.brands[i].brandId
5359          }
5360          found = true;
5361          break;
5362        }
5363      }
5364      return found;
5365    },
5366    sameString: function (s1, s2) {
5367      var samAs = '';
5368      for (var i = 0; i < s1.length; i++) {
5369        if (s2.length > i) {
5370          if (s1[i] == s2[i]) samAs += s1[i];
5371          else return samAs;
5372        }
5373      }
5374      return samAs;
5375    },
5376    productsLoaded: function (e) {
5377      // Remove loading state from filters
5378      $("#FiltersList").removeClass("filter-loading");
5379      $("#MobileFilterContent").removeClass("filter-loading");
5380      
5381      $("#SearchFilterArea").removeClass("disabled");
5382      $("#BrandingImage").hide();
5383      $("#ProductList").html("");
5384      
5385      // Apply client-side color filtering if colors are selected
5386      let filteredData = e.data;
5387      if (page.selectedColorFilters && page.selectedColorFilters.length > 0) {
5388        filteredData = e.data.filter(product => 
5389          page.productMatchesColorFilter(product.color, page.selectedColorFilters)
5390        );
5391        // Update total count to reflect filtered results
5392        e.total = filteredData.length;
5393      }
5394      
5395      page.products = filteredData;
5396			products.data = filteredData;
5397			products.total = e.total;
5398      
5399      // Update both brand and option counts with a single API call
5400      page.updateFilterCounts();
5401      
5402      // Update available sizes based on filtered products
5403      // page.updateAvailableSizes();
5404      
5405      // Update mobile filter pills and product count if panel is open
5406      if ($("#MobileFilterPanel").hasClass('active')) {
5407        page.syncMobilePills();
5408        page.updateMobileProductCount();
5409        
5410        // Ensure all mobile filter sections remain visible after updates
5411        // This fixes the issue where filters collapse after checkbox changes
5412        setTimeout(function() {
5413          // Make sure the main FiltersList container is visible
5414          $('#MobileFilterContent #FiltersList').show();
5415          // Force every accordion section open/visible by both removing closed class AND setting display
5416          $('#MobileFilterContent .filter-container').removeClass('closed').css('display', 'block');
5417          $('#MobileFilterContent .toggleright').removeClass('closed');
5418          $('#MobileFilterContent .filter-content').show().css('display', 'block');
5419          $('#MobileFilterContent #CategoryList').show();
5420          // Keep the user at the top of the list so content is visible
5421          const mobileContent = document.querySelector('.mobile-filter-content');
5422          if (mobileContent) mobileContent.scrollTop = 0;
5423        }, 100);
5424      } 
5425      
5426      // Sync checkbox checked states for all active filters
5427      page.terms?.brands?.forEach(brand => {
5428        if (brand.id) page.syncCheckboxes('brand-filter', brand.id.toString());
5429      }); 
5430      page.terms?.sizes?.forEach(size => {
5431        page.syncCheckboxes('size-filter', size);
5432      });
5433      page.terms?.widths?.forEach(width => {
5434        page.syncCheckboxes('width-filter', width);
5435      });
5436      // Sync gender checkboxes (pills are managed separately by hashChanged and checkbox handlers)
5437      if (page.terms.genders && page.terms.genders.length > 0) {
5438        page.terms.genders.forEach(gender => {
5439          $('#FiltersList #GenderCheckboxList input[value="' + gender + '"]').prop('checked', true);
5440          $('#MobileFilterContent #GenderArea input[value="' + gender + '"]').prop('checked', true);
5441        });
5442      }
5443      //page.products = context.get("products"+products.searchId);
5444      page.category = category.details(products.filter.category);
5445      if (page.category != null) {
5446        let categoryLabel = page.category.name;
5447        if (page.category.label) categoryLabel = page.category.label;
5448        $("#CategoryName").html(categoryLabel);
5449      }
5450      else $("#CategoryName").html("All Categories"); 
5451      if (page.products.length > 0) {
5452        let productIds = [];
5453        // Only use server total if no client-side color filtering is active
5454        if (!page.selectedColorFilters || page.selectedColorFilters.length === 0) {
5455          products.total = page.products[0].totalRows;
5456        }
5457        for (var i = 0; i < page.products.length; i++) {
5458          var element = $("#RowTemplate").clone();
5459          element.removeClass("template");
5460          element.css("display", "inline");
5461          element.attr("id", "Product" + i);
5462
5463          var brandLabel = page.products[i].brandName;
5464          if (page.products[i].label&&page.products[i].label.length>0) brandLabel = page.products[i].label;
5465          
5466          var url = "/product/" + page.products[i].productId + "/" + page.products[i].name.trim().toLowerCase().replace(/\W/g, '-');
5467          url = "/product/" + page.products[i].productId + "/" + brandLabel.trim().toLowerCase().replace(/\W/g, '-') + "/" + page.products[i].name.trim().toLowerCase().split('\'').join('').replace(/\W/g, '-');
5468
5469          element.attr("data-url", url);
5470          
5471          // Update wishlist button productId before string replacements
5472          element.find('.wishlist-toggle').attr('data-product-id', page.products[i].productId);
5473          
5474          // Update image, name, brand, etc using direct DOM manipulation where possible
5475          element.find('.image').css('background-image', 'url("' + products.getSize(380, page.products[i].url) + '")');
5476          element.find('.name').text(page.products[i].name);
5477          element.find('.brand').text(brandLabel);
5478          element.find('a[rel="cononical"]').attr('href', url).attr('aria-label', page.products[i].name);
5479          
5480          // Update color swatches data attributes
5481          element.find('.colorswatches')
5482            .attr('data-product-id', page.products[i].productId)
5483            .attr('data-product-name', page.products[i].name)
5484            .attr('data-site-id', site.id)
5485            .attr('data-total-colors', page.products[i].totalColors || 1);
5486          
5487
5488          if (page.products[i].markdown!=null && page.products[i].markdown>0 && page.products[i].isAuto) {
5489            page.products[i].realcost = page.products[i].cost;
5490            page.products[i].cost = page.products[i].markdown;
5491          }
5492          var onsale = "";
5493          var retail = page.products[i].retail;
5494          if (retail > page.products[i].cost) {
5495            var htmlString = '<span class="struck">$' + retail.toFixed(2) + '</span> $' + page.products[i].cost.toFixed(2);
5496            element.find('.price').html(htmlString);
5497            if (page.products[i].isOnSale || isAutoSale) onsale = " show";
5498          } else {
5499            element.find('.price').text("$" + page.products[i].cost.toFixed(2));
5500            if (page.products[i].isOnSale) onsale = " show";
5501          }
5502          element.find('.salelabel').addClass(onsale.trim());
5503          var releaseLabel = productRelease.getAvailabilityLabel(page.products[i].dateReleased);
5504          element.find('.releaselabel').text(releaseLabel).toggleClass('show', releaseLabel.length > 0);
5505          $("#ProductList").append(element);
5506          productIds.push(page.products[i].sku);
5507        }
5508
5509        try {
5510          var gTagListItems = [];
5511          var listName = (page.category && (page.category.label || page.category.name)) || "Shop";
5512          var listId = (page.category && page.category.categoryId) ? String(page.category.categoryId) : "shop";
5513          for (var j = 0; j < page.products.length; j++) {
5514            if (!page.products[j]) continue;
5515            gTagListItems.push({
5516              "id": page.products[j].productId,
5517              "name": page.products[j].name,
5518              "list_name": listName,
5519              "brand": page.products[j].brandName,
5520              "category": page.products[j].categories && page.products[j].categories[0] ? page.products[j].categories[0].name : 'All Categories',
5521              "variant": page.products[j].color,
5522              "list_position": j,
5523              "price": page.products[j].cost
5524            });
5525          }
5526          if (gTagListItems.length > 0) {
5527            trackEvent('view_item_list', {
5528              "item_list_id": listId,
5529              "item_list_name": listName,
5530              "items": gTagListItems
5531            });
5532          }
5533        } catch (e) {}
5534
5535        // Update wishlist button states for all products
5536        page.updateWishlistButtons();
5537        
5538        $("#PagingTotals").show(); 
5539        $("#PagingTotalsNone").hide();
5540        page.pageLoaded();
5541        if (!isNaN(products.filter.brand) && Number(products.filter.brand) > 0) {
5542          var brandData = brand.details(products.filter.brand);
5543          if (brandData.image && brandData.image.indexOf("NoImage.svg") == -1) {
5544            $("#BrandImage").prop("src", brandData.image);
5545            $("#BrandingImage").show();
5546          }
5547        } else if (brandImage && brandImage.trim() != '' && brandImage.indexOf("NoImage.svg") == -1) {
5548          $("#BrandImage").prop("src", brandImage);
5549          $("#BrandingImage").show();
5550        }
5551        if (page.lastSearch && typeof page.lastSearch === 'string' && page.lastSearch.trim().length>0) {
5552          if (window.blueshift!=null) {
5553            blueshift.track("search", {
5554              keywords: page.lastSearch, 
5555              product_ids: productIds
5556            });
5557          }
5558        }
5559      } else {
5560        $("#PagingArea").hide();
5561        $("#PagingTotals").hide();
5562        $("#PagingTotalsNone").show();
5563        
5564        $("#ProductList").html(
5565          "<style>#ProductList.grid.responsive-product-grid {grid-template-columns: 100%;} </style><div class='hidemobile'></div><div style='text-align: center; color: #d2d8e5; font-size: 16px; font-weight: 600;'><div class='sadsearch'></div><span style='font-size: 32px;'>Hmmm... <br><span style='font-size: 26px;'>We didn't find any matches</span></span><br>
5565Modify your search filters and try again</div><div class='hidemobile'></div>"
5566        );
5567        
5568        // Update mobile filter button to show "No Results" when there are no products
5569        const $applyButton = $("#ApplyMobileFilters");
5570        if ($applyButton.length && $applyButton.hasClass('loading')) {
5571          $applyButton.removeClass('loading').html('No Results');
5572        }
5573      } 
5574
5575      const pageTotal = typeof products.pageTotal === 'function' ? products.pageTotal() : Math.ceil(products.total / products.filter.size);
5576      if (pageTotal > 1) {
5577        $(".pages").html("");
5578        $("#PagingArea").show();
5579        const isFirst = typeof products.isFirst === 'function' ? products.isFirst() : (products.filter.page === 1);
5580        const isLast = typeof products.isLast === 'function' ? products.isLast() : (products.filter.page === pageTotal);
5581        if (!isFirst)
5582          $(".pages").append('<div class="page" data-page="' + (products.filter.page - 1) + '">&lt;</div>');
5583        var startIndex = 1;
5584        if (products.filter.page > 5) startIndex = products.filter.page - 5;
5585        var total = startIndex + 10;
5586        for (var i = startIndex; i <= total && i <= pageTotal; i++) {
5587          $(".pages").append('<div class="page' + (products.filter.page == i ? " current" : "") + '" data-page="' + i + '">' + i + "</div>");
5588        }
5589        if (!isLast) $(".pages").append('<div class="page" data-page="' + (products.filter.page + 1) + '">&gt;</div>');
5590        $(".page").click(page.page);
5591        $(".paging").show();
5592        $(".pageCount").show();
5593      } else {
5594        $("#PagingArea").hide();
5595        $(".paging").hide();
5596        $(".pageCount").hide();
5597      }
5598      
5599      // Remove initializing state after filtered products are loaded
5600      $('#ProductList').removeClass('initializing');
5601      $('#InitialLoader').remove();
5602      $('.search-page-container').removeClass('initializing');
5603    },
5604    pageLoaded: function () {
5605      // Attach click handler to .clickable for navigation
5606      // The goto function checks for wishlist button and swatch clicks
5607      $(".clickable").click(page.goto);
5608      
5609      // Attach wishlist toggle handlers directly (must be after .clickable to fire first)
5610      $('.wishlist-toggle').off('click').on('click', page.toggleWishlist);
5611      
5612      $("#SearchTotal").html(products.total);
5613      $("#SearchCurrentPage").html(products.filter.page);
5614      $("#SearchShowing").html(((products.filter.page - 1) * products.filter.size) + 1);
5615      const pageTotal = typeof products.pageTotal === 'function' ? products.pageTotal() : Math.ceil(products.total / products.filter.size);
5616      $("#SearchTotalPages").html(pageTotal);
5617      $("#SearchTo").html(((products.filter.page - 1) * products.filter.size) + products.data.length);
5618      
5619      // Restore mobile "View X Products" button (after #SearchTotal is updated!)
5620      const $applyButton = $("#ApplyMobileFilters");
5621      if ($applyButton.length && $applyButton.hasClass('loading')) {
5622        $applyButton.removeClass('loading');
5623        // Read the fresh product count that was just set
5624        const count = parseInt(products.total, 10) || 0;
5625        if (count === 0) {
5626          $applyButton.html('No Results');
5627        } else {
5628          $applyButton.html('View <span id="MobileFilterCount">' + count + '</span> Products');
5629        }
5630      }
5631      
5632      // Update mobile filter count
5633      page.updateMobileProductCount();
5634      
5635      // Apply stagger animation to dynamically loaded products
5636      document.querySelectorAll('.product').forEach((el, i) => el.style.setProperty('--i', i + 1));
5637      // Load color swatches for products with multiple colors
5638      colorSwatches.init('#ProductList');
5639      colorSwatches.load();
5640      
5641      // Re-render swatches after layout is complete to get accurate container widths
5642      setTimeout(function() {
5643        colorSwatches.load(true); // Force refresh with correct widths
5644      }, 300);
5645    },
5646    updateWishlistButtons: function() {
5647      // Update wishlist button states for all visible products
5648      if (!wishlist || !wishlist.isLoaded) {
5649        return;
5650      }
5651      
5652      $('#ProductList .wishlist-toggle').each(function() {
5653        const $button = $(this);
5654        const productId = parseInt($button.attr('data-product-id'));
5655        
5656        if (wishlist.has(productId)) {
5657          $button.removeClass('inactive').addClass('active');
5658          $button.attr('aria-label', 'Remove from wishlist');
5659        } else {
5660          $button.removeClass('active').addClass('inactive');
5661          $button.attr('aria-label', 'Add to wishlist');
5662        }
5663      });
5664    },
5665    toggleWishlist: function(e) {
5666      e.stopPropagation();
5667      e.stopImmediatePropagation();
5668      e.preventDefault();
5669      
5670      // Check if user is logged in
5671      if (!user || !user.data || !user.data.memberId) {
5672        modal.show('WishlistLoginModal');
5673        return;
5674      }
5675      
5676      const $button = $(e.currentTarget);
5677      const productId = parseInt($button.attr('data-product-id'));
5678      
5679      // Remove focus to hide tooltip immediately
5680      $button.blur();
5681      
5682      // Handle deactivate animation
5683      if ($button.hasClass("deactivate")) {
5684        $button.removeClass("deactivate");
5685      }
5686      if ($button.hasClass("active")) {
5687        $button.addClass("deactivate");
5688      }
5689      
5690      wishlist.toggle(productId, function(response) {
5691        if (response.error) {
5692          growler.error("Failed to update wishlist");
5693        } else {
5694          if (response.isAdded) {
5695            $button.removeClass("inactive deactivate").addClass("active");
5696            $button.attr("aria-label", "Remove from wishlist");
5697            growler.success("Added to wishlist");
5698          } else {
5699            // Deactivate animation will run, then switch to inactive
5700            setTimeout(function() {
5701              $button.removeClass("active deactivate").addClass("inactive");
5702              $button.attr("aria-label", "Add to wishlist");
5703            }, 800);
5704            growler.success("Removed from wishlist");
5705          }
5706        }
5707      });
5708},
5709    page: function (e) {
5710      $("#ProductList").html($("#CardLoader").html());
5711      var pageTo = $(e.currentTarget).data("page");
5712      if (!$(e.currentTarget).hasClass("current")) {
5713        page.terms.page = pageTo;
5714        context.set("storeTerms", page.terms);
5715        products.filter.page = pageTo;
5716		    service.call("products-search", products.filter, page.productsLoaded);
5717        $("html, body").animate({ scrollTop: "296px" });
5718      }
5719    },
5720    goto: function (e) {
5721      // Don't navigate if the click was on the wishlist button or color swatch
5722      // Check both e.target and any parent elements
5723      const $target = $(e.target);
5724      if ($target.closest('.wishlist-toggle, .colorswatch').length > 0 || 
5725          $target.hasClass('wishlist-toggle') ||
5726          $target.parents('.wishlist-toggle').length > 0) {
5727        e.stopPropagation();
5728        e.preventDefault();
5729        return false;
5730      }
5731      window.location = $(e.currentTarget).data("url");
5732    },
5733    getChildren: function(parentId) {
5734      return page.categories.filter(cat => cat.parentId === parentId);
5735    },
5736    toggleCategoryChildren: function(e) {
5737      e.stopPropagation();
5738      const categoryId = $(e.currentTarget).data('parent-id');
5739      const $icon = $(e.currentTarget);
5740      // Find the child container within the same parent context (mobile or desktop)
5741      const $childContainer = $icon.closest('.category-item').find('#category-children-' + categoryId);
5742      
5743      if ($icon.hasClass('fa-minus')) {
5744        // Currently expanded, so collapse
5745        $childContainer.slideUp(200);
5746        $icon.removeClass('fa-minus').addClass('fa-plus');
5747      } else {
5748        // Currently collapsed, so expand
5749        $childContainer.slideDown(200);
5750        $icon.removeClass('fa-plus').addClass('fa-minus');
5751      }
5752    },
5753    categoriesLoaded: function (e) {
5754      page.categories = e;
5755      
5756      // Sort categories alphabetically by label (or name if no label)
5757      page.categories.sort((a, b) => {
5758        const nameA = (a.label && a.label.trim().length > 0 ? a.label : a.name).toLowerCase();
5759        const nameB = (b.label && b.label.trim().length > 0 ? b.label : b.name).toLowerCase();
5760        return nameA.localeCompare(nameB);
5761      });
5762      
5763      // Filter out categories with 0 count and hidden categories
5764      page.categories = page.categories.filter(cat => (cat.total || 0) > 0 && !cat.isHidden && !cat.hidden);
5765      
5766      // Get parent categories
5767      page.parentCategories = page.categories.filter(cat => cat.parentId === -1);
5768      
5769      // Store all categories with their data
5770      page.allCategories = page.categories.map(cat => ({
5771        categoryId: cat.categoryId,
5772        name: cat.name,
5773        label: cat.label,
5774        parentId: cat.parentId,
5775        productCount: cat.total || 0
5776      }));
5777      
5778      // Handle forced category selection
5779      if (page.categories.length > 0) {
5780        for (var i = 0; i < page.categories.length; i++) {
5781          if (page.forceCategoryId > 0) {
5782            if (page.forceCategoryId == page.categories[i].categoryId) {
5783              page.terms.categories.label = page.categories[i].label;
5784              page.terms.categories.id = page.categories[i].categoryId;
5785            }
5786          } else {
5787            if (page.forceCategory != "" && (page.categories[i].name.toLowerCase() == page.forceCategory.toLowerCase() || page.categories[i].name.split(' ').join('').toLowerCase() == page.forceCategory.split(' ').join(''))) {
5788              page.terms.categories.label = page.categories[i].label;
5789              page.terms.categories.id = page.categories[i].categoryId;
5790              page.forceCategoryId = page.categories[i].categoryId; // Set the ID so filters are applied
5791            }
5792          }
5793        }
5794      }
5795      
5796      // Render category checkboxes
5797      page.renderCategoryCheckboxes();
5798      
5799      // Setup show more functionality
5800      $("#CategoryShowMore a").off("click").on("click", function(e) {
5801        e.preventDefault();
5802        page.showAllCategories();
5803      });
5804      
5805      // Setup category search functionality
5806      $("#CategorySearchInput").off("input").on("input", function() {
5807        page.filterCategoryLinks($(this).val());
5808      });
5809      
5810      page.category = category.details(products.filter.category);
5811      if (page.category != null) $("#CategoryName").html(page.category.name);
5812      else $("#CategoryName").html("All Categories");
5813      
5814      if (page.doAfterCatLoad) {
5815        page.urlParamsChanged();
5816        // After processing URL params with loaded categories, render pills if needed
5817        if (!(page.forceCategory != "" || page.forceCategoryId > 0)) {
5818          page.pills();
5819        }
5820      }
5821      
5822      if (page.forceCategory != "" || page.forceCategoryId > 0) {
5823        // Reset search state since we now have the category ID resolved
5824        // This ensures the API call includes the category filter
5825        page.isSearching = false;
5826        page.pills();
5827      }
5828      
5829      if (page.categories.length > 0) {
5830        $("#CategoryList").show();
5831      } else {
5832        $("#CategoryList").hide();
5833      }
5834    },
5835    renderCategoryCheckboxes: function(showAll, searchTerm, matchingChildIds) {
5836      const parentCategories = page.parentCategories;
5837      const showCount = showAll ? parentCategories.length : 10;
5838      const displayCategories = parentCategories.slice(0, showCount);
5839      const remainingCount = parentCategories.length - showCount;
5840      
5841      // Default to empty if not provided
5842      searchTerm = searchTerm || '';
5843      matchingChildIds = matchingChildIds || new Set();
5844      
5845      let html = '';
5846      for (let i = 0; i < displayCategories.length; i++) {
5847        const cat = displayCategories[i];
5848        const isSelected = page.terms.categories.id === cat.categoryId;
5849        const label = cat.label && cat.label.trim().length > 0 ? cat.label.trim() : cat.name;
5850        const countDisplay = "";//` (${cat.total || 0})`;
5851        const children = page.getChildren(cat.categoryId);
5852        const hasChildren = children.length > 0;
5853        
5854        html += '<div class="category-item">';
5855        
5856        if (hasChildren) {
5857          // Auto-expand if searching (show toggle as minus)
5858          const expandClass = searchTerm ? 'fa-minus' : 'fa-plus';
5859          const expandStyle = searchTerm ? 'display:block;' : 'display:none;';
5860          html += `<i class="fa ${expandClass} category-toggle" data-parent-id="${cat.categoryId}"></i><a href="javascript:void(0);" class="category-link ${isSelected ? 'selected' : ''}" data-category-id="${cat.categoryId}" data-category-name="${label}">${label}</a>`;
5861        } else {
5862          html += `<span class="category-spacer"></span><a href="javascript:void(0);" class="category-link ${isSelected ? 'selected' : ''}" data-category-id="${cat.categoryId}" data-category-name="${label}">${label}</a>`;
5863        }
5864        
5865        if (hasChildren) {
5866          // Filter children to only show matching ones (or all if parent directly matched)
5867          const parentName = (cat.label && cat.label.trim().length > 0 ? cat.label : cat.name).toLowerCase();
5868          const parentDirectlyMatched = searchTerm && parentName.includes(searchTerm.toLowerCase());
5869          
5870          // If parent directly matched, show all children. Otherwise, only show matching children.
5871          const childrenToShow = !searchTerm || parentDirectlyMatched 
5872            ? children 
5873            : children.filter(child => matchingChildIds.has(child.categoryId));
5874          
5875          if (childrenToShow.length > 0) {
5876            // Show children expanded when searching
5877            const childStyle = searchTerm ? 'display:block;' : 'display:none;';
5878            html += `<div id="category-children-${cat.categoryId}" class="category-children" style="${childStyle}">`;
5879            
5880            // Sort children alphabetically
5881            childrenToShow.sort((a, b) => {
5882              const nameA = (a.label && a.label.trim().length > 0 ? a.label : a.name).toLowerCase();
5883              const nameB = (b.label && b.label.trim().length > 0 ? b.label : b.name).toLowerCase();
5884              return nameA.localeCompare(nameB);
5885            });
5886            
5887            for (let j = 0; j < childrenToShow.length; j++) {
5888              const child = childrenToShow[j];
5889              const childLabel = child.label && child.label.trim().length > 0 ? child.label.trim() : child.name;
5890              const childIsSelected = page.terms.categories.id === child.categoryId;
5891              
5892              html += `<div class="category-child-item"><a href="javascript:void(0);" class="category-link ${childIsSelected ? 'selected' : ''}" data-category-id="${child.categoryId}" data-category-name="${childLabel}">${childLabel}</a></div>`;
5893            }
5894            
5895            html += '</div>';
5896          }
5897        }
5898        
5899        html += '</div>';
5900      }
5901      
5902      // Update both desktop and mobile (if mobile panel is open)
5903      $("#FiltersList #CategoryLinkList").html(html);
5904      $("#MobileFilterContent #CategoryLinkList").html(html);
5905      
5906      // Toggle "Show more/less" state (both desktop and mobile)
5907      if (showAll) {
5908        $("#FiltersList #CategoryShowMore a").html('Show less');
5909        $("#MobileFilterContent #CategoryArea #CategoryShowMore a").html('Show Less');
5910        $("#FiltersList #CategoryShowMore").show();
5911        $("#MobileFilterContent #CategoryArea #CategoryShowMore").show();
5912      } else if (remainingCount > 0) {
5913        $("#CategoryShowMoreCount").text(remainingCount);
5914        $("#FiltersList #CategoryShowMore a").html(`Show <span>${remainingCount}</span> more`);
5915        $("#MobileFilterContent #CategoryArea #CategoryShowMoreCount").text(remainingCount);
5916        $("#MobileFilterContent #CategoryArea #CategoryShowMore a").html(`Show <span>${remainingCount}</span> More`);
5917        $("#FiltersList #CategoryShowMore").show();
5918        $("#MobileFilterContent #CategoryArea #CategoryShowMore").show();
5919      } else {
5920        $("#FiltersList #CategoryShowMore").hide();
5921        $("#MobileFilterContent #CategoryArea #CategoryShowMore").hide();
5922      }
5923      
5924      // Re-attach handlers
5925      $(".category-toggle").off("click").on("click", page.toggleCategoryChildren);
5926      $(".category-link").off("click").on("click", function() {
5927        const categoryId = parseInt($(this).data("category-id"));
5928        const categoryName = $(this).data("category-name");
5929        $(".category-link").removeClass("selected");
5930        $(this).addClass("selected");
5931        page.terms.categories.id = categoryId;
5932        page.terms.categories.label = categoryName;
5933        page.addPill(categoryId, categoryName, "category");
5934        products.filter.category = page.terms.categories.id;
5935      });
5936    },
5937    showAllCategories: function() {
5938      // Check both desktop and mobile buttons to determine state
5939      const desktopText = $("#FiltersList #CategoryShowMore a").text().trim();
5940      const mobileText = $("#MobileFilterContent #CategoryShowMore a").text().trim();
5941      const isShowingAll = desktopText === 'Show less' || mobileText === 'Show Less';
5942      page.renderCategoryCheckboxes(!isShowingAll);
5943    },
5944    filterCategoryLinks: function(searchTerm) {
5945      // If search is empty, show all categories normally
5946      if (!searchTerm || searchTerm.trim() === '') {
5947        page.renderCategoryCheckboxes();
5948        return;
5949      }
5950      
5951      const term = searchTerm.toLowerCase().trim();
5952      
5953      // Find matching parent IDs - parents whose name matches OR who have a matching child
5954      const matchingParentIds = new Set();
5955      const matchingChildIds = new Set();
5956      
5957      // Check all categories
5958      page.allCategories.forEach(cat => {
5959        const name = (cat.label && cat.label.trim().length > 0 ? cat.label : cat.name).toLowerCase();
5960        if (name.includes(term)) {
5961          if (cat.parentId === -1) {
5962            // It's a parent - add it
5963            matchingParentIds.add(cat.categoryId);
5964          } else {
5965            // It's a child - add it AND its parent
5966            matchingChildIds.add(cat.categoryId);
5967            matchingParentIds.add(cat.parentId);
5968          }
5969        }
5970      });
5971      
5972      // Also show all children of matching parents (for context)
5973      page.allCategories.forEach(cat => {
5974        if (cat.parentId !== -1 && matchingParentIds.has(cat.parentId)) {
5975          // Check if the PARENT itself matched (not just got added because of a child)
5976          const parent = page.allCategories.find(p => p.categoryId === cat.parentId);
5977          if (parent) {
5978            const parentName = (parent.label && parent.label.trim().length > 0 ? parent.label : parent.name).toLowerCase();
5979            if (parentName.includes(term)) {
5980              // Parent directly matched, show all its children
5981              matchingChildIds.add(cat.categoryId);
5982            }
5983          }
5984        }
5985      });
5986      
5987      // Filter parent categories to only matching ones
5988      const filteredParents = page.parentCategories.filter(cat => matchingParentIds.has(cat.categoryId));
5989      
5990      // Render filtered results
5991      page.renderFilteredCategories(filteredParents, matchingChildIds, term);
5992    },
5993    renderFilteredCategories: function(filteredParents, matchingChildIds, searchTerm) {
5994      let html = '';
5995      
5996      for (let i = 0; i < filteredParents.length; i++) {
5997        const cat = filteredParents[i];
5998        const isSelected = page.terms.categories.id === cat.categoryId;
5999        const label = cat.label && cat.label.trim().length > 0 ? cat.label.trim() : cat.name;
6000        const children = page.getChildren(cat.categoryId);
6001        const hasChildren = children.length > 0;
6002        
6003        html += '<div class="category-item">';
6004        
6005        if (hasChildren) {
6006          // Auto-expand if searching (show toggle as minus)
6007          html += `<i class="fa fa-minus category-toggle" data-parent-id="${cat.categoryId}"></i><a href="javascript:void(0);" class="category-link ${isSelected ? 'selected' : ''}" data-category-id="${cat.categoryId}" data-category-name="${label}">${label}</a>`;
6008        } else {
6009          html += `<span class="category-spacer"></span><a href="javascript:void(0);" class="category-link ${isSelected ? 'selected' : ''}" data-category-id="${cat.categoryId}" data-category-name="${label}">${label}</a>`;
6010        }
6011        
6012        if (hasChildren) {
6013          // Filter children to only show matching ones (or all if parent directly matched)
6014          const parentName = (cat.label && cat.label.trim().length > 0 ? cat.label : cat.name).toLowerCase();
6015          const parentDirectlyMatched = parentName.includes(searchTerm);
6016          
6017          // If parent directly matched, show all children. Otherwise, only show matching children.
6018          const childrenToShow = parentDirectlyMatched 
6019            ? children 
6020            : children.filter(child => matchingChildIds.has(child.categoryId));
6021          
6022          if (childrenToShow.length > 0) {
6023            // Show children expanded when searching
6024            html += `<div id="category-children-${cat.categoryId}" class="category-children" style="display:block;">`;
6025            
6026            // Sort children alphabetically
6027            childrenToShow.sort((a, b) => {
6028              const nameA = (a.label && a.label.trim().length > 0 ? a.label : a.name).toLowerCase();
6029              const nameB = (b.label && b.label.trim().length > 0 ? b.label : b.name).toLowerCase();
6030              return nameA.localeCompare(nameB);
6031            });
6032            
6033            for (let j = 0; j < childrenToShow.length; j++) {
6034              const child = childrenToShow[j];
6035              const childLabel = child.label && child.label.trim().length > 0 ? child.label.trim() : child.name;
6036              const childIsSelected = page.terms.categories.id === child.categoryId;
6037              
6038              html += `<div class="category-child-item"><a href="javascript:void(0);" class="category-link ${childIsSelected ? 'selected' : ''}" data-category-id="${child.categoryId}" data-category-name="${childLabel}">${childLabel}</a></div>`;
6039            }
6040            
6041            html += '</div>';
6042          }
6043        }
6044        
6045        html += '</div>';
6046      }
6047      
6048      // Update both desktop and mobile
6049      $("#FiltersList #CategoryLinkList").html(html);
6050      $("#MobileFilterContent #CategoryLinkList").html(html);
6051      
6052      // Hide show more when filtering
6053      $("#FiltersList #CategoryShowMore").hide();
6054      $("#MobileFilterContent #CategoryArea #CategoryShowMore").hide();
6055      
6056      // Re-attach handlers
6057      $(".category-toggle").off("click").on("click", page.toggleCategoryChildren);
6058      $(".category-link").off("click").on("click", function() {
6059        const categoryId = parseInt($(this).data("category-id"));
6060        const categoryName = $(this).data("category-name");
6061        $(".category-link").removeClass("selected");
6062        $(this).addClass("selected");
6063        page.terms.categories.id = categoryId;
6064        page.terms.categories.label = categoryName;
6065        page.addPill(categoryId, categoryName, "category");
6066        products.filter.category = page.terms.categories.id;
6067      });
6068    },
6069    popularLoaded: function (e) {
6070      $("#PopularList").html("");
6071      var data = context.get("popular"); 
6072      page.popular = data.data; 
6073      if (page.popular.length > 0) {
6074        for (var i = 0; i < page.popular.length; i++) {
6075          var element = $("#PopularTemplate").clone();
6076          element.css("display", "grid");
6077          element.attr("id", "Product" + i);
6078          element.attr("data-url", "/product/" + page.popular[i].productId + "/" + page.popular[i].name.split(" ").join("-"));
6079          element.html(element.html().split("{{product.url}}").join(products.getSize(200, page.popular[i].url)));
6080          element.html(element.html().split("{{url}}").join(url));
6081          element.html(element.html().split("{{product.productId}}").join(page.popular[i].productId));
6082          element.html(element.html().split("{{product.name}}").join(page.popular[i].name));
6083          element.html(element.html().split("{{product.price}}").join(page.popular[i].cost.toFixed(2)));
6084          $("#PopularList").append(element);
6085        }
6086        $("#PopularArea").show();
6087        $(".clicker").click(page.goto);
6088      } else {
6089        $("#PopularArea").hide();
6090      }
6091    }
6092  };
6093</script>
6093
6094<footer class="footer-1 storefooter">
6095    <div id="SocialArea">
6096        <div class="footer-title" style="margin-bottom: 10px; font-weight: 600;">Follow Us, We're Social</div>
6097        <div id="SocialLinks" class="list-inline social-list" style="margin-bottom: 8px;"></div>
6098    </div>
6099    <div class="row">
6100        <div class="col-sm-12 text-center">
6101            <p style="margin-bottom: 0px;"><a href="/terms">Terms</a> • <a href="/privacy">Privacy</a><span class="ecomtrue"> • <a href="/returns">Shipping + Returns</a></span></p>
6102            <p style="margin-bottom: 0px;">© Copyright Naperville Running - All Rights Reserved</p>
6103            <p style="margin-bottom: 0px;"><a href="https://www.runfreeproject.com" class="proud box-shadow-wide-link bridaloff" style="margin-top: 10px;" target="_blank"><img alt="Background Image" class="background-image" width="200px" height="47px" style="margin-left: -15px;" src="/assets/images/proud.webp"></a></p>
6104        </div>
6105    </div>
6106    <a class="btn btn-sm back-to-top inner-link" href="#top">Top</a>
6107</footer> 
6108<p>&lt;meta name=&quot;google-site-verification&quot; content=&quot;p95OR9FvxmrT4bHAUMAuD5OZ6EvfRse2gyH_JKE3m2E&quot; /&gt;</p>
6109
6110</div>
6111<div class="fullLoading">
6112    <div id="progress">
6113        <span class="spinner-icon"></span>
6114    </div>
6115        <div class="running">
6116            <div class="outer">
6117                <div class="body">
6118                    <div class="arm behind"></div>
6119                    <div class="arm front"></div>
6120                    <div class="leg behind"></div>
6121                    <div class="leg front"></div>
6122                </div>
6123            </div>
6124        </div>
6125    </div>
6126</div>
6127<div class="fullLoadingOrders">
6128    <div id="progress">
6129        <span class="spinner-icon"></span>
6130    </div>
6131    <div class="running">
6132        <div class="outer">
6133            <div class="body">
6134                <div class="arm behind"></div>
6135                <div class="arm front"></div>
6136                <div class="leg behind"></div>
6137                <div class="leg front"></div>
6138            </div>
6139        </div>
6140    </div>
6141    <div class="loadMessage">
6142        <span class="header">Processing, Please be patient</span><br/>
6143        <span style="color: #ff0072; font-weight: 800;">
6144            Don't Tap Back or Close the Window!<br>
6145            This could cause the order to duplicate or fail.<br>
6146        </span>
6147        <span id="CheckoutStatus"></span>
6148    </div>
6149</div>
6150
6151<!-- 3rd Party Includes -->
6152<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
vendor: 2 bytes, line 6152
6152
6153<script src="/assets/scripts/flexslider.min.js"></script>
6153 
6154<script src="/assets/scripts/masonry.min.js"></script>
vendor: 2 bytes, line 6154
6154
6155<script src="/assets/scripts/smooth-scroll.min.js"></script>
vendor: 2 bytes, line 6155
6155
6156<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
vendor: 2 bytes, line 6156
6156
6157<script type="text/javascript" src="/assets/admin/scripts/spectrum.js?v=1.2.0"></script>
6157
6158<!-- Model Objects -->
6159<script type="text/javascript" src="/assets/admin/scripts/models/products.js?v=1.2.0"></script>
vendor: 2 bytes, line 6159
6159
6160<script type="text/javascript" src="/assets/admin/scripts/models/category.js?v=1.2.0"></script>
vendor: 2 bytes, line 6160
6160
6161<script type="text/javascript" src="/assets/admin/scripts/models/brand.js?v=1.2.0"></script>
vendor: 2 bytes, line 6161
6161
6162<script type="text/javascript" src="/assets/scripts/collection.js?v=1.2.0"></script>
vendor: 2 bytes, line 6162
6162
6163<script type="text/javascript" src="/assets/admin/scripts/models/discounts.js?v=1.2.0"></script>
vendor: 2 bytes, line 6163
6163
6164<script type="text/javascript" src="/assets/admin/scripts/models/orders.js?v=1.2.0"></script>
vendor: 2 bytes, line 6164
6164
6165<script type="text/javascript" src="/assets/admin/scripts/models/taxes.js?v=1.2.0"></script>
vendor: 2 bytes, line 6165
6165
6166<script type="text/javascript" src="/assets/admin/scripts/models/states.js?v=1.2.0"></script>
vendor: 2 bytes, line 6166
6166
6167<script type="text/javascript" src="/assets/admin/scripts/models/country.js?v=1.2.0"></script>
vendor: 2 bytes, line 6167
6167
6168<script type="text/javascript" src="/assets/admin/scripts/models/homepage.js?v=1.2.0"></script>
vendor: 2 bytes, line 6168
6168
6169<script type="text/javascript" src="/assets/admin/scripts/models/customers.js?v=1.2.0"></script>
vendor: 2 bytes, line 6169
6169
6170<script type="text/javascript" src="/assets/admin/scripts/models/site.js?v=1.2.0"></script>
vendor: 2 bytes, line 6170
6170
6171<script type="text/javascript" src="/assets/admin/scripts/models/user.js?v=1.2.0"></script>
vendor: 2 bytes, line 6171
6171
6172<script type="text/javascript" src="/assets/admin/scripts/models/address.js?v=1.2.0"></script>
vendor: 2 bytes, line 6172
6172
6173<script type="text/javascript" src="/assets/admin/scripts/models/contents.js?v=1.2.0"></script>
vendor: 2 bytes, line 6173
6173
6174<script type="text/javascript" src="/assets/admin/scripts/models/socials.js?v=1.2.0"></script>
vendor: 2 bytes, line 6174
6174
6175<script type="text/javascript" src="/assets/admin/scripts/models/orders.js?v=1.2.0"></script>
vendor: 2 bytes, line 6175
6175
6176<script type="text/javascript" src="/assets/admin/scripts/models/merchant.js?v=1.2.0"></script>
vendor: 2 bytes, line 6176
6176
6177<script type="text/javascript" src="/assets/admin/scripts/models/store.js?v=1.2.0"></script>
6177   
6178<script type="text/javascript" src="/assets/admin/scripts/models/settings.js?v=1.2.0"></script>
6178  
6179<script type="text/javascript" src="/assets/scripts/models/wishlist.js?v=1.2.0"></script>
6179
6180<!-- Application Core -->
6181<script type="text/javascript" src="/assets/admin/scripts/context.js?v=1.2.0"></script>
vendor: 2 bytes, line 6181
6181
6182<script type="text/javascript" src="/assets/admin/scripts/growler.js?v=1.2.0"></script>
vendor: 2 bytes, line 6182
6182
6183<script type="text/javascript" src="/assets/admin/scripts/modal.js?v=1.2.0"></script>
vendor: 2 bytes, line 6183
6183
6184<script type="text/javascript" src="/assets/scripts/jquery.datetimepicker.js"></script>
vendor: 2 bytes, line 6184
6184
6185<script type="text/javascript" src="/assets/admin/scripts/service.js?v=1.2.0"></script>
vendor: 2 bytes, line 6185
6185
6186<script type="text/javascript" src="/assets/admin/scripts/cart.js?v=1.2.0"></script>
6186     
6187<script type="text/javascript" src="/assets/admin/scripts/store.js?v=1.2.0"></script>
6187   
6188<script src="/assets/scripts/scripts.js?v=1.2.0"></script>
6188
6189 
6190</body>
6191</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.