@o2vend/theme-cli 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +425 -0
  2. package/assets/Logo_o2vend.png +0 -0
  3. package/assets/favicon.png +0 -0
  4. package/assets/logo-white.png +0 -0
  5. package/bin/o2vend +42 -0
  6. package/config/widget-map.json +50 -0
  7. package/lib/commands/check.js +201 -0
  8. package/lib/commands/generate.js +33 -0
  9. package/lib/commands/init.js +214 -0
  10. package/lib/commands/optimize.js +216 -0
  11. package/lib/commands/package.js +208 -0
  12. package/lib/commands/serve.js +105 -0
  13. package/lib/commands/validate.js +191 -0
  14. package/lib/lib/api-client.js +357 -0
  15. package/lib/lib/dev-server.js +2618 -0
  16. package/lib/lib/file-watcher.js +80 -0
  17. package/lib/lib/hot-reload.js +106 -0
  18. package/lib/lib/liquid-engine.js +822 -0
  19. package/lib/lib/liquid-filters.js +671 -0
  20. package/lib/lib/mock-api-server.js +989 -0
  21. package/lib/lib/mock-data.js +1468 -0
  22. package/lib/lib/widget-service.js +321 -0
  23. package/package.json +70 -0
  24. package/test-theme/README.md +27 -0
  25. package/test-theme/assets/async-sections.js +446 -0
  26. package/test-theme/assets/cart-drawer.js +463 -0
  27. package/test-theme/assets/cart-manager.js +223 -0
  28. package/test-theme/assets/checkout-price-handler.js +368 -0
  29. package/test-theme/assets/components.css +4629 -0
  30. package/test-theme/assets/delivery-zone.css +299 -0
  31. package/test-theme/assets/delivery-zone.js +396 -0
  32. package/test-theme/assets/logo.png +0 -0
  33. package/test-theme/assets/sections.css +48 -0
  34. package/test-theme/assets/theme.css +3500 -0
  35. package/test-theme/assets/theme.js +3745 -0
  36. package/test-theme/config/settings_data.json +292 -0
  37. package/test-theme/config/settings_schema.json +1050 -0
  38. package/test-theme/layout/theme.liquid +195 -0
  39. package/test-theme/locales/en.default.json +260 -0
  40. package/test-theme/sections/content-fallback.liquid +53 -0
  41. package/test-theme/sections/content.liquid +57 -0
  42. package/test-theme/sections/footer-fallback.liquid +328 -0
  43. package/test-theme/sections/footer.liquid +278 -0
  44. package/test-theme/sections/header-fallback.liquid +1805 -0
  45. package/test-theme/sections/header.liquid +1145 -0
  46. package/test-theme/sections/hero-fallback.liquid +212 -0
  47. package/test-theme/sections/hero.liquid +136 -0
  48. package/test-theme/snippets/account-sidebar.liquid +200 -0
  49. package/test-theme/snippets/add-to-cart-modal.liquid +484 -0
  50. package/test-theme/snippets/breadcrumbs.liquid +134 -0
  51. package/test-theme/snippets/cart-drawer.liquid +467 -0
  52. package/test-theme/snippets/delivery-zone-city-selector.liquid +79 -0
  53. package/test-theme/snippets/delivery-zone-modal.liquid +337 -0
  54. package/test-theme/snippets/delivery-zone-search.liquid +78 -0
  55. package/test-theme/snippets/icon.liquid +105 -0
  56. package/test-theme/snippets/login-modal.liquid +346 -0
  57. package/test-theme/snippets/mega-menu.liquid +812 -0
  58. package/test-theme/snippets/news-thumbnail.liquid +187 -0
  59. package/test-theme/snippets/pagination.liquid +120 -0
  60. package/test-theme/snippets/price.liquid +92 -0
  61. package/test-theme/snippets/product-card-related.liquid +78 -0
  62. package/test-theme/snippets/product-card-simple.liquid +41 -0
  63. package/test-theme/snippets/product-card.liquid +697 -0
  64. package/test-theme/snippets/rating.liquid +85 -0
  65. package/test-theme/snippets/skeleton-collection-grid.liquid +114 -0
  66. package/test-theme/snippets/skeleton-product-card.liquid +124 -0
  67. package/test-theme/snippets/skeleton-product-grid.liquid +34 -0
  68. package/test-theme/snippets/social-sharing.liquid +185 -0
  69. package/test-theme/templates/account/dashboard.liquid +401 -0
  70. package/test-theme/templates/account/loyalty-redemption.liquid +405 -0
  71. package/test-theme/templates/account/loyalty.liquid +588 -0
  72. package/test-theme/templates/account/order-detail.liquid +230 -0
  73. package/test-theme/templates/account/orders.liquid +349 -0
  74. package/test-theme/templates/account/profile.liquid +758 -0
  75. package/test-theme/templates/account/register.liquid +232 -0
  76. package/test-theme/templates/account/return-orders.liquid +348 -0
  77. package/test-theme/templates/account/store-credit.liquid +464 -0
  78. package/test-theme/templates/account/subscriptions.liquid +601 -0
  79. package/test-theme/templates/account/wishlist.liquid +419 -0
  80. package/test-theme/templates/address-book.liquid +1092 -0
  81. package/test-theme/templates/categories.liquid +452 -0
  82. package/test-theme/templates/checkout.liquid +4511 -0
  83. package/test-theme/templates/error.liquid +384 -0
  84. package/test-theme/templates/index.liquid +11 -0
  85. package/test-theme/templates/login.liquid +185 -0
  86. package/test-theme/templates/order-confirmation.liquid +720 -0
  87. package/test-theme/templates/page.liquid +297 -0
  88. package/test-theme/templates/product-detail.liquid +4363 -0
  89. package/test-theme/templates/products.liquid +518 -0
  90. package/test-theme/templates/search.liquid +922 -0
  91. package/test-theme/theme.json.example +19 -0
  92. package/test-theme/widgets/brand-carousel.liquid +676 -0
  93. package/test-theme/widgets/brand.liquid +245 -0
  94. package/test-theme/widgets/carousel.liquid +843 -0
  95. package/test-theme/widgets/category-list-carousel.liquid +656 -0
  96. package/test-theme/widgets/category-list.liquid +340 -0
  97. package/test-theme/widgets/category.liquid +475 -0
  98. package/test-theme/widgets/discount-time.liquid +176 -0
  99. package/test-theme/widgets/footer-menu.liquid +695 -0
  100. package/test-theme/widgets/footer.liquid +179 -0
  101. package/test-theme/widgets/gallery.liquid +271 -0
  102. package/test-theme/widgets/header-menu.liquid +932 -0
  103. package/test-theme/widgets/header.liquid +159 -0
  104. package/test-theme/widgets/html.liquid +214 -0
  105. package/test-theme/widgets/news.liquid +217 -0
  106. package/test-theme/widgets/product-canvas.liquid +235 -0
  107. package/test-theme/widgets/product-carousel.liquid +502 -0
  108. package/test-theme/widgets/product.liquid +45 -0
  109. package/test-theme/widgets/recently-viewed.liquid +26 -0
  110. package/test-theme/widgets/shared/product-grid.liquid +339 -0
  111. package/test-theme/widgets/simple-product.liquid +42 -0
  112. package/test-theme/widgets/single-product.liquid +610 -0
  113. package/test-theme/widgets/spacebar-carousel.liquid +663 -0
  114. package/test-theme/widgets/spacebar.liquid +279 -0
  115. package/test-theme/widgets/splash.liquid +378 -0
  116. package/test-theme/widgets/testimonial-carousel.liquid +709 -0
