Header
Header
<style>
/* ========================================
CSS Variables
======================================== */
:root {
--jr-marquee-bg: {{ [Link].marquee_bg_color }};
--jr-marquee-text: {{ [Link].marquee_text_color }};
--jr-header-bg: {% if [Link].header_bg_color %}{{ [Link].header_bg_color
}}{% else %}transparent{% endif %};
--jr-header-text: {{ [Link].header_text_color }};
--jr-header-scrolled-bg: {{ [Link].header_scrolled_bg }};
--jr-header-scrolled-text: {{ [Link].header_scrolled_text }};
--jr-nav-bg: {{ [Link].nav_bg_color }};
--jr-nav-text: {{ [Link].nav_text_color }};
--jr-accent: #CF7B69;
--jr-search-bg: #f8f8f8;
--jr-search-border: #606060;
--jr-transition: 0.3s ease;
}
/* ========================================
CRITICAL: Remove all default body/main padding
so header overlaps hero section
======================================== */
body {
padding-top: 0 !important;
margin-top: 0 !important;
}
/* ========================================
Announcement / Marquee Bar
======================================== */
.jr-marquee-section {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1002;
transition: transform 0.3s ease;
}
.[Link] {
transform: translateY(-100%);
pointer-events: none;
}
.[Link]-hidden {
transform: translateY(-100%);
}
.jr-marquee-wrapper {
position: relative;
background-color: var(--jr-marquee-bg);
color: var(--jr-marquee-text);
}
.jr-marquee-slider {
text-align: center;
overflow: hidden;
position: relative;
}
.jr-marquee-slide {
padding: 8px 60px;
display: none;
}
.jr-marquee-slide:first-child {
display: block;
}
.[Link] {
display: block;
}
.jr-marquee-slide p {
margin: 0;
font-size: 12px;
line-height: 1.4;
}
.jr-marquee-slide a {
color: var(--jr-marquee-text);
text-decoration: underline;
font-weight: 500;
}
.jr-marquee-close {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: var(--jr-marquee-text);
padding: 4px;
line-height: 0;
}
/* ========================================
Main Header - FIXED & OVERLAPPING
======================================== */
.jr-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1001;
background-color: transparent;
transition: background-color var(--jr-transition), box-shadow var(--jr-transition), top
var(--jr-transition);
}
/* ========================================
Transparent State (at top - overlapping hero)
======================================== */
.jr-header:not(.scrolled) {
background-color: transparent;
box-shadow: none;
}
.jr-header:not(.scrolled) .jr-header-icon,
.jr-header:not(.scrolled) .jr-nav-link,
.jr-header:not(.scrolled) .jr-appointment-link,
.jr-header:not(.scrolled) .jr-appointment-link span,
.jr-header:not(.scrolled) .jr-logo-text {
color: var(--jr-header-text);
}
.jr-header:not(.scrolled) .jr-mobile-toggle {
color: var(--jr-header-text);
}
.jr-header:not(.scrolled) .jr-store-icon {
color: var(--jr-header-text);
}
.jr-header:not(.scrolled) .jr-search-input::placeholder {
color: rgba(255, 255, 255, 0.7);
}
.jr-header:not(.scrolled) .jr-search-btn,
.jr-header:not(.scrolled) .jr-camera-btn {
color: #fff;
}
/* ========================================
Scrolled State (solid background)
======================================== */
.[Link] {
background-color: var(--jr-header-scrolled-bg);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
top: 0 !important;
}
.[Link] .jr-header-icon,
.[Link] .jr-nav-link,
.[Link] .jr-appointment-link,
.[Link] .jr-appointment-link span,
.[Link] .jr-logo-text {
color: var(--jr-header-scrolled-text);
}
.[Link] .jr-mobile-toggle {
color: var(--jr-header-scrolled-text);
}
.[Link] .jr-store-icon {
color: var(--jr-header-scrolled-text);
}
.[Link] .jr-logo-img {
filter: none;
}
.[Link] .jr-search-input {
background-color: var(--jr-search-bg);
border-color: var(--jr-search-border);
color: #333;
}
.[Link] .jr-search-input::placeholder {
color: #999;
}
.[Link] .jr-search-btn,
.[Link] .jr-camera-btn {
color: #333;
}
.[Link] .jr-navigation {
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
/* ========================================
Header Inner Layout
======================================== */
.jr-header-inner {
padding: 10px 20px;
}
.jr-header-container {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1620px;
margin: 0 auto;
}
/* ========================================
Header Left
======================================== */
.jr-header-left {
display: flex;
align-items: center;
gap: 12px;
flex: 0 0 auto;
}
.jr-mobile-toggle {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 4px;
line-height: 0;
color: inherit;
}
.jr-store-icon {
display: flex;
align-items: center;
}
.jr-logo a {
display: inline-block;
line-height: 0;
text-decoration: none;
}
.jr-logo-img {
max-width: 180px;
height: auto;
transition: filter var(--jr-transition);
}
.jr-logo-text {
font-size: 22px;
font-weight: 300;
letter-spacing: 4px;
text-transform: uppercase;
text-decoration: none;
color: inherit;
}
.jr-logo-mobile {
display: none;
}
/* ========================================
Header Center - Search
======================================== */
.jr-header-center {
flex: 1;
max-width: 600px;
margin: 0 30px;
}
.jr-search-bar {
width: 100%;
}
.jr-search-form {
position: relative;
display: flex;
align-items: center;
}
.jr-search-input {
width: 100%;
padding: 10px 100px 10px 20px;
background-color: var(--jr-search-bg);
border: 1px solid var(--jr-search-border);
height: 44px;
font-size: 14px;
outline: none;
text-transform: capitalize;
box-sizing: border-box;
transition: all var(--jr-transition);
}
.jr-search-input:focus {
outline: none;
border-color: #333;
}
.jr-search-btn {
position: absolute;
right: 45px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
padding: 8px;
line-height: 0;
transition: color var(--jr-transition);
}
.jr-camera-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
padding: 8px;
line-height: 0;
transition: color var(--jr-transition);
}
/* ========================================
Header Right
======================================== */
.jr-header-right {
display: flex;
align-items: center;
gap: 12px;
flex: 0 0 auto;
}
.jr-appointment-link {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
text-transform: uppercase;
text-decoration: none;
color: inherit;
white-space: nowrap;
transition: color var(--jr-transition);
}
.jr-header-icon {
position: relative;
display: flex;
align-items: center;
text-decoration: none;
color: inherit;
line-height: 0;
transition: color var(--jr-transition);
}
.jr-badge {
position: absolute;
top: -4px;
right: -10px;
background-color: var(--jr-accent);
color: #fff;
height: 14px;
width: 14px;
border-radius: 100%;
font-size: 10px;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
/* ========================================
Navigation
======================================== */
.jr-navigation {
transition: border-color var(--jr-transition);
}
.jr-nav-container {
max-width: 1620px;
margin: 0 auto;
padding: 0 20px;
}
.jr-nav-list {
display: flex;
align-items: center;
justify-content: space-between;
list-style: none;
margin: 0;
padding: 0;
}
.jr-nav-item {
position: relative;
}
.jr-nav-link {
display: block;
padding: 12px 8px;
font-size: 14px;
text-transform: uppercase;
text-decoration: none;
color: inherit;
letter-spacing: 0.5px;
white-space: nowrap;
transition: opacity 0.2s, color var(--jr-transition);
}
.jr-nav-link:hover {
opacity: 0.7;
}
/* ========================================
Mega Menu
======================================== */
.jr-mega-menu {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
background: #fff;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
min-width: 250px;
max-width: 1200px;
padding: 30px;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
z-index: 100;
}
.jr-nav-item:hover .jr-mega-menu {
opacity: 1;
visibility: visible;
}
.jr-mega-menu-inner {
display: flex;
gap: 40px;
}
.jr-mega-col {
min-width: 150px;
}
.jr-mega-title {
display: block;
font-size: 14px;
font-weight: 500;
text-transform: uppercase;
margin-bottom: 12px;
color: #000;
}
.jr-mega-links {
list-style: none;
padding: 0;
margin: 0;
}
.jr-mega-links li {
margin-bottom: 8px;
}
.jr-mega-links a {
font-size: 13px;
color: #555;
text-decoration: none;
text-transform: uppercase;
font-weight: 300;
transition: color 0.2s;
}
.jr-mega-links a:hover {
color: #000;
}
.jr-mega-single-link {
font-size: 13px;
color: #555;
text-decoration: none;
font-weight: 300;
display: block;
margin-bottom: 8px;
}
.jr-mega-single-link:hover {
color: #000;
}
/* ========================================
Image Search Modal
======================================== */
.jr-image-search-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10000;
align-items: center;
justify-content: center;
}
.[Link] {
display: flex;
}
.jr-image-search-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.jr-image-search-content {
position: relative;
background: #fff;
padding: 40px;
border-radius: 8px;
max-width: 500px;
width: 90%;
text-align: center;
z-index: 1;
}
.jr-image-search-close {
position: absolute;
top: 15px;
right: 15px;
background: none;
border: none;
cursor: pointer;
color: #333;
line-height: 0;
}
.jr-image-search-content h3 {
margin: 0 0 8px;
font-size: 22px;
font-weight: 500;
}
.jr-image-search-content > p {
margin: 0 0 24px;
color: #666;
font-size: 14px;
}
.jr-image-upload-area {
border: 2px dashed #ddd;
border-radius: 8px;
padding: 40px 20px;
margin-bottom: 20px;
transition: border-color 0.3s;
}
.jr-image-upload-area:hover,
.[Link] {
border-color: var(--jr-accent);
}
.jr-image-upload-label {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
cursor: pointer;
color: #888;
}
.jr-image-upload-label span {
font-size: 14px;
}
.jr-upload-subtitle {
font-size: 12px !important;
color: #aaa;
}
.jr-image-preview {
margin-bottom: 20px;
position: relative;
display: inline-block;
}
.jr-image-preview img {
max-width: 200px;
max-height: 200px;
border-radius: 4px;
object-fit: cover;
}
.jr-clear-image {
display: block;
margin: 8px auto 0;
background: none;
border: none;
color: var(--jr-accent);
cursor: pointer;
font-size: 13px;
text-decoration: underline;
}
.jr-image-search-submit {
width: 100%;
padding: 12px;
background-color: #000;
color: #fff;
border: none;
font-size: 14px;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 1px;
transition: opacity 0.3s;
}
.jr-image-search-submit:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jr-image-search-submit:not(:disabled):hover {
opacity: 0.85;
}
/* ========================================
Mobile Menu
======================================== */
.jr-mobile-menu-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 9998;
}
.[Link] {
display: block;
}
.jr-mobile-menu {
position: fixed;
top: 0;
left: -100%;
width: 320px;
max-width: 85%;
height: 100vh;
background: #fff;
z-index: 9999;
transition: left 0.3s ease;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.[Link] {
left: 0;
}
.jr-mobile-menu-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 20px;
border-bottom: 1px solid #eee;
min-height: 50px;
position: relative;
}
.jr-mobile-back,
.jr-mobile-close {
background: none;
border: none;
cursor: pointer;
padding: 4px;
line-height: 0;
color: #333;
z-index: 1;
}
.jr-mobile-menu-logo {
flex: 1;
text-align: center;
}
.jr-mobile-menu-logo img {
max-width: 130px;
height: auto;
}
.jr-mobile-menu-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 14px;
text-transform: uppercase;
letter-spacing: 1px;
display: none;
white-space: nowrap;
}
.jr-mobile-search {
padding: 15px 20px;
border-bottom: 1px solid #eee;
}
.jr-mobile-search .jr-search-form {
position: relative;
}
.jr-mobile-search .jr-search-input {
width: 100%;
padding: 8px 80px 8px 15px;
height: 40px;
font-size: 14px;
background-color: var(--jr-search-bg);
border: 1px solid var(--jr-search-border);
color: #333;
}
.jr-mobile-search .jr-search-btn,
.jr-mobile-search .jr-camera-btn {
color: #333;
}
.jr-mobile-menu-body {
flex: 1;
overflow-y: auto;
padding: 0;
}
.jr-mobile-nav-list {
list-style: none;
padding: 0;
margin: 0;
}
.jr-mobile-nav-item {
border-bottom: 1px solid #f0f0f0;
}
.jr-mobile-nav-link {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 20px;
font-size: 14px;
text-transform: uppercase;
text-decoration: none;
color: #333;
letter-spacing: 0.5px;
}
.jr-mobile-nav-link:hover {
background: #f9f9f9;
}
.jr-mobile-appointment {
font-weight: 600;
}
.jr-mobile-submenu {
list-style: none;
padding: 0;
margin: 0;
}
/* ========================================
HERO SECTION OVERLAP HELPER
The hero/first section must start from top
======================================== */
/* ========================================
Responsive Styles
======================================== */
@media (max-width: 1199px) {
.jr-logo-desktop {
display: none;
}
.jr-logo-mobile {
display: block;
}
.jr-mobile-toggle {
display: block;
}
.jr-navigation {
display: none;
}
.jr-header-center {
display: flex;
justify-content: center;
margin: 0 15px;
}
.jr-search-bar {
display: none;
}
.jr-appointment-link {
display: none;
}
.jr-header-container {
position: relative;
}
.jr-header-left {
flex: 0 0 auto;
}
.jr-header-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
margin: 0;
}
.jr-header-right {
flex: 0 0 auto;
}
}
.jr-logo-img {
max-width: 130px;
}
.jr-marquee-slide {
padding: 6px 30px;
}
.jr-marquee-slide a {
display: block;
}
.jr-image-search-content {
padding: 30px 20px;
}
}
.jr-logo-mobile {
display: none !important;
}
.jr-logo-desktop {
display: block !important;
}
}
/* ========================================
Image Search - Loading & Results
======================================== */
.jr-image-search-loading {
padding: 30px 0;
text-align: center;
}
.jr-loading-spinner {
width: 40px;
height: 40px;
border: 3px solid #f0f0f0;
border-top: 3px solid var(--jr-accent);
border-radius: 50%;
animation: jr-spin 0.8s linear infinite;
margin: 0 auto 15px;
}
@keyframes jr-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.jr-image-search-loading p {
color: #666;
font-size: 14px;
margin: 0;
}
.jr-image-search-results {
margin-bottom: 20px;
text-align: left;
}
.jr-image-search-results h4 {
font-size: 16px;
font-weight: 500;
margin: 0 0 15px;
text-align: center;
}
.jr-image-results-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 15px;
}
.jr-result-card {
text-decoration: none;
color: #333;
border: 1px solid #eee;
border-radius: 4px;
overflow: hidden;
transition: box-shadow 0.2s, transform 0.2s;
}
.jr-result-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.jr-result-image {
width: 100%;
aspect-ratio: 1;
overflow: hidden;
background: #f5f5f5;
}
.jr-result-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.jr-result-info {
padding: 8px;
}
.jr-result-title {
display: block;
font-size: 11px;
font-weight: 400;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.jr-result-price {
display: block;
font-size: 12px;
font-weight: 600;
margin-top: 4px;
color: var(--jr-accent);
}
.jr-view-all-results {
display: block;
text-align: center;
color: var(--jr-accent);
font-size: 14px;
text-decoration: none;
font-weight: 500;
padding: 10px;
transition: opacity 0.2s;
}
.jr-view-all-results:hover {
opacity: 0.7;
}
.jr-no-results {
text-align: center;
padding: 20px 0;
}
.jr-no-results p {
color: #666;
font-size: 14px;
margin: 0 0 12px;
}
.jr-color-suggestions {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
}
.jr-color-tag {
display: inline-block;
padding: 6px 16px;
border: 1px solid #ddd;
border-radius: 20px;
font-size: 13px;
color: #333;
text-decoration: none;
text-transform: capitalize;
transition: all 0.2s;
}
.jr-color-tag:hover {
background: #000;
color: #fff;
border-color: #000;
}
.jr-image-search-submit {
width: 100%;
padding: 12px;
background-color: #000;
color: #fff;
border: none;
font-size: 14px;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 1px;
transition: opacity 0.3s;
}
.jr-image-search-submit:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.jr-image-search-submit:not(:disabled):hover {
opacity: 0.85;
}
.jr-image-search-google {
width: 100%;
padding: 10px;
background: #fff;
color: #333;
border: 1px solid #ddd;
font-size: 13px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: all 0.2s;
}
.jr-image-search-google:hover {
background: #f5f5f5;
border-color: #999;
}
/* ========================================
Image Search Results - Additional Styles
======================================== */
.jr-image-search-loading {
padding: 30px 0;
text-align: center;
}
.jr-loading-spinner {
width: 40px;
height: 40px;
border: 3px solid #f0f0f0;
border-top: 3px solid var(--jr-accent);
border-radius: 50%;
animation: jr-spin 0.8s linear infinite;
margin: 0 auto 15px;
}
@keyframes jr-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.jr-image-search-loading p {
color: #666;
font-size: 14px;
margin: 0;
}
.jr-image-search-results {
margin-bottom: 20px;
text-align: left;
}
.jr-image-search-results h4 {
font-size: 16px;
font-weight: 500;
margin: 0 0 15px;
text-align: center;
}
.jr-image-results-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 15px;
}
.jr-result-card {
text-decoration: none;
color: #333;
border: 1px solid #eee;
border-radius: 4px;
overflow: hidden;
transition: box-shadow 0.2s, transform 0.2s;
display: block;
}
.jr-result-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.jr-result-image {
width: 100%;
aspect-ratio: 1;
overflow: hidden;
background: #f5f5f5;
}
.jr-result-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.jr-no-image {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #ccc;
font-size: 12px;
}
.jr-result-info {
padding: 8px;
}
.jr-result-title {
display: block;
font-size: 11px;
font-weight: 400;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.jr-result-price {
display: block;
font-size: 12px;
font-weight: 600;
margin-top: 4px;
color: var(--jr-accent);
}
.jr-view-all-results {
display: block;
text-align: center;
color: var(--jr-accent);
font-size: 14px;
text-decoration: none;
font-weight: 500;
padding: 10px;
transition: opacity 0.2s;
}
.jr-view-all-results:hover {
opacity: 0.7;
}
.jr-no-results {
text-align: center;
padding: 20px 0;
grid-column: 1 / -1;
}
.jr-no-results p {
color: #666;
font-size: 14px;
margin: 0 0 12px;
}
.jr-color-suggestions {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
}
.jr-color-tag {
display: inline-block;
padding: 6px 16px;
border: 1px solid #ddd;
border-radius: 20px;
font-size: 13px;
color: #333;
text-decoration: none;
text-transform: capitalize;
transition: all 0.2s;
}
.jr-color-tag:hover {
background: #000;
color: #fff;
border-color: #000;
}
.jr-image-search-actions {
display: flex;
flex-direction: column;
gap: 10px;
}
.jr-image-search-submit {
width: 100%;
padding: 12px;
background-color: #000;
color: #fff;
border: none;
font-size: 14px;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 1px;
transition: opacity 0.3s;
}
.jr-image-search-submit:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.jr-image-search-submit:not(:disabled):hover {
opacity: 0.85;
}
.jr-image-search-google {
width: 100%;
padding: 10px;
background: #fff;
color: #333;
border: 1px solid #ddd;
font-size: 13px;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
gap: 8px;
transition: all 0.2s;
}
.jr-image-search-google:hover {
background: #f5f5f5;
border-color: #999;
}
.jr-image-search-content {
padding: 25px 15px;
max-height: 90vh;
overflow-y: auto;
}
}
/* Match percentage badge */
.jr-match-badge {
position: absolute;
top: 4px;
left: 4px;
background: rgba(0,0,0,0.7);
color: #fff;
font-size: 9px;
padding: 2px 6px;
border-radius: 10px;
font-weight: 600;
}
.jr-result-image {
position: relative;
width: 100%;
aspect-ratio: 1;
overflow: hidden;
background: #f5f5f5;
}
.jr-image-results-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 15px;
max-height: 400px;
overflow-y: auto;
}
// ========================================
// Marquee Slider
// ========================================
const marqueeSlides = [Link]('.jr-marquee-slide');
let currentSlide = 0;
if ([Link] > 1) {
setInterval(function() {
marqueeSlides[currentSlide].[Link]('active');
marqueeSlides[currentSlide].[Link] = 'none';
currentSlide = (currentSlide + 1) % [Link];
marqueeSlides[currentSlide].[Link] = 'block';
marqueeSlides[currentSlide].[Link]('active');
}, 4000);
}
// ========================================
// Scroll Handler
// ========================================
const header = [Link]('jr-header');
const marquee = [Link]('jr-marquee');
function handleScroll() {
const scrollTop = [Link] || [Link];
if (scrollTop > 50) {
[Link]('scrolled');
if (marquee && )
[Link]('scroll-hidden');
} else {
[Link]('scrolled');
if (marquee && )
[Link]('scroll-hidden');
}
}
[Link]('scroll', handleScroll, { passive: true });
handleScroll();
// ========================================
// Mobile Menu Toggle
// ========================================
const mobileToggle = [Link]('jr-mobile-toggle');
if (mobileToggle) {
[Link]('click', function() {
[Link]('jr-mobile-menu').[Link]('active');
[Link]('jr-mobile-overlay').[Link]('active');
[Link] = 'hidden';
});
}
// ========================================
// Drag and Drop for image upload
// ========================================
const uploadArea = [Link]('jr-image-upload-area');
if (uploadArea) {
['dragenter','dragover','dragleave','drop'].forEach(evt => {
[Link](evt, function(e){ [Link](); [Link](); },
false);
});
['dragenter','dragover'].forEach(evt => {
[Link](evt, () => [Link]('dragover'), false);
});
['dragleave','drop'].forEach(evt => {
[Link](evt, () => [Link]('dragover'), false);
});
[Link]('drop', function(e) {
if ([Link] > 0) handleImageFile([Link][0]);
}, false);
}
// ========================================
// Pre-load all product data for comparison
// ========================================
loadAllProductData();
});
// ========================================
// GLOBAL VARIABLES
// ========================================
let uploadedImageFile = null;
let uploadedImageData = null;
let allStoreProducts = [];
let productFeatureCache = new Map(); // Cache: imageUrl -> features
let productsLoaded = false;
let featuresPrecomputed = false;
let precomputeInProgress = false;
// ========================================
// MARQUEE
// ========================================
function closeMarquee() {
const marquee = [Link]('jr-marquee');
const header = [Link]('jr-header');
[Link]('hidden');
[Link]('has-marquee');
[Link]('marquee-hidden');
[Link]('--jr-marquee-height', '0px');
}
// ========================================
// MOBILE MENU
// ========================================
let mobileMenuStack = [];
function closeMobileMenu() {
[Link]('jr-mobile-menu').[Link]('active');
[Link]('jr-mobile-overlay').[Link]('active');
[Link] = '';
[Link]('.jr-mobile-submenu').forEach(s => [Link] = 'none');
[Link]('#jr-mobile-nav-main > li').forEach(l => [Link] = '');
[Link]('jr-mobile-back').[Link] = 'none';
[Link]('jr-mobile-menu-title').[Link] = 'none';
[Link]('.jr-mobile-menu-logo').[Link] = 'block';
mobileMenuStack = [];
}
function mobileMenuBack() {
if ([Link] === 0) return;
const prev = [Link]();
[Link](':scope > li').forEach(li => {
const sub = [Link](':scope > .jr-mobile-submenu');
if (sub && [Link] === 'block') [Link] = 'none';
});
[Link]([Link]).forEach(li => [Link] = '');
if ([Link] === 0) {
[Link]('jr-mobile-back').[Link] = 'none';
[Link]('jr-mobile-menu-title').[Link] = 'none';
[Link]('.jr-mobile-menu-logo').[Link] = 'block';
} else {
[Link]('jr-mobile-menu-title').textContent =
mobileMenuStack[[Link] - 1].title;
}
}
// ========================================
// LOAD ALL PRODUCTS FROM STORE
// ========================================
async function loadAllProductData() {
try {
let page = 1;
let hasMore = true;
allStoreProducts = [];
} catch (e) {
[Link]('Failed to load products:', e);
try {
const response = await fetch('/collections/all/[Link]?limit=250');
if ([Link]) {
const data = await [Link]();
if ([Link]) {
allStoreProducts = [Link];
productsLoaded = true;
precomputeAllFeatures();
}
}
} catch (e2) {
[Link]('Alternate endpoint also failed:', e2);
}
}
}
// ========================================
// PRE-COMPUTE ALL PRODUCT IMAGE FEATURES IN BACKGROUND
// Uses requestIdleCallback to avoid blocking the UI
// ========================================
async function precomputeAllFeatures() {
if (precomputeInProgress) return;
precomputeInProgress = true;
featuresPrecomputed = true;
✅
precomputeInProgress = false;
[Link](` Pre-computation complete! ${[Link]} images cached.`);
}
// ========================================
// EXTRACT FEATURES FROM IMAGE URL (for product images)
// Uses a shared canvas to avoid GC pressure
// ========================================
const _sharedCanvas = [Link]('canvas');
const _sharedCtx = _sharedCanvas.getContext('2d', { willReadFrequently: true });
const FEATURE_SIZE = 32; // Smaller = faster, 32x32 is sufficient
function extractImageFeaturesFromUrl(imageUrl) {
return new Promise((resolve, reject) => {
const img = new Image();
[Link] = 'anonymous';
[Link] = function() {
try {
_sharedCanvas.width = FEATURE_SIZE;
_sharedCanvas.height = FEATURE_SIZE;
_sharedCtx.drawImage(img, 0, 0, FEATURE_SIZE, FEATURE_SIZE);
const pixels = _sharedCtx.getImageData(0, 0, FEATURE_SIZE, FEATURE_SIZE).data;
resolve(computeAllFeatures(pixels, FEATURE_SIZE, FEATURE_SIZE));
} catch(e) {
reject(e);
}
};
[Link] = () => reject(new Error('Failed to load: ' + imageUrl));
[Link] = imageUrl;
});
}
// ========================================
// COMPUTE ALL FEATURES IN ONE PASS (optimized)
// Single loop through pixels extracts everything at once
// ========================================
function computeAllFeatures(pixels, w, h) {
const hBins = 12, sBins = 3, lBins = 3;
const colorHist = new Float32Array(hBins * sBins * lBins);
// Color moments accumulators
let rSum = 0, gSum = 0, bSum = 0;
let rSq = 0, gSq = 0, bSq = 0;
// Spatial quadrants
const quads = [
{r:0,g:0,b:0,n:0}, {r:0,g:0,b:0,n:0},
{r:0,g:0,b:0,n:0}, {r:0,g:0,b:0,n:0}
];
const hw = w >> 1, hh = h >> 1;
const n = w * h;
// Grayscale
const grayVal = r * 0.299 + g * 0.587 + b * 0.114;
gray[y * w + x] = grayVal;
// Color moments
rSum += r; gSum += g; bSum += b;
rSq += r*r; gSq += g*g; bSq += b*b;
// Spatial quadrant
const qi = (y < hh ? 0 : 2) + (x < hw ? 0 : 1);
quads[qi].r += r; quads[qi].g += g; quads[qi].b += b; quads[qi].n++;
// Color moments
const colorMoments = new Float32Array(6);
colorMoments[0] = rSum / n;
colorMoments[1] = gSum / n;
colorMoments[2] = bSum / n;
colorMoments[3] = [Link]([Link](rSq/n - (rSum/n)**2));
colorMoments[4] = [Link]([Link](gSq/n - (gSum/n)**2));
colorMoments[5] = [Link]([Link](bSq/n - (bSum/n)**2));
// Spatial colors (flattened)
const spatialColors = new Float32Array(12);
for (let q = 0; q < 4; q++) {
const qn = quads[q].n || 1;
spatialColors[q*3] = quads[q].r / qn;
spatialColors[q*3+1] = quads[q].g / qn;
spatialColors[q*3+2] = quads[q].b / qn;
}
// ========================================
// FAST SIMILARITY CALCULATION
// Uses typed arrays for speed
// ========================================
function calculateSimilarity(f1, f2) {
let score = 0;
return score;
}
// ========================================
// IMAGE UPLOAD FUNCTIONS
// ========================================
function openImageSearch() {
[Link]('jr-image-search-modal').[Link]('active');
[Link] = 'hidden';
}
function closeImageSearch() {
[Link]('jr-image-search-modal').[Link]('active');
[Link] = '';
clearImageUpload();
[Link]('jr-image-search-results').[Link] = 'none';
[Link]('jr-image-search-loading').[Link] = 'none';
[Link]('jr-image-search-actions').[Link] = 'block';
}
function handleImageUpload(event) {
const file = [Link][0];
if (file) handleImageFile(file);
}
function handleImageFile(file) {
if () {
alert('Please upload an image file (JPG, PNG, or WEBP)');
return;
}
if ([Link] > 10 * 1024 * 1024) {
alert('Image is too large. Please upload under 10MB.');
return;
}
uploadedImageFile = file;
const reader = new FileReader();
[Link] = function(e) {
uploadedImageData = [Link];
[Link]('jr-preview-img').src = uploadedImageData;
[Link]('jr-image-preview').[Link] = 'inline-block';
[Link]('jr-image-upload-area').[Link] = 'none';
[Link]('jr-image-search-submit').disabled = false;
[Link]('jr-image-search-google').[Link] = 'inline-flex';
[Link]('jr-image-search-results').[Link] = 'none';
};
[Link](file);
}
function clearImageUpload() {
const inp = [Link]('jr-image-upload');
if (inp) [Link] = '';
[Link]('jr-preview-img').src = '';
[Link]('jr-image-preview').[Link] = 'none';
[Link]('jr-image-upload-area').[Link] = 'block';
[Link]('jr-image-search-submit').disabled = true;
[Link]('jr-image-search-google').[Link] = 'none';
[Link]('jr-image-search-results').[Link] = 'none';
[Link]('jr-image-search-loading').[Link] = 'none';
uploadedImageFile = null;
uploadedImageData = null;
}
// ========================================
// MAIN IMAGE SEARCH - OPTIMIZED
// If features are pre-computed, comparison is instant
// If not, loads only uncached images
// ========================================
async function submitImageSearch() {
if (!uploadedImageData) {
alert('Please upload an image first');
return;
}
// Show loading
const loadingEl = [Link]('jr-image-search-loading');
const loadingText = [Link]('p');
[Link] = 'block';
[Link]('jr-image-search-actions').[Link] = 'none';
[Link]('jr-image-preview').[Link] = 'none';
[Link]('jr-image-search-results').[Link] = 'none';
try {
// Step 1: Extract features from uploaded image (instant - it's local)
[Link] = 'Analyzing your image...';
const uploadedFeatures = await extractImageFeaturesFromDataUrl(uploadedImageData);
if (uncachedCount === 0) {
// ALL CACHED - instant comparison!
[Link] = 'Finding similar products...';
for (const product of productsWithImages) {
const features = [Link]([Link][0].src);
if (features) {
[Link]({
product: product,
score: calculateSimilarity(uploadedFeatures, features)
});
}
}
} else {
// Some uncached - process them
let processed = 0;
const total = [Link];
const BATCH = 10;
if (!features) {
try {
const thumbUrl = getSizedImageUrl(imageUrl, '100x100');
features = await extractImageFeaturesFromUrl(thumbUrl);
[Link](imageUrl, features);
} catch(e) {
return;
}
}
if (features) {
[Link]({
product: product,
score: calculateSimilarity(uploadedFeatures, features)
});
}
processed++;
}));
// Yield to UI
await new Promise(r => setTimeout(r, 0));
}
}
// Sort by similarity
[Link]((a, b) => [Link] - [Link]);
// Display results
displayVisualResults(results);
} catch (error) {
[Link]('Image search error:', error);
[Link] = 'none';
[Link]('jr-image-search-actions').[Link] = 'block';
[Link]('jr-image-preview').[Link] = 'inline-block';
alert('Something went wrong. Please try again.');
}
}
// ========================================
// DISPLAY VISUAL SEARCH RESULTS
// ========================================
function displayVisualResults(results) {
const loading = [Link]('jr-image-search-loading');
const resultsDiv = [Link]('jr-image-search-results');
const grid = [Link]('jr-image-results-grid');
const viewAll = [Link]('jr-view-all-results');
const actions = [Link]('jr-image-search-actions');
const preview = [Link]('jr-image-preview');
const title = [Link]('jr-results-title');
[Link] = 'none';
[Link] = 'inline-block';
[Link] = 'block';
[Link] = '';
if ([Link] > 0) {
[Link] = `Visually Similar Products (${[Link]([Link], 8)})`;
[Link]((result) => {
const product = [Link];
const imageUrl = [Link] && [Link] > 0 ? [Link][0].src : '';
const productTitle = [Link] || 'Product';
const price = [Link] && [Link] > 0 ? [Link][0].price : '';
const url = `/products/${[Link]}`;
const matchPercent = [Link]([Link] * 100);
[Link] = 'block';
[Link] = 'none';
} else {
[Link] = 'No Similar Products Found';
[Link] = `
<div class="jr-no-results">
<p>Try uploading a clearer image or browse our collection</p>
<div class="jr-color-suggestions">
<a href="/collections/all" class="jr-color-tag" onclick="closeImageSearch()">Browse All
Products</a>
</div>
</div>
`;
[Link] = 'block';
}
}
// ========================================
// GOOGLE LENS SEARCH
// ========================================
function searchWithGoogleLens() {
if (!uploadedImageFile) {
alert('Please upload an image first');
return;
}
try {
[Link]('[Link] '_blank');
} catch(e) {
[Link]('[Link] '_blank');
}
}
</script>
{% schema %}
{
"name": "Custom Header (JR Style)",
"settings": [
{
"type": "image_picker",
"id": "logo",
"label": "Logo"
},
{
"type": "link_list",
"id": "menu",
"label": "Main Menu",
"default": "main-menu"
},
{
"type": "url",
"id": "store_link",
"label": "Store Locator Link"
},
{
"type": "url",
"id": "appointment_link",
"label": "Book Appointment Link"
},
{
"type": "header",
"content": "Marquee / Announcement Bar"
},
{
"type": "color",
"id": "marquee_bg_color",
"label": "Marquee Background",
"default": "#EDD8C2"
},
{
"type": "color",
"id": "marquee_text_color",
"label": "Marquee Text Color",
"default": "#000000"
},
{
"type": "header",
"content": "Header Colors (Transparent State)"
},
{
"type": "color",
"id": "header_text_color",
"label": "Header Text Color (Top)",
"default": "#ffffff"
},
{
"type": "header",
"content": "Header Colors (Scrolled State)"
},
{
"type": "color",
"id": "header_scrolled_bg",
"label": "Header Background (Scrolled)",
"default": "#ffffff"
},
{
"type": "color",
"id": "header_scrolled_text",
"label": "Header Text Color (Scrolled)",
"default": "#000000"
},
{
"type": "header",
"content": "Navigation Colors"
},
{
"type": "color",
"id": "nav_bg_color",
"label": "Navigation Background",
"default": "#ffffff"
},
{
"type": "color",
"id": "nav_text_color",
"label": "Navigation Text Color",
"default": "#000000"
}
],
"blocks": [
{
"type": "announcement",
"name": "Announcement",
"settings": [
{
"type": "text",
"id": "text",
"label": "Announcement Text",
"default": "Send us an"
},
{
"type": "text",
"id": "link_text",
"label": "Link Text",
"default": "Email"
},
{
"type": "url",
"id": "link_url",
"label": "Link URL"
}
]
}
],
"presets": [
{
"name": "Custom Header (JR Style)",
"blocks": [
{
"type": "announcement",
"settings": {
"text": "Send us an",
"link_text": "Email"
}
},
{
"type": "announcement",
"settings": {
"text": "Get Free",
"link_text": "Virtual Consultation"
}
}
]
}
]
}
{% endschema %}