PageSourceSearch

https://runnerscorner.com/shop

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