1 2<!DOCTYPE html> 3<html lang="en-US"> 4<head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 7 <meta name="generator" content="frappe"> 8 9 10 <meta name="title" content="Wizfort - Quality Leather Shoes for the Whole Family"><meta name="description" content="Shop Wizfort's affordable leather shoes for men, women, and kids. Durable everyday footwear with classic style and comfort. Free standard shipping for retail orders."><meta name="image" content="https://wizfort.com/files/wizfort-og.png"><meta property="og:type" content="website"><meta property="og:url" content="https://wizfort.com/"><meta property="og:site_name" content="Wizfort"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:alt" content="Wizfort - Quality Leather Shoes for the Whole Family"><meta name="twitter:image:alt" content="Wizfort - Quality Leather Shoes for the Whole Family"><meta name="language" content="en-US"><meta property="og:title" content="Wizfort - Quality Leather Shoes for the Whole Family"><meta property="og:description" content="Shop Wizfort's affordable leather shoes for men, women, and kids. Durable everyday footwear with classic style and comfort. Free standard shipping for retail orders."><meta property="og:image" content="https://wizfort.com/files/wizfort-og.png"><meta name="twitter:title" content="Wizfort - Quality Leather Shoes for the Whole Family"><meta name="twitter:description" content="Shop Wizfort's affordable leather shoes for men, women, and kids. Durable everyday footwear with classic style and comfort. Free standard shipping for retail orders."><meta name="twitter:image" content="https://wizfort.com/files/wizfort-og.png"><meta name="twitter:card" content="summary_large_image"><meta property="og:locale" content="en_US"> 11 12 13 <title>Wizfort - Quality Leather Shoes for the Whole Family</title> 14 15 16 <link rel="icon" type="image/png" href="/files/cslshoes89cb70.png"> 17 <link rel="apple-touch-icon" href="/files/cslshoes89cb70.png"> 18<link type="text/css" rel="stylesheet" href="/assets/frappe/dist/css/website.bundle.GD6PKXQI.css"> 19<link type="text/css" rel="stylesheet" href="/assets/erpnext/dist/css/erpnext-web.bundle.XAPV6OJR.css"> 20<link type="text/css" rel="stylesheet" href="/assets/webshop/dist/css/webshop-web.bundle.GQDT63VG.css"> 21<link type="text/css" rel="stylesheet" href="/assets/cslshoes_erp/css/csl_design_tokens.css?v=20260613a"> 22<link type="text/css" rel="stylesheet" href="/assets/cslshoes_erp/css/webshop_filters.css?v=4b435436"> 23<link type="text/css" rel="stylesheet" href="/assets/cslshoes_erp/css/csl_custom.css?v=20260517a"> 24<link type="text/css" rel="stylesheet" href="/assets/blog/css/blog.scss"> 25 26 27 28 <!-- CSL web analytics (GA4) â deferred loader (A3 2026-06-03) -->
29<script> 30 window.dataLayer = window.dataLayer || []; 31 function gtag(){dataLayer.push(arguments);} 32 gtag('consent', 'default', {'ad_storage':'granted','ad_user_data':'granted','ad_personalization':'granted','analytics_storage':'granted'}); 33 gtag('consent', 'default', {'ad_storage':'denied','ad_user_data':'denied','ad_personalization':'denied','analytics_storage':'denied','region':["AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "IS", "LI", "NO", "GB"]}); 34 gtag('js', new Date()); 35 gtag('config', 'G-WJ5VB6BGCD'); 36 // A3 2026-06-03: defer the gtag.js loader off the critical render path. 37 // dataLayer calls above queue; gtag.js drains them on load (interaction, 38 // or idle-after-load, or an 8s safety net) so pageview/consent/config still fire. 39 (function(){ 40 var loaded=false; 41 function loadGA(){ if(loaded){return;} loaded=true; 42 var s=document.createElement("script"); s.async=true; 43 s.src="https://www.googletagmanager.com/gtag/js?id=G-WJ5VB6BGCD"; 44 (document.head||document.documentElement).appendChild(s); 45 } 46 ["pointerdown","keydown","scroll","touchstart"].forEach(function(e){ window.addEventListener(e, loadGA, {once:true, passive:true}); }); 47 function schedule(){ if("requestIdleCallback" in window){ requestIdleCallback(loadGA,{timeout:3500}); } else { setTimeout(loadGA,2500); } } 48 if(document.readyState==="complete"){ schedule(); } else { window.addEventListener("load", schedule); } 49 setTimeout(loadGA, 8000); 50 })(); 51</script>
51 52 53 <style>a,button,[role="button"],input,select,textarea{touch-action:manipulation}</style> 54 <link rel="preload" as="font" type="font/woff2" href="/assets/cslshoes_erp/fonts/InterVariable-Latin.woff2" crossorigin> 55 <link rel="canonical" href="https://wizfort.com/"> 56 57 <meta property="fb:app_id" content="806042942283128"> 58 <link rel="alternate" type="application/rss+xml" title="Wizfort Blog" href="/rss"> 59
59<script type="application/ld+json">{"@context": "https://schema.org", "@type": "Organization", "name": "Wizfort", "url": "https://wizfort.com", "logo": "https://wizfort.com/files/wizfort-og.png", "image": "https://wizfort.com/files/wizfort-og.png", "address": {"@type": "PostalAddress", "streetAddress": "3 Alpine Court, Unit W156", "addressLocality": "Chestnut Ridge", "addressRegion": "NY", "postalCode": "10977", "addressCountry": "US"}, "contactPoint": {"@type": "ContactPoint", "telephone": "+1-845-694-6700", "contactType": "customer service", "availableLanguage": ["English"]}, "openingHoursSpecification": [{"@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], "opens": "09:00", "closes": "18:00"}, {"@type": "OpeningHoursSpecification", "dayOfWeek": "Saturday", "opens": "10:00", "closes": "16:00"}]}</script>
59 60
60<script type="application/ld+json">{"@context": "https://schema.org", "@type": "WebSite", "name": "Wizfort", "url": "https://wizfort.com", "potentialAction": {"@type": "SearchAction", "target": {"@type": "EntryPoint", "urlTemplate": "https://wizfort.com/all-products?search={search_term_string}"}, "query-input": "required name=search_term_string"}}</script>
60 61 62 63<link rel="preload" as="image" href="/files/383_1.webp" type="image/webp"> 64<style> 65 :root { 66 --white: #ffffff; 67 --gray-50: #f9fafb; 68 --gray-100: #f3f4f6; 69 --gray-200: #e5e7eb; 70 --gray-300: #d1d5db; 71 --gray-400: #9ca3af; 72 --gray-500: #6b7280; 73 --gray-600: #4b5563; 74 --gray-700: #374151; 75 --gray-800: #1f2937; 76 --gray-900: #111827; 77 --black: #000000; 78 --accent: #2563eb; 79 --success: #059669; 80 --warning: #f59e0b; 81 --danger: #ef4444; 82 --font-main: InterVariable, 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; 83 --container-max: 1400px; 84 } 85 86 /* Dark Mode Variables */ 87 [data-theme="dark"] { 88 --white: #111827; 89 --gray-50: #1f2937; 90 --gray-100: #374151; 91 --gray-200: #4b5563; 92 --gray-300: #6b7280; 93 --gray-400: #9ca3af; 94 --gray-500: #d1d5db; 95 --gray-600: #e5e7eb; 96 --gray-700: #f3f4f6; 97 --gray-800: #f9fafb; 98 --gray-900: #ffffff; 99 --black: #ffffff; 100 } 101 102 * { margin: 0; padding: 0; box-sizing: border-box; } 103 104 body { 105 font-family: var(--font-main); 106 font-size: 14px; 107 color: var(--gray-800); 108 background: var(--white); 109 line-height: 1.5; 110 } 111 112 a { color: inherit; text-decoration: none; } 113 114 .container { 115 max-width: var(--container-max); 116 margin: 0 auto; 117 padding: 0 20px; 118 } 119 120 /* Top Bar */ 121 .top-bar { 122 background: var(--gray-900); 123 color: var(--white); 124 padding: 8px 0; 125 font-size: 12px; 126 } 127 .top-bar-content { 128 display: flex; 129 justify-content: space-between; 130 align-items: center; 131 } 132 .top-bar-message { font-weight: 500; } 133 .top-bar-links { display: flex; gap: 20px; align-items: center; } 134 .top-bar-links a:hover { text-decoration: underline; } 135 .top-bar-phone { display: flex; align-items: center; gap: 5px; font-weight: 600; } 136 .top-bar-phone svg { flex-shrink: 0; } 137 138 /* Header */ 139 .header { 140 background: var(--white); 141 border-bottom: 1px solid var(--gray-200); 142 padding: 16px 0; 143 position: sticky; 144 top: 0; 145 z-index: 100; 146 } 147 .header-inner { 148 display: flex; 149 align-items: center; 150 justify-content: space-between; 151 gap: 40px; 152 } 153 .logo { 154 font-size: 24px; 155 font-weight: 700; 156 color: var(--black); 157 } 158 .nav { 159 display: flex; 160 align-items: center; 161 gap: 32px; 162 } 163 .nav a { 164 font-size: 14px; 165 font-weight: 500; 166 color: var(--gray-700); 167 transition: color 0.2s; 168 } 169 .nav a:hover { color: var(--black); } 170 .nav-dropdown { 171 position: relative; 172 } 173 .nav-dropdown > a { 174 display: flex; 175 align-items: center; 176 gap: 4px; 177 } 178 .nav-dropdown > a svg { 179 width: 12px; 180 height: 12px; 181 stroke: currentColor; 182 stroke-width: 2; 183 fill: none; 184 transition: transform 0.2s; 185 } 186 .nav-dropdown:hover > a svg { 187 transform: rotate(180deg); 188 } 189 .dropdown-menu { 190 position: absolute; 191 top: 100%; 192 left: 50%; 193 transform: translateX(-50%); 194 background: var(--white); 195 border: 1px solid var(--gray-200); 196 border-radius: 8px; 197 box-shadow: 0 8px 24px rgba(0,0,0,0.12); 198 min-width: 180px; 199 padding: 8px 0; 200 opacity: 0; 201 visibility: hidden; 202 transition: all 0.2s ease; 203 z-index: 1000; 204 margin-top: 8px; 205 } 206 .nav-dropdown:hover .dropdown-menu { 207 opacity: 1; 208 visibility: visible; 209 } 210 .dropdown-menu a { 211 display: block; 212 padding: 10px 16px; 213 font-size: 14px; 214 color: var(--gray-700); 215 transition: all 0.15s; 216 } 217 .dropdown-menu a:hover { 218 background: var(--gray-50); 219 color: var(--black); 220 } 221 .header-actions { 222 display: flex; 223 align-items: center; 224 gap: 20px; 225 } 226 .search-box { 227 display: flex; 228 align-items: center; 229 background: var(--gray-100); 230 border: 1px solid var(--gray-200); 231 border-radius: 6px; 232 padding: 8px 12px; 233 width: 280px; 234 position: relative; 235 z-index: 50; 236 cursor: text; 237 } 238 .search-box input { 239 border: none; 240 background: transparent; 241 outline: none; 242 font-size: 14px; 243 width: 100%; 244 margin-left: 8px; 245 cursor: text; 246 color: var(--gray-900); 247 } 248 .search-box input::placeholder { 249 color: var(--gray-500); 250 } 251 .search-box:focus-within { 252 border-color: var(--gray-400); 253 box-shadow: 0 0 0 2px rgba(0,0,0,0.05); 254 } 255 .search-box svg {
256 width: 20px; 257 height: 20px; 258 stroke: var(--gray-500); 259 stroke-width: 1.5; 260 fill: none; 261 pointer-events: none; 262 flex-shrink: 0; 263 } 264 .header-icon { 265 width: 20px; 266 height: 20px; 267 stroke: var(--gray-500); 268 stroke-width: 1.5; 269 fill: none; 270 } 271 .header-icon { cursor: pointer; } 272 .header-icon:hover { stroke: var(--black); } 273 .cart-icon { position: relative; } 274 .cart-count { 275 position: absolute; 276 top: -6px; 277 right: -6px; 278 background: var(--black); 279 color: var(--white); 280 font-size: 10px; 281 font-weight: 600; 282 width: 18px; 283 height: 18px; 284 border-radius: 50%; 285 display: flex; 286 align-items: center; 287 justify-content: center; 288 } 289 .wishlist-icon { position: relative; } 290 .wishlist-count { 291 position: absolute; 292 top: -6px; 293 right: -6px; 294 background: var(--black); 295 color: var(--white); 296 font-size: 10px; 297 font-weight: 600; 298 width: 18px; 299 height: 18px; 300 border-radius: 50%; 301 display: flex; 302 align-items: center; 303 justify-content: center; 304 } 305 306 /* Remove any wrapper padding from base template */ 307 .main-section, [data-page-container], .page-content-wrapper, .container-fluid, .web-container, .page-content { 308 padding-top: 0 !important; 309 margin-top: 0 !important; 310 } 311 312 /* Hero - pull up to meet header */ 313 .hero { 314 background: var(--gray-100); 315 padding: 0; 316 margin: 0; 317 margin-top: -40px; 318 } 319 .hero-content { 320 display: grid; 321 grid-template-columns: 1fr 1fr; 322 gap: 60px; 323 align-items: center; 324 } 325 .hero-text h1 { 326 font-size: 42px; 327 font-weight: 700; 328 color: var(--gray-900); 329 line-height: 1.2; 330 margin-bottom: 16px; 331 } 332 .hero-text p { 333 font-size: 16px; 334 color: var(--gray-600); 335 margin-bottom: 28px; 336 max-width: 400px; 337 } 338 .btn { 339 display: inline-flex; 340 align-items: center; 341 gap: 8px; 342 padding: 14px 28px; 343 font-size: 14px; 344 font-weight: 600; 345 border-radius: 6px; 346 cursor: pointer; 347 transition: all 0.2s; 348 border: none; 349 } 350 .btn-primary { 351 background: var(--black); 352 color: var(--white); 353 border: 1px solid var(--black); 354 } 355 .btn-primary:hover { background: var(--gray-800); border-color: var(--gray-800); } 356 .btn-secondary { 357 background: var(--white); 358 color: var(--gray-800); 359 border: 1px solid var(--gray-300); 360 } 361 .btn-secondary:hover { 362 background: var(--gray-50); 363 border-color: var(--gray-400); 364 } 365 .hero-buttons { display: flex; gap: 12px; } 366 .hero-image { 367 display: flex; 368 justify-content: center; 369 align-items: center; 370 cursor: pointer; 371 transition: transform 0.3s ease; 372 } 373 .hero-image:hover { 374 transform: scale(1.02); 375 } 376 .hero-image-wrapper { 377 position: relative; 378 min-height: 350px; 379 display: flex; 380 align-items: center; 381 justify-content: center; 382 } 383 .hero-image img { 384 max-width: 100%; 385 height: auto; 386 max-height: 400px; 387 object-fit: contain; 388 transition: opacity 0.5s ease; 389 } 390 .hero-placeholder { 391 display: flex; 392 flex-direction: column; 393 align-items: center; 394 justify-content: center; 395 color: var(--gray-400); 396 gap: 16px; 397 } 398 .hero-placeholder p { 399 font-size: 14px; 400 } 401 .hero-placeholder.hidden { 402 display: none; 403 } 404 /* Trust Bar */ 405 .trust-bar { 406 background: var(--gray-50); 407 border-top: 1px solid var(--gray-200); 408 border-bottom: 1px solid var(--gray-200); 409 padding: 14px 0; 410 margin-top: -30px; 411 } 412 .trust-items { 413 display: flex; 414 justify-content: center; 415 gap: 60px; 416 } 417 .trust-item { 418 display: flex; 419 align-items: center; 420 gap: 10px; 421 font-size: 13px; 422 color: var(--gray-600); 423 } 424 .trust-item svg { 425 width: 20px; 426 height: 20px; 427 stroke: var(--gray-500); 428 stroke-width: 1.5; 429 fill: none; 430 } 431 .trust-item strong { 432 color: var(--gray-800); 433 font-weight: 600; 434 } 435 436 /* Sections */ 437 .section { padding: 16px 0; } 438 .section-header { 439 display: flex; 440 align-items: center; 441 justify-content: space-between; 442 margin-bottom: 12px; 443 } 444 .section-title { 445 font-size: 24px; 446 font-weight: 700; 447 color: var(--gray-900); 448 } 449 .section-link { 450 font-size: 14px; 451 font-weight: 500; 452 color: var(--accent); 453 display: flex; 454 align-items: center; 455 gap: 4px; 456 } 457 .section-link:hover { text-decoration: underline; } 458 .section-link svg { 459 width: 16px; 460 height: 16px; 461 stroke: currentColor; 462 stroke-width: 2; 463 fill: none; 464 } 465 466 /* Categories */ 467 .categories-grid { 468 display: grid; 469 grid-template-columns: repeat(4, 1fr); 470 gap: 20px; 471 } 472 .category-card { 473 background: var(--gray-100); 474 border-radius: 12px; 475 padding: 20px 16px; 476 text-align: center; 477 transition: all 0.3s ease; 478 cursor: pointer; 479 border: 2px solid transparent; 480 display: flex; 481 flex-direction: column; 482 align-items: center; 483 } 484 .category-card:hover { 485 background: var(--white); 486 border-color: var(--gray-900); 487 transform: translateY(-2px); 488 } 489 .category-icon { 490 width: 115px; 491 height: 80px; 492 margin-bottom: 12px; 493 display: flex; 494 align-items: center; 495 justify-content: center; 496 overflow: hidden; 497 border-radius: 8px; 498 background: transparent; 499 } 500 .category-icon img { 501 width: 100%; 502 height: 100%; 503 object-fit: contain; 504 transition: opacity 0.15s ease-in-out; 505 } 506 .category-icon svg { 507 transition: transform 0.3s ease; 508 } 509 .category-card:hover .category-icon svg { 510 transform: scale(1.1); 511 } 512 .category-card h3 { 513 font-size: 14px; 514 font-weight: 600; 515 color: var(--gray-900); 516 margin-bottom: 2px; 517 } 518 .category-card p { 519 font-size: 12px; 520 color: var(--gray-500); 521 } 522 523 /* Products */ 524 .products-grid { 525 display: flex; 526 justify-content: center; 527 flex-wrap: wrap; 528 gap: 24px; 529 } 530 .product-card { 531 background: var(--white); 532 border: 1px solid var(--gray-200); 533 border-radius: 12px; 534 overflow: hidden; 535 transition: all 0.3s ease; 536 cursor: pointer; 537 width: 280px; 538 } 539 .product-card:hover { 540 border-color: var(--gray-300); 541 box-shadow: 0 8px 24px rgba(0,0,0,0.12); 542 transform: translateY(-4px); 543 } 544 .product-image { 545 position: relative; 546 background: var(--gray-50); 547 padding: 20px; 548 aspect-ratio: 1; 549 display: flex; 550 align-items: center; 551 justify-content: center; 552 } 553 .product-image img { 554 max-width: 100%; 555 max-height: 100%; 556 object-fit: contain; 557 } 558 .product-badge { 559 position: absolute; 560 top: 12px; 561 left: 12px; 562 padding: 4px 10px; 563 font-size: 11px; 564 font-weight: 600; 565 border-radius: 4px; 566 text-transform: uppercase; 567 } 568 .product-info { padding: 16px; } 569 .product-brand { 570 font-size: 12px; 571 font-weight: 500; 572 color: var(--gray-500); 573 text-transform: uppercase; 574 letter-spacing: 0.5px; 575 margin-bottom: 4px; 576 } 577 .product-name { 578 font-size: 14px; 579 font-weight: 600; 580 color: var(--gray-900); 581 margin-bottom: 8px; 582 line-height: 1.4; 583 } 584 .product-price { 585 font-size: 16px; 586 font-weight: 700; 587 color: var(--gray-900); 588 } 589 .product-actions { padding: 0 16px 16px; } 590 .btn-add-cart { 591 width: 100%; 592 padding: 10px; 593 background: var(--white); 594 border: 1px solid var(--gray-300); 595 border-radius: 6px; 596 font-size: 13px; 597 font-weight: 600; 598 color: var(--gray-700); 599 cursor: pointer; 600 transition: all 0.2s; 601 } 602 .btn-add-cart:hover { 603 background: var(--black); 604 border-color: var(--black); 605 color: var(--white); 606 } 607 608 /* Brands */ 609 .brands-section { background: var(--gray-50); } 610 .brands-grid { 611 display: flex; 612 justify-content: center; 613 flex-wrap: wrap; 614 gap: 24px; 615 } 616 .brand-item { 617 text-align: center; 618 padding: 24px; 619 display: flex; 620 flex-direction: column; 621 align-items: center; 622 gap: 12px; 623 background: var(--white); 624 border-radius: 12px; 625 border: 1px solid var(--gray-200); 626 transition: all 0.3s ease; 627 } 628 .brand-item:hover { 629 border-color: var(--gray-900); 630 transform: translateY(-2px); 631 box-shadow: 0 8px 24px rgba(0,0,0,0.08); 632 } 633 .brand-logo { 634 width: 120px; 635 height: 80px; 636 display: flex; 637 align-items: center; 638 justify-content: center; 639 }
640 .brand-logo img { 641 max-width: 100%; 642 max-height: 100%; 643 object-fit: contain; 644 } 645 .brand-logo-fallback { 646 width: 60px; 647 height: 60px; 648 background: var(--gray-900); 649 color: var(--white); 650 border-radius: 50%; 651 display: flex; 652 align-items: center; 653 justify-content: center; 654 font-size: 24px; 655 font-weight: 700; 656 } 657 .brand-name { 658 font-size: 16px; 659 font-weight: 600; 660 color: var(--gray-800); 661 } 662 663 /* Value Props */ 664 .value-props { 665 background: var(--gray-900); 666 color: var(--white); 667 padding: 50px 0; 668 } 669 .value-grid { 670 display: grid; 671 grid-template-columns: repeat(4, 1fr); 672 gap: 40px; 673 text-align: center; 674 } 675 .value-item svg { 676 width: 32px; 677 height: 32px; 678 stroke: var(--white); 679 stroke-width: 1.5; 680 fill: none; 681 margin-bottom: 12px; 682 } 683 .value-item .value-title { 684 display: block; 685 font-size: 14px; 686 font-weight: 600; 687 margin-bottom: 6px; 688 } 689 .value-item p { 690 font-size: 13px; 691 color: var(--gray-400); 692 } 693 694 /* Why CSL Shoes */ 695 .why-csl { 696 padding: 70px 0; 697 background: var(--gray-50); 698 border-top: 1px solid var(--gray-200); 699 } 700 .why-csl-inner { 701 max-width: 800px; 702 margin: 0 auto; 703 text-align: center; 704 } 705 .why-csl-inner h2 { 706 font-size: 26px; 707 font-weight: 700; 708 color: var(--gray-900); 709 margin-bottom: 24px; 710 } 711 .why-csl-inner p { 712 font-size: 15px; 713 color: var(--gray-600); 714 line-height: 1.8; 715 margin-bottom: 18px; 716 } 717 .why-csl-inner p:last-of-type { 718 margin-bottom: 0; 719 } 720 .why-csl-link { 721 display: inline-block; 722 margin-top: 24px; 723 font-size: 14px; 724 font-weight: 600; 725 color: var(--gray-900); 726 text-decoration: underline; 727 } 728 .why-csl-link:hover { 729 color: var(--accent); 730 } 731 732 /* Newsletter */ 733 .newsletter { 734 padding: 60px 0; 735 background: var(--white); 736 border-top: 1px solid var(--gray-200); 737 } 738 .newsletter-content { 739 max-width: 500px; 740 margin: 0 auto; 741 text-align: center; 742 } 743 .newsletter-content h2 { 744 font-size: 24px; 745 font-weight: 700; 746 color: var(--gray-900); 747 margin-bottom: 8px; 748 } 749 .newsletter-content p { 750 font-size: 14px; 751 color: var(--gray-600); 752 margin-bottom: 24px; 753 } 754 .newsletter-form { 755 display: flex; 756 gap: 10px; 757 } 758 .newsletter-form input { 759 flex: 1; 760 padding: 12px 16px; 761 border: 1px solid var(--gray-300); 762 border-radius: 6px; 763 font-size: 14px; 764 outline: none; 765 } 766 .newsletter-form input:focus { border-color: var(--gray-400); } 767 .newsletter-form button { 768 padding: 12px 24px; 769 background: var(--black); 770 color: var(--white); 771 border: none; 772 border-radius: 6px; 773 font-size: 14px; 774 font-weight: 600; 775 cursor: pointer; 776 } 777 .newsletter-form button:hover { background: var(--gray-800); } 778 779 /* Footer styles moved to csl_footer.html shared template */ 780 781 /* Loading State */ 782 .loading { 783 text-align: center; 784 padding: 40px; 785 color: var(--gray-500); 786 } 787 .loading-spinner { 788 width: 40px; 789 height: 40px; 790 border: 3px solid var(--gray-200); 791 border-top-color: var(--black); 792 border-radius: 50%; 793 animation: spin 1s linear infinite; 794 margin: 0 auto 16px; 795 } 796 @keyframes spin { 797 to { transform: rotate(360deg); } 798 } 799 800 /* Mobile Menu Toggle */ 801 .mobile-menu-toggle { 802 display: none; 803 width: 40px; 804 height: 40px; 805 background: none; 806 border: 1px solid var(--gray-300); 807 border-radius: 8px; 808 cursor: pointer; 809 align-items: center; 810 justify-content: center; 811 } 812 .mobile-menu-toggle svg { 813 width: 24px; 814 height: 24px; 815 stroke: var(--gray-700); 816 } 817 .mobile-nav { 818 display: none; 819 position: fixed; 820 top: 0; 821 left: 0; 822 right: 0; 823 bottom: 0; 824 background: var(--white); 825 z-index: 9999; 826 padding: 20px; 827 flex-direction: column; 828 overflow-y: auto; 829 } 830 .mobile-nav.active { display: flex; } 831 .mobile-nav-header { 832 display: flex; 833 justify-content: space-between; 834 align-items: center; 835 margin-bottom: 24px; 836 padding-bottom: 16px; 837 border-bottom: 1px solid var(--gray-200); 838 } 839 .mobile-nav-close { 840 width: 40px; 841 height: 40px; 842 background: none; 843 border: none; 844 cursor: pointer; 845 display: flex; 846 align-items: center; 847 justify-content: center; 848 } 849 .mobile-nav-close svg { 850 width: 24px; 851 height: 24px; 852 stroke: var(--gray-700); 853 } 854 .mobile-nav-links { 855 display: flex; 856 flex-direction: column; 857 gap: 0; 858 } 859 .mobile-nav-links a { 860 padding: 16px 0; 861 font-size: 18px; 862 font-weight: 500; 863 color: var(--gray-800); 864 border-bottom: 1px solid var(--gray-100); 865 } 866 .mobile-nav-links a:hover { color: var(--accent); } 867 .mobile-search { 868 margin-top: 24px; 869 padding: 12px 16px; 870 background: var(--gray-100); 871 border: 1px solid var(--gray-200); 872 border-radius: 8px; 873 font-size: 16px; 874 width: 100%; 875 } 876 877 /* Sticky Mobile Cart Bar */ 878 .sticky-cart-bar { 879 display: none; 880 position: fixed; 881 bottom: 0; 882 left: 0; 883 right: 0; 884 background: var(--white); 885 border-top: 1px solid var(--gray-200); 886 padding: 10px 16px; 887 z-index: 999; 888 box-shadow: 0 -2px 10px rgba(0,0,0,0.1); 889 align-items: center; 890 gap: 12px; 891 transform: translateY(100%); 892 transition: transform 0.3s ease; 893 } 894 .sticky-cart-bar.visible { 895 transform: translateY(0); 896 } 897 .sticky-cart-bar-img { 898 width: 44px; 899 height: 44px; 900 border-radius: 6px; 901 object-fit: contain; 902 background: var(--gray-50); 903 flex-shrink: 0; 904 } 905 .sticky-cart-bar-info { 906 flex: 1; 907 min-width: 0; 908 } 909 .sticky-cart-bar-name { 910 font-size: 13px; 911 font-weight: 600; 912 color: var(--gray-900); 913 white-space: nowrap; 914 overflow: hidden; 915 text-overflow: ellipsis; 916 } 917 .sticky-cart-bar-price { 918 font-size: 14px; 919 font-weight: 700; 920 color: var(--gray-900); 921 } 922 .sticky-cart-bar .btn-add-cart { 923 flex-shrink: 0; 924 padding: 10px 20px; 925 font-size: 13px; 926 font-weight: 600; 927 width: auto; 928 } 929 @media (min-width: 769px) { 930 .sticky-cart-bar { display: none !important; } 931 } 932 @media (max-width: 768px) { 933 .sticky-cart-bar { display: flex; } 934 } 935 936 /* Responsive - Tablet */ 937 @media (max-width: 1024px) { 938 .hero-content { grid-template-columns: 1fr; text-align: center; } 939 .hero-text p { max-width: 100%; margin-left: auto; margin-right: auto; } 940 .hero-buttons { justify-content: center; } 941 .hero-image { order: -1; } 942 .categories-grid { grid-template-columns: repeat(2, 1fr); } 943 .value-grid { grid-template-columns: repeat(2, 1fr); } 944 /* footer responsive moved to csl_footer.html */ 945 .social-grid { grid-template-columns: repeat(3, 1fr); }
946 .modal-content { grid-template-columns: 1fr; } 947 .size-guide-link { display: none; } 948 } 949 950 /* Responsive - Mobile */ 951 @media (max-width: 768px) { 952 953 .top-bar { padding: 6px 0; } 954 .top-bar-links { display: none; } 955 .top-bar-message { font-size: 11px; text-align: center; width: 100%; } 956 957 .header { padding: 12px 0; } 958 .header-inner { gap: 12px; } 959 .logo { font-size: 20px; } 960 .nav, .search-box, .size-guide-link { display: none; } 961 .mobile-menu-toggle { display: flex; } 962 .header-actions { gap: 12px; } 963 .theme-toggle { width: 32px; height: 32px; } 964 .header-icon { width: 18px; height: 18px; } 965 .cart-count, .wishlist-count { width: 16px; height: 16px; font-size: 9px; top: -4px; right: -4px; } 966 967 .hero { padding: 0; } 968 .hero-text h1 { font-size: 28px; line-height: 1.3; } 969 .hero-text p { font-size: 14px; margin-bottom: 20px; } 970 .hero-buttons { flex-direction: column; gap: 10px; } 971 .btn { width: 100%; justify-content: center; padding: 12px 20px; } 972 .hero-image img { max-height: 280px; } 973 974 .trust-bar { padding: 3px 0; } 975 .trust-items { flex-wrap: wrap; gap: 16px; justify-content: center; } 976 .trust-item { font-size: 11px; gap: 6px; } 977 .trust-item svg { width: 16px; height: 16px; } 978 979 .section { padding: 6px 0; } 980 .section-header { flex-direction: column; gap: 12px; align-items: flex-start; } 981 .section-title { font-size: 20px; } 982 983 .filter-bar { justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; padding-bottom: 10px; gap: 8px; } 984 .filter-btn { flex-shrink: 0; padding: 6px 12px; font-size: 12px; } 985 986 .categories-grid { 987 display: flex; 988 overflow-x: auto; 989 scroll-snap-type: x mandatory; 990 -webkit-overflow-scrolling: touch; 991 gap: 12px; 992 padding-bottom: 8px; 993 scrollbar-width: none; 994 } 995 .categories-grid::-webkit-scrollbar { display: none; } 996 .category-card { 997 flex: 0 0 auto; 998 width: 140px; 999 padding: 16px 12px; 1000 scroll-snap-align: start; 1001 } 1002 .category-icon { width: 92px; height: 58px; margin-bottom: 12px; } 1003 .category-card h3 { font-size: 14px; } 1004 .category-card p { font-size: 11px; } 1005 1006 .products-grid { gap: 16px; } 1007 .product-card { width: calc(50% - 8px); min-width: 150px; max-width: none; } 1008 .product-image { padding: 12px; } 1009 .product-badge { font-size: 9px; padding: 3px 6px; top: 8px; left: 8px; } 1010 .quick-view-btn { display: none; } 1011 .product-info { padding: 12px; } 1012 .product-brand { font-size: 10px; } 1013 .star-rating { margin-bottom: 4px; } 1014 .stars svg { width: 12px; height: 12px; } 1015 .review-count { font-size: 10px; } 1016 .product-name { font-size: 13px; margin-bottom: 6px; line-height: 1.3; } 1017 .product-price { font-size: 14px; } 1018 .product-price .original-price { font-size: 11px; display: block; margin-left: 0; margin-top: 2px; } 1019 .product-price .discount-tag { font-size: 9px; padding: 1px 4px; } 1020 .color-swatches { margin-top: 6px; gap: 4px; } 1021 .color-swatch { width: 14px; height: 14px; } 1022 .size-pills { margin-top: 6px; padding-top: 6px; gap: 3px; } 1023 .size-pill { font-size: 9px; padding: 2px 4px; } 1024 .product-actions { padding: 8px 12px 12px; } 1025 .btn-add-cart { padding: 8px; font-size: 12px; } 1026 1027 .brands-section { padding: 40px 0; } 1028 .brands-grid { gap: 12px; } 1029 .brand-item { padding: 16px; } 1030 .brand-logo { width: 80px; height: 50px; } 1031 .brand-name { font-size: 14px; } 1032 1033 .value-props { padding: 40px 0; } 1034 .value-grid { grid-template-columns: repeat(2, 1fr); gap: 24px; } 1035 .value-item svg { width: 28px; height: 28px; margin-bottom: 8px; } 1036 .value-item .value-title { font-size: 12px; } 1037 .value-item p { font-size: 11px; } 1038 1039 .why-csl { padding: 40px 0; } 1040 .why-csl-inner h2 { font-size: 20px; } 1041 .why-csl-inner p { font-size: 14px; } 1042 1043 .newsletter { padding: 40px 0; } 1044 .newsletter-content h2 { font-size: 20px; } 1045 .newsletter-content p { font-size: 13px; } 1046 .newsletter-form { flex-direction: column; gap: 8px; } 1047 .newsletter-form input, .newsletter-form button { width: 100%; } 1048 1049 1050 .social-section { padding: 40px 0; } 1051 .social-grid { grid-template-columns: repeat(3, 1fr); gap: 6px; } 1052 1053 .recently-viewed { padding: 30px 0; } 1054 .recently-grid { gap: 12px; } 1055 .recently-item { width: 120px; padding: 10px; } 1056 .recently-item img { height: 80px; } 1057 .recently-item p { font-size: 11px; } 1058 1059 /* footer mobile responsive moved to csl_footer.html */ 1060 1061 .preview-banner { left: 10px; right: 10px; bottom: 10px; padding: 12px 16px; flex-direction: column; gap: 10px; text-align: center; } 1062 .preview-info { flex-direction: column; gap: 8px; } 1063 1064 /* Mobile touch targets â 44px minimum per Google guidelines */ 1065 .filter-btn { min-height: 44px; min-width: 44px; } 1066 .color-swatch { width: 28px; height: 28px; margin: 4px; } 1067 .size-pill { min-height: 32px; min-width: 32px; padding: 6px 8px; } 1068 .section-link { min-height: 44px; display: inline-flex; align-items: center; } 1069 } 1070 1071 /* Responsive - Small Mobile */ 1072 @media (max-width: 480px) { 1073 .container { padding: 0 16px; } 1074 .hero-text h1 { font-size: 24px; } 1075 .product-card { width: calc(50% - 6px); min-width: 140px; } 1076 .category-card { width: 130px; padding: 14px 8px; } 1077 .value-grid { grid-template-columns: 1fr 1fr; gap: 16px; } 1078 .social-grid { grid-template-columns: repeat(2, 1fr); } 1079 } 1080 1081 1082 /* Star Ratings */ 1083 .star-rating { 1084 display: flex; 1085 align-items: center; 1086 gap: 4px; 1087 margin-bottom: 6px; 1088 } 1089 .stars { 1090 display: flex; 1091 gap: 1px; 1092 } 1093 .stars svg { 1094 width: 14px; 1095 height: 14px; 1096 } 1097 .stars .filled { fill: #fbbf24; stroke: #fbbf24; } 1098 .stars .empty { fill: none; stroke: #d1d5db; } 1099 .review-count { 1100 font-size: 12px; 1101 color: var(--gray-500); 1102 } 1103 1104 /* Product Badges â canonical styles live in csl_custom.css (.badge-sale, .badge-toprated, .badge-* family) */ 1105 1106 /* Size Pills */ 1107 .size-pills { 1108 display: flex; 1109 flex-wrap: wrap; 1110 gap: 4px; 1111 margin-top: 8px; 1112 padding-top: 8px; 1113 border-top: 1px solid var(--gray-200); 1114 } 1115 .size-pill { 1116 font-size: 10px; 1117 padding: 2px 6px; 1118 background: var(--gray-100); 1119 border-radius: 4px; 1120 color: var(--gray-600); 1121 } 1122 .size-pill.available { 1123 background: var(--gray-900); 1124 color: var(--white); 1125 } 1126 1127 /* Color Swatches */ 1128 .color-swatches { 1129 display: flex; 1130 gap: 6px; 1131 margin-top: 8px; 1132 } 1133 .color-swatch { 1134 width: 16px; 1135 height: 16px; 1136 border-radius: 50%; 1137 border: 2px solid var(--white); 1138 box-shadow: 0 0 0 1px var(--gray-300); 1139 cursor: pointer; 1140 } 1141 .color-swatch:hover { 1142 box-shadow: 0 0 0 2px var(--gray-900); 1143 } 1144 1145 /* Quick View Modal */
1146 .modal-overlay { 1147 position: fixed; 1148 top: 0; 1149 left: 0; 1150 right: 0; 1151 bottom: 0; 1152 background: rgba(0,0,0,0.6); 1153 z-index: 10000; 1154 display: none; 1155 align-items: center; 1156 justify-content: center; 1157 padding: 20px; 1158 } 1159 .modal-overlay.active { display: flex; } 1160 .modal-content { 1161 background: var(--white); 1162 border-radius: 16px; 1163 max-width: 900px; 1164 width: 100%; 1165 max-height: 90vh; 1166 overflow-y: auto; 1167 display: grid; 1168 grid-template-columns: 1fr 1fr; 1169 gap: 0; 1170 } 1171 .modal-image { 1172 background: var(--gray-50); 1173 padding: 40px; 1174 display: flex; 1175 align-items: center; 1176 justify-content: center; 1177 } 1178 .modal-image img { 1179 max-width: 100%; 1180 max-height: 400px; 1181 object-fit: contain; 1182 } 1183 .modal-details { 1184 padding: 40px; 1185 } 1186 .modal-close { 1187 position: absolute; 1188 top: 20px; 1189 right: 20px; 1190 width: 40px; 1191 height: 40px; 1192 background: var(--white); 1193 border: none; 1194 border-radius: 50%; 1195 cursor: pointer; 1196 display: flex; 1197 align-items: center; 1198 justify-content: center; 1199 box-shadow: 0 2px 8px rgba(0,0,0,0.15); 1200 } 1201 .modal-close svg { 1202 width: 20px; 1203 height: 20px; 1204 stroke: var(--gray-600); 1205 } 1206 .modal-brand { 1207 font-size: 12px; 1208 text-transform: uppercase; 1209 color: var(--gray-500); 1210 letter-spacing: 1px; 1211 margin-bottom: 8px; 1212 } 1213 .modal-title { 1214 font-size: 24px; 1215 font-weight: 700; 1216 color: var(--gray-900); 1217 margin-bottom: 12px; 1218 } 1219 .modal-price { 1220 font-size: 28px; 1221 font-weight: 700; 1222 color: var(--gray-900); 1223 margin-bottom: 16px; 1224 } 1225 .modal-price .original { 1226 font-size: 18px; 1227 color: var(--gray-400); 1228 text-decoration: line-through; 1229 margin-left: 8px; 1230 } 1231 .modal-sizes { 1232 margin: 20px 0; 1233 } 1234 .modal-sizes h4 { 1235 font-size: 14px; 1236 font-weight: 600; 1237 margin-bottom: 10px; 1238 } 1239 .size-grid { 1240 display: flex; 1241 flex-wrap: wrap; 1242 gap: 8px; 1243 } 1244 .size-btn { 1245 padding: 10px 16px; 1246 border: 1px solid var(--gray-300); 1247 background: var(--white); 1248 border-radius: 6px; 1249 font-size: 14px; 1250 cursor: pointer; 1251 transition: all 0.2s; 1252 } 1253 .size-btn:hover { border-color: var(--gray-900); } 1254 .size-btn.selected { 1255 background: var(--gray-900); 1256 color: var(--white); 1257 border-color: var(--gray-900); 1258 } 1259 .size-btn.unavailable { 1260 opacity: 0.4; 1261 cursor: not-allowed; 1262 } 1263 .modal-actions { 1264 display: flex; 1265 gap: 12px; 1266 margin-top: 24px; 1267 } 1268 .modal-actions .btn { flex: 1; justify-content: center; } 1269 1270 /* Filter Buttons */ 1271 .filter-bar { 1272 display: flex; 1273 gap: 12px; 1274 margin-bottom: 24px; 1275 flex-wrap: wrap; 1276 justify-content: center; 1277 } 1278 .filter-btn { 1279 padding: 8px 16px; 1280 background: var(--white); 1281 border: 1px solid var(--gray-300); 1282 border-radius: 20px; 1283 font-size: 13px; 1284 font-weight: 500; 1285 color: var(--gray-700); 1286 cursor: pointer; 1287 transition: all 0.2s; 1288 } 1289 .filter-btn:hover { 1290 border-color: var(--gray-900); 1291 } 1292 .filter-btn.active { 1293 background: var(--gray-900); 1294 color: var(--white); 1295 border-color: var(--gray-900); 1296 } 1297 1298 /* Testimonials */ 1299 1300 /* Social Feed */ 1301 .social-section { 1302 padding: 60px 0; 1303 background: var(--gray-50); 1304 } 1305 .social-grid { 1306 display: grid; 1307 grid-template-columns: repeat(6, 1fr); 1308 gap: 8px; 1309 } 1310 .social-item { 1311 aspect-ratio: 1; 1312 background: var(--gray-200); 1313 border-radius: 8px; 1314 overflow: hidden; 1315 position: relative; 1316 cursor: pointer; 1317 } 1318 .social-item img { 1319 width: 100%; 1320 height: 100%; 1321 object-fit: cover; 1322 transition: transform 0.3s; 1323 } 1324 .social-item:hover img { 1325 transform: scale(1.1); 1326 } 1327 .social-item .overlay { 1328 position: absolute; 1329 inset: 0; 1330 background: rgba(0,0,0,0.4); 1331 display: flex; 1332 align-items: center; 1333 justify-content: center; 1334 opacity: 0; 1335 transition: opacity 0.3s; 1336 } 1337 .social-item:hover .overlay { opacity: 1; } 1338 .social-item .overlay svg { 1339 width: 24px; 1340 height: 24px; 1341 stroke: white; 1342 } 1343 1344 /* Trust Badges */ 1345 .trust-badges-section { 1346 padding: 40px 0; 1347 background: var(--white); 1348 border-top: 1px solid var(--gray-100); 1349 } 1350 .trust-badges-grid { 1351 display: flex; 1352 justify-content: center; 1353 align-items: center; 1354 flex-wrap: wrap; 1355 gap: 24px; 1356 } 1357 .trust-badge-item { 1358 display: flex; 1359 align-items: center; 1360 gap: 10px; 1361 padding: 12px 20px; 1362 background: var(--gray-50); 1363 border-radius: 8px; 1364 border: 1px solid var(--gray-200); 1365 } 1366 .trust-badge-item svg { 1367 width: 24px; 1368 height: 24px; 1369 stroke: var(--gray-600); 1370 fill: none; 1371 stroke-width: 1.5; 1372 flex-shrink: 0; 1373 } 1374 .trust-badge-item span { 1375 font-size: 13px; 1376 color: var(--gray-700); 1377 font-weight: 500; 1378 } 1379 .payment-logos { 1380 display: flex; 1381 justify-content: center; 1382 align-items: center; 1383 gap: 16px; 1384 margin-top: 24px; 1385 } 1386 .payment-logos img { 1387 height: 28px; 1388 width: auto; 1389 opacity: 0.7; 1390 transition: opacity 0.2s; 1391 } 1392 .payment-logos img:hover { opacity: 1; } 1393 .payment-logos span { 1394 font-size: 12px; 1395 color: var(--gray-400); 1396 font-weight: 500; 1397 } 1398 1399 /* Customer Reviews / Testimonials */ 1400 .testimonials-section { 1401 padding: 60px 0; 1402 background: var(--gray-50); 1403 } 1404 .testimonials-grid { 1405 display: grid; 1406 grid-template-columns: repeat(3, 1fr); 1407 gap: 24px; 1408 margin-top: 32px; 1409 } 1410 .testimonial-card { 1411 background: var(--white); 1412 border: 1px solid var(--gray-200); 1413 border-radius: 12px; 1414 padding: 28px; 1415 display: flex; 1416 flex-direction: column; 1417 gap: 12px; 1418 } 1419 .testimonial-stars { 1420 display: flex; 1421 gap: 2px; 1422 } 1423 .testimonial-stars svg { 1424 width: 16px; 1425 height: 16px; 1426 fill: #f59e0b; 1427 } 1428 .testimonial-title { 1429 font-size: 15px; 1430 font-weight: 600; 1431 color: var(--gray-900); 1432 line-height: 1.4; 1433 } 1434 .testimonial-text { 1435 font-size: 13px; 1436 line-height: 1.6; 1437 color: var(--gray-600); 1438 flex: 1; 1439 } 1440 .testimonial-footer { 1441 display: flex; 1442 align-items: center; 1443 gap: 10px; 1444 margin-top: 4px; 1445 } 1446 .testimonial-avatar { 1447 width: 36px; 1448 height: 36px; 1449 border-radius: 50%; 1450 background: var(--gray-200); 1451 display: flex; 1452 align-items: center; 1453 justify-content: center; 1454 font-size: 13px; 1455 font-weight: 600; 1456 color: var(--gray-600); 1457 flex-shrink: 0; 1458 } 1459 .testimonial-author { 1460 font-size: 13px; 1461 font-weight: 600; 1462 color: var(--gray-800); 1463 } 1464 .testimonial-meta { 1465 font-size: 11px; 1466 color: var(--gray-400); 1467 } 1468 .testimonial-verified { 1469 display: inline-flex; 1470 align-items: center; 1471 gap: 4px; 1472 font-size: 11px; 1473 color: var(--success); 1474 font-weight: 500; 1475 } 1476 .testimonial-verified svg { 1477 width: 12px; 1478 height: 12px; 1479 fill: currentColor; 1480 } 1481 @media (max-width: 1024px) { 1482 .testimonials-grid { grid-template-columns: repeat(2, 1fr); } 1483 } 1484 @media (max-width: 768px) { 1485 .testimonials-section { padding: 40px 0; } 1486 .testimonials-grid { grid-template-columns: 1fr; gap: 16px; } 1487 .testimonial-card { padding: 20px; } 1488 } 1489 1490 /* Recently Viewed */ 1491 .recently-viewed { 1492 padding: 40px 0; 1493 background: var(--white); 1494 border-top: 1px solid var(--gray-200); 1495 display: none; 1496 } 1497 .recently-viewed.has-items { display: block; } 1498 .recently-grid { 1499 display: flex; 1500 gap: 16px; 1501 overflow-x: auto; 1502 padding-bottom: 10px; 1503 } 1504 .recently-item { 1505 flex-shrink: 0; 1506 width: 150px; 1507 background: var(--gray-50); 1508 border-radius: 8px; 1509 padding: 12px; 1510 text-align: center; 1511 text-decoration: none; 1512 display: flex; 1513 flex-direction: column; 1514 transition: border-color 0.2s; 1515 border: 1px solid transparent; 1516 } 1517 .recently-item:hover { 1518 border-color: var(--gray-300); 1519 } 1520 .recently-item img { 1521 width: 100%; 1522 height: 100px; 1523 object-fit: contain; 1524 margin-bottom: 8px; 1525 } 1526 .recently-item-name { 1527 font-size: 12px; 1528 color: var(--gray-700); 1529 white-space: nowrap; 1530 overflow: hidden; 1531 text-overflow: ellipsis; 1532 margin-bottom: 4px; 1533 } 1534 .recently-item-price { 1535 font-size: 13px; 1536 font-weight: 600; 1537 color: var(--gray-900); 1538 margin-bottom: 8px; 1539 } 1540 .recently-item-cart { 1541 margin-top: auto; 1542 padding: 6px 10px; 1543 font-size: 11px; 1544 font-weight: 600; 1545 background: var(--gray-900); 1546 color: var(--white); 1547 border: none; 1548 border-radius: 4px; 1549 cursor: pointer; 1550 transition: background 0.2s; 1551 } 1552 .recently-item-cart:hover { 1553 background: var(--gray-700); 1554 } 1555 1556 /* Dark Mode Toggle */ 1557 .theme-toggle { 1558 width: 36px; 1559 height: 36px; 1560 display: flex; 1561 align-items: center; 1562 justify-content: center; 1563 background: var(--gray-100); 1564 border: 1px solid var(--gray-200); 1565 border-radius: 8px; 1566 cursor: pointer; 1567 transition: all 0.2s; 1568 } 1569 .theme-toggle:hover { 1570 background: var(--gray-200); 1571 } 1572 .theme-toggle svg { 1573 width: 18px; 1574 height: 18px; 1575 stroke: var(--gray-600); 1576 } 1577 .theme-toggle .sun { display: none; } 1578 .theme-toggle .moon { display: block; } 1579 [data-theme="dark"] .theme-toggle .sun { display: block; } 1580 [data-theme="dark"] .theme-toggle .moon { display: none; } 1581 1582 /* Size Guide Link */ 1583 .size-guide-link { 1584 font-size: 13px; 1585 color: var(--accent); 1586 display: flex; 1587 align-items: center; 1588 gap: 4px; 1589 margin-left: 16px; 1590 } 1591 .size-guide-link:hover { text-decoration: underline; } 1592 .size-guide-link svg { 1593 width: 14px; 1594 height: 14px; 1595 stroke: currentColor; 1596 } 1597 1598 /* Quick View Button */ 1599 .quick-view-btn { 1600 position: absolute; 1601 bottom: 12px; 1602 left: 50%; 1603 transform: translateX(-50%) translateY(10px); 1604 padding: 8px 16px; 1605 background: var(--white); 1606 border: 1px solid var(--gray-300); 1607 border-radius: 6px; 1608 font-size: 12px; 1609 font-weight: 600; 1610 cursor: pointer; 1611 opacity: 0; 1612 transition: all 0.3s; 1613 white-space: nowrap; 1614 } 1615 .product-card:hover .quick-view-btn { 1616 opacity: 1; 1617 transform: translateX(-50%) translateY(0); 1618 } 1619 .quick-view-btn:hover { 1620 background: var(--gray-900); 1621 color: var(--white); 1622 border-color: var(--gray-900); 1623 } 1624 1625 /* Sale Price */ 1626 .product-price .sale-price { 1627 color: #dc2626; 1628 } 1629 .product-price .original-price { 1630 font-size: 13px; 1631 color: var(--gray-400); 1632 text-decoration: line-through; 1633 font-weight: 400; 1634 margin-left: 6px; 1635 } 1636 .product-price .discount-tag { 1637 display: inline-block; 1638 font-size: 11px; 1639 background: #fef2f2; 1640 color: #dc2626; 1641 padding: 2px 6px; 1642 border-radius: 4px; 1643 margin-left: 6px; 1644 font-weight: 600; 1645 } 1646 1647 /* Search Results Dropdown */ 1648 .search-results { 1649 position: absolute; 1650 top: 100%; 1651 left: 0; 1652 right: 0; 1653 background: var(--white); 1654 border: 1px solid var(--gray-200); 1655 border-radius: 8px; 1656 box-shadow: 0 8px 24px rgba(0,0,0,0.12); 1657 max-height: 400px; 1658 overflow-y: auto; 1659 display: none; 1660 z-index: 1000; 1661 margin-top: 4px; 1662 } 1663 .search-results.active { display: block; } 1664 .search-result-item { 1665 display: flex; 1666 align-items: center; 1667 gap: 12px; 1668 padding: 12px; 1669 border-bottom: 1px solid var(--gray-100); 1670 cursor: pointer; 1671 transition: background 0.2s; 1672 } 1673 .search-result-item:hover { background: var(--gray-50); } 1674 .search-result-item:last-child { border-bottom: none; } 1675 .search-result-item img { 1676 width: 50px; 1677 height: 50px; 1678 object-fit: contain; 1679 background: var(--gray-50); 1680 border-radius: 4px; 1681 } 1682 .search-result-info h4 { 1683 font-size: 14px; 1684 font-weight: 500; 1685 color: var(--gray-900); 1686 } 1687 .search-result-info p { 1688 font-size: 12px; 1689 color: var(--gray-500); 1690 } 1691 .search-no-results { 1692 padding: 20px; 1693 text-align: center; 1694 color: var(--gray-500); 1695 } 1696 1697 /* Show More Button */ 1698 .show-more-container { 1699 text-align: center; 1700 padding: 40px 0; 1701 } 1702 .btn-show-more { 1703 background: var(--primary); 1704 color: white; 1705 border: none; 1706 padding: 14px 40px; 1707 border-radius: 8px; 1708 font-size: 1rem; 1709 font-weight: 600; 1710 cursor: pointer; 1711 transition: background 0.2s, transform 0.2s; 1712 } 1713 .btn-show-more:hover { 1714 background: #333; 1715 transform: translateY(-2px); 1716 } 1717 .btn-show-more:disabled { 1718 background: #ccc;
1719 cursor: not-allowed; 1720 transform: none; 1721 } 1722</style> 1723
1724<script type="application/ld+json">{"@context": "https://schema.org", "@type": "ItemList", "name": "Featured Products", "numberOfItems": 12, "itemListElement": [{"@type": "ListItem", "position": 1, "item": {"@type": "Product", "name": "Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-bicycle-toe-loafer-for-men-f9xq5", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort905_Main.webp"], "offers": {"@type": "Offer", "price": 149.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-bicycle-toe-loafer-for-men-f9xq5", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 2, "item": {"@type": "Product", "name": "Wizfort Men's Premium Leather Sole Chassidic Loafer - Black", "url": "https://wizfort.com/products/wizfort-prestige-comfortable-leather-sole-chassidic-loafer-ib58c", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort925_Main.webp"], "offers": {"@type": "Offer", "price": 149.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-prestige-comfortable-leather-sole-chassidic-loafer-ib58c", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 3, "item": {"@type": "Product", "name": "Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-moc-toe-loafer-for-men-jivbk", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort915_Main.webp"], "offers": {"@type": "Offer", "price": 149.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-moc-toe-loafer-for-men-jivbk", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 4, "item": {"@type": "Product", "name": "Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black", "url": "https://wizfort.com/products/wizfort-prestige-mens-moc-toe-lace-up-8svvp", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort910_Main.webp"], "offers": {"@type": "Offer", "price": 149.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-prestige-mens-moc-toe-lace-up-8svvp", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 5, "item": {"@type": "Product", "name": "Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-bicycle-toe-lace-up-shoe-for-men-bgki4", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort900_Main.webp"], "offers": {"@type": "Offer", "price": 149.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-prestige-leather-sole-bicycle-toe-lace-up-shoe-for-men-bgki4", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 6, "item": {"@type": "Product", "name": "Wizfort Men's Leather Lightweight Chassidic Loafer - Black", "url": "https://wizfort.com/products/wizfort-mens-lightweight-plain-toe-chassidic-loafer-r6fuh", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/825_Main.webp"], "offers": {"@type": "Offer", "price": 129.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-mens-lightweight-plain-toe-chassidic-loafer-r6fuh", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 7, "item": {"@type": "Product", "name": "Wizfort Men's Leather Lightweight Moc Toe Loafer - Black", "url": "https://wizfort.com/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-gpvip", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort810_Main.webp"], "offers": {"@type": "Offer", "price": 109.99, "priceCurrency": "USD", "availability": "https://schema.org/OutOfStock", "url": "https://wizfort.com/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-gpvip", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 8, "item": {"@type": "Product", "name": "Wizfort Men's Leather Lightweight Moc Toe Oxford - Black", "url": "https://wizfort.com/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-tlofo", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort810_Main.webp"], "offers": {"@type": "Offer", "price": 109.99, "priceCurrency": "USD", "availability": "https://schema.org/OutOfStock", "url": "https://wizfort.com/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-tlofo", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 9, "item": {"@type": "Product", "name": "Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black", "url": "https://wizfort.com/products/wizfort-mens-lightweight-bicycle-toe-loafer-njyyt", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort805_Main.webp"], "offers": {"@type": "Offer", "price": 109.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-mens-lightweight-bicycle-toe-loafer-njyyt", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 10, "item": {"@type": "Product", "name": "Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black", "url": "https://wizfort.com/products/wizfort-mens-lightweight-bicycle-toe-lace-up-ul7ri", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/Wizfort800_Main.webp"], "offers": {"@type": "Offer", "price": 109.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-mens-lightweight-bicycle-toe-lace-up-ul7ri", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 11, "item": {"@type": "Product", "name": "Wizfort Men's Leather Sole Moc Toe Loafer - Black", "url": "https://wizfort.com/products/wizfort-classics-mens-leather-sole-moc-toe-slip-on-3oiaf", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/725Main.webp"], "offers": {"@type": "Offer", "price": 119.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-classics-mens-leather-sole-moc-toe-slip-on-3oiaf", "priceValidUntil": "2027-12-31"}}}, {"@type": "ListItem", "position": 12, "item": {"@type": "Product", "name": "Wizfort Men's Leather Sole Moc Toe Oxford - Black", "url": "https://wizfort.com/products/wizfort-classics-mens-leather-sole-moc-toe-lace-up-ggqjf", "brand": {"@type": "Brand", "name": "Wizfort Shoes"}, "color": "Black", "material": "Leather", "image": ["https://wizfort.com/files/720Main.webp"], "offers": {"@type": "Offer", "price": 119.99, "priceCurrency": "USD", "availability": "https://schema.org/InStock", "url": "https://wizfort.com/products/wizfort-classics-mens-leather-sole-moc-toe-lace-up-ggqjf", "priceValidUntil": "2027-12-31"}}}]}</script>
1724 1725 1726 1727 1728 1729
1729<script> 1730 window.frappe = {}; 1731 frappe.ready_events = []; 1732 frappe.ready = function(fn) { 1733 frappe.ready_events.push(fn); 1734 } 1735 window.dev_server = 0; 1736 window.socketio_port = 9000; 1737 window.show_language_picker = false; 1738 </script>
1738 1739</head> 1740<body frappe-session-status="logged-out" data-path="index" class=""> 1741 1742 <svg id="csl-icons" aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden" xmlns="http://www.w3.org/2000/svg"> 1743 <symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="icon-assets"> 1744 <path d="M3 6h17" stroke="var(--icon-stroke)" stroke-miterlimit="10"></path> 1745 <path d="M20 19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6l3.4-3h10.2L20 6v13z" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="square" stroke-linejoin="round"></path> 1746 <path d="M15.582 10c0 2.29-1.8 4.09-4.091 4.09A4.051 4.051 0 0 1 7.4 10" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path> 1747 <circle cx="15.6" cy="10" r=".5" stroke="var(--icon-stroke)"></circle> 1748 <circle cx="7.3" cy="10" r=".5" stroke="var(--icon-stroke)"></circle> 1749 </symbol> 1750 <symbol id="icon-delete" viewBox="0 0 32 32" fill="none"> 1751 <path stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M7 7v18.118c0 2.145 1.492 3.882 3.333 3.882h11.333c1.842 0 3.333-1.737 3.333-3.882v-18.118"></path> 1752 <path stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M5 7h22"></path> 1753 <path stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M10 7v-1c0-1.657 1.343-3 3-3h6c1.657 0 3 1.343 3 3v1"></path> 1754 <path stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M18.8 14.4v8.571"></path> 1755 <path stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M13.2 14.4v8.571"></path> 1756 </symbol> 1757 <symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-down"> 1758 <path d="M3 5.5l5 5 5-5" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"></path> 1759 </symbol> 1760 <symbol viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-edit"> 1761 <path fill-rule="evenodd" clip-rule="evenodd" d="M10.6262 2.70711C11.0168 2.31658 11.6499 2.31658 12.0404 2.70711L13.2929 3.95956C13.6834 4.35008 13.6834 4.98325 13.2929 5.37377L6 12.6667L2 14L3.33333 10L10.6262 2.70711Z" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/> 1762 <line x1="9.79157" y1="3.92744" x2="12.0738" y2="6.2097" stroke="var(--icon-stroke)"/> 1763 </symbol> 1764 <symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-heart"> 1765 <path d="M7.606 3.799L8 4.302l.394-.503.106-.14c.048-.065.08-.108.129-.159a3.284 3.284 0 0 1 4.72 0c.424.434.655 1.245.65 2.278-.006 1.578-.685 2.931-1.728 4.159-1.05 1.234-2.439 2.308-3.814 3.328a.763.763 0 0 1-.914 0c-1.375-1.02-2.764-2.094-3.814-3.328C2.686 8.709 2.007 7.357 2 5.778c-.004-1.033.227-1.844.651-2.278a3.284 3.284 0 0 1 4.72 0c.05.05.081.094.129.158.028.038.061.083.106.14z" 1766 stroke="var(--icon-stroke)"></path> 1767 </symbol> 1768 <symbol viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-star"> 1769 <path d="M11.5516 2.90849C11.735 2.53687 12.265 2.53687 12.4484 2.90849L14.8226 7.71919C14.8954 7.86677 15.0362 7.96905 15.1991 7.99271L20.508 8.76415C20.9181 8.82374 21.0818 9.32772 20.7851 9.61699L16.9435 13.3616C16.8257 13.4765 16.7719 13.642 16.7997 13.8042L17.7066 19.0916C17.7766 19.5001 17.3479 19.8116 16.9811 19.6187L12.2327 17.1223C12.087 17.0457 11.913 17.0457 11.7673 17.1223L7.01888 19.6187C6.65207 19.8116 6.22335 19.5001 6.29341 19.0916L7.20028 13.8042C7.2281 13.642 7.17433 13.4765 7.05648 13.3616L3.21491 9.61699C2.91815 9.32772 3.08191 8.82374 3.49202 8.76415L8.80094 7.99271C8.9638 7.96905 9.10458 7.86677 9.17741 7.71919L11.5516 2.90849Z" fill="var(--star-fill)" stroke="var(--star-fill)"/> 1770 </symbol> 1771 <symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-tag"> 1772 <path d="M12.6401 10.2571L10.107 12.7901C9.52125 13.3759 8.5718 13.3756 7.98601 12.7898L2.49654 7.30037C2.40278 7.2066 2.3501 7.07942 2.3501 6.94682L2.3501 3C2.3501 2.72386 2.57396 2.5 2.8501 2.5L6.79691 2.5C6.92952 2.5 7.0567 2.55268 7.15047 2.64645L12.6399 8.13591C13.2257 8.7217 13.2259 9.67131 12.6401 10.2571Z" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/> 1773 <path d="M6.08001 5.46157C6.08001 5.88642 5.7356 6.23082 5.31076 6.23082C4.88591 6.23082 4.5415 5.88642 4.5415 5.46157C4.5415 5.03673 4.88591 4.69232 5.31076 4.69232C5.7356 4.69232 6.08001 5.03673 6.08001 5.46157Z" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/> 1774 </symbol> 1775 <!-- icon-list and icon-image-view: copied from apps/frappe/frappe/public/icons/timeless/icons.svg 1776 for the /all-products toolbar view-toggle. Keep in sync on Frappe upgrades (ERP-025). --> 1777 <symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-list"> 1778 <path fill-rule="evenodd" clip-rule="evenodd" d="M2.667 3.25a.75.75 0 0 0 0 1.5h.007a.75.75 0 0 0 0-1.5h-.007zm2.666.25a.5.5 0 0 0 0 1H14a.5.5 0 0 0 0-1H5.333zm0 4a.5.5 0 0 0 0 1H14a.5.5 0 0 0 0-1H5.333zm-.5 4.5a.5.5 0 0 1 .5-.5H14a.5.5 0 0 1 0 1H5.333a.5.5 0 0 1-.5-.5zM1.917 8a.75.75 0 0 1 .75-.75h.007a.75.75 0 0 1 0 1.5h-.007a.75.75 0 0 1-.75-.75zm.75 3.25a.75.75 0 0 0 0 1.5h.007a.75.75 0 0 0 0-1.5h-.007z" 1779 fill="var(--icon-stroke)" stroke-width="0"></path> 1780 </symbol> 1781 <symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-image-view"> 1782 <path d="M2.5 3.5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3h-3a1 1 0 0 1-1-1v-2zm0 7a1 1 0 0 1 1-1h3v3a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2zm7-7a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-3v-3zm0 6h3a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-3z"></path> 1783 </symbol> 1784</svg>
1785 <a href="#main-content" class="skip-to-content" style="position:absolute;top:-40px;left:0;background:#1a1a1a;color:#fff;padding:8px 16px;z-index:10001;font-size:14px;text-decoration:none;transition:top 0.2s;" onfocus="this.style.top='0'" onblur="this.style.top='-40px'">Skip to main content</a> 1786 1787 1788 1789 1790<style> 1791/* CSL Header Styles - Inline to avoid CSS conflicts with Frappe */ 1792:root { 1793 --csl-white: #ffffff; 1794 --csl-gray-50: #f9fafb; 1795 --csl-gray-100: #f3f4f6; 1796 --csl-gray-200: #e5e7eb; 1797 --csl-gray-300: #d1d5db; 1798 --csl-gray-400: #9ca3af; 1799 --csl-gray-500: #6b7280; 1800 --csl-gray-600: #4b5563; 1801 --csl-gray-700: #374151; 1802 --csl-gray-800: #1f2937; 1803 --csl-gray-900: #111827; 1804 --csl-black: #000000; 1805 --csl-danger: #ef4444; 1806} 1807 1808/* Hide default Frappe navbar */ 1809.navbar.navbar-expand-lg, .web-footer { display: none !important; } 1810 1811/* Top Bar */ 1812.csl-top-bar { 1813 background: var(--csl-gray-900); 1814 color: var(--csl-white); 1815 padding: 8px 0; 1816 font-size: 12px; 1817} 1818.csl-top-bar-content { 1819 max-width: 1400px; 1820 margin: 0 auto; 1821 padding: 0 20px; 1822 display: flex; 1823 justify-content: space-between; 1824 align-items: center; 1825} 1826.csl-top-bar-message { font-weight: 500; } 1827.csl-top-bar-links { display: flex; gap: 20px; align-items: center; } 1828.csl-top-bar-links a { color: var(--csl-white); text-decoration: none; } 1829.csl-top-bar-links a:hover { text-decoration: underline; } 1830.csl-top-bar-phone { display: flex; align-items: center; gap: 5px; font-weight: 600; } 1831.csl-top-bar-phone svg { flex-shrink: 0; } 1832 1833/* Header */ 1834.csl-header { 1835 background: var(--csl-white); 1836 border-bottom: 1px solid var(--csl-gray-200); 1837 padding: 16px 0; 1838 position: sticky; 1839 top: 0; 1840 z-index: 1000; 1841} 1842.csl-header-inner { 1843 max-width: 1400px; 1844 margin: 0 auto; 1845 padding: 0 20px; 1846 display: flex; 1847 align-items: center; 1848 justify-content: space-between; 1849 gap: 40px; 1850 position: relative; 1851 z-index: 100; 1852} 1853.csl-header-inner * { 1854 pointer-events: auto; 1855} 1856.csl-logo { 1857 font-size: 24px; 1858 font-weight: 700; 1859 color: var(--csl-black); 1860 text-decoration: none; 1861} 1862.csl-nav { 1863 display: flex; 1864 align-items: center; 1865 gap: 32px; 1866} 1867.csl-nav a { 1868 font-size: 14px; 1869 font-weight: 500; 1870 color: var(--csl-gray-700); 1871 text-decoration: none; 1872 transition: color 0.2s; 1873} 1874.csl-nav a:hover { color: var(--csl-black); } 1875.csl-nav-dropdown { position: relative; } 1876.csl-nav-dropdown > a { 1877 display: flex; 1878 align-items: center; 1879 gap: 4px; 1880} 1881.csl-nav-dropdown > a svg { 1882 width: 12px; 1883 height: 12px; 1884 stroke: currentColor; 1885 stroke-width: 2; 1886 fill: none; 1887 transition: transform 0.2s; 1888} 1889.csl-nav-dropdown:hover > a svg { transform: rotate(180deg); } 1890.csl-dropdown-menu { 1891 position: absolute; 1892 top: 100%; 1893 left: 50%; 1894 transform: translateX(-50%); 1895 background: var(--csl-white); 1896 border: 1px solid var(--csl-gray-200); 1897 border-radius: 8px; 1898 box-shadow: 0 8px 24px rgba(0,0,0,0.12); 1899 min-width: 180px; 1900 padding: 8px 0; 1901 opacity: 0; 1902 visibility: hidden; 1903 transition: all 0.2s ease; 1904 z-index: 1001; 1905 margin-top: 8px; 1906} 1907.csl-nav-dropdown:hover .csl-dropdown-menu { 1908 opacity: 1; 1909 visibility: visible; 1910} 1911.csl-dropdown-menu a { 1912 display: block; 1913 padding: 10px 16px; 1914 font-size: 14px; 1915 color: var(--csl-gray-700); 1916 transition: all 0.15s; 1917} 1918.csl-dropdown-menu a:hover { 1919 background: var(--csl-gray-50); 1920 color: var(--csl-black); 1921} 1922/* ERP-101: account icon dropdown (My Account + Sign Out). Right-aligned so it 1923 doesn't overflow the viewport edge; reuses .csl-dropdown-menu base styling. */ 1924.csl-account-dropdown { position: relative; display: inline-flex; align-items: center; } 1925.csl-account-menu { left: auto; right: 0; transform: none; min-width: 160px; } 1926.csl-account-dropdown:hover .csl-account-menu { opacity: 1; visibility: visible; } 1927 1928/* Header Actions */ 1929.csl-header-actions { 1930 display: flex; 1931 align-items: center; 1932 gap: 20px; 1933 pointer-events: auto; 1934 position: relative; 1935 z-index: 50; 1936} 1937.csl-search-box { 1938 display: flex !important; 1939 align-items: center; 1940 background: var(--csl-gray-100); 1941 border: 1px solid var(--csl-gray-200); 1942 border-radius: 6px; 1943 padding: 8px 12px; 1944 width: 280px; 1945 position: relative; 1946 cursor: text; 1947 z-index: 100; 1948 pointer-events: auto !important; 1949} 1950.csl-search-box input { 1951 border: none !important; 1952 background: transparent !important; 1953 outline: none !important; 1954 font-size: 14px; 1955 width: 100%; 1956 margin-left: 8px; 1957 cursor: text !important; 1958 color: var(--csl-gray-900); 1959 pointer-events: auto !important; 1960 position: relative; 1961 z-index: 10; 1962 display: block !important; 1963 visibility: visible !important; 1964 opacity: 1 !important; 1965} 1966.csl-search-box input::placeholder { color: var(--csl-gray-500); } 1967#csl-search-input { 1968 display: block !important; 1969 visibility: visible !important; 1970 opacity: 1 !important; 1971 pointer-events: auto !important; 1972 position: relative !important; 1973 z-index: 10 !important; 1974 -webkit-user-select: text !important; 1975 user-select: text !important; 1976 cursor: text !important; 1977} 1978.csl-search-box:focus-within { 1979 border-color: var(--csl-gray-400); 1980 box-shadow: 0 0 0 2px rgba(0,0,0,0.05); 1981} 1982.csl-search-box svg {
1983 width: 20px; 1984 height: 20px; 1985 stroke: var(--csl-gray-500); 1986 stroke-width: 1.5; 1987 fill: none; 1988 pointer-events: none; 1989 flex-shrink: 0; 1990} 1991.csl-search-results { 1992 position: absolute; 1993 top: 100%; 1994 left: 0; 1995 right: 0; 1996 background: var(--csl-white); 1997 border: 1px solid var(--csl-gray-200); 1998 border-radius: 8px; 1999 box-shadow: 0 8px 24px rgba(0,0,0,0.12); 2000 margin-top: 4px; 2001 max-height: 400px; 2002 overflow-y: auto; 2003 display: none; 2004 z-index: 1002; 2005} 2006.csl-search-results.active { display: block; } 2007.csl-search-result-item { 2008 display: flex; 2009 align-items: center; 2010 gap: 12px; 2011 padding: 10px 12px; 2012 text-decoration: none; 2013 color: var(--csl-gray-800); 2014 transition: background 0.15s; 2015} 2016.csl-search-result-item:hover { background: var(--csl-gray-50); } 2017.csl-search-result-item img { 2018 width: 50px; 2019 height: 50px; 2020 object-fit: contain; 2021 background: var(--csl-gray-100); 2022 border-radius: 4px; 2023} 2024.csl-search-result-name { 2025 font-size: 14px; 2026 font-weight: 500; 2027 margin: 0; 2028 display: block; 2029} 2030.csl-search-result-info p { 2031 font-size: 12px; 2032 color: var(--csl-gray-500); 2033 margin: 2px 0 0 0; 2034} 2035.csl-search-no-results { 2036 padding: 20px; 2037 text-align: center; 2038 color: var(--csl-gray-500); 2039} 2040 2041/* Header Icons */ 2042.csl-header-icon { 2043 width: 20px; 2044 height: 20px; 2045 stroke: var(--csl-gray-500); 2046 stroke-width: 1.5; 2047 fill: none; 2048 cursor: pointer; 2049 transition: stroke 0.2s; 2050} 2051.csl-header-icon:hover { stroke: var(--csl-black); } 2052.csl-header-icon-link { 2053 display: flex; 2054 align-items: center; 2055 justify-content: center; 2056 text-decoration: none; 2057} 2058.csl-cart-icon, .csl-wishlist-icon { position: relative; } 2059.csl-cart-count, .csl-wishlist-count { 2060 position: absolute; 2061 top: -6px; 2062 right: -6px; 2063 background: var(--csl-black); 2064 color: var(--csl-white); 2065 font-size: 10px; 2066 font-weight: 600; 2067 min-width: 18px; 2068 height: 18px; 2069 border-radius: 50%; 2070 display: flex; 2071 align-items: center; 2072 justify-content: center; 2073} 2074.csl-wishlist-count { background: var(--csl-danger); display: none; } 2075 2076/* Mobile Menu Toggle */ 2077.csl-mobile-menu-toggle { 2078 display: none; 2079 width: 40px; 2080 height: 40px; 2081 background: none; 2082 border: 1px solid var(--csl-gray-300); 2083 border-radius: 8px; 2084 cursor: pointer; 2085 align-items: center; 2086 justify-content: center; 2087} 2088.csl-mobile-menu-toggle svg { 2089 width: 24px; 2090 height: 24px; 2091 stroke: var(--csl-gray-700); 2092 stroke-width: 2; 2093 fill: none; 2094} 2095 2096/* Mobile Navigation - Hidden by default */ 2097.csl-mobile-nav { 2098 display: none !important; 2099 position: fixed; 2100 top: 0; 2101 left: 0; 2102 right: 0; 2103 bottom: 0; 2104 background: var(--csl-white); 2105 z-index: 9999; 2106 padding: 20px; 2107 flex-direction: column; 2108 overflow-y: auto; 2109} 2110.csl-mobile-nav.active { display: flex !important; } 2111.csl-mobile-nav-header { 2112 display: flex; 2113 justify-content: space-between; 2114 align-items: center; 2115 margin-bottom: 24px; 2116 padding-bottom: 16px; 2117 border-bottom: 1px solid var(--csl-gray-200); 2118} 2119.csl-mobile-nav-close { 2120 width: 40px; 2121 height: 40px; 2122 background: none; 2123 border: none; 2124 cursor: pointer; 2125 display: flex; 2126 align-items: center; 2127 justify-content: center; 2128} 2129.csl-mobile-nav-close svg { 2130 width: 24px; 2131 height: 24px; 2132 stroke: var(--csl-gray-700); 2133 stroke-width: 2; 2134 fill: none; 2135} 2136.csl-mobile-nav-links { 2137 display: flex; 2138 flex-direction: column; 2139} 2140.csl-mobile-nav-links a { 2141 padding: 16px 0; 2142 font-size: 18px; 2143 font-weight: 500; 2144 color: var(--csl-gray-800); 2145 text-decoration: none; 2146 border-bottom: 1px solid var(--csl-gray-100); 2147} 2148.csl-mobile-search { 2149 margin-bottom: 16px; 2150 padding: 12px 16px; 2151 background: var(--csl-gray-100); 2152 border: 1px solid var(--csl-gray-200); 2153 border-radius: 8px; 2154 font-size: 16px; 2155 width: 100%; 2156} 2157 2158/* Size Guide Link */ 2159.csl-size-guide-link { 2160 display: flex; 2161 align-items: center; 2162 gap: 4px; 2163 font-size: 13px; 2164 color: var(--csl-gray-600); 2165 text-decoration: none; 2166} 2167.csl-size-guide-link:hover { color: var(--csl-black); } 2168.csl-size-guide-link svg { 2169 width: 16px; 2170 height: 16px; 2171 stroke: currentColor; 2172 stroke-width: 1.5; 2173 fill: none; 2174} 2175 2176/* Responsive */ 2177@media (max-width: 1024px) { 2178 .csl-search-box { width: 200px; } 2179} 2180@media (max-width: 768px) { 2181 .csl-top-bar { padding: 6px 0; } 2182 .csl-top-bar-links { display: none; } 2183 .csl-top-bar-message { font-size: 11px; text-align: center; width: 100%; } 2184 .csl-header { padding: 12px 0; } 2185 .csl-header-inner { gap: 12px; } 2186 .csl-logo { font-size: 20px; flex-shrink: 0; max-width: 45vw; } 2187 .csl-logo img { height: 24px; width: auto; } 2188 .csl-nav, .csl-search-box, .csl-size-guide-link { display: none; } 2189 .csl-mobile-menu-toggle { display: flex; } 2190 .csl-mobile-search-toggle { display: flex; } 2191 .csl-header-actions { gap: 12px; } 2192 .csl-header-icon { width: 18px; height: 18px; } 2193 .csl-cart-count, .csl-wishlist-count { width: 16px; height: 16px; font-size: 9px; top: -4px; right: -4px; } 2194} 2195/* Mobile Search Overlay */
2196.csl-mobile-search-toggle { 2197 display: none; 2198 width: 44px; 2199 height: 44px; 2200 background: none; 2201 border: none; 2202 cursor: pointer; 2203 align-items: center; 2204 justify-content: center; 2205 padding: 0; 2206} 2207.csl-mobile-search-toggle svg { 2208 width: 20px; 2209 height: 20px; 2210 stroke: var(--csl-gray-700); 2211 stroke-width: 2; 2212 fill: none; 2213} 2214.csl-mobile-search-overlay { 2215 display: none; 2216 position: fixed; 2217 top: 0; 2218 left: 0; 2219 right: 0; 2220 z-index: 10000; 2221 background: var(--csl-white); 2222 padding: 12px 16px; 2223 box-shadow: 0 4px 12px rgba(0,0,0,0.1); 2224} 2225.csl-mobile-search-overlay.active { display: flex; gap: 8px; align-items: center; } 2226.csl-mobile-search-overlay input { 2227 flex: 1; 2228 padding: 12px 16px; 2229 font-size: 16px; 2230 border: 1px solid var(--csl-gray-300); 2231 border-radius: 8px; 2232 outline: none; 2233} 2234.csl-mobile-search-overlay input:focus { border-color: var(--csl-black); } 2235.csl-mobile-search-overlay .csl-mobile-search-close { 2236 width: 44px; 2237 height: 44px; 2238 background: none; 2239 border: none; 2240 cursor: pointer; 2241 display: flex; 2242 align-items: center; 2243 justify-content: center; 2244} 2245.csl-mobile-search-overlay .csl-mobile-search-close svg { 2246 width: 24px; 2247 height: 24px; 2248 stroke: var(--csl-gray-600); 2249 stroke-width: 2; 2250 fill: none; 2251} 2252.csl-mobile-search-overlay .csl-search-results { 2253 position: absolute; 2254 top: 100%; 2255 left: 0; 2256 right: 0; 2257 background: var(--csl-white); 2258 max-height: 60vh; 2259 overflow-y: auto; 2260 box-shadow: 0 4px 12px rgba(0,0,0,0.1); 2261} 2262</style> 2263 2264<!-- Mobile Navigation (hidden by default, shown on mobile menu click) --> 2265<div class="csl-mobile-nav" id="csl-mobile-nav" data-nosnippet> 2266 <div class="csl-mobile-nav-header"> 2267 <span class="csl-logo">CSL Shoes</span> 2268 <button class="csl-mobile-nav-close" onclick="cslCloseMobileNav()" aria-label="Close menu"> 2269 <svg viewBox="0 0 24 24" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> 2270 </button> 2271 </div> 2272 <input type="text" class="csl-mobile-search" placeholder="Search shoes..." id="csl-mobile-search-input" aria-label="Search products"> 2273 <div class="csl-mobile-nav-links"> 2274 2275 2276 2277 2278 2279 <a href="/shoes/oxfords" onclick="cslCloseMobileNav()">Oxfords</a> 2280 2281 2282 2283 <a href="/shoes/loafers" onclick="cslCloseMobileNav()">Loafers</a> 2284 2285 2286 2287 <a href="/shoes/slip-ons" onclick="cslCloseMobileNav()">Slip-Ons</a> 2288 2289 2290 2291 <a href="/shoes/wide-width" onclick="cslCloseMobileNav()">Wide Width</a> 2292 2293 2294 2295 <a href="/shoes/boys-dress-shoes" onclick="cslCloseMobileNav()">Boys' Shoes</a> 2296 2297 2298 2299 <a href="/all-products" onclick="cslCloseMobileNav()">All Products</a> 2300 2301 2302 2303 2304 2305 <a href="/brands/wizfort" onclick="cslCloseMobileNav()">Wizfort</a> 2306 2307 2308 2309 <a href="/brands/esse-comfort" onclick="cslCloseMobileNav()">Esse Comfort</a> 2310 2311 2312 2313 <a href="/brands/benelaccio" onclick="cslCloseMobileNav()">Benelaccio</a> 2314 2315 2316 2317 <a href="/blog" onclick="cslCloseMobileNav()">Blog</a> 2318 2319 2320 2321 <a href="/about" onclick="cslCloseMobileNav()">About</a> 2322 2323 2324 2325 2326 2327 <a href="/shoes/wedding-shoes" onclick="cslCloseMobileNav()">Wedding</a> 2328 2329 2330 2331 <a href="/shoes/school-shoes" onclick="cslCloseMobileNav()">School</a> 2332 2333 2334 2335 <a href="/shoes/office-shoes" onclick="cslCloseMobileNav()">Office</a> 2336 2337 2338 2339 2340 2341 <a href="/help" onclick="cslCloseMobileNav()">Help</a> 2342 2343 <a href="/track-order" onclick="cslCloseMobileNav()">Track Order</a> 2344 2345 <a href="/contact" onclick="cslCloseMobileNav()">Contact Us</a> 2346 2347 2348 2349 2350 <a href="/login" onclick="cslCloseMobileNav()">Sign In</a> 2351 2352 </div> 2353</div> 2354 2355<!-- Top Bar --> 2356 2357<div class="csl-top-bar" data-nosnippet> 2358 <div class="csl-top-bar-content"> 2359 2360 2361 2362 <span class="csl-top-bar-message">Free standard shipping for retail orders | Family-Owned Since 2008 | 60-Day Easy Returns</span> 2363 2364 <div class="csl-top-bar-links"> 2365 <a href="tel:+18456946700" class="csl-top-bar-phone"> 2366 <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg> 2367 (845) 694-6700 2368 </a> 2369 2370 2371 <a href="/help">Help</a> 2372 2373 <a href="/track-order">Track Order</a> 2374 2375 <a href="/contact">Contact Us</a> 2376 2377 2378 </div> 2379 </div> 2380</div> 2381 2382 2383<!-- Header --> 2384<header class="csl-header" data-nosnippet> 2385 <div class="csl-header-inner"> 2386 <button class="csl-mobile-menu-toggle" onclick="cslOpenMobileNav()" aria-label="Open menu"> 2387 <svg viewBox="0 0 24 24" aria-hidden="true"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg> 2388 </button> 2389 <a href="/" class="csl-logo"> 2390 2391 <img src="/files/cslshoes.webp" alt="CSL Shoes logo" width="213" height="32"> 2392 2393 </a> 2394 <nav class="csl-nav"> 2395 2396 2397 2398 <div class="csl-nav-dropdown"> 2399 <a href="/shoes">Styles <svg viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg></a> 2400 <div class="csl-dropdown-menu"> 2401 2402 2403 2404 2405 <a href="/shoes/oxfords">Oxfords</a> 2406 2407 2408 2409 <a href="/shoes/loafers">Loafers</a> 2410 2411 2412 2413 <a href="/shoes/slip-ons">Slip-Ons</a> 2414 2415 2416 2417 <a href="/shoes/wide-width">Wide Width</a> 2418 2419 2420 2421 <a href="/shoes/boys-dress-shoes">Boys' Shoes</a> 2422 2423 2424 2425 <a href="/all-products">All Products</a> 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 </div> 2449 </div> 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 <div class="csl-nav-dropdown"> 2466 <a href="/brands">Brands <svg viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg></a> 2467 <div class="csl-dropdown-menu"> 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 <a href="/brands/wizfort">Wizfort</a> 2487 2488 2489 2490 <a href="/brands/esse-comfort">Esse Comfort</a> 2491 2492 2493 2494 <a href="/brands/benelaccio">Benelaccio</a> 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 </div> 2510 </div> 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 <a href="/blog">Blog</a> 2521 2522 2523 2524 <a href="/about">About</a> 2525 2526 2527 2528 <div class="csl-nav-dropdown"> 2529 <a href="/shoes">Occasions <svg viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg></a> 2530 <div class="csl-dropdown-menu"> 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 <a href="/shoes/wedding-shoes">Wedding</a> 2562 2563 2564 2565 <a href="/shoes/school-shoes">School</a> 2566 2567 2568 2569 <a href="/shoes/office-shoes">Office</a> 2570 2571 2572 </div> 2573 </div> 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 </nav> 2584 <div class="csl-header-actions"> 2585 <button class="csl-mobile-search-toggle" onclick="cslOpenMobileSearch()" aria-label="Search"> 2586 <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg> 2587 </button> 2588 <a href="/size-guide" class="csl-size-guide-link"> 2589 <svg viewBox="0 0 24 24"><rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg> 2590 Size Guide 2591 </a> 2592 2593 <div class="csl-search-box"> 2594 <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg> 2595 <input type="text" id="csl-search-input" placeholder="Search shoes..." autocomplete="off" aria-label="Search products"> 2596 <div class="csl-search-results" id="csl-search-results"></div> 2597 </div> 2598 2599 2600 2601 <a href="/login" class="csl-header-icon-link" title="Sign In">
2602 <svg class="csl-header-icon" viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> 2603 </a> 2604 2605 2606 2607 <a href="/wishlist" class="csl-wishlist-icon csl-header-icon-link" title="Wishlist"> 2608 <svg class="csl-header-icon" viewBox="0 0 24 24"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg> 2609 <span class="csl-wishlist-count" id="csl-wishlist-count">0</span> 2610 </a> 2611 2612 2613 <a href="/cart" class="csl-cart-icon csl-header-icon-link" title="Cart"> 2614 <svg class="csl-header-icon" viewBox="0 0 24 24"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg> 2615 <span class="csl-cart-count" id="csl-cart-count">0</span> 2616 </a> 2617 2618 </div> 2619 </div> 2620</header> 2621 2622<!-- Mobile Search Overlay --> 2623<div class="csl-mobile-search-overlay" id="csl-mobile-search-overlay"> 2624 <input type="text" id="csl-mobile-search-input" placeholder="Search shoes..." autocomplete="off" aria-label="Search products"> 2625 <button class="csl-mobile-search-close" onclick="cslCloseMobileSearch()" aria-label="Close search"> 2626 <svg viewBox="0 0 24 24" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> 2627 </button> 2628 <div class="csl-search-results" id="csl-mobile-search-results"></div> 2629</div> 2630
2631<script> 2632// CSL Header JavaScript - Inline for reliability 2633(function() { 2634 var cslSearchTimeout; 2635 2636 // Mobile search 2637 window.cslOpenMobileSearch = function() { 2638 var overlay = document.getElementById('csl-mobile-search-overlay'); 2639 overlay.classList.add('active'); 2640 var input = document.getElementById('csl-mobile-search-input'); 2641 input.value = ''; 2642 input.focus(); 2643 }; 2644 2645 window.cslCloseMobileSearch = function() { 2646 document.getElementById('csl-mobile-search-overlay').classList.remove('active'); 2647 document.getElementById('csl-mobile-search-results').innerHTML = ''; 2648 }; 2649 2650 // Mobile navigation 2651 window.cslOpenMobileNav = function() { 2652 document.getElementById('csl-mobile-nav').classList.add('active'); 2653 document.body.style.overflow = 'hidden'; 2654 }; 2655 2656 window.cslCloseMobileNav = function() { 2657 document.getElementById('csl-mobile-nav').classList.remove('active'); 2658 document.body.style.overflow = ''; 2659 }; 2660 2661 // Search functionality 2662 function initCslSearch() { 2663 var searchInput = document.getElementById('csl-search-input'); 2664 var searchResults = document.getElementById('csl-search-results'); 2665 2666 if (!searchInput) return; 2667 2668 searchInput.addEventListener('input', function() { 2669 clearTimeout(cslSearchTimeout); 2670 var query = this.value.trim(); 2671 2672 if (query.length < 2) { 2673 searchResults.classList.remove('active'); 2674 return; 2675 } 2676 2677 cslSearchTimeout = setTimeout(function() { cslSearchProducts(query); }, 300); 2678 }); 2679 2680 searchInput.addEventListener('focus', function() { 2681 if (this.value.trim().length >= 2) { 2682 searchResults.classList.add('active'); 2683 } 2684 }); 2685 2686 searchInput.addEventListener('keypress', function(e) { 2687 if (e.key === 'Enter') { 2688 var query = this.value.trim(); 2689 if (query) { 2690 window.location.href = '/all-products?search=' + encodeURIComponent(query); 2691 } 2692 } 2693 }); 2694 2695 document.addEventListener('click', function(e) { 2696 if (!e.target.closest('.csl-search-box')) { 2697 searchResults.classList.remove('active'); 2698 } 2699 }); 2700 } 2701 2702 // Mobile search - reuse same search logic 2703 function initCslMobileSearch() { 2704 var mobileInput = document.getElementById('csl-mobile-search-input'); 2705 var mobileResults = document.getElementById('csl-mobile-search-results'); 2706 if (!mobileInput) return; 2707 2708 mobileInput.addEventListener('input', function() { 2709 clearTimeout(cslSearchTimeout); 2710 var query = this.value.trim(); 2711 if (query.length < 2) { mobileResults.innerHTML = ''; return; } 2712 cslSearchTimeout = setTimeout(function() { cslSearchProductsMobile(query); }, 300); 2713 }); 2714 2715 mobileInput.addEventListener('keypress', function(e) { 2716 if (e.key === 'Enter') { 2717 var query = this.value.trim(); 2718 if (query) { 2719 window.location.href = '/all-products?search=' + encodeURIComponent(query); 2720 cslCloseMobileSearch(); 2721 } 2722 } 2723 }); 2724 } 2725 2726 function cslSearchProductsMobile(query) { 2727 var mobileResults = document.getElementById('csl-mobile-search-results'); 2728 fetch('/api/method/cslshoes_erp.api.search.search_products?query=' + encodeURIComponent(query)) 2729 .then(function(response) { return response.json(); }) 2730 .then(function(data) { 2731 if (data.message && data.message.length > 0) { 2732 mobileResults.innerHTML = data.message.map(function(product) { 2733 var safeName = cslEscapeHtml(product.web_item_name); 2734 var safeRoute = encodeURI(product.route || ''); 2735 var safeImage = cslEscapeHtml(product.website_image || '/assets/webshop/images/cart-empty-state.png'); 2736 return '<a href="/' + safeRoute + '" style="display:flex;align-items:center;gap:12px;padding:12px 16px;text-decoration:none;color:#1a1a1a;border-bottom:1px solid #f3f4f6;">' + 2737 '<img src="' + safeImage + '" alt="' + safeName + '" width="50" height="50" style="border-radius:6px;object-fit:cover;">' + 2738 '<span style="font-size:14px;">' + safeName + '</span>' + 2739 '</a>'; 2740 }).join(''); 2741 } else { 2742 mobileResults.innerHTML = '<div style="padding:16px;text-align:center;color:#6b7280;">No products found</div>'; 2743 } 2744 }) 2745 .catch(function() { 2746 mobileResults.innerHTML = '<div style="padding:16px;text-align:center;color:#6b7280;">Search unavailable</div>'; 2747 }); 2748 } 2749 2750 function cslSearchProducts(query) { 2751 var searchResults = document.getElementById('csl-search-results'); 2752 2753 fetch('/api/method/cslshoes_erp.api.search.search_products?query=' + encodeURIComponent(query)) 2754 .then(function(response) { return response.json(); }) 2755 .then(function(data) { 2756 if (data.message && data.message.length > 0) {
2757 cslRenderSearchResults(data.message); 2758 } else { 2759 searchResults.innerHTML = '<div class="csl-search-no-results">No products found</div>'; 2760 } 2761 searchResults.classList.add('active'); 2762 }) 2763 .catch(function() { 2764 searchResults.innerHTML = '<div class="csl-search-no-results">Search unavailable</div>'; 2765 searchResults.classList.add('active'); 2766 }); 2767 } 2768 2769 function cslEscapeHtml(str) { 2770 if (!str) return ''; 2771 var div = document.createElement('div'); 2772 div.appendChild(document.createTextNode(String(str))); 2773 return div.innerHTML; 2774 } 2775 2776 function cslRenderSearchResults(products) { 2777 var searchResults = document.getElementById('csl-search-results'); 2778 searchResults.innerHTML = products.map(function(product) { 2779 var safeName = cslEscapeHtml(product.web_item_name); 2780 var safeRoute = encodeURI(product.route || ''); 2781 var safeBrand = cslEscapeHtml(product.brand || 'CSL Shoes'); 2782 var safeImage = cslEscapeHtml(product.website_image || '/assets/webshop/images/cart-empty-state.png'); 2783 return '<a href="/' + safeRoute + '" class="csl-search-result-item">' + 2784 '<img src="' + safeImage + '" alt="' + safeName + '">' + 2785 '<div class="csl-search-result-info">' + 2786 '<span class="csl-search-result-name">' + safeName + '</span>' + 2787 '<p>' + safeBrand + '</p>' + 2788 '</div>' + 2789 '</a>'; 2790 }).join(''); 2791 } 2792 2793 // Cart count update - supports both guests and logged-in users 2794 function updateCslCartCount() { 2795 var isGuest = document.body.getAttribute('frappe-session-status') === 'logged-out'; 2796 2797 if (isGuest) { 2798 // Guest: use guest cart API 2799 var cartIdMatch = document.cookie.match(/guest_cart_id=([^;]+)/); 2800 var cartId = cartIdMatch ? cartIdMatch[1] : null; 2801 2802 fetch('/api/method/cslshoes_erp.api.guest_cart.get_cart_count', { 2803 method: 'POST', 2804 headers: { 'Content-Type': 'application/json' }, 2805 credentials: 'same-origin', 2806 body: JSON.stringify({ cart_id: cartId }) 2807 }) 2808 .then(function(r) { return r.json(); }) 2809 .then(function(data) { 2810 if (data.message) { 2811 var count = data.message.count || 0; 2812 updateCartCountDisplay(count); 2813 } 2814 }) 2815 .catch(function() {}); 2816 } else { 2817 // Logged-in user: use quotation API 2818 fetch('/api/method/webshop.webshop.shopping_cart.cart.get_cart_quotation', { 2819 method: 'GET', 2820 headers: { 'Content-Type': 'application/json' }, 2821 credentials: 'same-origin' 2822 }) 2823 .then(function(r) { return r.json(); }) 2824 .then(function(data) { 2825 if (data.message && data.message.doc) { 2826 var totalQty = data.message.doc.total_qty || 0; 2827 updateCartCountDisplay(totalQty); 2828 } 2829 }) 2830 .catch(function() {}); 2831 } 2832 } 2833 2834 // Helper to update cart count display in header 2835 function updateCartCountDisplay(count) { 2836 count = Math.floor(count); 2837 var countEl = document.getElementById('csl-cart-count'); 2838 if (countEl) { 2839 countEl.textContent = count; 2840 countEl.style.display = count > 0 ? 'flex' : 'none'; 2841 } 2842 } 2843 2844 // Wishlist count update 2845 function updateCslWishlistCount() { 2846 fetch('/api/method/cslshoes_erp.api.wishlist.get_wishlist_count', { 2847 method: 'GET', 2848 credentials: 'same-origin' 2849 }) 2850 .then(function(r) { return r.json(); }) 2851 .then(function(data) { 2852 var count = data.message || 0; 2853 var countEl = document.getElementById('csl-wishlist-count'); 2854 if (countEl) { 2855 if (count > 0) { 2856 countEl.textContent = count; 2857 countEl.style.display = 'flex'; 2858 } else { 2859 countEl.style.display = 'none'; 2860 } 2861 } 2862 }) 2863 .catch(function() {}); 2864 } 2865 2866 // Initialize on DOM ready 2867 if (document.readyState === 'loading') { 2868 document.addEventListener('DOMContentLoaded', function() { 2869 initCslSearch(); 2870 initCslMobileSearch(); 2871 updateCslCartCount(); 2872 updateCslWishlistCount(); 2873 }); 2874 } else {
2875 initCslSearch(); 2876 initCslMobileSearch(); 2877 updateCslCartCount(); 2878 updateCslWishlistCount(); 2879 } 2880 2881 // BUG-W3 cart sub: expose count refreshers globally so add-to-cart handlers 2882 // in homepage / PDP / /all-products can trigger header re-sync after mutation. 2883 // Idempotency guard (auditor C1) â if a future include order re-exposes, keep 2884 // the first definition. 2885 window.updateCslCartCount = window.updateCslCartCount || updateCslCartCount; 2886 window.updateCslWishlistCount = window.updateCslWishlistCount || updateCslWishlistCount; 2887})(); 2888</script>
2888<main id="main-content"> 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900<div id="page-index" data-path="index"> 2901 2902<div class="page-content-wrapper"> 2903 <!-- breadcrumbs --> 2904 <div class="page-breadcrumbs"> 2905 2906 2907 2908 </div> 2909 2910 2911 <main class="container"> 2912 <div class="page-header-wrapper"> 2913 <div class="page-header"> 2914 2915 </div> 2916 2917 2918 </div> 2919 2920 <div class="page_content"> 2921 <!-- Hero --> 2922 <section class="hero"> 2923 <div class="container"> 2924 <div class="hero-content"> 2925 <div class="hero-text"> 2926 2927 <h1>Quality Leather Shoes for the Whole Family</h1> 2928 <p>Durable everyday footwear with classic style and comfort for men, women, and kids.</p> 2929 <div class="hero-buttons"> 2930 <a href="/all-products" class="btn btn-primary">Shop Wizfort</a> 2931 <a href="/all-products?filter=new_arrivals" class="btn btn-primary">View New Arrivals</a> 2932 </div> 2933 2934 </div> 2935 <a href="#featured-products" class="hero-image" id="hero-image-container"> 2936 <div class="hero-image-wrapper"> 2937 2938 <img id="hero-product-image" src="/files/383_1.webp" alt="Benelaccio Boys Moc Toe Velcro with Arc Buckle" fetchpriority="high" width="400" height="400"> 2939 2940 <div id="hero-placeholder" class="hero-placeholder" style="display:none;"> 2941 <svg viewBox="0 0 64 64" width="120" height="90"><path fill="#9CA3AF" d="M8 48c0-4 2-8 6-10l4-2c2-1 4-3 4-5V20c0-4 4-8 10-8h20c6 0 10 4 10 8v11c0 2 2 4 4 5l4 2c4 2 6 6 6 10v4H8v-4z"/></svg> 2942 <p>Loading featured shoes...</p> 2943 </div> 2944 </div> 2945 </a> 2946 </div> 2947 </div> 2948 </section> 2949 2950 2951 2952 <!-- Trust Bar --> 2953 <div class="trust-bar"> 2954 <div class="container"> 2955 <div class="trust-items"> 2956 <div class="trust-item"> 2957 <svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg> 2958 <span><strong>Secure Checkout</strong></span> 2959 </div> 2960 2961 <div class="trust-item"> 2962 <svg viewBox="0 0 24 24"><rect x="1" y="3" width="15" height="13" rx="2"/><path d="m16 8 5 3-5 3V8z"/></svg> 2963 <span><strong>Free Shipping</strong> Continental US</span> 2964 </div> 2965 2966 <div class="trust-item"> 2967 <svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg> 2968 <span><strong>Easy Returns</strong> 60-Day Policy</span> 2969 </div> 2970 <div class="trust-item"> 2971 <svg viewBox="0 0 24 24"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> 2972 <span><strong>100% Genuine</strong> Leather</span> 2973 </div> 2974 </div> 2975 </div> 2976 </div> 2977 2978 <!-- Categories --> 2979 <section class="section"> 2980 <div class="container"> 2981 <div class="section-header"> 2982 <h2 class="section-title">Shop by Category</h2> 2983 <a href="/all-products" class="section-link"> 2984 View All 2985 <svg viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7"/></svg> 2986 </a> 2987 </div> 2988 <div class="categories-grid" id="categories-container"> 2989 2990 2991 <a href="/closure-type/Lace-Up/items" class="category-card"> 2992 <div class="category-icon"> 2993 2994 <img src="/files/Wizfort800_Main_cat_thumb.webp" alt="Oxfords" width="115" height="80" style="width:100%;height:100%;object-fit:contain;" loading="lazy"> 2995 2996 </div> 2997 <h3>Oxfords</h3> 2998 <p>Classic oxford & derby styles</p> 2999 </a> 3000 3001 <a href="/closure-type/Slip-On/items" class="category-card"> 3002 <div class="category-icon"> 3003 3004 <img src="/files/Wizfort805_Main_cat_thumb.webp" alt="Slip On" width="115" height="80" style="width:100%;height:100%;object-fit:contain;" loading="lazy"> 3005 3006 </div> 3007 <h3>Slip On</h3> 3008 <p>Easy loafers & moccasins</p> 3009 </a> 3010 3011 <a href="/closure-type/Velcro/items" class="category-card"> 3012 <div class="category-icon"> 3013 3014 <img src="/files/303_Main_cat_thumb.webp" alt="Boys' Shoes" width="115" height="80" style="width:100%;height:100%;object-fit:contain;" loading="lazy"> 3015 3016 </div> 3017 <h3>Boys' Shoes</h3> 3018 <p>Comfortable & stylish shoes</p> 3019 </a> 3020 3021 <a href="/all-products" class="category-card"> 3022 <div class="category-icon"> 3023 3024 </div> 3025 <h3>All Shoes</h3> 3026 <p>
3026Browse entire collection</p> 3027 </a> 3028 3029 3030 </div> 3031 </div> 3032 </section> 3033 3034 <!-- Featured Products --> 3035 <section class="section" id="featured-products" style="background: var(--gray-50);"> 3036 <div class="container"> 3037 <div class="section-header"> 3038 <h2 class="section-title">Featured Products</h2> 3039 <a href="/all-products" class="section-link"> 3040 Shop All 3041 <svg viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7"/></svg> 3042 </a> 3043 </div> 3044 <div class="filter-bar" id="filter-bar"> 3045 <button class="filter-btn active" data-filter="all">All Products</button> 3046 <button class="filter-btn" data-filter="bestseller">Best Sellers</button> 3047 <button class="filter-btn" data-filter="new">New Arrivals</button> 3048 <button class="filter-btn" data-filter="sale">On Sale</button> 3049 <button class="filter-btn" data-filter="featured">Featured</button> 3050 <button class="filter-btn" data-filter="coming-soon">Coming Soon</button> 3051 </div> 3052 <div class="products-grid" id="products-container"> 3053 3054 3055 <div class="product-card ssr-card" data-route="products/wizfort-prestige-leather-sole-bicycle-toe-loafer-for-men-f9xq5"> 3056 <a href="/products/wizfort-prestige-leather-sole-bicycle-toe-loafer-for-men-f9xq5" class="product-card-link" data-item-id="WEB-ITM-1721" data-item-name="Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black" data-item-image="/files/Wizfort905_Main.png" data-item-brand="Wizfort Shoes"> 3057 <div class="product-image"> 3058 3059 <img src="/files/Wizfort905_Main.webp" alt="Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black" loading="eager" width="280" height="280" decoding="async"> 3060 3061 3062 <span class="product-badge badge-featured">Featured</span> 3063 3064 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1721" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3065 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black">Quick View</button> 3066 </div> 3067 </a> 3068 <div class="product-info"> 3069 <p class="product-brand">Wizfort Shoes</p> 3070 <h3 class="product-name">Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black</h3> 3071 <p class="product-price"> 3072 3073 $149.99 3074 3075 </p> 3076 </div> 3077 <div class="product-actions"> 3078 <button class="btn-add-cart" aria-label="Add Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black to cart">Add to Cart</button> 3079 </div> 3080 </div> 3081 3082 <div class="product-card ssr-card" data-route="products/wizfort-prestige-comfortable-leather-sole-chassidic-loafer-ib58c"> 3083 <a href="/products/wizfort-prestige-comfortable-leather-sole-chassidic-loafer-ib58c" class="product-card-link" data-item-id="WEB-ITM-1790" data-item-name="Wizfort Men's Premium Leather Sole Chassidic Loafer - Black" data-item-image="/files/Wizfort925_Main.png" data-item-brand="Wizfort Shoes"> 3084 <div class="product-image"> 3085 3086 <img src="/files/Wizfort925_Main.webp" alt="Wizfort Men's Premium Leather Sole Chassidic Loafer - Black" loading="eager" width="280" height="280" decoding="async"> 3087 3088 3089 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1790" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3090 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Premium Leather Sole Chassidic Loafer - Black">Quick View</button> 3091 </div> 3092 </a> 3093 <div class="product-info"> 3094 <p class="product-brand">Wizfort Shoes</p> 3095 <h3 class="product-name">Wizfort Men's Premium Leather Sole Chassidic Loafer - Black</h3> 3096 <p class="product-price"> 3097 3098 $149.99 3099 3100 </p> 3101 </div> 3102 <div class="product-actions"> 3103 <button class="btn-add-cart" aria-label="Add Wizfort Men's Premium Leather Sole Chassidic Loafer - Black to cart">Add to Cart</button> 3104 </div> 3105 </div> 3106 3107 <div class="product-card ssr-card" data-route="products/wizfort-prestige-leather-sole-moc-toe-loafer-for-men-jivbk"> 3108 <a href="/products/wizfort-prestige-leather-sole-moc-toe-loafer-for-men-jivbk" class="product-card-link" data-item-id="WEB-ITM-1778" data-item-name="Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black" data-item-image="/files/Wizfort915_Main.png" data-item-brand="Wizfort Shoes"> 3109 <div class="product-image"> 3110 3111 <img src="/files/Wizfort915_Main.webp" alt="Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black" loading="eager" width="280" height="280" decoding="async"> 3112 3113 3114 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1778" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
3114<path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3115 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black">Quick View</button> 3116 </div> 3117 </a> 3118 <div class="product-info"> 3119 <p class="product-brand">Wizfort Shoes</p> 3120 <h3 class="product-name">Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black</h3> 3121 <p class="product-price"> 3122 3123 $149.99 3124 3125 </p> 3126 </div> 3127 <div class="product-actions"> 3128 <button class="btn-add-cart" aria-label="Add Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black to cart">Add to Cart</button> 3129 </div> 3130 </div> 3131 3132 <div class="product-card ssr-card" data-route="products/wizfort-prestige-mens-moc-toe-lace-up-8svvp"> 3133 <a href="/products/wizfort-prestige-mens-moc-toe-lace-up-8svvp" class="product-card-link" data-item-id="WEB-ITM-1766" data-item-name="Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black" data-item-image="/files/Wizfort910_Main.png" data-item-brand="Wizfort Shoes"> 3134 <div class="product-image"> 3135 3136 <img src="/files/Wizfort910_Main.webp" alt="Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black" loading="eager" width="280" height="280" decoding="async"> 3137 3138 3139 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1766" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3140 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black">Quick View</button> 3141 </div> 3142 </a> 3143 <div class="product-info"> 3144 <p class="product-brand">Wizfort Shoes</p> 3145 <h3 class="product-name">Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black</h3> 3146 <p class="product-price"> 3147 3148 $149.99 3149 3150 </p> 3151 </div> 3152 <div class="product-actions"> 3153 <button class="btn-add-cart" aria-label="Add Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black to cart">Add to Cart</button> 3154 </div> 3155 </div> 3156 3157 <div class="product-card ssr-card" data-route="products/wizfort-prestige-leather-sole-bicycle-toe-lace-up-shoe-for-men-bgki4"> 3158 <a href="/products/wizfort-prestige-leather-sole-bicycle-toe-lace-up-shoe-for-men-bgki4" class="product-card-link" data-item-id="WEB-ITM-0001" data-item-name="Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black" data-item-image="/files/Wizfort900_Main.png" data-item-brand="Wizfort Shoes"> 3159 <div class="product-image"> 3160 3161 <img src="/files/Wizfort900_Main.webp" alt="Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black" loading="lazy" width="280" height="280" decoding="async"> 3162 3163 3164 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-0001" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3165 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black">Quick View</button> 3166 </div> 3167 </a> 3168 <div class="product-info"> 3169 <p class="product-brand">Wizfort Shoes</p> 3170 <h3 class="product-name">Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black</h3> 3171 <p class="product-price"> 3172 3173 $149.99 3174 3175 </p> 3176 </div> 3177 <div class="product-actions"> 3178 <button class="btn-add-cart" aria-label="Add Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black to cart">Add to Cart</button> 3179 </div> 3180 </div> 3181 3182 <div class="product-card ssr-card" data-route="products/wizfort-mens-lightweight-plain-toe-chassidic-loafer-r6fuh"> 3183 <a href="/products/wizfort-mens-lightweight-plain-toe-chassidic-loafer-r6fuh" class="product-card-link" data-item-id="WEB-ITM-1697" data-item-name="Wizfort Men's Leather Lightweight Chassidic Loafer - Black" data-item-image="/files/825_Main.png" data-item-brand="Wizfort Shoes"> 3184 <div class="product-image"> 3185 3186 <img src="/files/825_Main.webp" alt="Wizfort Men's Leather Lightweight Chassidic Loafer - Black" loading="lazy" width="280" height="280" decoding="async"> 3187 3188 3189 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1697" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
3189<path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3190 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Lightweight Chassidic Loafer - Black">Quick View</button> 3191 </div> 3192 </a> 3193 <div class="product-info"> 3194 <p class="product-brand">Wizfort Shoes</p> 3195 <h3 class="product-name">Wizfort Men's Leather Lightweight Chassidic Loafer - Black</h3> 3196 <p class="product-price"> 3197 3198 $129.99 3199 3200 </p> 3201 </div> 3202 <div class="product-actions"> 3203 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Lightweight Chassidic Loafer - Black to cart">Add to Cart</button> 3204 </div> 3205 </div> 3206 3207 <div class="product-card ssr-card" data-route="products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-gpvip"> 3208 <a href="/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-gpvip" class="product-card-link" data-item-id="WEB-ITM-1684" data-item-name="Wizfort Men's Leather Lightweight Moc Toe Loafer - Black" data-item-image="/files/Wizfort810_Main.png" data-item-brand="Wizfort Shoes"> 3209 <div class="product-image"> 3210 3211 <img src="/files/Wizfort810_Main.webp" alt="Wizfort Men's Leather Lightweight Moc Toe Loafer - Black" loading="lazy" width="280" height="280" decoding="async"> 3212 3213 3214 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1684" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3215 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Lightweight Moc Toe Loafer - Black">Quick View</button> 3216 </div> 3217 </a> 3218 <div class="product-info"> 3219 <p class="product-brand">Wizfort Shoes</p> 3220 <h3 class="product-name">Wizfort Men's Leather Lightweight Moc Toe Loafer - Black</h3> 3221 <p class="product-price"> 3222 3223 $109.99 3224 3225 </p> 3226 </div> 3227 <div class="product-actions"> 3228 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Lightweight Moc Toe Loafer - Black to cart">Add to Cart</button> 3229 </div> 3230 </div> 3231 3232 <div class="product-card ssr-card" data-route="products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-tlofo"> 3233 <a href="/products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-tlofo" class="product-card-link" data-item-id="WEB-ITM-1671" data-item-name="Wizfort Men's Leather Lightweight Moc Toe Oxford - Black" data-item-image="/files/Wizfort810_Main.png" data-item-brand="Wizfort Shoes"> 3234 <div class="product-image"> 3235 3236 <img src="/files/Wizfort810_Main.webp" alt="Wizfort Men's Leather Lightweight Moc Toe Oxford - Black" loading="lazy" width="280" height="280" decoding="async"> 3237 3238 3239 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1671" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3240 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Lightweight Moc Toe Oxford - Black">Quick View</button> 3241 </div> 3242 </a> 3243 <div class="product-info"> 3244 <p class="product-brand">Wizfort Shoes</p> 3245 <h3 class="product-name">Wizfort Men's Leather Lightweight Moc Toe Oxford - Black</h3> 3246 <p class="product-price"> 3247 3248 $109.99 3249 3250 </p> 3251 </div> 3252 <div class="product-actions"> 3253 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Lightweight Moc Toe Oxford - Black to cart">Add to Cart</button> 3254 </div> 3255 </div> 3256 3257 <div class="product-card ssr-card" data-route="products/wizfort-mens-lightweight-bicycle-toe-loafer-njyyt"> 3258 <a href="/products/wizfort-mens-lightweight-bicycle-toe-loafer-njyyt" class="product-card-link" data-item-id="WEB-ITM-1658" data-item-name="Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black" data-item-image="/files/Wizfort805_Main.png" data-item-brand="Wizfort Shoes"> 3259 <div class="product-image"> 3260 3261 <img src="/files/Wizfort805_Main.webp" alt="Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black" loading="lazy" width="280" height="280" decoding="async"> 3262 3263 3264 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1658" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
3264<path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3265 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black">Quick View</button> 3266 </div> 3267 </a> 3268 <div class="product-info"> 3269 <p class="product-brand">Wizfort Shoes</p> 3270 <h3 class="product-name">Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black</h3> 3271 <p class="product-price"> 3272 3273 $109.99 3274 3275 </p> 3276 </div> 3277 <div class="product-actions"> 3278 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black to cart">Add to Cart</button> 3279 </div> 3280 </div> 3281 3282 <div class="product-card ssr-card" data-route="products/wizfort-mens-lightweight-bicycle-toe-lace-up-ul7ri"> 3283 <a href="/products/wizfort-mens-lightweight-bicycle-toe-lace-up-ul7ri" class="product-card-link" data-item-id="WEB-ITM-1645" data-item-name="Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black" data-item-image="/files/Wizfort800_Main.png" data-item-brand="Wizfort Shoes"> 3284 <div class="product-image"> 3285 3286 <img src="/files/Wizfort800_Main.webp" alt="Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black" loading="lazy" width="280" height="280" decoding="async"> 3287 3288 3289 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1645" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3290 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black">Quick View</button> 3291 </div> 3292 </a> 3293 <div class="product-info"> 3294 <p class="product-brand">Wizfort Shoes</p> 3295 <h3 class="product-name">Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black</h3> 3296 <p class="product-price"> 3297 3298 $109.99 3299 3300 </p> 3301 </div> 3302 <div class="product-actions"> 3303 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black to cart">Add to Cart</button> 3304 </div> 3305 </div> 3306 3307 <div class="product-card ssr-card" data-route="products/wizfort-classics-mens-leather-sole-moc-toe-slip-on-3oiaf"> 3308 <a href="/products/wizfort-classics-mens-leather-sole-moc-toe-slip-on-3oiaf" class="product-card-link" data-item-id="WEB-ITM-1632" data-item-name="Wizfort Men's Leather Sole Moc Toe Loafer - Black" data-item-image="/files/725Main.png" data-item-brand="Wizfort Shoes"> 3309 <div class="product-image"> 3310 3311 <img src="/files/725Main.webp" alt="Wizfort Men's Leather Sole Moc Toe Loafer - Black" loading="lazy" width="280" height="280" decoding="async"> 3312 3313 3314 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1632" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3315 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Sole Moc Toe Loafer - Black">Quick View</button> 3316 </div> 3317 </a> 3318 <div class="product-info"> 3319 <p class="product-brand">Wizfort Shoes</p> 3320 <h3 class="product-name">Wizfort Men's Leather Sole Moc Toe Loafer - Black</h3> 3321 <p class="product-price"> 3322 3323 $119.99 3324 3325 </p> 3326 </div> 3327 <div class="product-actions"> 3328 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Sole Moc Toe Loafer - Black to cart">Add to Cart</button> 3329 </div> 3330 </div> 3331 3332 <div class="product-card ssr-card" data-route="products/wizfort-classics-mens-leather-sole-moc-toe-lace-up-ggqjf"> 3333 <a href="/products/wizfort-classics-mens-leather-sole-moc-toe-lace-up-ggqjf" class="product-card-link" data-item-id="WEB-ITM-1619" data-item-name="Wizfort Men's Leather Sole Moc Toe Oxford - Black" data-item-image="/files/720Main.png" data-item-brand="Wizfort Shoes"> 3334 <div class="product-image"> 3335 3336 <img src="/files/720Main.webp" alt="Wizfort Men's Leather Sole Moc Toe Oxford - Black" loading="lazy" width="280" height="280" decoding="async"> 3337 3338 3339 <button type="button" class="csl-tile-heart" data-website-item="WEB-ITM-1619" aria-label="Add to wishlist" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
3339<path d="M12 21s-7-4.534-7-10.5a4.5 4.5 0 0 1 8-2.85A4.5 4.5 0 0 1 19 10.5C19 16.466 12 21 12 21z"></path></svg></button> 3340 <button class="quick-view-btn" aria-label="Quick view of Wizfort Men's Leather Sole Moc Toe Oxford - Black">Quick View</button> 3341 </div> 3342 </a> 3343 <div class="product-info"> 3344 <p class="product-brand">Wizfort Shoes</p> 3345 <h3 class="product-name">Wizfort Men's Leather Sole Moc Toe Oxford - Black</h3> 3346 <p class="product-price"> 3347 3348 $119.99 3349 3350 </p> 3351 </div> 3352 <div class="product-actions"> 3353 <button class="btn-add-cart" aria-label="Add Wizfort Men's Leather Sole Moc Toe Oxford - Black to cart">Add to Cart</button> 3354 </div> 3355 </div> 3356 3357 3358 </div> 3359 <div class="show-more-container" id="show-more-container" style="display: none;"> 3360 <button class="btn-show-more" id="btn-show-more" onclick="loadMoreProducts()"> 3361 Show More Products 3362 </button> 3363 </div> 3364 </div> 3365 </section> 3366 3367 3368 3369 <!-- About CSL Shoes â moved below products for better mobile flow --> 3370 <section class="section" style="padding: 40px 0 20px;"> 3371 <div class="container"> 3372 <div style="max-width:820px;margin:0 auto;text-align:left;color:#4b5563;font-size:15px;line-height:1.8"> 3373 <p style="margin-bottom:14px">CSL Shoes is a family-owned footwear importer based in Chestnut Ridge, New York, serving customers nationwide since 2008. We carry three in-house brands of genuine leather dress shoes for men and boys â <a href="/brands/wizfort" style="color:#111827;text-decoration:underline">Wizfort</a> for classic men's dress shoes at fair prices, <a href="/brands/esse-comfort" style="color:#111827;text-decoration:underline">Esse Comfort</a> for cushioned all-day wear including wide widths, and <a href="/brands/benelaccio" style="color:#111827;text-decoration:underline">Benelaccio</a> for Italian-inspired style.</p> 3374 <div id="intro-more" style="display:none;"> 3375 <p style="margin-bottom:14px">Every pair in our collection uses genuine leather uppers â no synthetic substitutes. We control quality from material selection through final inspection, which is why we can offer a 60-day return policy with confidence. Whether you need <a href="/shoes/oxfords" style="color:#111827;text-decoration:underline">Oxfords</a> for the office, <a href="/shoes/loafers" style="color:#111827;text-decoration:underline">loafers</a> for the weekend, <a href="/shoes/wide-width" style="color:#111827;text-decoration:underline">wide width shoes</a> that actually fit, or <a href="/shoes/boys-dress-shoes" style="color:#111827;text-decoration:underline">boys' dress shoes</a> for a communion or bar mitzvah, you will find it here with free standard shipping for retail orders.</p> 3376 <p>Not sure where to start? Our <a href="/guides/shoe-buying-guide" style="color:#111827;text-decoration:underline">shoe buying guide</a> covers leather types, construction methods, and fit â or use our <a href="/size-guide" style="color:#111827;text-decoration:underline">size chart</a> to find your perfect fit before ordering.</p> 3377 </div> 3378 <button id="intro-toggle" onclick="var m=document.getElementById('intro-more');var b=this;if(m.style.display==='none'){m.style.display='block';b.textContent='Read less';}else{m.style.display='none';b.textContent='Read more about us';}" style="background:none;border:none;color:#111827;font-size:14px;font-weight:600;cursor:pointer;padding:0;text-decoration:underline;">Read more about us</button> 3379 </div> 3380 </div> 3381 </section> 3382
3382<script> 3383 // On desktop (>768px), auto-expand the intro text 3384 if (window.innerWidth > 768) { 3385 var introMore = document.getElementById('intro-more'); 3386 var introToggle = document.getElementById('intro-toggle'); 3387 if (introMore) introMore.style.display = 'block'; 3388 if (introToggle) introToggle.style.display = 'none'; 3389 } 3390 </script>
3390 3391 3392 <!-- Why Choose Us --> 3393 <section class="why-csl"> 3394 <div class="container"> 3395 <div class="why-csl-inner"> 3396 3397 <h2>Why Choose Wizfort</h2> 3398 <p>Wizfort makes quality leather shoes for the whole family â men, women, and kids. We focus on durable everyday footwear with classic styling that works for school, special occasions, and everything in between.</p> 3399 <p>Our shoes feature genuine leather uppers, cushioned footbeds, and reinforced construction built to handle active lifestyles. From boys' dress shoes for their first formal event to comfortable styles for parents, every pair is designed to last and look great doing it.</p> 3400 <p>Wizfort is part of the CSL Shoes family, a New York-based footwear company trusted by families across the United States since 2008. We personally inspect every product for quality and offer free standard shipping on all retail orders with a 60-day easy return policy.</p> 3401 <a href="/about" class="why-csl-link">Learn more about our story →</a> 3402 3403 </div> 3404 </div> 3405 </section> 3406 3407 <!-- Newsletter --> 3408 <section class="newsletter"> 3409 <div class="container"> 3410 <div class="newsletter-content"> 3411 <h2>Stay in the Know</h2> 3412 <p>New arrivals, exclusive deals, and style tips â delivered straight to your inbox.</p> 3413 <form class="newsletter-form" id="newsletter-form" onsubmit="return handleNewsletterSubmit(event);"> 3414 <input type="email" id="newsletter-email" placeholder="Enter your email address" required aria-label="Email address for newsletter"> 3415 <button type="submit" id="newsletter-btn">Subscribe</button> 3416 </form> 3417 <p class="newsletter-status" id="newsletter-status" style="font-size: 0.85rem; margin-top: 10px; display: none;"></p> 3418 </div> 3419 </div> 3420 </section> 3421 3422 <!-- Social Follow --> 3423 <section class="social-section"> 3424 <div class="container"> 3425 <div class="section-header" style="justify-content: center; margin-bottom: 16px;"> 3426 <h2 class="section-title">Follow CSL Shoes</h2> 3427 </div> 3428 <p style="text-align: center; color: var(--gray-500); margin-bottom: 32px; max-width: 460px; margin-left: auto; margin-right: auto;">Follow us for style inspiration, new arrivals, and behind-the-scenes looks at our leather craftsmanship.</p> 3429 <div style="display: flex; justify-content: center; flex-wrap: wrap; gap: 20px; max-width: 600px; margin: 0 auto;"> 3430 <a href="https://www.instagram.com/cslshoes" target="_blank" rel="noopener noreferrer" style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 24px 32px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; transition: all 0.3s ease; text-decoration: none; min-width: 130px;" onmouseover="this.style.borderColor='var(--gray-900)';this.style.transform='translateY(-2px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,0.08)'" onmouseout="this.style.borderColor='var(--gray-200)';this.style.transform='none';this.style.boxShadow='none'" aria-label="Follow CSL Shoes on Instagram"> 3431 <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="var(--gray-700)" stroke-width="1.5"><rect x="2" y="2" width="20" height="20" rx="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><circle cx="17.5" cy="6.5" r="1.5"/></svg> 3432 <span style="font-size: 13px; font-weight: 600; color: var(--gray-800);">Instagram</span> 3433 </a> 3434 <a href="https://www.facebook.com/cslshoes" target="_blank" rel="noopener noreferrer" style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 24px 32px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; transition: all 0.3s ease; text-decoration: none; min-width: 130px;" onmouseover="this.style.borderColor='var(--gray-900)';this.style.transform='translateY(-2px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,0.08)'" onmouseout="this.style.borderColor='var(--gray-200)';this.style.transform='none';this.style.boxShadow='none'" aria-label="Follow CSL Shoes on Facebook"> 3435 <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="var(--gray-700)" stroke-width="1.5"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>
3436 <span style="font-size: 13px; font-weight: 600; color: var(--gray-800);">Facebook</span> 3437 </a> 3438 <a href="https://www.tiktok.com/@cslshoes" target="_blank" rel="noopener noreferrer" style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 24px 32px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; transition: all 0.3s ease; text-decoration: none; min-width: 130px;" onmouseover="this.style.borderColor='var(--gray-900)';this.style.transform='translateY(-2px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,0.08)'" onmouseout="this.style.borderColor='var(--gray-200)';this.style.transform='none';this.style.boxShadow='none'" aria-label="Follow CSL Shoes on TikTok"> 3439 <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="var(--gray-700)" stroke-width="1.5"><path d="M9 12a4 4 0 1 0 4 4V4a5 5 0 0 0 5 5"/></svg> 3440 <span style="font-size: 13px; font-weight: 600; color: var(--gray-800);">TikTok</span> 3441 </a> 3442 <a href="https://www.pinterest.com/cslshoes" target="_blank" rel="noopener noreferrer" style="display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 24px 32px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; transition: all 0.3s ease; text-decoration: none; min-width: 130px;" onmouseover="this.style.borderColor='var(--gray-900)';this.style.transform='translateY(-2px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,0.08)'" onmouseout="this.style.borderColor='var(--gray-200)';this.style.transform='none';this.style.boxShadow='none'" aria-label="Follow CSL Shoes on Pinterest"> 3443 <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="var(--gray-700)" stroke-width="1.5"><path d="M8 12a4 4 0 0 1 8 0c0 2.5-1 4.5-2 6"/><path d="M9.5 15.5L7 22"/><circle cx="12" cy="12" r="10"/></svg> 3444 <span style="font-size: 13px; font-weight: 600; color: var(--gray-800);">Pinterest</span> 3445 </a> 3446 </div> 3447 </div> 3448 </section> 3449 3450 <!-- Customer Reviews (only rendered when approved reviews exist) --> 3451 3452 3453 <!-- Trust Badges --> 3454 <section class="trust-badges-section"> 3455 <div class="container"> 3456 <div class="trust-badges-grid"> 3457 <div class="trust-badge-item"> 3458 <svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg> 3459 <span>Secure Checkout</span> 3460 </div> 3461 3462 <div class="trust-badge-item"> 3463 <svg viewBox="0 0 24 24"><rect x="1" y="3" width="15" height="13" rx="2"/><path d="m16 8 5 3-5 3V8z"/></svg> 3464 <span>Free Standard Shipping</span> 3465 </div> 3466 3467 <div class="trust-badge-item"> 3468 <svg viewBox="0 0 24 24"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg> 3469 <span>60-Day Easy Returns</span> 3470 </div> 3471 <div class="trust-badge-item"> 3472 <svg viewBox="0 0 24 24"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> 3473 <span>100% Genuine Leather</span> 3474 </div> 3475 </div> 3476 <div class="payment-logos"> 3477 <span>We accept</span> 3478 <img src="/assets/cslshoes_erp/images/visa.svg" alt="Visa" width="48" height="28"> 3479 <img src="/assets/cslshoes_erp/images/mastercard.svg" alt="Mastercard" width="48" height="28"> 3480 <img src="/assets/cslshoes_erp/images/amex.svg" alt="American Express" width="48" height="28"> 3481 </div> 3482 </div> 3483 </section> 3484 3485 <!-- Recently Viewed --> 3486 <section class="recently-viewed" id="recently-viewed"> 3487 <div class="container"> 3488 <h3 style="font-size: 18px; font-weight: 600; margin-bottom: 16px;">Recently Viewed</h3> 3489 <div class="recently-grid" id="recently-viewed-grid"></div> 3490 </div> 3491 </section> 3492 3493 <!-- Quick View Modal --> 3494 <div class="modal-overlay" id="quick-view-modal"> 3495 <div class="modal-content" style="position: relative;"> 3496 <button class="modal-close" onclick="closeQuickView()" aria-label="Close quick view"> 3497 <svg viewBox="0 0 24 24" fill="none" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> 3498 </button> 3499 <div class="modal-image"> 3500 <img id="modal-product-image" src="" alt="Selected product preview"> 3501 </div> 3502 <div class="modal-details"> 3503 <p class="modal-brand" id="modal-product-brand">BRAND</p> 3504 <h2 class="modal-title" id="modal-product-name">Product Name</h2> 3505 <div class="star-rating"> 3506 <div class="stars" id="modal-stars"></div>
3507 <span class="review-count" id="modal-reviews">(0 reviews)</span> 3508 </div> 3509 <p class="modal-price" id="modal-product-price">$0.00</p> 3510 <div class="modal-sizes"> 3511 <p style="font-weight: 600; font-size: 14px; margin-bottom: 8px;">Select Size <a href="/size-guide" style="font-weight: normal; color: var(--accent); font-size: 12px; margin-left: 8px;">Size Guide</a></p> 3512 <div class="size-grid" id="modal-sizes"> 3513 <button class="size-btn">39</button> 3514 <button class="size-btn">40</button> 3515 <button class="size-btn">41</button> 3516 <button class="size-btn">42</button> 3517 <button class="size-btn">43</button> 3518 <button class="size-btn">44</button> 3519 <button class="size-btn">45</button> 3520 <button class="size-btn unavailable">46</button> 3521 <button class="size-btn">47</button> 3522 <button class="size-btn unavailable">48</button> 3523 </div> 3524 </div> 3525 <div class="modal-actions"> 3526 <button class="btn btn-primary" id="modal-add-cart">Add to Cart</button> 3527 <a href="#" class="btn btn-secondary" id="modal-view-details">View Full Details</a> 3528 </div> 3529 </div> 3530 </div> 3531 </div> 3532 3533 3534 3535 <!-- Sticky Mobile Cart Bar --> 3536 <div class="sticky-cart-bar" id="sticky-cart-bar"> 3537 <img class="sticky-cart-bar-img" id="sticky-cart-img" src="" alt="Cart product thumbnail"> 3538 <div class="sticky-cart-bar-info"> 3539 <div class="sticky-cart-bar-name" id="sticky-cart-name"></div> 3540 <div class="sticky-cart-bar-price" id="sticky-cart-price"></div> 3541 </div> 3542 <button class="btn-add-cart" id="sticky-cart-btn" aria-label="Add to cart">Add to Cart</button> 3543 </div> 3544 3545
3545<script> 3546 // HTML escape helper to prevent XSS 3547 function escapeHtml(str) { 3548 if (!str) return ''; 3549 return String(str) 3550 .replace(/&/g, '&') 3551 .replace(/</g, '<') 3552 .replace(/>/g, '>') 3553 .replace(/"/g, '"') 3554 .replace(/'/g, '''); 3555 } 3556 3557 // Brand filtering for brand-specific domains 3558 const BRAND_FILTER = "Wizfort Shoes"; 3559 3560 // SSR products pre-rendered by server (for SEO + instant display) 3561 const SSR_PRODUCTS = [{"name": "WEB-ITM-1721", "web_item_name": "Wizfort Men's Premium Leather Sole Bicycle Toe Loafer - Black", "item_code": "905", "website_image": "/files/Wizfort905_Main.png", "route": "products/wizfort-prestige-leather-sole-bicycle-toe-loafer-for-men-f9xq5", "brand": "Wizfort Shoes", "short_description": "Men's premium leather sole bicycle toe loafer with genuine leather upper and Flex Fit technology. The executive slip-on dress shoe that delivers handcrafted quality and all-day comfort.", "wished": false, "onSale": false, "formatted_price": "$149.99", "isBestseller": false, "isFeatured": true, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1790", "web_item_name": "Wizfort Men's Premium Leather Sole Chassidic Loafer - Black", "item_code": "925", "website_image": "/files/Wizfort925_Main.png", "route": "products/wizfort-prestige-comfortable-leather-sole-chassidic-loafer-ib58c", "brand": "Wizfort Shoes", "short_description": "Men's premium traditional plain toe loafer with genuine leather sole and Flex Fit technology. The finest Shabbos shoe available \u2014 executive-grade leather construction with cushioned comfort for all-day wear.", "wished": false, "onSale": false, "formatted_price": "$149.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1778", "web_item_name": "Wizfort Men's Premium Leather Sole Moc Toe Loafer - Black", "item_code": "915", "website_image": "/files/Wizfort915_Main.png", "route": "products/wizfort-prestige-leather-sole-moc-toe-loafer-for-men-jivbk", "brand": "Wizfort Shoes", "short_description": "Men's premium moc toe loafer with genuine leather sole and Flex Fit technology. An executive slip-on dress shoe combining handcrafted quality with cushioned, all-day comfort.", "wished": false, "onSale": false, "formatted_price": "$149.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1766", "web_item_name": "Wizfort Men's Premium Leather Sole Moc Toe Oxford - Black", "item_code": "910", "website_image": "/files/Wizfort910_Main.png", "route": "products/wizfort-prestige-mens-moc-toe-lace-up-8svvp", "brand": "Wizfort Shoes", "short_description": "Men's premium moc toe Oxford with genuine leather sole and Flex Fit technology. Handcrafted cemented construction and executive-grade materials define Wizfort's prestige lace-up dress shoe.", "wished": false, "onSale": false, "formatted_price": "$149.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-0001", "web_item_name": "Wizfort Men's Premium Leather Sole Bicycle Toe Oxford - Black", "item_code": "900", "website_image": "/files/Wizfort900_Main.png", "route": "products/wizfort-prestige-leather-sole-bicycle-toe-lace-up-shoe-for-men-bgki4", "brand": "Wizfort Shoes", "short_description": "Men's premium leather sole bicycle toe Oxford with genuine leather upper and Flex Fit technology. Executive-grade craftsmanship meets modern comfort in Wizfort's finest dress shoe.", "wished": false, "onSale": false, "formatted_price": "$149.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1697", "web_item_name": "Wizfort Men's Leather Lightweight Chassidic Loafer - Black", "item_code": "825", "website_image": "/files/825_Main.png", "route": "products/wizfort-mens-lightweight-plain-toe-chassidic-loafer-r6fuh", "brand": "Wizfort Shoes", "short_description": "Men's lightweight traditional plain toe loafer in genuine leather with Flex Fit technology. The lightest Shabbos shoe available \u2014 built for comfort during long services and all-day walking.", "wished": false, "onSale": false, "formatted_price": "$129.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1684", "web_item_name": "Wizfort Men's Leather Lightweight Moc Toe Loafer - Black", "item_code": "815", "website_image": "/files/Wizfort810_Main.png", "route": "products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-gpvip", "brand": "Wizfort Shoes", "short_description": "Men's lightweight moc toe slip-on loafer in genuine leather with Flex Fit comfort technology. Featherlight construction and effortless style make this the ultimate comfortable dress shoe.", "wished": false, "onSale": false, "formatted_price": "$109.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1671", "web_item_name": "Wizfort Men's Leather Lightweight Moc Toe Oxford - Black", "item_code": "810", "website_image": "/files/Wizfort810_Main.png", "route": "products/wizfort-mens-lightweight-moc-toe-lace-up-shoes-tlofo", "brand": "Wizfort Shoes", "short_description": "Men's lightweight moc toe lace-up dress shoe with genuine leather upper and Flex Fit technology. All the style of a traditional formal shoe at a fraction of the weight.", "wished": false, "onSale": false, "formatted_price": "$109.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1658", "web_item_name": "Wizfort Men's Leather Lightweight Bicycle Toe Loafer - Black", "item_code": "805", "website_image": "/files/Wizfort805_Main.png", "route": "products/wizfort-mens-lightweight-bicycle-toe-loafer-njyyt", "brand": "Wizfort Shoes", "short_description": "Men's lightweight bicycle toe loafer in genuine leather with Flex Fit comfort technology. The lightest slip-on dress shoe for professionals who refuse to sacrifice comfort for style.", "wished": false, "onSale": false, "formatted_price": "$109.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1645", "web_item_name": "Wizfort Men's Leather Lightweight Bicycle Toe Oxford - Black", "item_code": "800", "website_image": "/files/Wizfort800_Main.png", "route": "products/wizfort-mens-lightweight-bicycle-toe-lace-up-ul7ri", "brand": "Wizfort Shoes", "short_description": "Men's lightweight bicycle toe Oxford with genuine leather upper and Flex Fit technology. Engineered for professionals who need all-day comfort without compromising on dress shoe style.", "wished": false, "onSale": false, "formatted_price": "$109.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1632", "web_item_name": "Wizfort Men's Leather Sole Moc Toe Loafer - Black", "item_code": "725", "website_image": "/files/725Main.png", "route": "products/wizfort-classics-mens-leather-sole-moc-toe-slip-on-3oiaf", "brand": "Wizfort Shoes", "short_description": "Men's leather sole moc toe slip-on loafer in genuine leather. Traditional cemented construction and a full leather sole deliver the quality and polish of a premium dress loafer.", "wished": false, "onSale": false, "formatted_price": "$119.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}, {"name": "WEB-ITM-1619", "web_item_name": "Wizfort Men's Leather Sole Moc Toe Oxford - Black", "item_code": "720", "website_image": "/files/720Main.png", "route": "products/wizfort-classics-mens-leather-sole-moc-toe-lace-up-ggqjf", "brand": "Wizfort Shoes", "short_description": "Men's leather sole moc toe lace-up in genuine leather. Classic cemented construction and a true leather sole make this the dress shoe for men who appreciate traditional craftsmanship.", "wished": false, "onSale": false, "formatted_price": "$119.99", "isBestseller": false, "isFeatured": false, "isComingSoon": false, "isNewArrival": false}]; 3562 3563 // Frappe API calls to get real data 3564 let featuredProducts = []; 3565 let allProducts = [];
3566 let currentHeroIndex = 0; 3567 let heroRotationInterval = null; 3568 3569 // Pagination state 3570 let currentOffset = 0; 3571 let hasMoreProducts = false; 3572 let currentFilter = 'all'; 3573 let ssrHydrated = false; 3574 let searchTimeout = null; 3575 3576 // Update cart count in header 3577 function updateHeaderCartCount() { 3578 return fetch('/api/method/webshop.webshop.shopping_cart.cart.get_cart_quotation', { 3579 method: 'GET', 3580 headers: { 'Content-Type': 'application/json' } 3581 }) 3582 .then(r => r.json()) 3583 .then(data => { 3584 if (data.message && data.message.doc) { 3585 const totalQty = Math.floor(data.message.doc.total_qty || 0); 3586 const cartCountEl = document.getElementById('cart-count'); 3587 if (cartCountEl) { 3588 cartCountEl.textContent = totalQty; 3589 cartCountEl.style.display = totalQty > 0 ? 'flex' : 'none'; 3590 } 3591 } 3592 }) 3593 .catch(() => {}); 3594 } 3595 3596 // Update wishlist count in header 3597 function updateHeaderWishlistCount() { 3598 const wishlistCountEl = document.getElementById('wishlist-count'); 3599 if (!wishlistCountEl) return Promise.resolve(); 3600 3601 return fetch('/api/method/cslshoes_erp.api.wishlist.get_wishlist_count', { 3602 credentials: 'same-origin' 3603 }) 3604 .then(r => r.json()) 3605 .then(data => { 3606 const wishCount = parseInt(data.message) || 0; 3607 wishlistCountEl.textContent = wishCount; 3608 wishlistCountEl.style.display = wishCount > 0 ? 'flex' : 'none'; 3609 }) 3610 .catch(() => { 3611 wishlistCountEl.style.display = 'none'; 3612 }); 3613 } 3614 3615 // B4 perf (ERP-102): run non-critical, below-the-fold work AFTER the browser 3616 // has painted LCP and gone idle, instead of competing with it on the main 3617 // thread at DOMContentLoaded. This is the "defer below-the-fold JS" lever 3618 // from the B4 diagnosis (the biggest Total-Blocking-Time cut). The { timeout } 3619 // bounds the delay so work that backs an interactive control (e.g. loadBrands 3620 // populating the nav Brands dropdown) can't be starved on a busy main thread. 3621 function deferIdle(fn) { 3622 if ('requestIdleCallback' in window) { 3623 requestIdleCallback(fn, { timeout: 2000 }); 3624 } else { 3625 setTimeout(fn, 1); 3626 } 3627 } 3628 3629 document.addEventListener('DOMContentLoaded', function() { 3630 // Sync initializations (run immediately) â above-the-fold interactivity 3631 initThemeToggle(); 3632 initSearch(); 3633 initFilterButtons(); 3634 3635 // If SSR products were rendered server-side, hydrate them instead of fetching. 3636 // Hydration wires up the above-the-fold product grid + hero, so it stays sync. 3637 if (SSR_PRODUCTS && SSR_PRODUCTS.length > 0) { 3638 hydrateSSRProducts(); 3639 // Brands/categories grids are below the fold; header counts are non-blocking 3640 // â defer past LCP to cut Total Blocking Time. 3641 deferIdle(function() { 3642 Promise.all([ 3643 loadBrands(), 3644 loadCategories(), 3645 updateHeaderCartCount(), 3646 updateHeaderWishlistCount() 3647 ]).catch(err => console.error('Homepage load error:', err)); 3648 }); 3649 } else { 3650 // No SSR products (shouldn't happen) â loadProducts() is the primary 3651 // content on this path, so keep it sync; defer only the rest. 3652 loadProducts().catch(err => console.error('Homepage load error:', err)); 3653 deferIdle(function() { 3654 Promise.all([ 3655 loadBrands(), 3656 loadCategories(), 3657 updateHeaderCartCount(), 3658 updateHeaderWishlistCount() 3659 ]).catch(err => console.error('Homepage load error:', err)); 3660 }); 3661 } 3662 3663 // Recently viewed + sticky mobile cart bar are below the fold â defer. 3664 deferIdle(function() { 3665 initRecentlyViewed(); 3666 initStickyCartBar(); 3667 }); 3668 }); 3669 3670 // Mobile navigation 3671 function openMobileNav() { 3672 document.getElementById('mobile-nav').classList.add('active'); 3673 document.body.style.overflow = 'hidden'; 3674 } 3675 3676 function closeMobileNav() { 3677 document.getElementById('mobile-nav').classList.remove('active'); 3678 document.body.style.overflow = ''; 3679 } 3680 3681 // Mobile search 3682 document.getElementById('mobile-search-input')?.addEventListener('keypress', function(e) { 3683 if (e.key === 'Enter') { 3684 const query = this.value.trim(); 3685 if (query) { 3686 window.location.href = '/all-products?search=' + encodeURIComponent(query); 3687 } 3688 } 3689 }); 3690 3691 // Dark mode toggle 3692 function initThemeToggle() { 3693 const toggle = document.getElementById('theme-toggle'); 3694 const savedTheme = localStorage.getItem('theme'); 3695 3696 if (savedTheme === 'dark') { 3697 document.documentElement.setAttribute('data-theme', 'dark'); 3698 } 3699 3700 toggle?.addEventListener('click', function() { 3701 const currentTheme = document.documentElement.getAttribute('data-theme'); 3702 const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; 3703 3704 document.documentElement.setAttribute('data-theme', newTheme); 3705 localStorage.setItem('theme', newTheme); 3706 }); 3707 } 3708 3709 // Search functionality 3710 function initSearch() { 3711 const searchInput = document.getElementById('search-input'); 3712 const searchResults = document.getElementById('search-results'); 3713 3714 if (!searchInput) return; 3715 3716 searchInput.addEventListener('input', function() { 3717 clearTimeout(searchTimeout); 3718 const query = this.value.trim(); 3719 3720 if (query.length < 2) { 3721 searchResults.classList.remove('active'); 3722 return; 3723 } 3724 3725 searchTimeout = setTimeout(() => searchProducts(query), 300); 3726 }); 3727 3728 searchInput.addEventListener('focus', function() { 3729 if (this.value.trim().length >= 2) { 3730 searchResults.classList.add('active'); 3731 } 3732 }); 3733 3734 document.addEventListener('click', function(e) { 3735 if (!e.target.closest('.search-box')) { 3736 searchResults.classList.remove('active'); 3737 } 3738 }); 3739 } 3740 3741 async function searchProducts(query) { 3742 const searchResults = document.getElementById('search-results'); 3743
3744 try { 3745 const response = await fetch('/api/method/cslshoes_erp.api.search.search_products?query=' + encodeURIComponent(query)); 3746 const data = await response.json(); 3747 3748 if (data.message && data.message.length > 0) { 3749 renderSearchResults(data.message); 3750 } else { 3751 searchResults.innerHTML = '<div class="search-no-results">No products found</div>'; 3752 } 3753 searchResults.classList.add('active'); 3754 } catch (error) { 3755 searchResults.innerHTML = '<div class="search-no-results">Search unavailable</div>'; 3756 searchResults.classList.add('active'); 3757 } 3758 } 3759 3760 function renderSearchResults(products) { 3761 const searchResults = document.getElementById('search-results'); 3762 searchResults.innerHTML = products.map(product => { 3763 const safeName = escapeHtml(product.web_item_name); 3764 const safeRoute = encodeURI(product.route || ''); 3765 const safeBrand = escapeHtml(product.brand || 'CSL Shoes'); 3766 const safeImage = escapeHtml(product.website_image || '/assets/erpnext/images/shoe-placeholder.png'); 3767 const safeId = escapeHtml(product.name); 3768 const safeCode = product.item_code ? ' · #' + escapeHtml(product.item_code) : ''; 3769 return `<a href="/${safeRoute}" class="search-result-item" data-item-id="${safeId}" data-item-name="${safeName}" data-item-image="${safeImage}" data-item-brand="${safeBrand}"> 3770 <img src="${safeImage.replace(/\.(png|jpe?g)$/i, '.webp')}" alt="${safeName}"> 3771 <div class="search-result-info"> 3772 <strong>${safeName}</strong> 3773 <p>${safeBrand}${safeCode}</p> 3774 </div> 3775 </a>`; 3776 }).join(''); 3777 // Attach click handlers via data attributes instead of inline onclick 3778 searchResults.querySelectorAll('.search-result-item').forEach(el => { 3779 el.addEventListener('click', function() { 3780 addToRecentlyViewed( 3781 this.dataset.itemId, 3782 this.dataset.itemName, 3783 this.dataset.itemImage, 3784 this.dataset.itemBrand, 3785 '', 3786 this.getAttribute('href') || '' 3787 ); 3788 }); 3789 }); 3790 } 3791 3792 // Filter buttons 3793 function initFilterButtons() { 3794 const filterBtns = document.querySelectorAll('.filter-btn'); 3795 3796 filterBtns.forEach(btn => { 3797 btn.addEventListener('click', function() { 3798 filterBtns.forEach(b => b.classList.remove('active')); 3799 this.classList.add('active'); 3800 3801 const filter = this.dataset.filter; 3802 currentFilter = filter; 3803 3804 // Hide show more button during reload 3805 const showMoreContainer = document.getElementById('show-more-container'); 3806 if (showMoreContainer) showMoreContainer.style.display = 'none'; 3807 3808 // All filters are now server-side for accurate results 3809 const serverFilters = ['new', 'bestseller', 'featured', 'sale', 'coming-soon']; 3810 if (filter === 'all' || serverFilters.includes(filter)) { 3811 loadProducts(); 3812 } else { 3813 filterProducts(filter); 3814 } 3815 }); 3816 }); 3817 } 3818 3819 // Store which filter categories have products (set once on initial load) 3820 let filterHasProducts = null; 3821 3822 // Hide filter buttons that have no qualifying products 3823 // Only updates on initial "all" load to prevent buttons from disappearing when switching filters 3824 function updateFilterButtonVisibility(products, isInitialLoad = false) { 3825 // Only update the stored state on initial load with all products 3826 if (isInitialLoad && products && products.length > 0) { 3827 filterHasProducts = { 3828 'all': true, 3829 'bestseller': products.some(p => p.isBestseller), 3830 'new': products.some(p => p.isNewArrival),
3831 'sale': products.some(p => p.onSale), 3832 'featured': products.some(p => p.isFeatured), 3833 'coming-soon': products.some(p => p.isComingSoon) 3834 }; 3835 } 3836 3837 // If we don't have stored state yet, show all buttons 3838 if (!filterHasProducts) return; 3839 3840 const filterBtns = document.querySelectorAll('.filter-btn'); 3841 filterBtns.forEach(btn => { 3842 const filter = btn.dataset.filter; 3843 const hasProducts = filterHasProducts[filter] !== false; 3844 btn.style.display = hasProducts ? '' : 'none'; 3845 }); 3846 } 3847 3848 function filterProducts(filter) { 3849 let filtered = [...allProducts]; 3850 3851 switch(filter) { 3852 case 'bestseller': 3853 // Show products marked as bestseller (within date range) 3854 filtered = allProducts.filter(p => p.isBestseller); 3855 break; 3856 case 'new': 3857 // Show products marked as new arrival (within date range) 3858 filtered = allProducts.filter(p => p.isNewArrival); 3859 break; 3860 case 'sale': 3861 // Show products currently on sale 3862 filtered = allProducts.filter(p => p.onSale); 3863 break; 3864 case 'featured': 3865 // Show products marked as featured (within date range) 3866 filtered = allProducts.filter(p => p.isFeatured); 3867 break; 3868 case 'coming-soon': 3869 // Show products marked as coming soon 3870 filtered = allProducts.filter(p => p.isComingSoon); 3871 break; 3872 default: 3873 filtered = allProducts; 3874 } 3875 3876 renderProducts(filtered, filter); 3877 } 3878 3879 // Recently viewed 3880 // Newsletter subscription handler 3881 async function handleNewsletterSubmit(e) { 3882 e.preventDefault(); 3883 const emailInput = document.getElementById('newsletter-email'); 3884 const statusEl = document.getElementById('newsletter-status'); 3885 const btn = document.getElementById('newsletter-btn'); 3886 const email = emailInput.value.trim(); 3887 3888 if (!email) return false; 3889 3890 btn.disabled = true; 3891 btn.textContent = 'Subscribing...'; 3892 statusEl.style.display = 'none'; 3893 3894 try { 3895 const response = await fetch('/api/method/cslshoes_erp.api.newsletter.subscribe', { 3896 method: 'POST', 3897 headers: { 3898 'Content-Type': 'application/json', 3899 'X-Frappe-CSRF-Token': (window.frappe && frappe.csrf_token) || '' 3900 }, 3901 credentials: 'same-origin', 3902 body: JSON.stringify({ email: email }) 3903 }); 3904 const data = await response.json(); 3905 3906 if (data.message) { 3907 if (data.message.status === 'already_subscribed') { 3908 statusEl.textContent = "You're already subscribed! We'll keep you posted."; 3909 } else { 3910 statusEl.textContent = "You're in! Watch your inbox for the latest from CSL Shoes."; 3911 emailInput.value = ''; 3912 } 3913 statusEl.style.color = 'var(--success, #059669)'; 3914 } else if (data.exc_type || data.exception) { 3915 statusEl.textContent = 'Please enter a valid email address.'; 3916 statusEl.style.color = 'var(--danger, #ef4444)'; 3917 } 3918 } catch (err) { 3919 statusEl.textContent = 'Something went wrong. Please try again.'; 3920 statusEl.style.color = 'var(--danger, #ef4444)'; 3921 } 3922 3923 statusEl.style.display = 'block'; 3924 btn.disabled = false; 3925 btn.textContent = 'Subscribe'; 3926 return false; 3927 } 3928 3929 // Sticky mobile cart bar â shows when scrolling through products on mobile 3930 function initStickyCartBar() { 3931 if (window.innerWidth > 768) return; 3932 3933 const bar = document.getElementById('sticky-cart-bar'); 3934 const productsSection = document.getElementById('featured-products'); 3935 if (!bar || !productsSection) return; 3936 3937 let stickyProduct = null; 3938 3939 const observer = new IntersectionObserver((entries) => { 3940 entries.forEach(entry => { 3941 if (entry.isIntersecting) { 3942 bar.classList.add('visible'); 3943 } else { 3944 bar.classList.remove('visible'); 3945 } 3946 }); 3947 }, { threshold: 0.1 }); 3948 3949 observer.observe(productsSection); 3950 3951 // Update sticky bar when user scrolls near product cards 3952 const updateStickyProduct = () => { 3953 const cards = document.querySelectorAll('#products-container .product-card'); 3954 const viewportCenter = window.innerHeight / 2; 3955 let closest = null; 3956 let closestDist = Infinity; 3957 3958 cards.forEach(card => { 3959 const rect = card.getBoundingClientRect(); 3960 const dist = Math.abs(rect.top + rect.height / 2 - viewportCenter); 3961 if (dist < closestDist) { 3962 closestDist = dist; 3963 closest = card; 3964 } 3965 }); 3966 3967 if (closest) { 3968 const link = closest.querySelector('.product-card-link'); 3969 if (link) { 3970 const name = link.dataset.itemName || ''; 3971 const image = link.dataset.itemImage || ''; 3972 const itemId = link.dataset.itemId || ''; 3973 const priceEl = closest.querySelector('.product-price'); 3974 const price = priceEl ? priceEl.textContent.trim() : ''; 3975 3976 if (name !== (stickyProduct && stickyProduct.name)) { 3977 stickyProduct = { name, image, itemId, price }; 3978 document.getElementById('sticky-cart-name').textContent = name; 3979 document.getElementById('sticky-cart-price').textContent = price; 3980 const img = document.getElementById('sticky-cart-img'); 3981 if (image) { 3982 img.src = image; 3983 img.alt = name; 3984 img.style.display = ''; 3985 } else { 3986 img.style.display = 'none'; 3987 } 3988 } 3989 } 3990 } 3991 }; 3992 3993 let scrollTicking = false;
3994 window.addEventListener('scroll', () => { 3995 if (!scrollTicking) { 3996 requestAnimationFrame(() => { 3997 updateStickyProduct(); 3998 scrollTicking = false; 3999 }); 4000 scrollTicking = true; 4001 } 4002 }, { passive: true }); 4003 4004 // Add to cart from sticky bar 4005 document.getElementById('sticky-cart-btn').addEventListener('click', async function() { 4006 if (!stickyProduct || !stickyProduct.itemId) return; 4007 4008 // Find product data from allProducts 4009 const product = allProducts.find(p => p.name === stickyProduct.itemId); 4010 if (product) { 4011 openQuickView(product); 4012 } else { 4013 // Fallback: direct add without size selection 4014 this.disabled = true; 4015 this.textContent = 'Adding...'; 4016 try { 4017 const card = document.querySelector(`.product-card-link[data-item-id="${stickyProduct.itemId}"]`); 4018 if (card) { 4019 const b64 = card.closest('.product-card')?.dataset.productB64; 4020 if (b64) { 4021 const p = JSON.parse(decodeURIComponent(escape(atob(b64)))); 4022 openQuickView(p); 4023 } 4024 } 4025 } finally { 4026 this.disabled = false; 4027 this.textContent = 'Add to Cart'; 4028 } 4029 } 4030 }); 4031 } 4032 4033 function initRecentlyViewed() { 4034 renderRecentlyViewed(); 4035 } 4036 4037 // Store visible brands for filtering recently viewed 4038 let visibleBrandNames = new Set(); 4039 4040 function addToRecentlyViewed(id, name, image, brand, price, route) { 4041 let recent = JSON.parse(localStorage.getItem('recentlyViewed') || '[]'); 4042 4043 // Remove if already exists 4044 recent = recent.filter(item => item.id !== id); 4045 4046 // Add to beginning (include brand, price, route for enhanced display) 4047 recent.unshift({ id, name, image, brand: brand || '', price: price || '', route: route || '' }); 4048 4049 // Keep only last 10 4050 recent = recent.slice(0, 10); 4051 4052 localStorage.setItem('recentlyViewed', JSON.stringify(recent)); 4053 renderRecentlyViewed(); 4054 } 4055 4056 async function renderRecentlyViewed() { 4057 const section = document.getElementById('recently-viewed'); 4058 const grid = document.getElementById('recently-viewed-grid'); 4059 let recent = JSON.parse(localStorage.getItem('recentlyViewed') || '[]'); 4060 4061 if (recent.length === 0) { 4062 section?.classList.remove('has-items'); 4063 return; 4064 } 4065 4066 // Filter via server API to ensure only visible brand items show 4067 try { 4068 const response = await fetch('/api/method/cslshoes_erp.overrides.ecommerce.filter_recently_viewed', { 4069 method: 'POST', 4070 headers: { 'Content-Type': 'application/json' }, 4071 body: JSON.stringify({ items: JSON.stringify(recent) }) 4072 }); 4073 const data = await response.json(); 4074 if (data.message && Array.isArray(data.message)) { 4075 recent = data.message; 4076 // Update localStorage with filtered items 4077 localStorage.setItem('recentlyViewed', JSON.stringify(recent)); 4078 } 4079 } catch (e) { 4080 console.error('Error filtering recently viewed:', e); 4081 } 4082 4083 if (recent.length === 0) { 4084 section?.classList.remove('has-items'); 4085 return; 4086 } 4087 4088 section?.classList.add('has-items'); 4089 4090 if (grid) { 4091 grid.innerHTML = recent.map(item => { 4092 const safeRoute = item.route ? encodeURI(item.route) : '#'; 4093 const safeName = escapeHtml(item.web_item_name || item.name); 4094 const safeImage = escapeHtml(item.image || '/assets/erpnext/images/shoe-placeholder.png'); 4095 const safePrice = escapeHtml(item.price || ''); 4096 const safeId = escapeHtml(item.id); 4097 return ` 4098 <a href="${safeRoute}" class="recently-item" data-item-id="${safeId}"> 4099 <img src="${safeImage.replace(/\.(png|jpe?g)$/i, '.webp')}" alt="${safeName}" loading="lazy" width="120" height="120" decoding="async"> 4100 <p class="recently-item-name">${safeName}</p> 4101 ${safePrice ? `<p class="recently-item-price">${safePrice}</p>` : ''} 4102 <button class="recently-item-cart" aria-label="Add ${safeName} to cart">Add to Cart</button> 4103 </a>`; 4104 }).join(''); 4105 // Attach cart handlers via event delegation (avoids inline onclick) 4106 grid.querySelectorAll('.recently-item-cart').forEach(btn => { 4107 btn.addEventListener('click', function(e) { 4108 e.preventDefault(); 4109 e.stopPropagation(); 4110 const itemId = this.closest('.recently-item')?.dataset.itemId; 4111 if (itemId) addToCartFromRecent(itemId); 4112 }); 4113 }); 4114 } 4115 } 4116 4117 // Add to cart from recently viewed section 4118 async function addToCartFromRecent(itemId) { 4119 // Try to find the product in allProducts first (for quick view with size selection) 4120 const product = allProducts.find(p => p.name === itemId); 4121 if (product) { 4122 openQuickView(product); 4123 return; 4124 } 4125 // Fallback: add the template item directly 4126 const btn = document.querySelector(`.recently-item[data-item-id="${itemId}"] .recently-item-cart`); 4127 if (btn) { 4128 btn.disabled = true; 4129 btn.textContent = 'Adding...'; 4130 }
4131 try { 4132 await addToCart(itemId); 4133 } finally { 4134 if (btn) { 4135 btn.disabled = false; 4136 btn.textContent = 'Add to Cart'; 4137 } 4138 } 4139 } 4140 4141 // Quick View 4142 function openQuickView(product) { 4143 const modal = document.getElementById('quick-view-modal'); 4144 4145 // Store product reference and reset size selection 4146 window.currentQuickViewProduct = product; 4147 window.selectedQuickViewSize = null; 4148 window.currentQuickViewHasVariants = false; 4149 4150 document.getElementById('modal-product-image').src = (product.website_image || '').replace(/\.(png|jpe?g)$/i, '.webp'); 4151 document.getElementById('modal-product-image').alt = product.web_item_name; 4152 document.getElementById('modal-product-brand').textContent = product.brand || 'CSL SHOES'; 4153 document.getElementById('modal-product-name').textContent = product.web_item_name; 4154 4155 // Price 4156 const priceEl = document.getElementById('modal-product-price'); 4157 if (product.formatted_price) { 4158 if (product.onSale) { 4159 priceEl.innerHTML = `<span class="sale-price">${product.formatted_price}</span><span class="original">${product.original_price}</span>`; 4160 } else { 4161 priceEl.textContent = product.formatted_price; 4162 } 4163 } else { 4164 priceEl.textContent = 'Contact for Price'; 4165 } 4166 4167 // Stars (only show if real rating exists) 4168 const modalStarsEl = document.getElementById('modal-stars'); 4169 const modalReviewsEl = document.getElementById('modal-reviews'); 4170 if (product.rating && product.rating > 0) { 4171 const starsHtml = generateStarsHtml(product.rating); 4172 modalStarsEl.innerHTML = starsHtml; 4173 modalReviewsEl.textContent = `(${product.reviews || 0} reviews)`; 4174 modalStarsEl.parentElement.style.display = ''; 4175 } else { 4176 modalStarsEl.innerHTML = ''; 4177 modalReviewsEl.textContent = ''; 4178 modalStarsEl.parentElement.style.display = 'none'; 4179 } 4180 4181 // View details link 4182 document.getElementById('modal-view-details').href = '/' + product.route; 4183 4184 // Load actual sizes from product variants 4185 loadModalSizes(product.item_code); 4186 4187 // Add to cart button with size validation 4188 document.getElementById('modal-add-cart').onclick = async () => { 4189 // Check if size selection is required 4190 if (window.currentQuickViewHasVariants && !window.selectedQuickViewSize) { 4191 showCartNotification('Please select a size', true); 4192 return; 4193 } 4194 4195 const addBtn = document.getElementById('modal-add-cart'); 4196 addBtn.disabled = true; 4197 addBtn.textContent = 'Adding...'; 4198 4199 try { 4200 // Get variant code if size selected 4201 let itemCode = product.item_code; 4202 if (window.selectedQuickViewSize) { 4203 const variantCode = await getVariantCode(product.item_code, window.selectedQuickViewSize); 4204 if (variantCode) itemCode = variantCode; 4205 } 4206 4207 await addToCart(itemCode); 4208 closeQuickView(); 4209 } finally { 4210 addBtn.disabled = false; 4211 addBtn.textContent = 'Add to Cart'; 4212 } 4213 }; 4214 4215 modal.classList.add('active'); 4216 document.body.style.overflow = 'hidden'; 4217 } 4218 4219 function closeQuickView() { 4220 document.getElementById('quick-view-modal').classList.remove('active'); 4221 document.body.style.overflow = ''; 4222 } 4223 4224 // Close modal on overlay click 4225 document.getElementById('quick-view-modal')?.addEventListener('click', function(e) { 4226 if (e.target === this) closeQuickView(); 4227 }); 4228 4229 // Close on Escape key 4230 document.addEventListener('keydown', function(e) { 4231 if (e.key === 'Escape') closeQuickView(); 4232 }); 4233 4234 // Generate star rating HTML 4235 function generateStarsHtml(rating) { 4236 let html = ''; 4237 for (let i = 1; i <= 5; i++) { 4238 if (i <= rating) { 4239 html += '<svg viewBox="0 0 24 24" class="filled"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>'; 4240 } else if (i - 0.5 <= rating) { 4241 html += '<svg viewBox="0 0 24 24" class="filled"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>'; 4242 } else { 4243 html += '<svg viewBox="0 0 24 24" class="empty">
4243<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>'; 4244 } 4245 } 4246 return html; 4247 } 4248 4249 function showHeroImage(src, alt) { 4250 const heroImg = document.getElementById('hero-product-image'); 4251 const heroSource = document.getElementById('hero-product-source'); 4252 const placeholder = document.getElementById('hero-placeholder'); 4253 4254 if (!src) return; 4255 4256 // Create a new image to preload 4257 const img = new Image(); 4258 img.onload = function() { 4259 heroImg.src = src; 4260 heroImg.alt = alt || 'Featured Product'; 4261 heroImg.style.display = 'block'; 4262 heroImg.style.opacity = '1'; 4263 // Update WebP source for <picture> element 4264 if (heroSource) { 4265 heroSource.srcset = src.replace(/\.(png|jpe?g)$/i, '.webp'); 4266 } 4267 if (placeholder) placeholder.classList.add('hidden'); 4268 }; 4269 img.onerror = function() { 4270 console.log('Hero image failed to load:', src); 4271 // Keep placeholder visible 4272 }; 4273 img.src = src; 4274 } 4275 4276 // MKT2-LCP (WEEKEND-001 / MKT-001 perf §2): the hero slideshow's first swap 4277 // RE-TRIGGERS LCP â the rotated slide paints larger than the preloaded first 4278 // frame, so the browser emits a new, later LCP entry (~9-11 s in edge lab runs). 4279 // Browsers freeze LCP observation at the first user interaction (pointerdown / 4280 // keydown) or scroll, so gating the FIRST rotation on interaction keeps the 4281 // preloaded first frame as the LCP element for lab and idle loads, while 4282 // engaged users still get the slideshow. A 15 s fallback keeps the rotation 4283 // alive for passive viewers (far past any LCP measurement window). 4284 const HERO_ROTATION_ARM_EVENTS = ['pointerdown', 'touchstart', 'keydown', 'wheel']; 4285 let heroRotationArmed = false; 4286 4287 function armHeroRotation() { 4288 if (heroRotationArmed) return; 4289 heroRotationArmed = true; 4290 let heroFallbackTimer = null; 4291 const beginHeroRotation = function() { 4292 if (heroFallbackTimer) clearTimeout(heroFallbackTimer); 4293 startHeroRotation(); 4294 }; 4295 HERO_ROTATION_ARM_EVENTS.forEach(function(evt) { 4296 window.addEventListener(evt, beginHeroRotation, { once: true, passive: true }); 4297 }); 4298 heroFallbackTimer = setTimeout(beginHeroRotation, 15000); 4299 } 4300 4301 function startHeroRotation() { 4302 if (heroRotationInterval) return; // idempotent â beginHeroRotation may fire once per arm event 4303 if (featuredProducts.length <= 1) return; 4304 4305 heroRotationInterval = setInterval(() => { 4306 currentHeroIndex = (currentHeroIndex + 1) % featuredProducts.length; 4307 const product = featuredProducts[currentHeroIndex]; 4308 const heroImg = document.getElementById('hero-product-image'); 4309 4310 // Fade out 4311 heroImg.style.opacity = '0'; 4312 4313 setTimeout(() => { 4314 showHeroImage(product.website_image, product.web_item_name); 4315 }, 300); 4316 }, 4000); 4317 } 4318 4319 function hydrateSSRProducts() { 4320 // SSR cards are already in the DOM â just wire up JS state and handlers 4321 allProducts = SSR_PRODUCTS; 4322 currentOffset = SSR_PRODUCTS.length; 4323 ssrHydrated = true; 4324 4325 // Add data-product-b64 to SSR cards so Quick View and Add to Cart work 4326 const container = document.getElementById('products-container'); 4327 if (container) { 4328 const ssrCards = container.querySelectorAll('.ssr-card'); 4329 ssrCards.forEach((card, idx) => { 4330 if (idx < SSR_PRODUCTS.length) { 4331 const b64 = btoa(unescape(encodeURIComponent(JSON.stringify(SSR_PRODUCTS[idx])))); 4332 card.dataset.productB64 = b64; 4333 } 4334 }); 4335 attachProductCardHandlers(container); 4336 } 4337 4338 // Set up hero rotation from featured products 4339 featuredProducts = SSR_PRODUCTS.filter(p => p.isFeatured && p.website_image); 4340 if (featuredProducts.length > 0) { 4341 showHeroImage(featuredProducts[0].website_image, featuredProducts[0].web_item_name); 4342 armHeroRotation(); // MKT2-LCP: rotation starts on first interaction or after 15 s 4343 } 4344 4345 // Update filter button visibility 4346 updateFilterButtonVisibility(SSR_PRODUCTS, true); 4347 4348 // Check if there are more products beyond the SSR set 4349 // Fire a lightweight count check 4350 let countUrl = `/api/method/cslshoes_erp.overrides.ecommerce.get_homepage_products?limit=1&offset=0`; 4351 if (BRAND_FILTER) countUrl += `&brand=${encodeURIComponent(BRAND_FILTER)}`; 4352 fetch(countUrl).then(r => r.json()).then(data => { 4353 if (data.message && data.message.total > SSR_PRODUCTS.length) { 4354 hasMoreProducts = true; 4355 const showMoreContainer = document.getElementById('show-more-container'); 4356 if (showMoreContainer) showMoreContainer.style.display = 'block'; 4357 } 4358 }).catch(() => {}); 4359 4360 console.log('[CSL] Hydrated', SSR_PRODUCTS.length, 'SSR products'); 4361 } 4362 4363 async function loadProducts(append = false) { 4364 console.log('[CSL] loadProducts() called - v5, append:', append); 4365 const container = document.getElementById('products-container'); 4366 const showMoreBtn = document.getElementById('btn-show-more'); 4367 const showMoreContainer = document.getElementById('show-more-container'); 4368 4369 if (!append) { 4370 // Reset pagination for fresh load 4371 currentOffset = 0; 4372 allProducts = []; 4373 if (container) { 4374 container.innerHTML = '<div style="padding:20px;text-align:center;">Loading products...</div>'; 4375 } 4376 } else if (showMoreBtn) { 4377 showMoreBtn.disabled = true; 4378 showMoreBtn.textContent = 'Loading...'; 4379 } 4380
4381 try { 4382 // Build API URL with pagination 4383 let apiUrl = `/api/method/cslshoes_erp.overrides.ecommerce.get_homepage_products?limit=12&offset=${currentOffset}`; 4384 if (BRAND_FILTER) { 4385 apiUrl += `&brand=${encodeURIComponent(BRAND_FILTER)}`; 4386 } 4387 if (currentFilter && currentFilter !== 'all') { 4388 const filterMap = { 4389 'new': 'new_arrivals', 4390 'bestseller': 'bestsellers', 4391 'featured': 'featured', 4392 'sale': 'sale', 4393 'coming-soon': 'coming_soon' 4394 }; 4395 if (filterMap[currentFilter]) { 4396 apiUrl += `&filter_type=${filterMap[currentFilter]}`; 4397 } 4398 } 4399 4400 const response = await fetch(apiUrl); 4401 const data = await response.json(); 4402 4403 if (data.message && data.message.products && !data.exception) { 4404 const products = data.message.products; 4405 hasMoreProducts = data.message.has_more; 4406 4407 if (append) { 4408 // Append to existing products 4409 allProducts = allProducts.concat(products); 4410 appendProductsToGrid(products); 4411 } else { 4412 // Replace products 4413 allProducts = products; 4414 renderProducts(products); 4415 4416 // Update filter button visibility - only set initial state on "all" filter 4417 const isInitialLoad = !currentFilter || currentFilter === 'all'; 4418 updateFilterButtonVisibility(products, isInitialLoad); 4419 4420 // Store featured products for hero rotation 4421 featuredProducts = products.filter(p => p.isFeatured && p.website_image); 4422 if (featuredProducts.length > 0) { 4423 showHeroImage(featuredProducts[0].website_image, featuredProducts[0].web_item_name); 4424 armHeroRotation(); // MKT2-LCP: rotation starts on first interaction or after 15 s 4425 } 4426 } 4427 4428 // Update offset for next load 4429 currentOffset += products.length; 4430 4431 // Show/hide "Show More" button 4432 if (showMoreContainer) { 4433 showMoreContainer.style.display = hasMoreProducts ? 'block' : 'none'; 4434 } 4435 } else if (data.exception) { 4436 console.warn('API exception:', data.exception); 4437 loadProductsFallback(data.exception); 4438 } else { 4439 renderProducts([]); 4440 if (showMoreContainer) showMoreContainer.style.display = 'none'; 4441 } 4442 } catch (error) { 4443 console.error('[CSL] Error loading products:', error.message, error.stack); 4444 loadProductsFallback(error.message); 4445 } finally { 4446 if (showMoreBtn) { 4447 showMoreBtn.disabled = false; 4448 showMoreBtn.textContent = 'Show More Products'; 4449 } 4450 } 4451 } 4452 4453 function loadMoreProducts() { 4454 loadProducts(true); 4455 } 4456 4457 function appendProductsToGrid(products) { 4458 const container = document.getElementById('products-container'); 4459 if (!container || !products.length) return; 4460 4461 const html = products.map(product => renderProductCard(product)).join(''); 4462 container.insertAdjacentHTML('beforeend', html); 4463 } 4464 4465 function loadProductsFallback(errorMsg) { 4466 // Show error message 4467 console.error('[CSL] Product API failed:', errorMsg); 4468 allProducts = []; 4469 // Don't update filter visibility on error - keep buttons visible 4470 const container = document.getElementById('products-container'); 4471 if (container) { 4472 container.innerHTML = `<div style="padding:40px;text-align:center;color:#c00;grid-column:1/-1;"> 4473 <p>Error loading products</p> 4474 <p style="font-size:0.8em;color:#666;">${errorMsg || 'Unknown error'}</p> 4475 </div>`; 4476 } 4477 } 4478 4479 function renderProductCard(product) { 4480 const rating = product.rating || 0; 4481 const reviews = product.reviews || 0; 4482 // Only show colors/sizes if API returns real data for this product 4483 const colors = product.colors || []; 4484 const sizes = product.sizes || []; 4485 4486 // Escape all user-controlled strings 4487 const safeName = escapeHtml(product.web_item_name); 4488 const safeRoute = encodeURI(product.route || ''); 4489 const safeBrand = escapeHtml(product.brand || 'CSL Shoes'); 4490 const safeImage = escapeHtml(product.website_image || ''); 4491 const safeId = escapeHtml(product.name); 4492 const safePrice = escapeHtml(product.formatted_price || ''); 4493 const safeOrigPrice = escapeHtml(product.original_price || ''); 4494 4495 // Determine badge based on actual product flags from database 4496 let badgeHtml = ''; 4497 if (product.onSale) { 4498 badgeHtml = '<span class="product-badge badge-sale">Sale</span>'; 4499 } else if (product.isComingSoon) { 4500 badgeHtml = '<span class="product-badge badge-coming-soon">Coming Soon</span>'; 4501 } else if (product.isBestseller) { 4502 badgeHtml = '<span class="product-badge badge-bestseller">Best Seller</span>'; 4503 } else if (product.isFeatured) { 4504 badgeHtml = '<span class="product-badge badge-featured">Featured</span>'; 4505 } else if (parseFloat(rating) >= 4.8) { 4506 badgeHtml = '<span class="product-badge badge-toprated">Top Rated</span>'; 4507 } 4508 4509 // Price display 4510 let priceHtml = ''; 4511 if (safePrice) { 4512 if (product.onSale && safeOrigPrice) { 4513 const priceNum = parseFloat(safePrice.replace(/[^0-9.]/g, '')); 4514 const origNum = parseFloat(safeOrigPrice.replace(/[^0-9.]/g, '')); 4515 const discount = origNum > 0 ? Math.round((1 - priceNum / origNum) * 100) : 0; 4516 priceHtml = `<span class="sale-price">${safePrice}</span><span class="original-price">${safeOrigPrice}</span><span class="discount-tag">-${discount}%</span>`;
4517 } else { 4518 priceHtml = safePrice; 4519 } 4520 } else { 4521 priceHtml = 'Contact for Price'; 4522 } 4523 4524 // Stars HTML 4525 const starsHtml = generateStarsHtml(parseFloat(rating)); 4526 4527 // Store product data safely via data attribute using base64 4528 const productDataB64 = btoa(unescape(encodeURIComponent(JSON.stringify(product)))); 4529 4530 // Color swatches - only show if real data exists 4531 let colorHtml = ''; 4532 if (colors.length > 0) { 4533 colorHtml = '<div class="color-swatches">' + 4534 colors.slice(0, 4).map(color => { 4535 const safeColor = escapeHtml(color); 4536 return `<span class="color-swatch" style="background-color: ${safeColor};" title="${safeColor}" aria-label="Color: ${safeColor}"></span>`; 4537 }).join('') + '</div>'; 4538 } 4539 4540 // Size pills - only show if real data exists 4541 let sizeHtml = ''; 4542 if (sizes.length > 0) { 4543 sizeHtml = '<div class="size-pills">' + 4544 sizes.slice(0, 6).map(size => `<span class="size-pill available">${escapeHtml(size)}</span>`).join('') + 4545 '</div>'; 4546 } 4547 4548 const heartHtml = (window.cslTileWishlist && typeof cslTileWishlist.html === 'function') 4549 ? cslTileWishlist.html({ websiteItem: safeId, wished: !!product.wished }) 4550 : ''; 4551 4552 return ` 4553 <div class="product-card" data-product-b64="${productDataB64}"> 4554 <a href="/${safeRoute}" class="product-card-link" data-item-id="${safeId}" data-item-name="${safeName}" data-item-image="${safeImage}" data-item-brand="${safeBrand}"> 4555 <div class="product-image"> 4556 ${safeImage ? 4557 `<img src="${safeImage.replace(/\.(png|jpe?g)$/i, '.webp')}" alt="${safeName}" loading="lazy" width="280" height="280" decoding="async" onerror="this.style.display='none';this.nextElementSibling.style.display='flex'"><div style="background:#f3f4f6;height:100%;display:none;align-items:center;justify-content:center;color:#9ca3af">
4557No Image</div>` : 4558 '<div style="background:#f3f4f6;height:100%;display:flex;align-items:center;justify-content:center;color:#9ca3af">No Image</div>' 4559 } 4560 ${badgeHtml} 4561 ${heartHtml} 4562 <button class="quick-view-btn" aria-label="Quick view of ${safeName}">Quick View</button> 4563 </div> 4564 </a> 4565 <div class="product-info"> 4566 <p class="product-brand">${safeBrand}</p> 4567 ${rating > 0 ? `<div class="star-rating"> 4568 <div class="stars">${starsHtml}</div> 4569 <span class="review-count">(${parseInt(reviews)})</span> 4570 </div>` : ''} 4571 <h3 class="product-name">${safeName}</h3> 4572 <p class="product-price">${priceHtml}</p> 4573 ${colorHtml} 4574 ${sizeHtml} 4575 </div> 4576 <div class="product-actions"> 4577 <button class="btn-add-cart" aria-label="Add ${safeName} to cart">Add to Cart</button> 4578 </div> 4579 </div> 4580 `; 4581 } 4582 4583 function renderProducts(products, filter = 'all') { 4584 const container = document.getElementById('products-container'); 4585 const section = document.getElementById('featured-products'); 4586 4587 // Always show section 4588 if (section) section.style.display = 'block'; 4589 4590 // Show message if no products match filter 4591 if (!products || products.length === 0) { 4592 const filterLabels = { 4593 'all': 'products', 4594 'bestseller': 'bestsellers', 4595 'new': 'new arrivals',
4596 'sale': 'products on sale', 4597 'featured': 'featured products', 4598 'coming-soon': 'coming soon products' 4599 }; 4600 const label = filterLabels[filter] || 'products'; 4601 container.innerHTML = ` 4602 <div class="no-products-message" style="grid-column: 1/-1; text-align: center; padding: 60px 20px; color: #666;"> 4603 <p style="font-size: 1.2rem; margin-bottom: 10px;">No ${label} found</p> 4604 <p style="font-size: 0.9rem;">Check back soon for updates!</p> 4605 </div> 4606 `; 4607 return; 4608 } 4609 4610 container.innerHTML = products.map(product => renderProductCard(product)).join(''); 4611 attachProductCardHandlers(container); 4612 // BUG-W4: repaint wishlist hearts to current truth after re-render. 4613 // Frappe page cache may have served guest SSR (wished=false) to a 4614 // logged-in user; sync corrects every .csl-tile-heart on the page. 4615 if (window.cslTileWishlist && typeof cslTileWishlist.syncHearts === 'function') { 4616 cslTileWishlist.syncHearts(); 4617 } 4618 } 4619 4620 // Attach event handlers to product cards (replaces inline onclick) 4621 function attachProductCardHandlers(container) { 4622 // Recently viewed tracking on card link clicks 4623 container.querySelectorAll('.product-card-link').forEach(el => { 4624 el.addEventListener('click', function() { 4625 const card = this.closest('.product-card'); 4626 const priceEl = card ? card.querySelector('.product-price') : null; 4627 const price = priceEl ? priceEl.textContent.trim() : ''; 4628 const route = this.getAttribute('href') || ''; 4629 addToRecentlyViewed( 4630 this.dataset.itemId, 4631 this.dataset.itemName, 4632 this.dataset.itemImage, 4633 this.dataset.itemBrand, 4634 price, 4635 route 4636 ); 4637 }); 4638 }); 4639 // Quick View buttons 4640 container.querySelectorAll('.quick-view-btn').forEach(btn => { 4641 btn.addEventListener('click', function(e) { 4642 e.preventDefault(); 4643 e.stopPropagation(); 4644 const card = this.closest('.product-card'); 4645 if (card && card.dataset.productB64) { 4646 try { 4647 const product = JSON.parse(decodeURIComponent(escape(atob(card.dataset.productB64)))); 4648 openQuickView(product); 4649 } catch(err) { console.error('Error parsing product data:', err); } 4650 } 4651 }); 4652 }); 4653 // Add to Cart buttons 4654 container.querySelectorAll('.btn-add-cart').forEach(btn => { 4655 btn.addEventListener('click', function(e) { 4656 e.stopPropagation(); 4657 const card = this.closest('.product-card'); 4658 if (card && card.dataset.productB64) { 4659 try { 4660 const product = JSON.parse(decodeURIComponent(escape(atob(card.dataset.productB64)))); 4661 openQuickView(product); 4662 } catch(err) { console.error('Error parsing product data:', err); } 4663 } 4664 }); 4665 }); 4666 } 4667 4668 async function loadBrands() { 4669 try { 4670 const response = await fetch('/api/method/cslshoes_erp.overrides.ecommerce.get_homepage_brands'); 4671 const data = await response.json(); 4672 4673 if (data.message && data.message.length > 0 && !data.exception) { 4674 // Store visible brand names for filtering recently viewed 4675 visibleBrandNames = new Set(data.message.map(b => b.name)); 4676 renderBrands(data.message); 4677 // Re-render recently viewed with brand filtering 4678 renderRecentlyViewed(); 4679 } else { 4680 renderBrandsFallback(); 4681 } 4682 } catch (error) { 4683 console.error('Error loading brands:', error); 4684 renderBrandsFallback(); 4685 } 4686 } 4687 4688 function renderBrandsFallback() { 4689 const brands = [ 4690 { name: 'Benelaccio', description: 'Italian-inspired elegance', image: '/files/benelaccio_Squarefb78b5.png' }, 4691 { name: 'Esse Comfort', description: 'All-day comfort technology', image: '/files/Esse Square.png' }, 4692 { name: 'Wizfort Shoes', description: 'Modern classics redefined', image: '/files/wizfort_Squareb65af6.png' } 4693 ]; 4694 renderBrands(brands); 4695 } 4696 4697 function renderBrands(brands) { 4698 // Render brands section with logos 4699 const container = document.getElementById('brands-container'); 4700 container.innerHTML = brands.map(brand => { 4701 const slugMap = {'Wizfort Shoes':'wizfort','Esse Comfort':'esse-comfort','Benelaccio':'benelaccio'}; 4702 const brandUrl = '/brands/' + (slugMap[brand.name] || brand.name.toLowerCase().replace(/\s+/g, '-')); 4703 const hasImage = brand.image && brand.image.trim() !== ''; 4704 return ` 4705 <a href="${brandUrl}" class="brand-item"> 4706 <div class="brand-logo"> 4707 ${hasImage 4708 ? `<img src="${brand.image.replace(/\.(png|jpe?g)$/i, '.webp')}" alt="${brand.name} logo" loading="lazy">` 4709 : `<span class="brand-logo-fallback">${brand.name.charAt(0)}</span>` 4710 } 4711 </div> 4712 <p class="brand-name">${brand.name}</p> 4713 </a> 4714 `; 4715 }).join(''); 4716 4717 // Populate brands dropdown in navigation 4718 const dropdown = document.getElementById('brands-dropdown'); 4719 if (dropdown) { 4720 dropdown.innerHTML = brands.map(brand => { 4721 const slugMap2 = {'Wizfort Shoes':'wizfort','Esse Comfort':'esse-comfort','Benelaccio':'benelaccio'}; 4722 const brandUrl = '/brands/' + (slugMap2[brand.name] || brand.name.toLowerCase().replace(/\s+/g, '-')); 4723 return `<a href="${brandUrl}">${brand.name}</a>`; 4724 }).join(''); 4725 } 4726 } 4727 4728 async function loadCategories() {
4729 try { 4730 const response = await fetch('/api/method/cslshoes_erp.overrides.ecommerce.get_shop_categories'); 4731 4732 const data = await response.json(); 4733 console.log('Categories API response:', data); 4734 4735 if (data.message && data.message.length > 0) { 4736 renderCategories(data.message); 4737 } else { 4738 console.log('No categories in response, using fallback'); 4739 renderCategoriesFallback(); 4740 } 4741 } catch (error) { 4742 console.error('Error loading categories:', error); 4743 renderCategoriesFallback(); 4744 } 4745 } 4746 4747 function renderCategoriesFallback() { 4748 // Fallback with basic categories if API fails 4749 // ST-4: canonical facet-slug casing (Title-Case hyphenated) â keep in sync 4750 // with _normalize_closure_type_link in overrides/ecommerce.py. 4751 const categories = [ 4752 { name: 'Lace Up', link: '/closure-type/Lace-Up/items', images: [], rotation_interval: 4000 }, 4753 { name: 'Slip On', link: '/closure-type/Slip-On/items', images: [], rotation_interval: 4000 }, 4754 { name: 'Velcro', link: '/closure-type/Velcro/items', images: [], rotation_interval: 4000 } 4755 ]; 4756 renderCategories(categories); 4757 } 4758 4759 // Store category rotation intervals for cleanup 4760 const categoryRotationIntervals = {}; 4761 4762 function renderCategories(categories) { 4763 const container = document.getElementById('categories-container'); 4764 4765 // Clear any existing rotation intervals 4766 Object.values(categoryRotationIntervals).forEach(interval => clearInterval(interval)); 4767 4768 // Display name overrides (DB closure type - customer-friendly label) 4769 const categoryDisplayNames = { 4770 'Monk Strap': "Boys' Shoes", 4771 'Velcro': "Boys' Shoes" 4772 }; 4773 const categoryDescriptions = { 4774 'Lace Up': 'Classic oxford & derby styles', 4775 'Oxfords': 'Classic oxford & derby styles', 4776 'Slip On': 'Easy loafers & moccasins', 4777 "Boys' Shoes": 'Comfortable & stylish shoes', 4778 'Velcro': 'Convenient & comfortable', 4779 'Coming Soon': 'New arrivals', 4780 'All Shoes': 'Browse entire collection' 4781 }; 4782 4783 // Fallback SVG icon when no images available 4784 const fallbackIcon = '<svg viewBox="0 0 64 64" width="80" height="60"><path fill="#374151" d="M8 44c0-4 2-8 6-10l4-2c2-1 4-3 4-5V18c0-4 4-6 8-6h24c4 0 8 2 8 6v9c0 2 2 4 4 5l4 2c4 2 6 6 6 10v4H8v-4z"/><path fill="#6B7280" d="M16 48h32v2H16z"/></svg>'; 4785 4786 // Add "All Shoes" category at the end 4787 const allCategories = [ 4788 ...categories, 4789 { name: 'All Shoes', link: '/all-products', images: [], rotation_interval: 4000 } 4790 ]; 4791 4792 container.innerHTML = allCategories.map((cat, idx) => { 4793 const hasImages = cat.images && cat.images.length > 0; 4794 const categoryId = `category-${idx}`; 4795 const displayName = categoryDisplayNames[cat.name] || cat.name; 4796 4797 return ` 4798 <a href="${cat.link}" class="category-card"> 4799 <div class="category-icon" id="${categoryId}"> 4800 ${hasImages 4801 ? `<img src="${cat.images[0].replace(/\.(png|jpe?g)$/i, '.webp')}" alt="${displayName}" width="115" height="80" style="width: 100%; height: 100%; object-fit: contain;" loading="lazy">` 4802 : fallbackIcon 4803 } 4804 </div> 4805 <h3>${displayName}</h3> 4806 <p>${categoryDescriptions[displayName] || categoryDescriptions[cat.name] || 'Shop ' + displayName + ' styles'}</p> 4807 </a> 4808 `; 4809 }).join(''); 4810 4811 // Set up image rotation for categories with multiple images 4812 allCategories.forEach((cat, idx) => { 4813 if (cat.images && cat.images.length > 1) { 4814 const categoryId = `category-${idx}`; 4815 const interval = cat.rotation_interval || 4000; 4816 let currentImageIndex = 0; 4817 4818 categoryRotationIntervals[categoryId] = setInterval(() => { 4819 currentImageIndex = (currentImageIndex + 1) % cat.images.length; 4820 const container = document.getElementById(categoryId); 4821 if (container) { 4822 const img = container.querySelector('img'); 4823 if (img) { 4824 // Fade effect
4825 img.style.opacity = '0'; 4826 setTimeout(() => { 4827 img.src = cat.images[currentImageIndex].replace(/\.(png|jpe?g)$/i, '.webp'); 4828 img.style.opacity = '1'; 4829 }, 150); 4830 } 4831 } 4832 }, interval); 4833 } 4834 }); 4835 } 4836 4837 // ============== CART FUNCTIONALITY ============== 4838 4839 // Guest cart cookie helpers - client-side management to avoid SameSite cookie issues 4840 function getGuestCartId() { 4841 const match = document.cookie.match(/guest_cart_id=([^;]+)/); 4842 return match ? match[1] : null; 4843 } 4844 4845 function setGuestCartId(cartId) { 4846 if (cartId) { 4847 const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toUTCString(); 4848 document.cookie = `guest_cart_id=${cartId}; expires=${expires}; path=/; SameSite=Lax`; 4849 } 4850 } 4851 4852 async function addToCart(itemCode, qty = 1) { 4853 try { 4854 const headers = { 'Content-Type': 'application/json' }; 4855 4856 // Get CSRF token from cookie or frappe object 4857 let csrfToken = null; 4858 if (typeof frappe !== 'undefined' && frappe.csrf_token) { 4859 csrfToken = frappe.csrf_token; 4860 } else { 4861 // Try to get from cookie for guests 4862 const match = document.cookie.match(/csrf_token=([^;]+)/); 4863 if (match) csrfToken = decodeURIComponent(match[1]); 4864 } 4865 4866 if (csrfToken) { 4867 headers['X-Frappe-CSRF-Token'] = csrfToken; 4868 } 4869 4870 // Use guest cart API (automatically uses regular cart for logged-in users) 4871 const response = await fetch('/api/method/cslshoes_erp.api.guest_cart.update_guest_cart', { 4872 method: 'POST', 4873 headers: headers, 4874 credentials: 'same-origin', // Include cookies for session tracking 4875 body: JSON.stringify({ 4876 item_code: itemCode, 4877 qty: qty, 4878 cart_id: getGuestCartId() // Include existing cart_id from cookie 4879 }) 4880 }); 4881 4882 const data = await response.json(); 4883 if (data.message && data.message.success !== false) { 4884 // Store the cart_token (signed) in cookie for future requests 4885 if (data.message.cart_token) { 4886 setGuestCartId(data.message.cart_token); 4887 } else if (data.message.cart_id) { 4888 // Backwards compatibility 4889 setGuestCartId(data.message.cart_id); 4890 } 4891 showCartNotification('Added to cart!'); 4892 // BUG-W3 cart sub: re-fetch via canonical csl_header.html reader 4893 // (handles both guest cart and webshop logged-in cart, single source 4894 // of truth). Replaces broken inline updateCartCountDisplay which 4895 // targeted .nav-link[href="/cart"] and .cart-count-badge â selectors 4896 // that don't exist in production CSL header. 4897 if (window.updateCslCartCount) window.updateCslCartCount(); 4898 } else if (data.message && data.message.error) { 4899 showCartNotification(data.message.error, true); 4900 } else if (data.exception) { 4901 console.error('Cart exception:', data.exception); 4902 showCartNotification('Error adding to cart', true); 4903 } 4904 } catch (e) { 4905 console.error('Cart error:', e); 4906 showCartNotification('Error adding to cart', true); 4907 } 4908 } 4909 4910 function updateCartCountDisplay(count) { 4911 const cartLink = document.querySelector('.nav-link[href="/cart"]'); 4912 if (cartLink) { 4913 cartLink.textContent = 'Cart (' + count + ')'; 4914 } 4915 // Also update any cart badge 4916 const cartBadge = document.querySelector('.cart-count-badge'); 4917 if (cartBadge) { 4918 cartBadge.textContent = count; 4919 cartBadge.style.display = count > 0 ? 'inline-block' : 'none'; 4920 } 4921 } 4922 4923 function showCartNotification(message, isError = false) { 4924 // Remove any existing toast 4925 const existing = document.querySelector('.cart-toast'); 4926 if (existing) existing.remove(); 4927 4928 const toast = document.createElement('div'); 4929 toast.className = 'cart-toast'; 4930 toast.style.cssText = `position:fixed;bottom:80px;right:20px;padding:15px 25px;background:${isError ? '#ef4444' : '#22c55e'};color:white;border-radius:8px;z-index:10000;font-weight:600;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:slideIn 0.3s ease;`; 4931 toast.textContent = message; 4932 document.body.appendChild(toast); 4933 setTimeout(() => { 4934 toast.style.opacity = '0'; 4935 toast.style.transition = 'opacity 0.3s'; 4936 setTimeout(() => toast.remove(), 300); 4937 }, 2500); 4938 } 4939
4940 // ============== QUICK VIEW MODAL SIZES ============== 4941 async function loadModalSizes(itemCode) { 4942 const container = document.getElementById('modal-sizes'); 4943 container.innerHTML = '<div style="color:#666;padding:10px;">Loading sizes...</div>'; 4944 4945 try { 4946 const headers = { 'Content-Type': 'application/json' }; 4947 if (typeof frappe !== 'undefined' && frappe.csrf_token) { 4948 headers['X-Frappe-CSRF-Token'] = frappe.csrf_token; 4949 } 4950 4951 const response = await fetch('/api/method/cslshoes_erp.overrides.variant_selector.get_attributes_and_values_with_stock', { 4952 method: 'POST', 4953 headers: headers, 4954 body: JSON.stringify({ item_code: itemCode }) 4955 }); 4956 const data = await response.json(); 4957 4958 if (data.message && data.message.length > 0) { 4959 const sizeAttr = data.message.find(a => a.attribute.toLowerCase() === 'size'); 4960 if (sizeAttr && sizeAttr.values && sizeAttr.values.length > 0) { 4961 renderModalSizes(sizeAttr.values); 4962 window.currentQuickViewHasVariants = true; 4963 } else { 4964 container.innerHTML = '<div style="color:#666;padding:10px;">One size available</div>'; 4965 window.currentQuickViewHasVariants = false; 4966 } 4967 } else { 4968 container.innerHTML = '<div style="color:#666;padding:10px;">One size available</div>'; 4969 window.currentQuickViewHasVariants = false; 4970 } 4971 } catch (e) { 4972 console.error('Error loading sizes:', e); 4973 container.innerHTML = '<div style="color:#c00;padding:10px;">Error loading sizes</div>'; 4974 window.currentQuickViewHasVariants = false; 4975 } 4976 } 4977 4978 function renderModalSizes(sizes) { 4979 const container = document.getElementById('modal-sizes'); 4980 const sorted = sizes.sort((a, b) => parseFloat(a.value) - parseFloat(b.value)); 4981 4982 container.innerHTML = sorted.map(size => { 4983 const inStock = size.in_stock !== false; 4984 return `<button class="size-btn ${inStock ? '' : 'unavailable'}" 4985 data-size="${size.value}" 4986 ${inStock ? '' : 'disabled'} 4987 onclick="selectModalSize(this, '${size.value}')">${size.value}</button>`; 4988 }).join(''); 4989 } 4990 4991 function selectModalSize(btn, size) { 4992 document.querySelectorAll('#modal-sizes .size-btn').forEach(b => b.classList.remove('selected')); 4993 btn.classList.add('selected'); 4994 window.selectedQuickViewSize = size; 4995 } 4996 4997 async function getVariantCode(templateCode, size) { 4998 try { 4999 const headers = { 'Content-Type': 'application/json' }; 5000 if (typeof frappe !== 'undefined' && frappe.csrf_token) { 5001 headers['X-Frappe-CSRF-Token'] = frappe.csrf_token; 5002 } 5003 5004 const response = await fetch('/api/method/cslshoes_erp.overrides.variant_selector.get_next_attribute_and_values_with_stock', { 5005 method: 'POST', 5006 headers: headers, 5007 body: JSON.stringify({ 5008 item_code: templateCode, 5009 selected_attributes: { 'Size': size } 5010 }) 5011 }); 5012 const data = await response.json(); 5013 if (data.message && data.message.exact_match && data.message.exact_match.length > 0) { 5014 return data.message.exact_match[0]; 5015 } 5016 } catch (e) { 5017 console.error('Error getting variant:', e); 5018 } 5019 return null; 5020 } 5021 </script>
5021 5022</div> 5023 5024 <div class="page-footer"></div> 5025 </main> 5026 5027</div> 5028 5029</div> 5030 5031 5032 5033 </main><style> 5034/* CSL Shoes Shared Footer */ 5035.csl-footer { 5036 background: #111; 5037 color: #9ca3af; 5038 padding: 60px 0 30px; 5039 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 5040} 5041.csl-footer .container { 5042 max-width: 1400px; 5043 margin: 0 auto; 5044 padding: 0 20px; 5045} 5046.csl-footer-grid { 5047 display: grid; 5048 grid-template-columns: 2fr 1fr 1fr 1fr 1.5fr; 5049 gap: 40px; 5050 margin-bottom: 40px; 5051} 5052.csl-footer-brand p { 5053 font-size: 13px; 5054 line-height: 1.6; 5055 margin-bottom: 20px; 5056 max-width: 280px; 5057} 5058.csl-footer-logo { 5059 font-size: 20px; 5060 font-weight: 700; 5061 color: #fff; 5062 margin-bottom: 12px; 5063} 5064.csl-footer-heading { 5065 font-size: 13px; 5066 font-weight: 600; 5067 color: #fff; 5068 text-transform: uppercase; 5069 letter-spacing: 0.5px; 5070 margin-bottom: 16px; 5071} 5072.csl-footer-links { list-style: none; padding: 0; margin: 0; } 5073.csl-footer-links li { margin-bottom: 10px; } 5074.csl-footer-links a { 5075 font-size: 13px; 5076 color: #9ca3af; 5077 text-decoration: none; 5078 transition: color 0.2s; 5079} 5080.csl-footer-links a:hover { color: #fff; } 5081.csl-footer-contact p { 5082 font-size: 13px; 5083 margin-bottom: 6px; 5084} 5085.csl-footer-contact a { color: #fff; text-decoration: none; } 5086.csl-footer-bottom { 5087 padding-top: 30px; 5088 border-top: 1px solid #374151; 5089 display: flex; 5090 align-items: center; 5091 justify-content: space-between; 5092} 5093.csl-footer-copyright { 5094 font-size: 12px; 5095 color: #6b7280; 5096} 5097.csl-footer-payments { display: flex; gap: 10px; align-items: center; } 5098.csl-footer-payments img { 5099 height: 24px; 5100 width: auto; 5101 opacity: 0.6; 5102 transition: opacity 0.2s; 5103} 5104.csl-footer-payments img:hover { opacity: 0.9; } 5105 5106/* Footer Responsive - Tablet */ 5107@media (max-width: 1024px) { 5108 .csl-footer-grid { grid-template-columns: repeat(2, 1fr); } 5109} 5110 5111/* Footer Responsive - Mobile */ 5112@media (max-width: 768px) { 5113 .csl-footer { padding: 40px 0 20px; } 5114 .csl-footer-grid { grid-template-columns: 1fr; gap: 24px; } 5115 .csl-footer-brand p { font-size: 12px; } 5116 .csl-footer-heading { font-size: 12px; margin-bottom: 12px; } 5117 .csl-footer-links a { font-size: 12px; } 5118 .csl-footer-bottom { flex-direction: column; gap: 12px; text-align: center; } 5119 .csl-footer-payments { flex-wrap: wrap; justify-content: center; } 5120} 5121</style> 5122 5123<footer class="csl-footer" data-nosnippet> 5124 <div class="container"> 5125 <div class="csl-footer-grid"> 5126 <div class="csl-footer-brand"> 5127 <p class="csl-footer-logo">CSL Shoes</p> 5128 <p>Premium leather footwear for the whole family since 2008. Genuine leather uppers, handcrafted quality, and exceptional customer service.</p> 5129 <p class="csl-footer-entity" style="font-size:12px;line-height:1.6;color:#9ca3af;margin-bottom:16px;max-width:280px;">Retail purchases on this website are sold by CSL Retail LLC. Wholesale purchases are sold by The CSL Group, Inc â both operate from 3 Alpine Court, Unit W156, Chestnut Ridge, NY 10977.</p> 5130 </div> 5131 <div> 5132 <div class="csl-footer-heading">Shop</div> 5133 <ul class="csl-footer-links"> 5134 <li><a href="/all-products">All Products</a></li> 5135 <li><a href="/closure-type/Lace-Up/items">Oxfords</a></li> 5136 <li><a href="/closure-type/Velcro/items">Boys' Shoes</a></li> 5137 <li><a href="/closure-type/Slip-On/items">Loafers</a></li> 5138 <li><a href="/all-products">New Arrivals</a></li> 5139 </ul> 5140 </div> 5141 <div> 5142 <div class="csl-footer-heading">Support</div> 5143 <ul class="csl-footer-links"> 5144 <li><a href="/size-guide">Size Guide</a></li> 5145 <li><a href="/shipping">Shipping Info</a></li> 5146 <li><a href="/returns">Returns</a></li> 5147 <li><a href="/guides/leather-shoe-care">Shoe Care</a></li> 5148 <li><a href="/help">FAQ</a></li> 5149 <li><a href="/blog">Blog</a></li> 5150 </ul> 5151 </div> 5152 <div> 5153 <div class="csl-footer-heading">Company</div> 5154 <ul class="csl-footer-links"> 5155 <li><a href="/about">About Us</a></li> 5156 <li><a href="/contact">Contact</a></li> 5157 <li><a href="/privacy-policy">Privacy Policy</a></li> 5158 <li><a href="/terms-of-service">Terms of Service</a></li> 5159 </ul> 5160 </div> 5161 <div class="csl-footer-contact"> 5162 <div class="csl-footer-heading">Contact Us</div> 5163 <p><a href="/cdn-cgi/l/email-protection#224b4c444d6241514e514a4d47510c414d4f"><span class="__cf_email__" data-cfemail="1a73747c755a7969766972757f6934797577">[email protected]</span></a></p> 5164 <p>Mon - Fri: 9am - 6pm EST</p> 5165 </div> 5166 </div> 5167 <div class="csl-footer-bottom"> 5168 <p class="csl-footer-copyright">© 2026 CSL Shoes. All rights reserved.</p> 5169 <div class="csl-footer-payments"> 5170 <img src="/assets/cslshoes_erp/images/visa.svg" alt="Visa" width="40" height="24"> 5171 <img src="/assets/cslshoes_erp/images/mastercard.svg" alt="Mastercard" width="40" height="24"> 5172 <img src="/assets/cslshoes_erp/images/amex.svg" alt="American Express" width="40" height="24"> 5173 </div> 5174 </div> 5175 </div> 5176</footer> 5177 5178 <a href="https://wa.me/18456946700?text=Hi%2C%20I%20have%20a%20question%20about%20your%20shoes" 5179 target="_blank" rel="noopener" 5180 class="csl-whatsapp-widget" 5181 aria-label="Chat with us on WhatsApp" 5182 style="position:fixed;bottom:24px;right:24px;z-index:9998;width:56px;height:56px;background:#25D366;border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 12px rgba(0,0,0,0.15);transition:transform 0.2s;" 5183 onmouseover="this.style.transform='scale(1.1)'" 5184 onmouseout="this.style.transform='scale(1)'"> 5185 <svg viewBox="0 0 24 24" width="28" height="28" fill="white"> 5186 <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.
5186198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/> 5187 </svg> 5188 </a>
vendor: 110 bytes, lines 5188-5189
5188 5189 <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
5189<script> 5190 frappe.boot = { 5191 "apps_data": { 5192 "apps": [], 5193 "default_path": "", 5194 "is_desk_apps": 1 5195 }, 5196 "assets_json": { 5197 "bank-reconciliation-tool.bundle.js": "/assets/erpnext/dist/js/bank-reconciliation-tool.bundle.3OD5XE4B.js", 5198 "billing.bundle.js": "/assets/frappe/dist/js/billing.bundle.XJXMQXLI.js", 5199 "bom_configurator.bundle.js": "/assets/erpnext/dist/js/bom_configurator.bundle.KVVOL5AV.js", 5200 "bootstrap-4-web.bundle.js": "/assets/frappe/dist/js/bootstrap-4-web.bundle.OGQ7JEDG.js", 5201 "build_events.bundle.js": "/assets/frappe/dist/js/build_events.bundle.BCX32TWL.js", 5202 "calendar.bundle.js": "/assets/frappe/dist/js/calendar.bundle.4A4YITIU.js", 5203 "controls.bundle.js": "/assets/frappe/dist/js/controls.bundle.GHTVO2AR.js", 5204 "csl-web.bundle.js": "/assets/cslshoes_erp/dist/js/csl-web.bundle.SBA57Y6F.js", 5205 "cslshoes_erp-web.bundle.js": "/assets/cslshoes_erp/dist/js/cslshoes_erp-web.bundle.VKBRYFDI.js", 5206 "data_import_tools.bundle.js": "/assets/frappe/dist/js/data_import_tools.bundle.AIMRIHAY.js", 5207 "desk.bundle.css": "/assets/frappe/dist/css/desk.bundle.E3JNXVFK.css", 5208 "desk.bundle.js": "/assets/frappe/dist/js/desk.bundle.LRVAENER.js", 5209 "dialog.bundle.js": "/assets/frappe/dist/js/dialog.bundle.4Y7AGZYX.js", 5210 "email.bundle.css": "/assets/frappe/dist/css/email.bundle.FRP6ZWO5.css", 5211 "erpnext-web.bundle.css": "/assets/erpnext/dist/css/erpnext-web.bundle.XAPV6OJR.css", 5212 "erpnext.bundle.css": "/assets/erpnext/dist/css/erpnext.bundle.U3ZULTHY.css", 5213 "erpnext.bundle.js": "/assets/erpnext/dist/js/erpnext.bundle.W4BKB7EY.js", 5214 "erpnext_email.bundle.css": "/assets/erpnext/dist/css/erpnext_email.bundle.QDPP6JFP.css", 5215 "file_uploader.bundle.js": "/assets/frappe/dist/js/file_uploader.bundle.NFWQ74RI.js", 5216 "form.bundle.js": "/assets/frappe/dist/js/form.bundle.V6TJPRRA.js", 5217 "form_builder.bundle.js": "/assets/frappe/dist/js/form_builder.bundle.TJDI53IC.js", 5218 "frappe-web.bundle.js": "/assets/frappe/dist/js/frappe-web.bundle.6AGRRLFL.js", 5219 "hierarchy-chart.bundle.js": "/assets/hrms/dist/js/hierarchy-chart.bundle.5E224PCR.js", 5220 "hrms.bundle.css": "/assets/hrms/dist/css/hrms.bundle.2Y752HAB.css", 5221 "hrms.bundle.js": "/assets/hrms/dist/js/hrms.bundle.QS2GRVNQ.js", 5222 "interview.bundle.js": "/assets/hrms/dist/js/interview.bundle.C7CDEMYA.js",
5223 "item-dashboard.bundle.js": "/assets/erpnext/dist/js/item-dashboard.bundle.7LUKZCYJ.js", 5224 "kanban_board.bundle.js": "/assets/frappe/dist/js/kanban_board.bundle.WBHS2NSO.js", 5225 "libs.bundle.js": "/assets/frappe/dist/js/libs.bundle.JEM3HUCP.js", 5226 "list.bundle.js": "/assets/frappe/dist/js/list.bundle.C5NWOGPL.js", 5227 "login.bundle.css": "/assets/frappe/dist/css/login.bundle.PUSGKFZL.css", 5228 "logtypes.bundle.js": "/assets/frappe/dist/js/logtypes.bundle.WKQH7KBM.js", 5229 "onboarding_tours.bundle.js": "/assets/frappe/dist/js/onboarding_tours.bundle.3QPQU5AO.js", 5230 "performance.bundle.js": "/assets/hrms/dist/js/performance.bundle.63UL5NS7.js", 5231 "photoswipe.bundle.js": "/assets/frappe/dist/js/photoswipe.bundle.YSXZQA64.js", 5232 "point-of-sale.bundle.js": "/assets/erpnext/dist/js/point-of-sale.bundle.QTZY4HXK.js", 5233 "print.bundle.css": "/assets/frappe/dist/css/print.bundle.TFESFRRQ.css", 5234 "print_format.bundle.css": "/assets/frappe/dist/css/print_format.bundle.G3JSEXTM.css", 5235 "print_format_builder.bundle.js": "/assets/frappe/dist/js/print_format_builder.bundle.EY2DZ4XK.js", 5236 "report.bundle.css": "/assets/frappe/dist/css/report.bundle.YRLG53MK.css", 5237 "report.bundle.js": "/assets/frappe/dist/js/report.bundle.YZUQRDTQ.js", 5238 "rtl_desk.bundle.css": "/assets/frappe/dist/css-rtl/desk.bundle.GTUX6NUS.css", 5239 "rtl_email.bundle.css": "/assets/frappe/dist/css-rtl/email.bundle.S6OLPJLO.css", 5240 "rtl_erpnext-web.bundle.css": "/assets/erpnext/dist/css-rtl/erpnext-web.bundle.MY3OHIQG.css", 5241 "rtl_erpnext.bundle.css": "/assets/erpnext/dist/css-rtl/erpnext.bundle.NFI4TDNU.css", 5242 "rtl_erpnext_email.bundle.css": "/assets/erpnext/dist/css-rtl/erpnext_email.bundle.4SUQQPOC.css", 5243 "rtl_hrms.bundle.css": "/assets/hrms/dist/css-rtl/hrms.bundle.2VFWZIH4.css", 5244 "rtl_login.bundle.css": "/assets/frappe/dist/css-rtl/login.bundle.LAUNAKDN.css", 5245 "rtl_print.bundle.css": "/assets/frappe/dist/css-rtl/print.bundle.46KW2M23.css", 5246 "rtl_print_format.bundle.css": "/assets/frappe/dist/css-rtl/print_format.bundle.WRCRSWVB.css", 5247 "rtl_report.bundle.css": "/assets/frappe/dist/css-rtl/report.bundle.J47TQ5QB.css", 5248 "rtl_web_form.bundle.css": "/assets/frappe/dist/css-rtl/web_form.bundle.V6TATNAO.css", 5249 "rtl_webshop-web.bundle.css": "/assets/webshop/dist/css-rtl/webshop-web.bundle.MXY3MF47.css", 5250 "rtl_website.bundle.css": "/assets/frappe/dist/css-rtl/website.bundle.UYAJRC2H.css", 5251 "sentry.bundle.js": "/assets/frappe/dist/js/sentry.bundle.AX44GVWW.js", 5252 "syntax_highlighting.bundle.js": "/assets/frappe/dist/js/syntax_highlighting.bundle.YHGNRCUE.js", 5253 "telemetry.bundle.js": "/assets/frappe/dist/js/telemetry.bundle.RXBBNH3H.js", 5254 "user_onboarding.bundle.js": "/assets/frappe/dist/js/user_onboarding.bundle.RGMWXG2C.js", 5255 "video_player.bundle.js": "/assets/frappe/dist/js/video_player.bundle.DUYYLSFO.js", 5256 "web.bundle.js": "/assets/webshop/dist/js/web.bundle.WLOGYSZO.js", 5257 "web_form.bundle.css": "/assets/frappe/dist/css/web_form.bundle.6KU4CLFY.css", 5258 "web_form.bundle.js": "/assets/frappe/dist/js/web_form.bundle.ALVCCXE4.js", 5259 "webshop-web.bundle.css": "/assets/webshop/dist/css/webshop-web.bundle.GQDT63VG.css", 5260 "website.bundle.css": "/assets/frappe/dist/css/website.bundle.GD6PKXQI.css", 5261 "workflow_builder.bundle.js": "/assets/frappe/dist/js/workflow_builder.bundle.O2QPXUEI.js" 5262 }, 5263 "is_fc_site": 0, 5264 "lang": "en-US", 5265 "sitename": "csl.local", 5266 "sysdefaults": { 5267 "currency": "USD", 5268 "date_format": "mm/dd/yyyy", 5269 "first_day_of_the_week": "Sunday", 5270 "float_precision": 3, 5271 "number_format": "#,###.##", 5272 "time_format": "HH:mm:ss" 5273 }, 5274 "time_zone": { 5275 "system": "America/New_York", 5276 "user": "America/New_York" 5277 } 5278} 5279 frappe.sys_defaults = frappe.boot.sysdefaults; 5280 </script>
5280 5281 5282
5282<script type="text/javascript" src="/assets/cslshoes_erp/dist/js/csl-web.bundle.SBA57Y6F.js"></script>
5282 5283 5284
5284<script type="text/javascript" src="/website_script.js" defer></script>
5284 5285
5285<script type="text/javascript" src="/assets/webshop/dist/js/web.bundle.WLOGYSZO.js" defer></script>
5285 5286
5286<script type="text/javascript" src="/assets/cslshoes_erp/dist/js/cslshoes_erp-web.bundle.VKBRYFDI.js" defer></script>
5286 5287
5287<script type="text/javascript" src="/assets/cslshoes_erp/js/csl-analytics.js?v=20260528a" defer></script>
5287 5288
5288<script type="text/javascript" src="/assets/cslshoes_erp/js/product_image_autoplay.js?v=20260613a" defer></script>
5288 5289
5289<script type="text/javascript" src="/assets/cslshoes_erp/js/compare.js" defer></script>
5289 5290
5290<script type="text/javascript" src="/assets/cslshoes_erp/js/tile_wishlist.js?v=20260517e" defer></script>
5290 5291
5291<script type="text/javascript" src="/assets/cslshoes_erp/js/all_products_patches.js?v=20260613a" defer></script>
5291 5292
5292<script type="text/javascript" src="/assets/cslshoes_erp/js/wishlist_page.js?v=20260517c" defer></script>
5292 5293
5293<script type="text/javascript" src="/assets/cslshoes_erp/js/wholesale_order_banner.js?v=20260520c" defer></script>
5293 5294
5294<script type="text/javascript" src="/assets/cslshoes_erp/js/sso_login_order.js?v=20260531b" defer></script>
5294 5295
5295<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"02110bd8a9eb40e98c9fc92b32ecf849","r":1,"spa":2}' crossorigin="anonymous"></script>
5295 5296</body> 5297</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.