@@ -0,0 +1,1805 @@
1
+ {% comment %}
2
+ Header Fallback Content
3
+ Used when widgets are not available or widget mode is disabled
4
+ {% endcomment %}
5
+
6
+ <div class="site-header__fallback">
7
+ {% comment %}Mobile Header Wrapper{% endcomment %}
8
+ <div class="mobile-header-wrapper">
9
+ <div class="mobile-header-top">
10
+ <button type="button" class="mobile-header__menu-toggle" aria-label="Toggle navigation menu" aria-expanded="false" data-mobile-menu-toggle>
11
+ <svg class="hamburger-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
12
+ <line x1="3" y1="6" x2="21" y2="6"></line>
13
+ <line x1="3" y1="12" x2="21" y2="12"></line>
14
+ <line x1="3" y1="18" x2="21" y2="18"></line>
15
+ </svg>
16
+ </button>
17
+
18
+ <div class="mobile-header__brand">
19
+ <a href="/" aria-label="{{ shop.name }}" class="mobile-header__brand-link">
20
+ {% assign logo_image = settings.logo | default: section.settings.logo %}
21
+ {% assign logo_text = settings.logo_text | default: section.settings.logo_text | default: shop.name %}
22
+ {% assign logo_width = settings.logo_width | default: section.settings.logo_width | default: 150 %}
23
+ {% if logo_image %}
24
+ <img src="{{ logo_image }}" alt="{{ logo_text }}" class="mobile-header__logo" loading="lazy" style="max-height: {{ logo_width }}px;">
25
+ {% elsif shop.logo %}
26
+ <img src="{{ shop.logo }}" alt="{{ shop.name }}" class="mobile-header__logo" loading="lazy" style="max-height: {{ logo_width }}px;">
27
+ {% else %}
28
+ <span class="mobile-header__logo-text">{{ logo_text }}</span>
29
+ {% endif %}
30
+ </a>
31
+ </div>
32
+
33
+ <div class="mobile-header__actions">
34
+ {% liquid
35
+ assign cart_icon_val = section.settings.show_cart_icon
36
+ if cart_icon_val == blank or cart_icon_val == null
37
+ assign cart_icon_val = settings.show_cart_icon
38
+ endif
39
+ if cart_icon_val == blank or cart_icon_val == null
40
+ assign cart_icon_val = true
41
+ endif
42
+ %}
43
+ {% if cart_icon_val or cart_icon_val == true or cart_icon_val == 'true' or cart_icon_val == 1 %}
44
+ <button type="button" class="mobile-header__cart-btn" aria-label="Shopping cart" data-cart-toggle title="Shopping Cart">
45
+ <svg class="cart-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
46
+ <circle cx="9" cy="21" r="1"></circle>
47
+ <circle cx="20" cy="21" r="1"></circle>
48
+ <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
49
+ </svg>
50
+ <span data-cart-count>{{ cart.itemCount | default: 0 }}</span>
51
+ </button>
52
+ {% endif %}
53
+ </div>
54
+ </div>
55
+
56
+ {% comment %}Mobile Search Bar{% endcomment %}
57
+ {% liquid
58
+ assign search_val = section.settings.show_search
59
+ if search_val == blank or search_val == null
60
+ assign search_val = settings.show_search
61
+ endif
62
+ if search_val == blank or search_val == null
63
+ assign search_val = true
64
+ endif
65
+ %}
66
+ {% if search_val or search_val == true or search_val == 'true' or search_val == 1 %}
67
+ <div class="mobile-header__search">
68
+ <form class="mobile-search-form" role="search" data-search-form>
69
+ <div class="mobile-search-input-wrapper">
70
+ <svg class="mobile-search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
71
+ <circle cx="11" cy="11" r="8"></circle>
72
+ <path d="m21 21-4.35-4.35"></path>
73
+ </svg>
74
+ <input type="search" name="q" class="mobile-search-input" placeholder="Search for..." aria-label="Search products" autocomplete="off" data-search-input>
75
+ <button type="submit" class="mobile-search-submit" aria-label="Search" style="display: none;">Search</button>
76
+ </div>
77
+ </form>
78
+ </div>
79
+ {% endif %}
80
+ </div>
81
+
82
+ {% comment %}Desktop Header (Original Structure){% endcomment %}
83
+ <div class="site-header__fallback-inner">
84
+ <div class="site-header__brand">
85
+ <a href="/" aria-label="{{ shop.name }}" class="site-header__brand-link">
86
+ {% assign logo_image = settings.logo | default: section.settings.logo %}
87
+ {% assign logo_text = settings.logo_text | default: section.settings.logo_text | default: shop.name %}
88
+ {% assign logo_width = settings.logo_width | default: section.settings.logo_width | default: 150 %}
89
+ {% if logo_image %}
90
+ <img src="{{ logo_image }}" alt="{{ logo_text }}" class="site-header__logo" loading="lazy" style="max-height: {{ logo_width }}px;">
91
+ {% elsif shop.logo %}
92
+ <img src="{{ shop.logo }}" alt="{{ shop.name }}" class="site-header__logo" loading="lazy" style="max-height: {{ logo_width }}px;">
93
+ {% else %}
94
+ <span class="site-header__logo-text">{{ logo_text }}</span>
95
+ {% endif %}
96
+ </a>
97
+ </div>
98
+
99
+ {% comment %}Desktop Inline Search{% endcomment %}
100
+ {% liquid
101
+ assign search_val = section.settings.show_search
102
+ if search_val == blank or search_val == null
103
+ assign search_val = settings.show_search
104
+ endif
105
+ if search_val == blank or search_val == null
106
+ assign search_val = true
107
+ endif
108
+ %}
109
+ {% if search_val or search_val == true or search_val == 'true' or search_val == 1 %}
110
+ <div class="site-header__search-container" data-search-container>
111
+ <form class="site-header__search-form" action="/search" method="get" role="search">
112
+ <div class="site-header__search-input-wrapper">
113
+ <svg class="site-header__search-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
114
+ <circle cx="11" cy="11" r="8"></circle>
115
+ <path d="m21 21-4.35-4.35"></path>
116
+ </svg>
117
+ <input
118
+ type="search"
119
+ name="q"
120
+ class="site-header__search-input"
121
+ placeholder="{{ section.settings.search_placeholder | default: settings.search_placeholder | default: 'Search for products...' }}"
122
+ aria-label="Search products"
123
+ autocomplete="off"
124
+ data-search-input>
125
+ <button type="button" class="site-header__search-clear" aria-label="Clear search" data-search-clear style="display: none;">
126
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
127
+ <line x1="18" y1="6" x2="6" y2="18"></line>
128
+ <line x1="6" y1="6" x2="18" y2="18"></line>
129
+ </svg>
130
+ </button>
131
+ </div>
132
+ </form>
133
+ <div class="site-header__search-dropdown" data-search-dropdown style="display: none;">
134
+ <div class="site-header__search-loading" data-search-loading style="display: none;">
135
+ <div class="site-header__search-spinner"></div>
136
+ <span>Searching...</span>
137
+ </div>
138
+ <div class="site-header__search-results" data-search-results></div>
139
+ <div class="site-header__search-empty" data-search-empty style="display: none;">
140
+ <p>No products found</p>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ {% endif %}
145
+
146
+ {% assign menu_handle = settings.menu | default: section.settings.menu | default: 'main-menu' %}
147
+ {% if menu_handle %}
148
+ {% render 'snippets/mega-menu', menu: menu_handle %}
149
+ {% elsif mainMenu and mainMenu.items and mainMenu.items.size > 0 %}
150
+ {% render 'snippets/mega-menu', menu: mainMenu %}
151
+ {% else %}
152
+ <nav class="site-header__menu" role="navigation" aria-label="Main navigation">
153
+ <ul class="site-header__menu-list">
154
+ <li class="site-header__menu-item"><a href="/products" class="site-header__menu-link">Shop</a></li>
155
+ <li class="site-header__menu-item"><a href="/contact" class="site-header__menu-link">Contact</a></li>
156
+ </ul>
157
+ </nav>
158
+ {% endif %}
159
+ <div class="site-header__actions">
160
+ {% comment %}Search icon - Check section.settings first (merged from global), then global settings{% endcomment %}
161
+ {% liquid
162
+ assign search_val = section.settings.show_search
163
+ if search_val == blank or search_val == null
164
+ assign search_val = settings.show_search
165
+ endif
166
+ if search_val == blank or search_val == null
167
+ assign search_val = true
168
+ endif
169
+ %}
170
+ {% if search_val or search_val == true or search_val == 'true' or search_val == 1 %}
171
+ <button type="button" aria-label="Search" class="site-header__search-btn" title="Search" data-search-toggle>🔍</button>
172
+ {% endif %}
173
+
174
+ {%- comment -%}
175
+ Account / Login actions
176
+ - If customer is authenticated, show account link and logout
177
+ - Otherwise, show login trigger that opens the global login modal
178
+ {%- endcomment -%}
179
+ {% if customer and customer.isAuthenticated %}
180
+ <a href="/account" class="site-header__account-btn" aria-label="Account" title="My Account">
181
+ 👤
182
+ </a>
183
+ <form method="post" action="/webstoreapi/customer/logout" class="site-header__logout-form">
184
+ <button type="submit" class="site-header__logout-btn" aria-label="Logout" title="Logout">
185
+
186
+ </button>
187
+ </form>
188
+ {% else %}
189
+ <button type="button"
190
+ class="site-header__account-btn"
191
+ aria-label="Login"
192
+ title="Login"
193
+ data-login-modal-trigger>
194
+ 👤
195
+ </button>
196
+ {% endif %}
197
+
198
+ {% comment %}Cart icon - Check section.settings first (merged from global), then global settings{% endcomment %}
199
+ {% liquid
200
+ assign cart_icon_val = section.settings.show_cart_icon
201
+ if cart_icon_val == blank or cart_icon_val == null
202
+ assign cart_icon_val = settings.show_cart_icon
203
+ endif
204
+ if cart_icon_val == blank or cart_icon_val == null
205
+ assign cart_icon_val = true
206
+ endif
207
+ %}
208
+ {% if cart_icon_val or cart_icon_val == true or cart_icon_val == 'true' or cart_icon_val == 1 %}
209
+ <button type="button" class="site-header__cart-btn" aria-label="Shopping cart" data-cart-toggle title="Shopping Cart">
210
+ 🛒 <span data-cart-count>{{ cart.itemCount | default: 0 }}</span>
211
+ </button>
212
+ {% endif %}
213
+ </div>
214
+ </div>
215
+ </div>
216
+
217
+ <style>
218
+ .site-header__fallback {
219
+ background: var(--color-background, {{ settings.color_background }});
220
+ border-bottom: 1px solid var(--color-border, rgba(15, 23, 42, 0.08));
221
+ position: relative;
222
+ overflow: visible;
223
+ }
224
+ .site-header__fallback-inner {
225
+ max-width: var(--container-width, {{ settings.container_width }}px);
226
+ margin: 0 auto;
227
+ padding: var(--spacing-element, 0.85rem) var(--spacing-component, 1.25rem);
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: space-between;
231
+ gap: var(--spacing-component, 1.5rem);
232
+ position: relative;
233
+ }
234
+ .site-header__actions {
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 0.75rem;
238
+ flex-shrink: 0;
239
+ }
240
+
241
+ .site-header__actions a,
242
+ .site-header__actions button {
243
+ text-decoration: none;
244
+ color: var(--color-text, {{ settings.color_text }});
245
+ font-weight: var(--font-weight-normal, 400);
246
+ background: none;
247
+ border: none;
248
+ cursor: pointer;
249
+ font-size: inherit;
250
+ padding: var(--spacing-element, 0.5rem);
251
+ display: inline-flex;
252
+ align-items: center;
253
+ justify-content: center;
254
+ width: 44px;
255
+ height: 44px;
256
+ border-radius: var(--border-radius-small, 0);
257
+ transition: opacity var(--transition-fast, 0.2s) var(--ease-out, ease);
258
+ position: relative;
259
+ }
260
+
261
+ .site-header__actions a:hover,
262
+ .site-header__actions button:hover {
263
+ opacity: 0.6;
264
+ }
265
+
266
+ .site-header__cart-btn {
267
+ position: relative;
268
+ font-size: var(--text-xl, 1.25rem);
269
+ line-height: 1;
270
+ }
271
+
272
+ .site-header__cart-btn [data-cart-count] {
273
+ position: absolute;
274
+ top: 0;
275
+ right: 0;
276
+ min-width: 18px;
277
+ height: 18px;
278
+ padding: 0 var(--spacing-element, 5px);
279
+ background: var(--color-text, {{ settings.color_text }});
280
+ color: var(--color-background, {{ settings.color_background }});
281
+ border-radius: var(--border-radius-medium, 9px);
282
+ font-size: var(--text-xs, 0.75rem);
283
+ font-weight: var(--font-weight-bold, 600);
284
+ display: inline-flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ line-height: 1;
288
+ font-family: var(--font-primary, var(--font-body));
289
+ }
290
+
291
+ .site-header__cart-btn [data-cart-count]:empty,
292
+ .site-header__cart-btn [data-cart-count="0"] {
293
+ display: none;
294
+ }
295
+ .site-header__brand {
296
+ flex-shrink: 0;
297
+ display: flex;
298
+ align-items: center;
299
+ }
300
+
301
+ .site-header__brand-link {
302
+ display: flex;
303
+ align-items: center;
304
+ text-decoration: none;
305
+ color: inherit;
306
+ }
307
+
308
+ .site-header__logo {
309
+ max-height: 44px;
310
+ width: auto;
311
+ height: auto;
312
+ display: block;
313
+ }
314
+
315
+ .site-header__logo-text {
316
+ font-size: var(--text-xl, 1.25rem);
317
+ font-weight: var(--font-weight-bold, 600);
318
+ color: var(--color-text, {{ settings.color_text }});
319
+ }
320
+
321
+ /* Desktop Search Container */
322
+ .site-header__search-container {
323
+ display: none;
324
+ flex: 1;
325
+ max-width: 500px;
326
+ margin: 0 2rem;
327
+ position: relative;
328
+ }
329
+
330
+ .site-header__search-form {
331
+ width: 100%;
332
+ }
333
+
334
+ .site-header__search-input-wrapper {
335
+ position: relative;
336
+ display: flex;
337
+ align-items: center;
338
+ width: 100%;
339
+ }
340
+
341
+ .site-header__search-icon {
342
+ position: absolute;
343
+ left: 1rem;
344
+ color: var(--color-text, {{ settings.color_text }});
345
+ opacity: 0.5;
346
+ pointer-events: none;
347
+ z-index: 1;
348
+ }
349
+
350
+ .site-header__search-input {
351
+ width: 100%;
352
+ padding: 0.75rem 2.5rem 0.75rem 3rem;
353
+ border: 1px solid rgba(0, 0, 0, 0.15);
354
+ border-radius: 8px;
355
+ font-size: 1rem;
356
+ color: var(--color-text, {{ settings.color_text }});
357
+ background: var(--color-background, {{ settings.color_background }});
358
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
359
+ font-family: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
360
+ }
361
+
362
+ .site-header__search-input:focus {
363
+ outline: none;
364
+ border-color: var(--color-text, #000);
365
+ box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
366
+ }
367
+
368
+ .site-header__search-input::placeholder {
369
+ color: rgba(0, 0, 0, 0.4);
370
+ }
371
+
372
+ .site-header__search-clear {
373
+ position: absolute;
374
+ right: 0.75rem;
375
+ width: 32px;
376
+ height: 32px;
377
+ display: flex;
378
+ align-items: center;
379
+ justify-content: center;
380
+ border: none;
381
+ background: transparent;
382
+ color: var(--color-text, {{ settings.color_text }});
383
+ opacity: 0.5;
384
+ cursor: pointer;
385
+ padding: 0;
386
+ border-radius: 4px;
387
+ transition: opacity 0.2s ease, background-color 0.2s ease;
388
+ z-index: 1;
389
+ }
390
+
391
+ .site-header__search-clear:hover {
392
+ opacity: 1;
393
+ background-color: rgba(0, 0, 0, 0.05);
394
+ }
395
+
396
+ .site-header__search-clear svg {
397
+ width: 16px;
398
+ height: 16px;
399
+ }
400
+
401
+ /* Search Dropdown */
402
+ .site-header__search-dropdown {
403
+ position: absolute;
404
+ top: calc(100% + 0.5rem);
405
+ left: 0;
406
+ right: 0;
407
+ background: #fff;
408
+ border-radius: 8px;
409
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
410
+ z-index: 1000;
411
+ max-height: 500px;
412
+ overflow-y: auto;
413
+ animation: fadeInDown 0.2s ease;
414
+ }
415
+
416
+ @keyframes fadeInDown {
417
+ from {
418
+ opacity: 0;
419
+ transform: translateY(-10px);
420
+ }
421
+ to {
422
+ opacity: 1;
423
+ transform: translateY(0);
424
+ }
425
+ }
426
+
427
+ .site-header__search-loading {
428
+ display: flex;
429
+ align-items: center;
430
+ justify-content: center;
431
+ gap: 0.75rem;
432
+ padding: 2rem;
433
+ color: var(--color-text, {{ settings.color_text }});
434
+ opacity: 0.6;
435
+ }
436
+
437
+ .site-header__search-spinner {
438
+ width: 20px;
439
+ height: 20px;
440
+ border: 2px solid rgba(0, 0, 0, 0.1);
441
+ border-top-color: var(--color-text, #000);
442
+ border-radius: 50%;
443
+ animation: spin 0.6s linear infinite;
444
+ }
445
+
446
+ @keyframes spin {
447
+ to { transform: rotate(360deg); }
448
+ }
449
+
450
+ .site-header__search-results {
451
+ padding: 0.5rem 0;
452
+ }
453
+
454
+ .site-header__search-result {
455
+ display: flex;
456
+ align-items: center;
457
+ gap: 1rem;
458
+ padding: 0.75rem 1rem;
459
+ text-decoration: none;
460
+ color: var(--color-text, {{ settings.color_text }});
461
+ transition: background-color 0.2s ease;
462
+ cursor: pointer;
463
+ }
464
+
465
+ .site-header__search-result:hover {
466
+ background-color: rgba(0, 0, 0, 0.04);
467
+ }
468
+
469
+ .site-header__search-result-image {
470
+ flex-shrink: 0;
471
+ width: 60px;
472
+ height: 60px;
473
+ object-fit: cover;
474
+ border-radius: 6px;
475
+ background-color: rgba(0, 0, 0, 0.05);
476
+ }
477
+
478
+ .site-header__search-result-info {
479
+ flex: 1;
480
+ min-width: 0;
481
+ }
482
+
483
+ .site-header__search-result-name {
484
+ font-weight: 600;
485
+ font-size: 0.9375rem;
486
+ margin: 0 0 0.25rem 0;
487
+ color: var(--color-text, {{ settings.color_text }});
488
+ white-space: nowrap;
489
+ overflow: hidden;
490
+ text-overflow: ellipsis;
491
+ }
492
+
493
+ .site-header__search-result-price {
494
+ font-size: 0.875rem;
495
+ color: rgba(0, 0, 0, 0.6);
496
+ font-weight: 500;
497
+ }
498
+
499
+ .site-header__search-empty {
500
+ padding: 2rem;
501
+ text-align: center;
502
+ color: rgba(0, 0, 0, 0.5);
503
+ }
504
+
505
+ .site-header__search-empty p {
506
+ margin: 0;
507
+ font-size: 0.9375rem;
508
+ }
509
+
510
+ /* Hide search button on desktop when search container is visible */
511
+ @media (min-width: 1024px) {
512
+ .site-header__search-container {
513
+ display: block;
514
+ }
515
+
516
+ .site-header__search-btn {
517
+ display: none !important;
518
+ }
519
+ }
520
+
521
+ /* Hide search container on mobile */
522
+ @media (max-width: 1023px) {
523
+ .site-header__search-container {
524
+ display: none !important;
525
+ }
526
+
527
+ .site-header__search-btn {
528
+ display: inline-flex !important;
529
+ }
530
+ }
531
+
532
+ /* Menu styling - matching mega-menu.liquid styles */
533
+ .site-header__menu {
534
+ flex: 1;
535
+ display: flex;
536
+ justify-content: center;
537
+ position: relative;
538
+ overflow: visible;
539
+ }
540
+
541
+ .site-header__menu-list {
542
+ list-style: none;
543
+ display: flex;
544
+ align-items: center;
545
+ gap: 0;
546
+ margin: 0;
547
+ padding: 0;
548
+ position: relative;
549
+ }
550
+
551
+ .site-header__menu-item {
552
+ position: static;
553
+ margin: 0;
554
+ padding: 0;
555
+ }
556
+
557
+ .site-header__menu-link {
558
+ display: flex;
559
+ align-items: center;
560
+ gap: var(--spacing-element, 0.375rem);
561
+ padding: var(--spacing-element, 0.75rem) var(--spacing-element, 1rem);
562
+ text-decoration: none;
563
+ color: var(--color-text, {{ settings.color_text }});
564
+ font-weight: var(--font-weight-normal, 400);
565
+ font-size: var(--text-xl, 2rem);
566
+ letter-spacing: var(--letter-spacing-heading, 0);
567
+ transition: color var(--transition-fast, 0.2s) var(--ease-out, ease);
568
+ white-space: nowrap;
569
+ font-family: var(--font-primary, var(--font-body));
570
+ }
571
+
572
+ .site-header__menu-link:hover {
573
+ color: var(--color-primary, {{ settings.color_primary | default: '#000000' }});
574
+ }
575
+
576
+ @media (min-width: 769px) {
577
+ .mobile-header-wrapper {
578
+ display: none;
579
+ }
580
+ }
581
+
582
+ @media (max-width: 768px) {
583
+ .site-header__fallback-inner {
584
+ display: none;
585
+ }
586
+
587
+ .site-header__fallback {
588
+ position: sticky;
589
+ top: 0;
590
+ z-index: var(--z-sticky, 1020);
591
+ }
592
+
593
+ .mobile-header-wrapper {
594
+ display: block;
595
+ background: var(--color-background, {{ settings.color_background }});
596
+ border-bottom: 1px solid var(--color-border, rgba(15, 23, 42, 0.08));
597
+ }
598
+
599
+ .mobile-header-top {
600
+ display: flex;
601
+ align-items: center;
602
+ justify-content: space-between;
603
+ padding: var(--spacing-element, 0.75rem) var(--spacing-component, 1rem);
604
+ gap: var(--spacing-element, 0.75rem);
605
+ }
606
+
607
+ .mobile-header__menu-toggle {
608
+ display: flex;
609
+ align-items: center;
610
+ justify-content: center;
611
+ width: 44px;
612
+ height: 44px;
613
+ background: none;
614
+ border: none;
615
+ cursor: pointer;
616
+ padding: 0;
617
+ color: var(--color-text, {{ settings.color_text }});
618
+ border-radius: var(--border-radius-small, 0);
619
+ transition: background-color var(--transition-fast, 0.2s) var(--ease-out, ease);
620
+ flex-shrink: 0;
621
+ }
622
+
623
+ .mobile-header__menu-toggle:hover,
624
+ .mobile-header__menu-toggle:focus {
625
+ background-color: var(--color-surface, rgba(0, 0, 0, 0.05));
626
+ outline: 2px solid var(--color-primary, transparent);
627
+ outline-offset: 2px;
628
+ }
629
+
630
+ .mobile-header__menu-toggle.active .hamburger-icon line:nth-child(1) {
631
+ transform: rotate(45deg) translate(5px, 5px);
632
+ }
633
+
634
+ .mobile-header__menu-toggle.active .hamburger-icon line:nth-child(2) {
635
+ opacity: 0;
636
+ }
637
+
638
+ .mobile-header__menu-toggle.active .hamburger-icon line:nth-child(3) {
639
+ transform: rotate(-45deg) translate(7px, -6px);
640
+ }
641
+
642
+ .hamburger-icon {
643
+ width: 24px;
644
+ height: 24px;
645
+ transition: transform var(--transition-fast, 0.2s) var(--ease-out, ease);
646
+ }
647
+
648
+ .hamburger-icon line {
649
+ transition: transform var(--transition-fast, 0.2s) var(--ease-out, ease), opacity var(--transition-fast, 0.2s) var(--ease-out, ease);
650
+ transform-origin: center;
651
+ }
652
+
653
+ .mobile-header__brand {
654
+ flex: 1;
655
+ display: flex;
656
+ align-items: center;
657
+ justify-content: center;
658
+ min-width: 0;
659
+ }
660
+
661
+ .mobile-header__brand-link {
662
+ display: flex;
663
+ align-items: center;
664
+ justify-content: center;
665
+ text-decoration: none;
666
+ color: inherit;
667
+ }
668
+
669
+ .mobile-header__logo {
670
+ max-height: 40px;
671
+ width: auto;
672
+ height: auto;
673
+ display: block;
674
+ }
675
+
676
+ .mobile-header__logo-text {
677
+ font-size: var(--text-lg, 1.125rem);
678
+ font-weight: var(--font-weight-bold, 600);
679
+ color: var(--color-text, {{ settings.color_text }});
680
+ white-space: nowrap;
681
+ overflow: hidden;
682
+ text-overflow: ellipsis;
683
+ }
684
+
685
+ .mobile-header__actions {
686
+ display: flex;
687
+ align-items: center;
688
+ flex-shrink: 0;
689
+ }
690
+
691
+ .mobile-header__cart-btn {
692
+ position: relative;
693
+ display: flex;
694
+ align-items: center;
695
+ justify-content: center;
696
+ width: 44px;
697
+ height: 44px;
698
+ background: none;
699
+ border: none;
700
+ cursor: pointer;
701
+ padding: 0;
702
+ color: var(--color-text, {{ settings.color_text }});
703
+ border-radius: var(--border-radius-small, 0);
704
+ transition: background-color var(--transition-fast, 0.2s) var(--ease-out, ease);
705
+ }
706
+
707
+ .mobile-header__cart-btn:hover,
708
+ .mobile-header__cart-btn:focus {
709
+ background-color: var(--color-surface, rgba(0, 0, 0, 0.05));
710
+ outline: 2px solid var(--color-primary, transparent);
711
+ outline-offset: 2px;
712
+ }
713
+
714
+ .mobile-header__cart-btn .cart-icon {
715
+ width: 24px;
716
+ height: 24px;
717
+ }
718
+
719
+ .mobile-header__cart-btn [data-cart-count] {
720
+ position: absolute;
721
+ top: 6px;
722
+ right: 6px;
723
+ min-width: 18px;
724
+ height: 18px;
725
+ padding: 0 var(--spacing-element, 5px);
726
+ background: var(--color-text, {{ settings.color_text }});
727
+ color: var(--color-background, {{ settings.color_background }});
728
+ border-radius: var(--border-radius-medium, 9px);
729
+ font-size: var(--text-xs, 0.75rem);
730
+ font-weight: var(--font-weight-bold, 600);
731
+ display: inline-flex;
732
+ align-items: center;
733
+ justify-content: center;
734
+ line-height: 1;
735
+ font-family: var(--font-primary, var(--font-body));
736
+ }
737
+
738
+ .mobile-header__cart-btn [data-cart-count]:empty,
739
+ .mobile-header__cart-btn [data-cart-count="0"] {
740
+ display: none;
741
+ }
742
+
743
+ .mobile-header__search {
744
+ padding: 0 var(--spacing-component, 1rem) var(--spacing-element, 0.75rem);
745
+ }
746
+
747
+ .mobile-search-form {
748
+ width: 100%;
749
+ }
750
+
751
+ .mobile-search-input-wrapper {
752
+ position: relative;
753
+ display: flex;
754
+ align-items: center;
755
+ }
756
+
757
+ .mobile-search-icon {
758
+ position: absolute;
759
+ left: var(--spacing-element, 0.75rem);
760
+ color: var(--color-text-muted, rgba(0, 0, 0, 0.5));
761
+ pointer-events: none;
762
+ width: 20px;
763
+ height: 20px;
764
+ }
765
+
766
+ .mobile-search-input {
767
+ width: 100%;
768
+ padding: var(--spacing-element, 0.75rem) var(--spacing-element, 0.75rem) var(--spacing-element, 0.75rem) calc(var(--spacing-element, 0.75rem) * 2 + 20px);
769
+ border: 1px solid var(--color-border, rgba(15, 23, 42, 0.15));
770
+ border-radius: var(--border-radius-medium, 8px);
771
+ font-size: var(--text-base, 0.875rem);
772
+ font-family: var(--font-primary, var(--font-body));
773
+ color: var(--color-text, {{ settings.color_text }});
774
+ background-color: var(--color-background, {{ settings.color_background }});
775
+ min-height: 44px;
776
+ transition: border-color var(--transition-fast, 0.2s) var(--ease-out, ease);
777
+ }
778
+
779
+ .mobile-search-input:focus {
780
+ outline: none;
781
+ border-color: var(--color-primary, {{ settings.color_primary | default: '#000000' }});
782
+ }
783
+
784
+ .mobile-search-input::placeholder {
785
+ color: var(--color-text-muted, rgba(0, 0, 0, 0.5));
786
+ }
787
+
788
+ .mobile-nav-drawer {
789
+ position: fixed;
790
+ top: 0;
791
+ left: 0;
792
+ right: 0;
793
+ bottom: 0;
794
+ background-color: rgba(0, 0, 0, 0.5);
795
+ backdrop-filter: blur(4px);
796
+ -webkit-backdrop-filter: blur(4px);
797
+ z-index: var(--z-modal, 1050);
798
+ opacity: 0;
799
+ visibility: hidden;
800
+ transition: opacity var(--transition, 0.2s) var(--ease-out, ease), visibility var(--transition, 0.2s) var(--ease-out, ease);
801
+ }
802
+
803
+ .mobile-nav-drawer.active {
804
+ opacity: 1;
805
+ visibility: visible;
806
+ }
807
+
808
+ .mobile-nav-drawer-content {
809
+ position: absolute;
810
+ top: 0;
811
+ left: 0;
812
+ width: 280px;
813
+ max-width: 85vw;
814
+ height: 100vh;
815
+ max-height: 100vh;
816
+ background-color: var(--color-background, {{ settings.color_background }});
817
+ padding: var(--spacing-component, 1.5rem);
818
+ overflow-y: auto;
819
+ overflow-x: hidden;
820
+ -webkit-overflow-scrolling: touch;
821
+ transform: translateX(-100%);
822
+ transition: transform var(--transition, 0.3s) var(--ease-out, ease);
823
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
824
+ display: flex;
825
+ flex-direction: column;
826
+ z-index: calc(var(--z-modal, 1050) + 1);
827
+ }
828
+
829
+ .mobile-nav-drawer.active .mobile-nav-drawer-content {
830
+ transform: translateX(0);
831
+ }
832
+
833
+ .mobile-nav-drawer-header {
834
+ display: flex;
835
+ align-items: center;
836
+ justify-content: space-between;
837
+ margin-bottom: var(--spacing-component, 1.5rem);
838
+ padding-bottom: var(--spacing-element, 0.75rem);
839
+ border-bottom: 1px solid var(--color-border, rgba(15, 23, 42, 0.08));
840
+ flex-shrink: 0;
841
+ }
842
+
843
+ .mobile-nav-drawer-title {
844
+ font-size: var(--text-lg, 1.125rem);
845
+ font-weight: var(--font-weight-bold, 600);
846
+ color: var(--color-text, {{ settings.color_text }});
847
+ margin: 0;
848
+ }
849
+
850
+ .mobile-nav-drawer-close {
851
+ display: flex;
852
+ align-items: center;
853
+ justify-content: center;
854
+ width: 40px;
855
+ height: 40px;
856
+ background: none;
857
+ border: none;
858
+ color: var(--color-text, {{ settings.color_text }});
859
+ cursor: pointer;
860
+ border-radius: var(--border-radius-small, 0);
861
+ transition: background-color var(--transition-fast, 0.2s) var(--ease-out, ease);
862
+ }
863
+
864
+ .mobile-nav-drawer-close:hover,
865
+ .mobile-nav-drawer-close:focus {
866
+ background-color: var(--color-surface, rgba(0, 0, 0, 0.05));
867
+ outline: 2px solid var(--color-primary, transparent);
868
+ outline-offset: 2px;
869
+ }
870
+
871
+ .mobile-nav-drawer-list {
872
+ list-style: none;
873
+ margin: 0;
874
+ padding: 0;
875
+ }
876
+
877
+ .mobile-nav-drawer-item {
878
+ border-bottom: 1px solid var(--color-border, rgba(15, 23, 42, 0.08));
879
+ }
880
+
881
+ .mobile-nav-drawer-item:last-child {
882
+ border-bottom: none;
883
+ }
884
+
885
+ .mobile-nav-drawer-link {
886
+ display: block;
887
+ padding: var(--spacing-component, 1rem) 0;
888
+ color: var(--color-text, {{ settings.color_text }});
889
+ text-decoration: none;
890
+ font-weight: var(--font-weight-medium, 500);
891
+ font-size: var(--text-base, 1rem);
892
+ transition: color var(--transition-fast, 0.2s) var(--ease-out, ease);
893
+ }
894
+
895
+ .mobile-nav-drawer-link:hover,
896
+ .mobile-nav-drawer-link:focus {
897
+ color: var(--color-primary, {{ settings.color_primary | default: '#000000' }});
898
+ }
899
+
900
+ /* Override mega-menu styles inside mobile drawer */
901
+ .mobile-nav-drawer-nav {
902
+ display: block;
903
+ width: 100%;
904
+ }
905
+
906
+ .mobile-nav-drawer-nav .site-header__menu {
907
+ display: block;
908
+ width: 100%;
909
+ flex: none;
910
+ justify-content: flex-start;
911
+ position: static;
912
+ overflow: visible;
913
+ }
914
+
915
+ .mobile-nav-drawer-nav .site-header__menu-list {
916
+ list-style: none;
917
+ margin: 0;
918
+ padding: 0;
919
+ display: block;
920
+ flex-direction: column;
921
+ gap: 0;
922
+ align-items: stretch;
923
+ }
924
+
925
+ .mobile-nav-drawer-nav .site-header__menu-item {
926
+ border-bottom: 1px solid var(--color-border, rgba(15, 23, 42, 0.08));
927
+ position: relative;
928
+ width: 100%;
929
+ }
930
+
931
+ .mobile-nav-drawer-nav .site-header__menu-item:last-child {
932
+ border-bottom: none;
933
+ }
934
+
935
+ .mobile-nav-drawer-nav .site-header__menu-link {
936
+ display: block;
937
+ padding: var(--spacing-component, 1rem) 0;
938
+ color: var(--color-text, {{ settings.color_text }});
939
+ text-decoration: none;
940
+ font-weight: var(--font-weight-medium, 500);
941
+ font-size: var(--text-base, 1rem);
942
+ transition: color var(--transition-fast, 0.2s) var(--ease-out, ease);
943
+ white-space: normal;
944
+ line-height: 1.5;
945
+ }
946
+
947
+ .mobile-nav-drawer-nav .site-header__menu-link:hover,
948
+ .mobile-nav-drawer-nav .site-header__menu-link:focus {
949
+ color: var(--color-primary, {{ settings.color_primary | default: '#000000' }});
950
+ }
951
+
952
+ /* Hide desktop mega-menu features in mobile drawer */
953
+ .mobile-nav-drawer-nav .site-header__mega-menu {
954
+ display: none !important;
955
+ position: static !important;
956
+ }
957
+
958
+ .mobile-nav-drawer-nav .site-header__menu-arrow {
959
+ display: none;
960
+ }
961
+
962
+ /* Search Overlay Styles */
963
+ .search-overlay {
964
+ position: fixed;
965
+ top: 0;
966
+ left: 0;
967
+ right: 0;
968
+ bottom: 0;
969
+ background-color: rgba(0, 0, 0, 0.5);
970
+ backdrop-filter: blur(4px);
971
+ -webkit-backdrop-filter: blur(4px);
972
+ z-index: var(--z-modal, 1050);
973
+ opacity: 0;
974
+ visibility: hidden;
975
+ transition: opacity var(--transition, 0.2s) var(--ease-out, ease), visibility var(--transition, 0.2s) var(--ease-out, ease);
976
+ }
977
+
978
+ .search-overlay.active {
979
+ opacity: 1;
980
+ visibility: visible;
981
+ }
982
+
983
+ .search-results-panel {
984
+ position: fixed;
985
+ top: 0;
986
+ right: 0;
987
+ width: 420px;
988
+ max-width: 90vw;
989
+ height: 100vh;
990
+ background-color: #ffffff;
991
+ box-shadow: -4px 0 16px rgba(0, 0, 0, 0.12);
992
+ display: flex;
993
+ flex-direction: column;
994
+ z-index: calc(var(--z-modal, 1050) + 1);
995
+ transform: translateX(100%);
996
+ transition: transform var(--transition, 0.3s) var(--ease-out, ease);
997
+ }
998
+
999
+ @media (min-width: 769px) {
1000
+ .search-results-panel {
1001
+ width: 420px;
1002
+ }
1003
+ }
1004
+
1005
+ .search-overlay.active .search-results-panel {
1006
+ transform: translateX(0);
1007
+ }
1008
+
1009
+ .search-results-header {
1010
+ display: flex;
1011
+ align-items: center;
1012
+ justify-content: space-between;
1013
+ padding: 1rem 1.25rem;
1014
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
1015
+ flex-shrink: 0;
1016
+ background-color: #ffffff;
1017
+ position: sticky;
1018
+ top: 0;
1019
+ z-index: 10;
1020
+ }
1021
+
1022
+ .search-results-input-wrapper {
1023
+ flex: 1;
1024
+ position: relative;
1025
+ display: flex;
1026
+ align-items: center;
1027
+ margin-right: 1rem;
1028
+ }
1029
+
1030
+ .search-results-input {
1031
+ width: 100%;
1032
+ padding: 0.75rem 2.5rem 0.75rem 2.75rem;
1033
+ border: 1px solid rgba(0, 0, 0, 0.15);
1034
+ border-radius: 6px;
1035
+ font-size: 0.9375rem;
1036
+ outline: none;
1037
+ background-color: #ffffff;
1038
+ color: #000000;
1039
+ font-weight: 400;
1040
+ }
1041
+
1042
+ .search-results-input:focus {
1043
+ border-color: rgba(0, 0, 0, 0.4);
1044
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
1045
+ }
1046
+
1047
+ .search-results-input::placeholder {
1048
+ color: rgba(0, 0, 0, 0.4);
1049
+ }
1050
+
1051
+ .search-results-icon {
1052
+ position: absolute;
1053
+ left: 0.875rem;
1054
+ width: 18px;
1055
+ height: 18px;
1056
+ color: rgba(0, 0, 0, 0.5);
1057
+ pointer-events: none;
1058
+ }
1059
+
1060
+ .search-results-close {
1061
+ display: flex;
1062
+ align-items: center;
1063
+ justify-content: center;
1064
+ width: 32px;
1065
+ height: 32px;
1066
+ background: none;
1067
+ border: none;
1068
+ color: rgba(0, 0, 0, 0.7);
1069
+ cursor: pointer;
1070
+ border-radius: 4px;
1071
+ transition: all var(--transition-fast, 0.2s) var(--ease-out, ease);
1072
+ padding: 0;
1073
+ }
1074
+
1075
+ .search-results-close:hover {
1076
+ background-color: rgba(0, 0, 0, 0.05);
1077
+ color: rgba(0, 0, 0, 1);
1078
+ }
1079
+
1080
+ .search-results-close svg {
1081
+ width: 20px;
1082
+ height: 20px;
1083
+ }
1084
+
1085
+ .search-results-content {
1086
+ flex: 1;
1087
+ overflow-y: auto;
1088
+ overflow-x: hidden;
1089
+ -webkit-overflow-scrolling: touch;
1090
+ padding: 0;
1091
+ background-color: #ffffff;
1092
+ }
1093
+
1094
+ .search-results-list {
1095
+ list-style: none;
1096
+ margin: 0;
1097
+ padding: 0.5rem 0;
1098
+ }
1099
+
1100
+ .search-result-item {
1101
+ display: flex;
1102
+ align-items: center;
1103
+ padding: 0.875rem 1.25rem;
1104
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
1105
+ cursor: pointer;
1106
+ transition: background-color var(--transition-fast, 0.15s) var(--ease-out, ease);
1107
+ text-decoration: none;
1108
+ color: inherit;
1109
+ }
1110
+
1111
+ .search-result-item:hover {
1112
+ background-color: rgba(0, 0, 0, 0.03);
1113
+ }
1114
+
1115
+ .search-result-item:last-child {
1116
+ border-bottom: none;
1117
+ }
1118
+
1119
+ .search-result-image {
1120
+ width: 60px;
1121
+ height: 60px;
1122
+ object-fit: cover;
1123
+ border-radius: 4px;
1124
+ margin-right: 0.875rem;
1125
+ flex-shrink: 0;
1126
+ background-color: #f5f5f5;
1127
+ }
1128
+
1129
+ .search-result-info {
1130
+ flex: 1;
1131
+ min-width: 0;
1132
+ }
1133
+
1134
+ .search-result-name {
1135
+ font-size: 0.9375rem;
1136
+ font-weight: 400;
1137
+ color: #1a1a1a;
1138
+ margin-bottom: 0.25rem;
1139
+ line-height: 1.4;
1140
+ }
1141
+
1142
+ .search-result-name strong {
1143
+ font-weight: 600;
1144
+ color: #000000;
1145
+ }
1146
+
1147
+ .search-result-price {
1148
+ font-size: 0.875rem;
1149
+ font-weight: 500;
1150
+ color: #666666;
1151
+ }
1152
+
1153
+ .search-results-loading {
1154
+ display: flex;
1155
+ align-items: center;
1156
+ justify-content: center;
1157
+ padding: 3rem 1.5rem;
1158
+ color: rgba(0, 0, 0, 0.5);
1159
+ font-size: 0.9375rem;
1160
+ }
1161
+
1162
+ .search-results-empty {
1163
+ display: flex;
1164
+ flex-direction: column;
1165
+ align-items: center;
1166
+ justify-content: center;
1167
+ padding: 3rem 1.5rem;
1168
+ text-align: center;
1169
+ color: rgba(0, 0, 0, 0.5);
1170
+ font-size: 0.9375rem;
1171
+ }
1172
+
1173
+ .search-results-empty-icon {
1174
+ width: 48px;
1175
+ height: 48px;
1176
+ margin-bottom: 1rem;
1177
+ opacity: 0.3;
1178
+ }
1179
+
1180
+ @media (max-width: 768px) {
1181
+ .search-results-panel {
1182
+ width: 100%;
1183
+ min-width: 100%;
1184
+ max-width: 100%;
1185
+ }
1186
+
1187
+ .search-results-header {
1188
+ padding: 1rem;
1189
+ }
1190
+
1191
+ .search-result-item {
1192
+ padding: 0.875rem 1rem;
1193
+ }
1194
+
1195
+ .search-result-image {
1196
+ width: 60px;
1197
+ height: 60px;
1198
+ }
1199
+ }
1200
+ }
1201
+ </style>
1202
+
1203
+ {% comment %}Mobile Navigation Drawer{% endcomment %}
1204
+ <div class="mobile-nav-drawer" id="mobile-nav-drawer" aria-hidden="true">
1205
+ <div class="mobile-nav-drawer-content">
1206
+ <div class="mobile-nav-drawer-header">
1207
+ <h2 class="mobile-nav-drawer-title">Menu</h2>
1208
+ <button type="button" class="mobile-nav-drawer-close" aria-label="Close menu" data-mobile-menu-close>
1209
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1210
+ <line x1="18" y1="6" x2="6" y2="18"></line>
1211
+ <line x1="6" y1="6" x2="18" y2="18"></line>
1212
+ </svg>
1213
+ </button>
1214
+ </div>
1215
+ <nav class="mobile-nav-drawer-nav" role="navigation" aria-label="Mobile navigation" style="flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; min-height: 0;">
1216
+ <ul class="mobile-nav-drawer-list">
1217
+ {% assign menu_handle = settings.menu | default: section.settings.menu | default: 'main-menu' %}
1218
+ {% if menu_handle %}
1219
+ {% render 'snippets/mega-menu', menu: menu_handle %}
1220
+ {% elsif mainMenu and mainMenu.items and mainMenu.items.size > 0 %}
1221
+ {% for item in mainMenu.items %}
1222
+ <li class="mobile-nav-drawer-item">
1223
+ <a href="{{ item.link | default: '#' }}" class="mobile-nav-drawer-link">{{ item.name | default: item.title }}</a>
1224
+ </li>
1225
+ {% endfor %}
1226
+ {% else %}
1227
+ <li class="mobile-nav-drawer-item">
1228
+ <a href="/products" class="mobile-nav-drawer-link">Shop</a>
1229
+ </li>
1230
+ <li class="mobile-nav-drawer-item">
1231
+ <a href="/contact" class="mobile-nav-drawer-link">Contact</a>
1232
+ </li>
1233
+ {% endif %}
1234
+ </ul>
1235
+ </nav>
1236
+ </div>
1237
+ </div>
1238
+
1239
+ <!-- Search Overlay -->
1240
+ <div class="search-overlay" id="search-overlay" aria-hidden="true">
1241
+ <div class="search-results-panel">
1242
+ <div class="search-results-header">
1243
+ <div class="search-results-input-wrapper">
1244
+ <svg class="search-results-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1245
+ <circle cx="11" cy="11" r="8"></circle>
1246
+ <path d="m21 21-4.35-4.35"></path>
1247
+ </svg>
1248
+ <input type="text" class="search-results-input" placeholder="Search for products..." aria-label="Search products" autocomplete="off" id="search-results-input">
1249
+ </div>
1250
+ <button type="button" class="search-results-close" aria-label="Close search" data-search-close>
1251
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1252
+ <line x1="18" y1="6" x2="6" y2="18"></line>
1253
+ <line x1="6" y1="6" x2="18" y2="18"></line>
1254
+ </svg>
1255
+ </button>
1256
+ </div>
1257
+ <div class="search-results-content" id="search-results-content">
1258
+ <div class="search-results-empty">
1259
+ <svg class="search-results-empty-icon" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1260
+ <circle cx="11" cy="11" r="8"></circle>
1261
+ <path d="m21 21-4.35-4.35"></path>
1262
+ </svg>
1263
+ <p>Start typing to search for products</p>
1264
+ </div>
1265
+ </div>
1266
+ </div>
1267
+ </div>
1268
+
1269
+ <script>
1270
+ document.addEventListener('DOMContentLoaded', function() {
1271
+ const menuToggle = document.querySelector('[data-mobile-menu-toggle]');
1272
+ const menuClose = document.querySelector('[data-mobile-menu-close]');
1273
+ const drawer = document.getElementById('mobile-nav-drawer');
1274
+ const body = document.body;
1275
+
1276
+ function openMenu() {
1277
+ if (drawer && menuToggle) {
1278
+ drawer.classList.add('active');
1279
+ drawer.setAttribute('aria-hidden', 'false');
1280
+ menuToggle.setAttribute('aria-expanded', 'true');
1281
+ menuToggle.classList.add('active');
1282
+ body.style.overflow = 'hidden';
1283
+ }
1284
+ }
1285
+
1286
+ function closeMenu() {
1287
+ if (drawer && menuToggle) {
1288
+ drawer.classList.remove('active');
1289
+ drawer.setAttribute('aria-hidden', 'true');
1290
+ menuToggle.setAttribute('aria-expanded', 'false');
1291
+ menuToggle.classList.remove('active');
1292
+ body.style.overflow = '';
1293
+ }
1294
+ }
1295
+
1296
+ if (menuToggle) {
1297
+ menuToggle.addEventListener('click', function(e) {
1298
+ e.preventDefault();
1299
+ e.stopPropagation();
1300
+ if (drawer && drawer.classList.contains('active')) {
1301
+ closeMenu();
1302
+ } else {
1303
+ openMenu();
1304
+ }
1305
+ });
1306
+ }
1307
+
1308
+ if (menuClose) {
1309
+ menuClose.addEventListener('click', function(e) {
1310
+ e.preventDefault();
1311
+ e.stopPropagation();
1312
+ closeMenu();
1313
+ });
1314
+ }
1315
+
1316
+ if (drawer) {
1317
+ drawer.addEventListener('click', function(e) {
1318
+ if (e.target === drawer) {
1319
+ closeMenu();
1320
+ }
1321
+ });
1322
+
1323
+ document.addEventListener('keydown', function(e) {
1324
+ if (e.key === 'Escape' && drawer.classList.contains('active')) {
1325
+ closeMenu();
1326
+ }
1327
+ });
1328
+ }
1329
+
1330
+ // Search functionality
1331
+ const searchToggle = document.querySelector('[data-search-toggle]');
1332
+ const searchOverlay = document.getElementById('search-overlay');
1333
+ const searchClose = document.querySelector('[data-search-close]');
1334
+ const searchInput = document.getElementById('search-results-input');
1335
+ const mobileSearchInput = document.querySelector('.mobile-search-input[data-search-input]');
1336
+ const searchResultsContent = document.getElementById('search-results-content');
1337
+ const searchForms = document.querySelectorAll('[data-search-form]');
1338
+ let searchTimeout = null;
1339
+ let isSearching = false;
1340
+
1341
+ function highlightSearchTerm(text, searchTerm) {
1342
+ if (!searchTerm || !text) return text;
1343
+ const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
1344
+ return text.replace(regex, '<strong>$1</strong>');
1345
+ }
1346
+
1347
+ function formatPrice(price, priceString) {
1348
+ if (typeof price === 'number') {
1349
+ return 'Price: ' + Math.round(price).toString();
1350
+ }
1351
+ if (priceString) {
1352
+ // Extract numeric value from priceString if it contains currency symbols
1353
+ const numericMatch = priceString.match(/[\d,]+\.?\d*/);
1354
+ if (numericMatch) {
1355
+ return 'Price: ' + numericMatch[0].replace(/,/g, '');
1356
+ }
1357
+ return 'Price: ' + priceString;
1358
+ }
1359
+ return price ? 'Price: ' + price : '';
1360
+ }
1361
+
1362
+ async function performSearch(query) {
1363
+ if (!query || query.trim().length === 0) {
1364
+ searchResultsContent.innerHTML = `
1365
+ <div class="search-results-empty">
1366
+ <svg class="search-results-empty-icon" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1367
+ <circle cx="11" cy="11" r="8"></circle>
1368
+ <path d="m21 21-4.35-4.35"></path>
1369
+ </svg>
1370
+ <p>Start typing to search for products</p>
1371
+ </div>
1372
+ `;
1373
+ return;
1374
+ }
1375
+
1376
+ if (isSearching) return;
1377
+ isSearching = true;
1378
+
1379
+ searchResultsContent.innerHTML = `
1380
+ <div class="search-results-loading">
1381
+ <p>Searching...</p>
1382
+ </div>
1383
+ `;
1384
+
1385
+ try {
1386
+ const response = await fetch(`/webstoreapi/search/autocomplete?q=${encodeURIComponent(query.trim())}`, {
1387
+ method: 'GET',
1388
+ headers: {
1389
+ 'Accept': 'application/json',
1390
+ 'X-Requested-With': 'XMLHttpRequest'
1391
+ }
1392
+ });
1393
+
1394
+ if (!response.ok) {
1395
+ throw new Error('Search failed');
1396
+ }
1397
+
1398
+ const data = await response.json();
1399
+ const products = data.success && data.products ? data.products : [];
1400
+
1401
+ if (!products || products.length === 0) {
1402
+ searchResultsContent.innerHTML = `
1403
+ <div class="search-results-empty">
1404
+ <svg class="search-results-empty-icon" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1405
+ <circle cx="11" cy="11" r="8"></circle>
1406
+ <path d="m21 21-4.35-4.35"></path>
1407
+ </svg>
1408
+ <p>No products found</p>
1409
+ </div>
1410
+ `;
1411
+ return;
1412
+ }
1413
+
1414
+ const productsHtml = products.map(product => {
1415
+ const productName = highlightSearchTerm(product.name || '', query.trim());
1416
+ const productImage = product.thumbnailUrl || '/assets/placeholder-product.png';
1417
+ const productPrice = product.prices?.priceString || formatPrice(product.prices?.price, product.prices?.priceString);
1418
+ const productSlug = product.slug || product.id;
1419
+ const productUrl = productSlug ? `/${productSlug}` : '#';
1420
+
1421
+ return `
1422
+ <li>
1423
+ <a href="${productUrl}" class="search-result-item">
1424
+ <img src="${productImage}" alt="${product.name || 'Product'}" class="search-result-image" loading="lazy">
1425
+ <div class="search-result-info">
1426
+ <div class="search-result-name">${productName}</div>
1427
+ <div class="search-result-price">${productPrice}</div>
1428
+ </div>
1429
+ </a>
1430
+ </li>
1431
+ `;
1432
+ }).join('');
1433
+
1434
+ searchResultsContent.innerHTML = `<ul class="search-results-list">${productsHtml}</ul>`;
1435
+ } catch (error) {
1436
+ console.error('Search error:', error);
1437
+ searchResultsContent.innerHTML = `
1438
+ <div class="search-results-empty">
1439
+ <p>Error searching products. Please try again.</p>
1440
+ </div>
1441
+ `;
1442
+ } finally {
1443
+ isSearching = false;
1444
+ }
1445
+ }
1446
+
1447
+ function openSearch() {
1448
+ if (searchOverlay) {
1449
+ searchOverlay.classList.add('active');
1450
+ searchOverlay.setAttribute('aria-hidden', 'false');
1451
+ document.body.style.overflow = 'hidden';
1452
+ if (searchInput) {
1453
+ setTimeout(() => searchInput.focus(), 100);
1454
+ }
1455
+ }
1456
+ }
1457
+
1458
+ function closeSearch() {
1459
+ if (searchOverlay) {
1460
+ searchOverlay.classList.remove('active');
1461
+ searchOverlay.setAttribute('aria-hidden', 'true');
1462
+ document.body.style.overflow = '';
1463
+ if (searchInput) {
1464
+ searchInput.value = '';
1465
+ }
1466
+ if (mobileSearchInput) {
1467
+ mobileSearchInput.value = '';
1468
+ }
1469
+ if (searchResultsContent) {
1470
+ searchResultsContent.innerHTML = `
1471
+ <div class="search-results-empty">
1472
+ <svg class="search-results-empty-icon" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1473
+ <circle cx="11" cy="11" r="8"></circle>
1474
+ <path d="m21 21-4.35-4.35"></path>
1475
+ </svg>
1476
+ <p>Start typing to search for products</p>
1477
+ </div>
1478
+ `;
1479
+ }
1480
+ }
1481
+ }
1482
+
1483
+ if (searchToggle) {
1484
+ searchToggle.addEventListener('click', function(e) {
1485
+ e.preventDefault();
1486
+ openSearch();
1487
+ });
1488
+ }
1489
+
1490
+ if (searchClose) {
1491
+ searchClose.addEventListener('click', function(e) {
1492
+ e.preventDefault();
1493
+ closeSearch();
1494
+ });
1495
+ }
1496
+
1497
+ if (searchOverlay) {
1498
+ searchOverlay.addEventListener('click', function(e) {
1499
+ if (e.target === searchOverlay) {
1500
+ closeSearch();
1501
+ }
1502
+ });
1503
+ }
1504
+
1505
+ if (searchInput) {
1506
+ searchInput.addEventListener('input', function(e) {
1507
+ const query = e.target.value.trim();
1508
+ clearTimeout(searchTimeout);
1509
+ searchTimeout = setTimeout(() => {
1510
+ performSearch(query);
1511
+ }, 300);
1512
+ });
1513
+
1514
+ searchInput.addEventListener('keydown', function(e) {
1515
+ if (e.key === 'Escape') {
1516
+ closeSearch();
1517
+ }
1518
+ });
1519
+ }
1520
+
1521
+ if (mobileSearchInput) {
1522
+ mobileSearchInput.addEventListener('input', function(e) {
1523
+ const query = e.target.value.trim();
1524
+ if (query.length > 0 && searchOverlay && !searchOverlay.classList.contains('active')) {
1525
+ openSearch();
1526
+ if (searchInput) {
1527
+ searchInput.value = query;
1528
+ performSearch(query);
1529
+ }
1530
+ } else {
1531
+ clearTimeout(searchTimeout);
1532
+ searchTimeout = setTimeout(() => {
1533
+ if (searchInput) {
1534
+ performSearch(query);
1535
+ }
1536
+ }, 300);
1537
+ }
1538
+ });
1539
+ }
1540
+
1541
+ if (searchForms && searchForms.length > 0) {
1542
+ searchForms.forEach(form => {
1543
+ form.addEventListener('submit', function(e) {
1544
+ e.preventDefault();
1545
+ const input = form.querySelector('[data-search-input], input[type="search"], input[name="q"]');
1546
+ if (input && input.value.trim()) {
1547
+ openSearch();
1548
+ if (searchInput) {
1549
+ searchInput.value = input.value.trim();
1550
+ performSearch(input.value.trim());
1551
+ }
1552
+ }
1553
+ });
1554
+ });
1555
+ }
1556
+
1557
+ document.addEventListener('keydown', function(e) {
1558
+ if (e.key === 'Escape' && searchOverlay && searchOverlay.classList.contains('active')) {
1559
+ closeSearch();
1560
+ }
1561
+ });
1562
+
1563
+ // Desktop Search Functionality
1564
+ const desktopSearchContainer = document.querySelector('[data-search-container]');
1565
+ if (desktopSearchContainer) {
1566
+ const searchInput = desktopSearchContainer.querySelector('[data-search-input]');
1567
+ const searchClear = desktopSearchContainer.querySelector('[data-search-clear]');
1568
+ const searchDropdown = desktopSearchContainer.querySelector('[data-search-dropdown]');
1569
+ const searchResults = desktopSearchContainer.querySelector('[data-search-results]');
1570
+ const searchLoading = desktopSearchContainer.querySelector('[data-search-loading]');
1571
+ const searchEmpty = desktopSearchContainer.querySelector('[data-search-empty]');
1572
+ const searchForm = desktopSearchContainer.querySelector('.site-header__search-form');
1573
+
1574
+ let searchTimeout = null;
1575
+ let selectedIndex = -1;
1576
+ let currentResults = [];
1577
+
1578
+ // Debounce function
1579
+ function debounce(func, wait) {
1580
+ return function(...args) {
1581
+ clearTimeout(searchTimeout);
1582
+ searchTimeout = setTimeout(() => func.apply(this, args), wait);
1583
+ };
1584
+ }
1585
+
1586
+ // Perform search
1587
+ async function performDesktopSearch(query) {
1588
+ if (!query || query.trim().length < 2) {
1589
+ hideDesktopDropdown();
1590
+ return;
1591
+ }
1592
+
1593
+ showDesktopLoading();
1594
+ hideDesktopEmpty();
1595
+
1596
+ try {
1597
+ const response = await fetch(`/webstoreapi/search/autocomplete?q=${encodeURIComponent(query.trim())}`, {
1598
+ headers: {
1599
+ 'Accept': 'application/json',
1600
+ 'X-Requested-With': 'XMLHttpRequest'
1601
+ }
1602
+ });
1603
+
1604
+ const data = await response.json();
1605
+
1606
+ if (data.success && data.products && data.products.length > 0) {
1607
+ currentResults = data.products;
1608
+ displayDesktopResults(data.products);
1609
+ } else {
1610
+ showDesktopEmpty();
1611
+ currentResults = [];
1612
+ }
1613
+ } catch (error) {
1614
+ console.error('Search error:', error);
1615
+ showDesktopEmpty();
1616
+ currentResults = [];
1617
+ } finally {
1618
+ hideDesktopLoading();
1619
+ }
1620
+ }
1621
+
1622
+ // Display search results
1623
+ function displayDesktopResults(products) {
1624
+ searchResults.innerHTML = '';
1625
+ selectedIndex = -1;
1626
+
1627
+ products.forEach((product, index) => {
1628
+ const resultItem = document.createElement('a');
1629
+ const productSlug = product.slug || product.id;
1630
+ resultItem.href = productSlug ? `/${productSlug}` : '#';
1631
+ resultItem.className = 'site-header__search-result';
1632
+ resultItem.setAttribute('data-search-result-index', index);
1633
+
1634
+ const imageHtml = product.thumbnailUrl
1635
+ ? `<img src="${product.thumbnailUrl}" alt="${escapeHtml(product.name)}" class="site-header__search-result-image" loading="lazy">`
1636
+ : `<div class="site-header__search-result-image" style="background-color: rgba(0,0,0,0.05); display: flex; align-items: center; justify-content: center; color: rgba(0,0,0,0.3); font-size: 0.75rem;">No image</div>`;
1637
+
1638
+ resultItem.innerHTML = `
1639
+ ${imageHtml}
1640
+ <div class="site-header__search-result-info">
1641
+ <div class="site-header__search-result-name">${escapeHtml(product.name)}</div>
1642
+ <div class="site-header__search-result-price">${product.prices.priceString || 'Price not available'}</div>
1643
+ </div>
1644
+ `;
1645
+
1646
+ resultItem.addEventListener('click', (e) => {
1647
+ e.preventDefault();
1648
+ window.location.href = resultItem.href;
1649
+ });
1650
+
1651
+ resultItem.addEventListener('mouseenter', () => {
1652
+ selectedIndex = index;
1653
+ updateDesktopSelected();
1654
+ });
1655
+
1656
+ searchResults.appendChild(resultItem);
1657
+ });
1658
+
1659
+ showDesktopDropdown();
1660
+ }
1661
+
1662
+ // Escape HTML to prevent XSS
1663
+ function escapeHtml(text) {
1664
+ const div = document.createElement('div');
1665
+ div.textContent = text;
1666
+ return div.innerHTML;
1667
+ }
1668
+
1669
+ // Show/hide dropdown
1670
+ function showDesktopDropdown() {
1671
+ if (searchDropdown) {
1672
+ searchDropdown.style.display = 'block';
1673
+ }
1674
+ }
1675
+
1676
+ function hideDesktopDropdown() {
1677
+ if (searchDropdown) {
1678
+ searchDropdown.style.display = 'none';
1679
+ }
1680
+ selectedIndex = -1;
1681
+ currentResults = [];
1682
+ }
1683
+
1684
+ function showDesktopLoading() {
1685
+ if (searchLoading) {
1686
+ searchLoading.style.display = 'flex';
1687
+ }
1688
+ if (searchResults) {
1689
+ searchResults.innerHTML = '';
1690
+ }
1691
+ }
1692
+
1693
+ function hideDesktopLoading() {
1694
+ if (searchLoading) {
1695
+ searchLoading.style.display = 'none';
1696
+ }
1697
+ }
1698
+
1699
+ function showDesktopEmpty() {
1700
+ if (searchEmpty) {
1701
+ searchEmpty.style.display = 'block';
1702
+ }
1703
+ showDesktopDropdown();
1704
+ }
1705
+
1706
+ function hideDesktopEmpty() {
1707
+ if (searchEmpty) {
1708
+ searchEmpty.style.display = 'none';
1709
+ }
1710
+ }
1711
+
1712
+ function updateDesktopSelected() {
1713
+ const results = searchResults.querySelectorAll('.site-header__search-result');
1714
+ results.forEach((result, index) => {
1715
+ if (index === selectedIndex) {
1716
+ result.style.backgroundColor = 'rgba(0, 0, 0, 0.06)';
1717
+ } else {
1718
+ result.style.backgroundColor = '';
1719
+ }
1720
+ });
1721
+ }
1722
+
1723
+ // Debounced search function
1724
+ const debouncedDesktopSearch = debounce(performDesktopSearch, 300);
1725
+
1726
+ // Input event handler
1727
+ if (searchInput) {
1728
+ searchInput.addEventListener('input', (e) => {
1729
+ const query = e.target.value.trim();
1730
+
1731
+ if (searchClear) {
1732
+ searchClear.style.display = query ? 'flex' : 'none';
1733
+ }
1734
+
1735
+ if (query.length >= 2) {
1736
+ debouncedDesktopSearch(query);
1737
+ } else {
1738
+ hideDesktopDropdown();
1739
+ }
1740
+ });
1741
+
1742
+ // Focus event handler
1743
+ searchInput.addEventListener('focus', () => {
1744
+ const query = searchInput.value.trim();
1745
+ if (query.length >= 2 && currentResults.length > 0) {
1746
+ showDesktopDropdown();
1747
+ }
1748
+ });
1749
+
1750
+ // Keyboard navigation
1751
+ searchInput.addEventListener('keydown', (e) => {
1752
+ const results = searchResults.querySelectorAll('.site-header__search-result');
1753
+
1754
+ if (e.key === 'ArrowDown') {
1755
+ e.preventDefault();
1756
+ selectedIndex = Math.min(selectedIndex + 1, results.length - 1);
1757
+ updateDesktopSelected();
1758
+ if (results[selectedIndex]) {
1759
+ results[selectedIndex].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
1760
+ }
1761
+ } else if (e.key === 'ArrowUp') {
1762
+ e.preventDefault();
1763
+ selectedIndex = Math.max(selectedIndex - 1, -1);
1764
+ updateDesktopSelected();
1765
+ if (selectedIndex >= 0 && results[selectedIndex]) {
1766
+ results[selectedIndex].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
1767
+ }
1768
+ } else if (e.key === 'Enter') {
1769
+ e.preventDefault();
1770
+ if (selectedIndex >= 0 && results[selectedIndex]) {
1771
+ window.location.href = results[selectedIndex].href;
1772
+ } else {
1773
+ // Submit form to search page
1774
+ searchForm.submit();
1775
+ }
1776
+ } else if (e.key === 'Escape') {
1777
+ hideDesktopDropdown();
1778
+ searchInput.blur();
1779
+ }
1780
+ });
1781
+ }
1782
+
1783
+ // Clear button handler
1784
+ if (searchClear) {
1785
+ searchClear.addEventListener('click', (e) => {
1786
+ e.preventDefault();
1787
+ if (searchInput) {
1788
+ searchInput.value = '';
1789
+ searchInput.focus();
1790
+ hideDesktopDropdown();
1791
+ searchClear.style.display = 'none';
1792
+ }
1793
+ });
1794
+ }
1795
+
1796
+ // Click outside to close dropdown
1797
+ document.addEventListener('click', (e) => {
1798
+ if (desktopSearchContainer && !desktopSearchContainer.contains(e.target)) {
1799
+ hideDesktopDropdown();
1800
+ }
1801
+ });
1802
+ }
1803
+ });
1804
+ </script>
1805
+