simpleshop_theme/priv/static/demo.html
Jamey Greenwood c5a251398a chore: add demo.html to static assets
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 16:17:05 +00:00

6278 lines
204 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SimpleShop Theme Studio v28</title>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&family=Libre+Baskerville:wght@400;700&family=Nunito:wght@400;600;700&family=Nunito+Sans:opsz,wght@6..12,300;6..12,400;6..12,500;6..12,600&family=Outfit:wght@300;400;500;600&family=Source+Sans+3:wght@400;500;600&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* ========================================
LAYER 1: PRIMITIVES
======================================== */
:root {
--p-space-1: 0.25rem;
--p-space-2: 0.5rem;
--p-space-3: 0.75rem;
--p-space-4: 1rem;
--p-space-6: 1.5rem;
--p-space-8: 2rem;
--p-space-12: 3rem;
--p-space-16: 4rem;
--p-space-24: 6rem;
--p-radius-none: 0;
--p-radius-sm: 0.25rem;
--p-radius-md: 0.5rem;
--p-radius-lg: 0.75rem;
--p-radius-xl: 1rem;
--p-radius-full: 9999px;
--p-font-inter: 'Inter', system-ui, sans-serif;
--p-font-fraunces: 'Fraunces', serif;
--p-font-source: 'Source Sans 3', system-ui, sans-serif;
--p-font-space: 'Space Grotesk', system-ui, sans-serif;
--p-font-baskerville: 'Libre Baskerville', Georgia, serif;
--p-font-nunito: 'Nunito', system-ui, sans-serif;
--p-font-outfit: 'Outfit', system-ui, sans-serif;
--p-font-avenir: 'Nunito Sans', 'Avenir Next', 'Avenir', system-ui, sans-serif;
--p-text-xs: 0.75rem;
--p-text-sm: 0.875rem;
--p-text-base: 1rem;
--p-text-lg: 1.125rem;
--p-text-xl: 1.25rem;
--p-text-2xl: 1.5rem;
--p-text-3xl: 1.875rem;
--p-text-4xl: 2.25rem;
--p-duration-fast: 0.1s;
--p-duration-normal: 0.2s;
--p-duration-slow: 0.35s;
--p-ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--p-ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
--p-shadow-color: 0 0% 0%;
--p-shadow-strength: 0.06;
}
/* ========================================
LAYER 2: THEME TOKENS
======================================== */
.preview-frame {
--t-surface-base: #ffffff;
--t-surface-raised: #ffffff;
--t-surface-sunken: #f5f5f5;
--t-surface-overlay: rgba(255, 255, 255, 0.95);
--t-text-primary: #171717;
--t-text-secondary: #525252;
--t-text-tertiary: #a3a3a3;
--t-text-inverse: #ffffff;
--t-border-default: #e5e5e5;
--t-border-subtle: #f0f0f0;
}
.preview-frame[data-mood="warm"] {
--t-surface-base: #fdf8f3;
--t-surface-raised: #fffcf8;
--t-surface-sunken: #f5ebe0;
--t-text-primary: #1c1917;
--t-text-secondary: #57534e;
--t-text-tertiary: #a8a29e;
--t-border-default: #e7e0d8;
--t-border-subtle: #f0ebe4;
}
.preview-frame[data-mood="cool"] {
--t-surface-base: #f4f7fb;
--t-surface-raised: #f8fafc;
--t-surface-sunken: #e8eff7;
--t-text-primary: #0f172a;
--t-text-secondary: #475569;
--t-text-tertiary: #94a3b8;
--t-border-default: #d4dce8;
--t-border-subtle: #e8eff5;
}
.preview-frame[data-mood="dark"] {
--t-surface-base: #0a0a0a;
--t-surface-raised: #171717;
--t-surface-sunken: #000000;
--t-surface-overlay: rgba(23, 23, 23, 0.95);
--t-text-primary: #fafafa;
--t-text-secondary: #a3a3a3;
--t-text-tertiary: #737373;
--t-text-inverse: #171717;
--t-border-default: #262626;
--t-border-subtle: #1c1c1c;
--p-shadow-strength: 0.25;
}
/* Typography */
.preview-frame {
--t-font-heading: var(--p-font-inter);
--t-font-body: var(--p-font-inter);
--t-heading-weight: 600;
--t-heading-tracking: -0.025em;
}
.preview-frame[data-typography="editorial"] {
--t-font-heading: var(--p-font-fraunces);
--t-font-body: var(--p-font-source);
--t-heading-weight: 600;
--t-heading-tracking: -0.02em;
}
.preview-frame[data-typography="modern"] {
--t-font-heading: var(--p-font-space);
--t-font-body: var(--p-font-space);
--t-heading-weight: 500;
--t-heading-tracking: -0.03em;
}
.preview-frame[data-typography="classic"] {
--t-font-heading: var(--p-font-baskerville);
--t-font-body: var(--p-font-source);
--t-heading-weight: 400;
--t-heading-tracking: 0;
}
.preview-frame[data-typography="friendly"] {
--t-font-heading: var(--p-font-nunito);
--t-font-body: var(--p-font-nunito);
--t-heading-weight: 700;
--t-heading-tracking: -0.01em;
}
.preview-frame[data-typography="minimal"] {
--t-font-heading: var(--p-font-outfit);
--t-font-body: var(--p-font-outfit);
--t-heading-weight: 300;
--t-heading-tracking: 0;
}
.preview-frame[data-typography="impulse"] {
--t-font-heading: var(--p-font-avenir);
--t-font-body: var(--p-font-avenir);
--t-heading-weight: 300;
--t-heading-tracking: 0.02em;
}
/* Shape */
.preview-frame {
--t-radius-sm: var(--p-radius-sm);
--t-radius-md: var(--p-radius-md);
--t-radius-lg: var(--p-radius-lg);
--t-radius-button: var(--p-radius-md);
--t-radius-card: var(--p-radius-lg);
--t-radius-input: var(--p-radius-md);
--t-radius-image: var(--p-radius-md);
}
.preview-frame[data-shape="sharp"] {
--t-radius-sm: 0;
--t-radius-md: 0;
--t-radius-lg: 0;
--t-radius-button: 0;
--t-radius-card: 0;
--t-radius-input: 0;
--t-radius-image: 0;
}
.preview-frame[data-shape="round"] {
--t-radius-sm: var(--p-radius-md);
--t-radius-md: var(--p-radius-lg);
--t-radius-lg: var(--p-radius-xl);
--t-radius-button: var(--p-radius-lg);
--t-radius-card: var(--p-radius-xl);
--t-radius-input: var(--p-radius-lg);
--t-radius-image: var(--p-radius-lg);
}
.preview-frame[data-shape="pill"] {
--t-radius-sm: var(--p-radius-full);
--t-radius-md: var(--p-radius-full);
--t-radius-lg: var(--p-radius-xl);
--t-radius-button: var(--p-radius-full);
--t-radius-card: var(--p-radius-xl);
--t-radius-input: var(--p-radius-full);
--t-radius-image: var(--p-radius-lg);
}
/* Density */
.preview-frame {
--t-density: 1;
}
.preview-frame[data-density="spacious"] {
--t-density: 1.25;
}
.preview-frame[data-density="compact"] {
--t-density: 0.85;
}
/* ========================================
LAYER 3: SEMANTIC TOKENS
======================================== */
.preview-frame {
--t-accent-h: 24;
--t-accent-s: 95%;
--t-accent-l: 53%;
--t-accent: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
--t-accent-hover: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 8%));
--t-accent-subtle: hsl(var(--t-accent-h) 40% 95%);
--t-accent-ring: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.4);
--t-secondary-accent: #ea580c;
--t-sale-color: #dc2626;
--t-font-size-scale: 1;
--t-heading-weight: 600;
--t-layout-max-width: 1400px;
--t-button-style: filled;
--t-card-shadow: none;
--t-product-text-align: left;
--color-page: var(--t-surface-base);
--color-card: var(--t-surface-raised);
--color-input: var(--t-surface-raised);
--color-heading: var(--t-text-primary);
--color-body: var(--t-text-secondary);
--color-caption: var(--t-text-tertiary);
--color-button-primary: var(--t-accent);
--color-button-primary-hover: var(--t-secondary-accent);
--color-button-primary-text: var(--t-text-inverse);
--color-border: var(--t-border-default);
--font-heading: var(--t-font-heading);
--font-body: var(--t-font-body);
--weight-heading: var(--t-heading-weight);
--tracking-heading: var(--t-heading-tracking);
--space-xs: calc(var(--p-space-2) * var(--t-density));
--space-sm: calc(var(--p-space-3) * var(--t-density));
--space-md: calc(var(--p-space-4) * var(--t-density));
--space-lg: calc(var(--p-space-6) * var(--t-density));
--space-xl: calc(var(--p-space-8) * var(--t-density));
--space-2xl: calc(var(--p-space-12) * var(--t-density));
--radius-button: var(--t-radius-button);
--radius-card: var(--t-radius-card);
--radius-input: var(--t-radius-input);
--radius-image: var(--t-radius-image);
--shadow-sm:
0 1px 2px hsl(var(--p-shadow-color) / calc(var(--p-shadow-strength) * 0.5)),
0 1px 3px hsl(var(--p-shadow-color) / var(--p-shadow-strength));
--shadow-md:
0 2px 4px hsl(var(--p-shadow-color) / calc(var(--p-shadow-strength) * 0.5)),
0 4px 8px hsl(var(--p-shadow-color) / var(--p-shadow-strength)),
0 8px 16px hsl(var(--p-shadow-color) / calc(var(--p-shadow-strength) * 0.5));
--transition-fast: var(--p-duration-fast) var(--p-ease-out);
--transition-normal: var(--p-duration-normal) var(--p-ease-out);
--transition-bounce: var(--p-duration-normal) var(--p-ease-out-back);
}
.preview-frame[data-mood="dark"] {
--t-accent-subtle: hsl(var(--t-accent-h) 30% 15%);
}
/* ========================================
PAGE LAYOUT
======================================== */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
}
body {
font-family: var(--p-font-inter);
background: #f5f5f5;
height: 100vh;
overflow: hidden;
color: #171717;
}
.page-layout {
display: grid;
grid-template-columns: 380px 1fr;
height: 100vh;
}
@media (max-width: 1000px) {
.page-layout {
grid-template-columns: 1fr;
}
}
/* ========================================
CONTROLS PANEL
======================================== */
.controls-panel {
background: #ffffff;
border-right: 1px solid #e5e5e5;
padding: var(--p-space-6);
overflow-y: auto;
max-height: 100vh;
position: sticky;
top: 0;
}
.controls-header {
margin-bottom: var(--p-space-6);
}
.controls-header h1 {
font-size: var(--p-text-xl);
font-weight: 600;
margin-bottom: var(--p-space-2);
letter-spacing: -0.025em;
}
.controls-header p {
font-size: var(--p-text-sm);
color: #737373;
line-height: 1.5;
}
.control-section {
margin-bottom: var(--p-space-6);
}
.control-label {
font-size: var(--p-text-xs);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #737373;
margin-bottom: var(--p-space-3);
display: block;
}
/* Customise accordion */
.customise-section {
border-top: 1px solid #e5e5e5;
margin-top: var(--p-space-6);
padding-top: var(--p-space-4);
}
.customise-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--p-space-3) 0;
cursor: pointer;
user-select: none;
}
.customise-header:hover .customise-title {
color: #171717;
}
.customise-title {
font-size: var(--p-text-sm);
font-weight: 600;
color: #525252;
transition: color 0.15s ease;
}
.customise-icon {
width: 20px;
height: 20px;
color: #a3a3a3;
transition: transform 0.2s ease;
}
.customise-section.open .customise-icon {
transform: rotate(180deg);
}
.customise-content {
display: none;
padding-top: var(--p-space-4);
}
.customise-section.open .customise-content {
display: block;
}
/* Control groups within customise */
.control-group {
margin-bottom: var(--p-space-6);
padding-bottom: var(--p-space-6);
border-bottom: 1px solid #f0f0f0;
}
.control-group:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.control-group-header {
display: flex;
align-items: center;
gap: var(--p-space-2);
margin-bottom: var(--p-space-4);
}
.control-group-icon {
width: 16px;
height: 16px;
color: #a3a3a3;
}
.control-group-title {
font-size: var(--p-text-sm);
font-weight: 600;
color: #171717;
}
.control-group .control-section {
margin-bottom: var(--p-space-4);
}
.control-group .control-section:last-child {
margin-bottom: 0;
}
/* Text input */
.text-input {
width: 100%;
padding: var(--p-space-3) var(--p-space-4);
border: 1px solid #e5e5e5;
border-radius: var(--p-radius-md);
font-size: var(--p-text-base);
font-family: inherit;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.text-input:focus {
outline: none;
border-color: #171717;
box-shadow: 0 0 0 3px rgba(0,0,0,0.05);
}
/* Logo/Header section */
.branding-section {
background: #f9f9f9;
border-radius: var(--p-radius-lg);
padding: var(--p-space-4);
margin-bottom: var(--p-space-6);
}
.branding-section .control-label {
margin-bottom: var(--p-space-4);
}
.logo-mode-options {
display: flex;
flex-direction: column;
gap: var(--p-space-2);
margin-bottom: var(--p-space-4);
}
.logo-mode-option {
display: flex;
align-items: center;
gap: var(--p-space-3);
padding: var(--p-space-3);
background: #ffffff;
border: 2px solid transparent;
border-radius: var(--p-radius-md);
cursor: pointer;
transition: all 0.15s ease;
}
.logo-mode-option:hover {
border-color: #e5e5e5;
}
.logo-mode-option.active {
border-color: #171717;
}
.logo-mode-option input[type="radio"] {
display: none;
}
.logo-mode-radio {
width: 18px;
height: 18px;
border: 2px solid #d4d4d4;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.15s ease;
}
.logo-mode-option.active .logo-mode-radio {
border-color: #171717;
}
.logo-mode-radio::after {
content: '';
width: 8px;
height: 8px;
background: #171717;
border-radius: 50%;
opacity: 0;
transform: scale(0);
transition: all 0.15s ease;
}
.logo-mode-option.active .logo-mode-radio::after {
opacity: 1;
transform: scale(1);
}
.logo-mode-content {
flex: 1;
}
.logo-mode-title {
font-size: var(--p-text-sm);
font-weight: 500;
margin-bottom: 2px;
}
.logo-mode-desc {
font-size: var(--p-text-xs);
color: #737373;
}
/* Upload areas */
.upload-section {
margin-top: var(--p-space-4);
padding-top: var(--p-space-4);
border-top: 1px solid #e5e5e5;
}
.upload-row {
display: none;
margin-bottom: var(--p-space-3);
}
.upload-row.visible {
display: block;
}
.upload-label {
font-size: var(--p-text-xs);
font-weight: 500;
color: #525252;
margin-bottom: var(--p-space-2);
display: block;
}
.upload-area {
display: flex;
align-items: center;
gap: var(--p-space-3);
}
.upload-btn {
flex: 1;
background: #ffffff;
border: 1px dashed #d4d4d4;
border-radius: var(--p-radius-md);
padding: var(--p-space-3);
font-size: var(--p-text-sm);
color: #737373;
cursor: pointer;
transition: all 0.15s ease;
text-align: center;
}
.upload-btn:hover {
border-color: #a3a3a3;
color: #525252;
}
.upload-btn input {
display: none;
}
.upload-preview {
width: 64px;
height: 40px;
background: #ffffff;
border: 1px solid #e5e5e5;
border-radius: var(--p-radius-md);
display: none;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
}
.upload-preview.has-image {
display: flex;
}
.upload-preview img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.upload-preview-wide {
width: 100%;
height: 60px;
margin-top: var(--p-space-2);
}
.upload-preview-wide img {
width: 100%;
height: 100%;
object-fit: cover;
}
.remove-upload {
position: absolute;
top: -6px;
right: -6px;
width: 18px;
height: 18px;
background: #171717;
color: white;
border: none;
border-radius: 50%;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
/* Size control slider */
.size-control {
margin-top: var(--p-space-3);
display: none;
}
.size-control.visible {
display: block;
}
.size-control-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--p-space-2);
}
.size-control-label {
font-size: var(--p-text-xs);
font-weight: 500;
color: #525252;
}
.size-control-value {
font-family: 'SF Mono', Monaco, monospace;
font-size: var(--p-text-xs);
color: #737373;
}
.size-slider {
width: 100%;
height: 6px;
border-radius: 3px;
background: #e5e5e5;
outline: none;
-webkit-appearance: none;
appearance: none;
}
.size-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: #171717;
cursor: pointer;
transition: transform 0.1s ease;
}
.size-slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
.size-slider::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
background: #171717;
cursor: pointer;
border: none;
}
/* Header image controls */
.header-image-controls {
margin-top: var(--p-space-3);
display: none;
flex-direction: column;
gap: var(--p-space-3);
}
.header-image-controls.visible {
display: flex;
}
.control-row {
display: flex;
flex-direction: column;
gap: var(--p-space-2);
}
#header-position-x-row {
display: none;
}
#header-position-x-row.visible {
display: flex;
}
/* Logo color control */
.logo-color-control {
margin-top: var(--p-space-3);
display: none;
}
.logo-color-control.visible {
display: block;
}
.logo-color-toggle {
margin-bottom: var(--p-space-2);
}
.toggle-label {
display: flex;
align-items: center;
gap: var(--p-space-2);
cursor: pointer;
}
.toggle-label input[type="checkbox"] {
display: none;
}
.toggle-switch {
width: 36px;
height: 20px;
background: #e5e5e5;
border-radius: 10px;
position: relative;
transition: background 0.2s ease;
}
.toggle-switch::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
background: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: transform 0.2s ease;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.toggle-label input:checked + .toggle-switch {
background: #171717;
}
.toggle-label input:checked + .toggle-switch::after {
transform: translateX(16px);
}
.toggle-text {
font-size: var(--p-text-sm);
color: #525252;
}
.toggle-list {
display: flex;
flex-direction: column;
gap: var(--p-space-2);
}
.toggle-list .toggle-label {
padding: var(--p-space-2) 0;
}
.logo-color-picker-row {
display: none;
align-items: center;
gap: var(--p-space-3);
margin-top: var(--p-space-2);
}
.logo-color-picker-row.visible {
display: flex;
}
.color-picker-small {
width: 36px;
height: 36px;
}
/* Preset grid */
.preset-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--p-space-2);
margin-bottom: var(--p-space-6);
}
.preset-button {
background: #f5f5f5;
border: 2px solid transparent;
border-radius: var(--p-radius-md);
padding: var(--p-space-3);
cursor: pointer;
text-align: left;
transition: all var(--p-duration-normal) var(--p-ease-out);
font-family: inherit;
}
.preset-button:hover {
background: #ebebeb;
}
.preset-button.active {
border-color: #171717;
background: #ffffff;
}
.preset-button .preset-name {
font-size: var(--p-text-sm);
font-weight: 600;
margin-bottom: 2px;
}
.preset-button .preset-desc {
font-size: var(--p-text-xs);
color: #737373;
}
/* Option buttons */
.option-group {
display: flex;
flex-wrap: wrap;
gap: var(--p-space-2);
}
.option-button {
background: #f5f5f5;
border: 2px solid transparent;
border-radius: var(--p-radius-md);
padding: var(--p-space-2) var(--p-space-3);
cursor: pointer;
font-size: var(--p-text-sm);
font-family: inherit;
transition: all var(--p-duration-normal) var(--p-ease-out);
}
.option-button:hover {
background: #ebebeb;
}
.option-button.active {
border-color: #171717;
background: #ffffff;
}
/* Color picker */
.color-picker-wrapper {
display: flex;
align-items: center;
gap: var(--p-space-3);
}
.color-picker {
width: 48px;
height: 48px;
border: none;
border-radius: var(--p-radius-md);
cursor: pointer;
padding: 0;
overflow: hidden;
}
.color-picker::-webkit-color-swatch-wrapper {
padding: 0;
}
.color-picker::-webkit-color-swatch {
border: 2px solid rgba(0,0,0,0.1);
border-radius: var(--p-radius-md);
}
.color-value {
font-family: 'SF Mono', Monaco, monospace;
font-size: var(--p-text-sm);
color: #525252;
}
/* Combo display */
.combo-display {
background: #f5f5f5;
border-radius: var(--p-radius-md);
padding: var(--p-space-4);
margin-top: var(--p-space-6);
}
.combo-display .combo-label {
font-size: var(--p-text-xs);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #737373;
margin-bottom: var(--p-space-2);
}
.combo-display .combo-value {
font-size: var(--p-text-sm);
color: #171717;
line-height: 1.6;
}
.combo-display .combo-count {
font-size: var(--p-text-xs);
color: #a3a3a3;
margin-top: var(--p-space-2);
}
/* ========================================
PREVIEW AREA
======================================== */
.preview-area {
padding: var(--p-space-6);
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
}
.preview-container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: hidden;
}
.page-toggle {
display: flex;
gap: var(--p-space-1);
margin-bottom: var(--p-space-3);
background: #e5e5e5;
padding: 4px;
border-radius: var(--p-radius-md);
width: fit-content;
flex-shrink: 0;
}
.page-toggle-btn {
padding: var(--p-space-2) var(--p-space-4);
border: none;
background: transparent;
border-radius: var(--p-radius-sm);
font-family: inherit;
font-size: var(--p-text-sm);
font-weight: 500;
color: #525252;
cursor: pointer;
transition: all 0.15s ease;
}
.page-toggle-btn:hover {
color: #171717;
}
.page-toggle-btn.active {
background: #ffffff;
color: #171717;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
/* Browser Chrome Mockup - macOS style */
.browser-chrome {
display: flex;
align-items: center;
background: linear-gradient(180deg, #e8e8e8 0%, #d8d8d8 100%);
border: 1px solid #c0c0c0;
border-bottom: 1px solid #b0b0b0;
border-radius: 10px 10px 0 0;
padding: 10px 14px;
gap: 14px;
flex-shrink: 0;
}
.browser-traffic-lights {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.traffic-light {
width: 12px;
height: 12px;
border-radius: 50%;
border: 1px solid rgba(0,0,0,0.1);
}
.traffic-light.red { background: #ff5f57; border-color: #e14640; }
.traffic-light.yellow { background: #ffbd2e; border-color: #dfa123; }
.traffic-light.green { background: #28c940; border-color: #1aab29; }
.browser-nav {
display: flex;
gap: 6px;
flex-shrink: 0;
}
.browser-nav-btn {
width: 24px;
height: 24px;
border-radius: 4px;
background: transparent;
border: none;
color: #999;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
}
.browser-nav-btn svg {
width: 14px;
height: 14px;
}
.browser-url-bar {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
background: #ffffff;
border: 1px solid #c0c0c0;
border-radius: 6px;
padding: 5px 12px;
min-width: 0;
}
.browser-url-icon {
width: 14px;
height: 14px;
color: #28c940;
flex-shrink: 0;
}
.browser-favicon {
width: 16px;
height: 16px;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
background: var(--t-accent, #e85d04);
}
.browser-favicon.has-logo {
background: transparent;
}
.favicon-letter {
font-family: system-ui, sans-serif;
font-size: 10px;
font-weight: 600;
color: white;
}
.browser-favicon.has-logo .favicon-letter {
display: none;
}
.favicon-logo {
width: 100%;
height: 100%;
object-fit: contain;
}
.browser-url-text {
font-family: system-ui, sans-serif;
font-size: 12px;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.browser-url-text .domain {
color: #111;
}
.browser-actions {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.browser-action-btn {
width: 24px;
height: 24px;
border-radius: 4px;
background: transparent;
border: none;
color: #666;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
}
.browser-action-btn svg {
width: 16px;
height: 16px;
}
.preview-frame {
width: 100%;
flex: 1;
min-height: 0;
background: var(--color-page);
border-radius: 0 0 var(--p-radius-lg) var(--p-radius-lg);
border: 1px solid #c0c0c0;
border-top: none;
box-shadow:
0 4px 6px rgba(0,0,0,0.05),
0 10px 20px rgba(0,0,0,0.05),
0 20px 40px rgba(0,0,0,0.05);
overflow-y: auto;
overflow-x: hidden;
transition: background-color var(--p-duration-slow) var(--p-ease-out);
}
/* Styled scrollbar for the preview */
.preview-frame::-webkit-scrollbar {
width: 10px;
}
.preview-frame::-webkit-scrollbar-track {
background: rgba(0,0,0,0.05);
}
.preview-frame::-webkit-scrollbar-thumb {
background: rgba(0,0,0,0.2);
border-radius: 5px;
}
.preview-frame::-webkit-scrollbar-thumb:hover {
background: rgba(0,0,0,0.3);
}
/* Announcement bar */
.announcement-bar {
background: var(--t-accent);
color: var(--t-text-inverse);
text-align: center;
padding: var(--space-xs) var(--space-md);
font-family: var(--font-body);
font-size: var(--p-text-sm);
transition: all var(--transition-normal);
}
.announcement-bar.hidden {
display: none;
}
.announcement-bar p {
margin: 0;
}
/* Sticky header */
.preview-frame[data-sticky-header="true"] .shop-header {
position: sticky;
top: 0;
z-index: 100;
box-shadow: var(--shadow-sm);
}
.preview-frame[data-sticky-header="true"][data-has-announcement="true"] .shop-header {
top: 0;
}
/* ========================================
SHOP HEADER MODES
======================================== */
.shop-header {
padding: var(--space-md) var(--space-lg);
border-bottom: 1px solid var(--color-border);
display: flex;
align-items: center;
justify-content: space-between;
transition: all var(--transition-normal);
position: relative;
background: var(--t-surface-base);
}
.shop-header[data-header="centered"] {
flex-direction: column;
gap: var(--space-sm);
text-align: center;
}
.shop-header[data-header="minimal"] .shop-nav {
display: none;
}
/* Header with background image */
.shop-header[data-logo-mode="header-image"] {
min-height: 160px;
padding: var(--space-lg);
border-bottom: none;
background-size: cover;
background-position: center;
}
.shop-header[data-logo-mode="header-image"]::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(to bottom, rgba(0,0,0,0.3), rgba(0,0,0,0.5));
pointer-events: none;
}
.shop-header[data-logo-mode="header-image"] .shop-logo,
.shop-header[data-logo-mode="header-image"] .shop-nav a,
.shop-header[data-logo-mode="header-image"] .shop-cart {
position: relative;
z-index: 1;
color: #ffffff;
}
.shop-header[data-logo-mode="header-image"] .shop-logo-text {
color: #ffffff;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.shop-header[data-logo-mode="header-image"] .cart-icon {
stroke: #ffffff;
}
/* Header with logo + background image */
.shop-header[data-logo-mode="logo-header-image"] {
min-height: 160px;
padding: var(--space-lg);
border-bottom: none;
background-size: cover;
background-position: center;
}
.shop-header[data-logo-mode="logo-header-image"]::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(to bottom, rgba(0,0,0,0.3), rgba(0,0,0,0.5));
pointer-events: none;
}
.shop-header[data-logo-mode="logo-header-image"] .shop-logo,
.shop-header[data-logo-mode="logo-header-image"] .shop-nav a,
.shop-header[data-logo-mode="logo-header-image"] .shop-cart {
position: relative;
z-index: 1;
color: #ffffff;
}
.shop-header[data-logo-mode="logo-header-image"] .cart-icon {
stroke: #ffffff;
}
/* Logo display */
.shop-logo {
display: flex;
align-items: center;
gap: var(--space-sm);
transition: all var(--transition-normal);
}
.shop-logo-text {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
transition: all var(--transition-normal);
}
.shop-logo-image {
height: 36px;
width: auto;
display: none;
flex-shrink: 0;
}
.shop-logo-image.visible {
display: block;
}
.shop-logo-image img {
height: 100%;
width: auto;
object-fit: contain;
}
.shop-nav {
display: flex;
gap: var(--space-lg);
}
.shop-nav a {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
text-decoration: none;
transition: color var(--transition-fast);
}
.shop-nav a:hover {
color: var(--color-heading);
}
.shop-cart {
display: flex;
align-items: center;
gap: var(--space-xs);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
cursor: pointer;
}
.cart-count {
background: var(--t-accent);
color: var(--t-text-inverse);
font-size: 11px;
font-weight: 600;
width: 18px;
height: 18px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
/* Hero */
.shop-hero {
padding: var(--space-2xl) var(--space-lg);
text-align: center;
transition: all var(--transition-normal);
background: var(--t-surface-base);
}
.shop-hero h1 {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-4xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin-bottom: var(--space-sm);
transition: all var(--transition-normal);
}
/* Minimal/Impulse style - much larger, lighter hero text */
.preview-frame[data-typography="minimal"] .shop-hero {
padding: var(--space-2xl) var(--space-lg) calc(var(--space-2xl) * 1.5);
}
.preview-frame[data-typography="minimal"] .shop-hero h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 300;
letter-spacing: -0.02em;
margin-bottom: var(--space-md);
}
.preview-frame[data-typography="minimal"] .shop-hero p {
font-weight: 300;
font-size: var(--p-text-base);
color: var(--color-caption);
}
.shop-hero p {
font-family: var(--font-body);
font-size: var(--p-text-lg);
color: var(--color-body);
max-width: 500px;
margin: 0 auto var(--space-lg);
line-height: 1.6;
transition: all var(--transition-normal);
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--font-body);
font-weight: 500;
font-size: var(--p-text-sm);
padding: var(--space-sm) var(--space-lg);
border-radius: var(--radius-button);
border: none;
cursor: pointer;
transition:
transform var(--transition-bounce),
box-shadow var(--transition-normal),
background-color var(--transition-fast);
}
.btn:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.btn:active {
transform: translateY(0);
transition-duration: 0.05s;
}
.btn-primary {
background: var(--color-button-primary);
color: var(--color-button-primary-text);
}
.btn-primary:hover {
background: var(--color-button-primary-hover);
}
/* Button style variations */
.preview-frame[data-button-style="outline"] .btn-primary {
background: transparent;
color: var(--color-button-primary);
border: 2px solid var(--color-button-primary);
}
.preview-frame[data-button-style="outline"] .btn-primary:hover {
background: var(--color-button-primary);
color: var(--color-button-primary-text);
}
.preview-frame[data-button-style="soft"] .btn-primary {
background: var(--t-accent-subtle);
color: var(--color-button-primary);
}
.preview-frame[data-button-style="soft"] .btn-primary:hover {
background: var(--color-button-primary);
color: var(--color-button-primary-text);
}
/* Layout width variations - controls content width within the full-width browser */
.preview-frame[data-layout-width="contained"] .shop-hero,
.preview-frame[data-layout-width="contained"] .product-section,
.preview-frame[data-layout-width="contained"] .home-categories,
.preview-frame[data-layout-width="contained"] .home-about,
.preview-frame[data-layout-width="contained"] .pdp-container,
.preview-frame[data-layout-width="contained"] .pdp-reviews,
.preview-frame[data-layout-width="contained"] .pdp-related,
.preview-frame[data-layout-width="contained"] .cart-container,
.preview-frame[data-layout-width="contained"] .content-page,
.preview-frame[data-layout-width="contained"] .error-container,
.preview-frame[data-layout-width="contained"] .collection-header,
.preview-frame[data-layout-width="contained"] .collection-grid-container {
max-width: 800px;
margin-left: auto;
margin-right: auto;
padding-left: var(--space-lg);
padding-right: var(--space-lg);
}
.preview-frame[data-layout-width="wide"] .shop-hero,
.preview-frame[data-layout-width="wide"] .product-section,
.preview-frame[data-layout-width="wide"] .home-categories,
.preview-frame[data-layout-width="wide"] .home-about,
.preview-frame[data-layout-width="wide"] .pdp-container,
.preview-frame[data-layout-width="wide"] .pdp-reviews,
.preview-frame[data-layout-width="wide"] .pdp-related,
.preview-frame[data-layout-width="wide"] .cart-container,
.preview-frame[data-layout-width="wide"] .content-page,
.preview-frame[data-layout-width="wide"] .error-container,
.preview-frame[data-layout-width="wide"] .collection-header,
.preview-frame[data-layout-width="wide"] .collection-grid-container {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
/* Full width has no max-width constraint */
.preview-frame[data-layout-width="full"] .shop-hero,
.preview-frame[data-layout-width="full"] .product-section,
.preview-frame[data-layout-width="full"] .home-categories,
.preview-frame[data-layout-width="full"] .home-about,
.preview-frame[data-layout-width="full"] .pdp-container,
.preview-frame[data-layout-width="full"] .pdp-reviews,
.preview-frame[data-layout-width="full"] .pdp-related,
.preview-frame[data-layout-width="full"] .cart-container,
.preview-frame[data-layout-width="full"] .content-page,
.preview-frame[data-layout-width="full"] .error-container,
.preview-frame[data-layout-width="full"] .collection-header,
.preview-frame[data-layout-width="full"] .collection-grid-container {
max-width: none;
}
/* Font size scale */
.preview-frame[data-font-size="small"] {
font-size: 14px;
}
.preview-frame[data-font-size="medium"] {
font-size: 16px;
}
.preview-frame[data-font-size="large"] {
font-size: 18px;
}
/* Heading weight */
.preview-frame[data-heading-weight="regular"] {
--weight-heading: 400;
}
.preview-frame[data-heading-weight="medium"] {
--weight-heading: 500;
}
.preview-frame[data-heading-weight="bold"] {
--weight-heading: 700;
}
/* Impulse typography special styling */
.preview-frame[data-typography="impulse"] {
--weight-heading: 300;
}
.preview-frame[data-typography="impulse"] .shop-hero h1 {
font-size: 3.5rem;
font-weight: 300;
letter-spacing: 0.04em;
text-transform: uppercase;
line-height: 1.1;
}
.preview-frame[data-typography="impulse"] .shop-hero p {
font-size: 1.125rem;
font-weight: 300;
letter-spacing: 0.02em;
max-width: 500px;
}
.preview-frame[data-typography="impulse"] .section-title {
font-size: 1.5rem;
font-weight: 400;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.preview-frame[data-typography="impulse"] .product-title {
font-weight: 400;
letter-spacing: 0.02em;
}
.preview-frame[data-typography="impulse"] .product-price {
font-weight: 300;
letter-spacing: 0.01em;
}
.preview-frame[data-typography="impulse"] .btn-primary {
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
font-size: 0.75rem;
padding: 1rem 2rem;
}
.preview-frame[data-typography="impulse"] .shop-nav a {
font-weight: 400;
letter-spacing: 0.04em;
text-transform: uppercase;
font-size: 0.75rem;
}
.preview-frame[data-typography="impulse"] .announcement-bar {
font-weight: 400;
letter-spacing: 0.06em;
text-transform: uppercase;
font-size: 0.7rem;
}
.preview-frame[data-typography="impulse"] .category-name {
font-weight: 400;
letter-spacing: 0.04em;
text-transform: uppercase;
font-size: 0.75rem;
}
/* Product grid */
.product-section {
padding: var(--space-xl) var(--space-lg);
transition: all var(--transition-normal);
background: var(--t-surface-sunken);
}
.section-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-2xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin-bottom: var(--space-lg);
transition: all var(--transition-normal);
}
.product-grid {
display: grid;
gap: var(--space-lg);
transition: all var(--transition-normal);
}
.product-grid[data-grid="2"] { grid-template-columns: repeat(2, 1fr); }
.product-grid[data-grid="3"] { grid-template-columns: repeat(3, 1fr); }
.product-grid[data-grid="4"] { grid-template-columns: repeat(4, 1fr); }
.product-card {
background: var(--t-surface-raised);
border-radius: var(--radius-card);
overflow: hidden;
cursor: pointer;
}
/* Card shadow variations */
.preview-frame[data-card-shadow="subtle"] .product-card {
box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.06);
}
.preview-frame[data-card-shadow="pronounced"] .product-card {
box-shadow: 0 4px 12px rgba(0,0,0,0.1), 0 8px 24px rgba(0,0,0,0.08);
}
/* Product text alignment */
.preview-frame[data-product-text="center"] .product-info {
text-align: center;
}
/* Show/hide prices */
.preview-frame[data-show-prices="false"] .product-price {
display: none;
}
transition:
transform var(--transition-normal),
box-shadow var(--transition-normal);
cursor: pointer;
box-shadow: var(--shadow-sm);
position: relative;
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.product-image {
aspect-ratio: 1;
overflow: hidden;
border-radius: var(--radius-image) var(--radius-image) 0 0;
position: relative;
}
.product-image-primary,
.product-image-hover {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
transition: opacity 0.3s ease;
}
.product-image-hover {
opacity: 0;
}
.preview-frame[data-hover-image="true"] .product-card:hover .product-image-hover {
opacity: 1;
}
.quick-add-btn {
position: absolute;
bottom: var(--space-sm);
left: var(--space-sm);
right: var(--space-sm);
background: var(--t-surface-raised);
color: var(--color-heading);
border: none;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-button);
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
cursor: pointer;
opacity: 0;
transform: translateY(8px);
transition: all 0.2s ease;
box-shadow: var(--shadow-sm);
}
.preview-frame[data-quick-add="true"] .product-card:hover .quick-add-btn {
opacity: 1;
transform: translateY(0);
}
.quick-add-btn:hover {
background: var(--color-heading);
color: var(--t-text-inverse);
}
/* Product badges */
.product-badge {
position: absolute;
top: var(--space-sm);
left: var(--space-sm);
padding: 4px 10px;
border-radius: var(--radius-button);
font-family: var(--font-body);
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
z-index: 1;
}
.badge-new {
background: var(--t-accent);
color: var(--t-text-inverse);
}
.badge-sale {
background: var(--t-sale-color);
color: white;
}
.badge-sold {
background: var(--t-surface-raised);
color: var(--color-body);
border: 1px solid var(--color-border);
}
.price-was {
text-decoration: line-through;
color: var(--color-caption);
margin-right: 4px;
}
/* Aspect ratios */
.preview-frame[data-aspect="square"] .product-image {
aspect-ratio: 1;
}
.preview-frame[data-aspect="portrait"] .product-image {
aspect-ratio: 3 / 4;
}
.preview-frame[data-aspect="landscape"] .product-image {
aspect-ratio: 4 / 3;
}
/* Header icons */
.header-icon-btn {
background: none;
border: none;
padding: var(--space-xs);
cursor: pointer;
color: var(--color-body);
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-button);
transition: all 0.15s ease;
position: relative;
}
.header-icon-btn:hover {
color: var(--color-heading);
background: var(--t-surface-sunken);
}
.shop-cart {
display: flex;
align-items: center;
gap: var(--space-xs);
}
.cart-count {
position: absolute;
top: -2px;
right: -2px;
background: var(--t-accent);
color: var(--t-text-inverse);
font-size: 10px;
font-weight: 600;
min-width: 16px;
height: 16px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.shop-header[data-logo-mode="header-image"] .header-icon-btn,
.shop-header[data-logo-mode="logo-header-image"] .header-icon-btn {
color: #ffffff;
}
.shop-header[data-logo-mode="header-image"] .header-icon-btn:hover,
.shop-header[data-logo-mode="logo-header-image"] .header-icon-btn:hover {
background: rgba(255,255,255,0.1);
}
.product-info {
padding: var(--space-md);
transition: all var(--transition-normal);
}
.product-title {
font-family: var(--font-body);
font-weight: 500;
font-size: var(--p-text-sm);
color: var(--color-heading);
margin-bottom: var(--space-xs);
transition: all var(--transition-normal);
}
.product-price {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
font-variant-numeric: tabular-nums;
transition: all var(--transition-normal);
}
/* Minimal/Impulse style product cards - cleaner, lighter */
.preview-frame[data-typography="minimal"] .product-info {
padding: var(--space-sm) 0;
}
.preview-frame[data-typography="minimal"] .product-title {
font-weight: 400;
font-size: var(--p-text-base);
letter-spacing: 0;
}
.preview-frame[data-typography="minimal"] .product-price {
font-weight: 300;
color: var(--color-caption);
}
.preview-frame[data-typography="minimal"] .product-card {
background: transparent;
}
.preview-frame[data-typography="minimal"] .quick-add-btn {
opacity: 0;
transition: opacity 0.2s ease;
}
.preview-frame[data-typography="minimal"] .product-card:hover .quick-add-btn {
opacity: 1;
}
/* Minimal section titles */
.preview-frame[data-typography="minimal"] .section-title {
font-weight: 300;
font-size: var(--p-text-xl);
letter-spacing: 0.05em;
text-transform: uppercase;
}
/* Footer */
.shop-footer {
padding: var(--space-xl) var(--space-lg);
border-top: 1px solid var(--color-border);
transition: all var(--transition-normal);
background: var(--t-surface-base);
}
.footer-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-xl);
margin-bottom: var(--space-lg);
padding-bottom: var(--space-lg);
border-bottom: 1px solid var(--color-border);
}
.footer-newsletter {
max-width: 320px;
}
.footer-heading {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-lg);
color: var(--color-heading);
margin-bottom: var(--space-xs);
}
.footer-text {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
margin-bottom: var(--space-sm);
line-height: 1.5;
}
.newsletter-form {
display: flex;
gap: var(--space-xs);
}
.newsletter-input {
flex: 1;
padding: var(--space-xs) var(--space-sm);
border: 1px solid var(--color-border);
border-radius: var(--radius-input);
font-family: var(--font-body);
font-size: var(--p-text-sm);
background: var(--t-surface-raised);
color: var(--color-heading);
}
.newsletter-input::placeholder {
color: var(--color-caption);
}
.newsletter-btn {
padding: var(--space-xs) var(--space-md);
white-space: nowrap;
}
.footer-links {
display: flex;
gap: var(--space-xl);
justify-content: flex-end;
}
.footer-column {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.footer-column-title {
font-family: var(--font-body);
font-weight: 600;
font-size: var(--p-text-sm);
color: var(--color-heading);
margin-bottom: var(--space-xs);
}
.footer-column a {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
text-decoration: none;
transition: color 0.15s ease;
}
.footer-column a:hover {
color: var(--color-heading);
}
.footer-bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.footer-bottom p {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
margin: 0;
}
.footer-social {
display: flex;
gap: var(--space-sm);
}
.social-link {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-body);
border-radius: var(--radius-button);
transition: all 0.15s ease;
}
.social-link:hover {
color: var(--color-heading);
background: var(--t-surface-sunken);
}
.social-link svg {
width: 20px;
height: 20px;
}
/* Product images - using picsum.photos with alt views */
.product-image-primary.img-1 {
background-color: #e8e4df;
background-image: url('https://picsum.photos/seed/fern/400/400');
}
.product-image-hover.img-1-alt {
background-color: #e8e4df;
background-image: url('https://picsum.photos/seed/fern-alt/400/400');
}
.product-image-primary.img-2 {
background-color: #f5e6e0;
background-image: url('https://picsum.photos/seed/roses/400/400');
}
.product-image-hover.img-2-alt {
background-color: #f5e6e0;
background-image: url('https://picsum.photos/seed/roses-alt/400/400');
}
.product-image-primary.img-3 {
background-color: #e0e8e4;
background-image: url('https://picsum.photos/seed/morning/400/400');
}
.product-image-hover.img-3-alt {
background-color: #e0e8e4;
background-image: url('https://picsum.photos/seed/morning-alt/400/400');
}
.product-image-primary.img-4 {
background-color: #e4e8e0;
background-image: url('https://picsum.photos/seed/oak/400/400');
}
.product-image-hover.img-4-alt {
background-color: #e4e8e0;
background-image: url('https://picsum.photos/seed/oak-alt/400/400');
}
.product-image-primary.img-5 {
background-color: #f0e8e4;
background-image: url('https://picsum.photos/seed/bloom/400/400');
}
.product-image-hover.img-5-alt {
background-color: #f0e8e4;
background-image: url('https://picsum.photos/seed/bloom-alt/400/400');
}
.product-image-primary.img-6 {
background-color: #e8e0f0;
background-image: url('https://picsum.photos/seed/lavender/400/400');
}
.product-image-hover.img-6-alt {
background-color: #e8e0f0;
background-image: url('https://picsum.photos/seed/lavender-alt/400/400');
}
.icon {
width: 20px;
height: 20px;
}
.preview-frame ::selection {
background: var(--t-accent-subtle);
}
/* Page views */
.page-view {
display: none;
}
.page-view.active {
display: block;
}
/* PDP Styles */
.pdp-container {
padding: var(--space-lg);
background: var(--t-surface-base);
}
.pdp-breadcrumb {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
margin-bottom: var(--space-lg);
display: flex;
align-items: center;
gap: var(--space-xs);
}
.pdp-breadcrumb a {
color: var(--color-body);
text-decoration: none;
}
.pdp-breadcrumb a:hover {
color: var(--color-heading);
}
.breadcrumb-sep {
color: var(--color-caption);
}
.pdp-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-xl);
}
/* Gallery position */
.preview-frame[data-gallery-position="right"] .pdp-layout {
direction: rtl;
}
.preview-frame[data-gallery-position="right"] .pdp-layout > * {
direction: ltr;
}
/* PDP section visibility */
.preview-frame[data-pdp-trust="false"] .pdp-trust-badges {
display: none;
}
.preview-frame[data-pdp-reviews="false"] .pdp-reviews {
display: none;
}
.preview-frame[data-pdp-related="false"] .pdp-related {
display: none;
}
.pdp-gallery {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.pdp-main-image {
aspect-ratio: 1;
border-radius: var(--radius-image);
overflow: hidden;
}
.pdp-thumbnails {
display: flex;
gap: var(--space-xs);
}
.pdp-thumb {
width: 64px;
height: 64px;
border-radius: var(--t-radius-sm);
cursor: pointer;
opacity: 0.6;
transition: opacity 0.15s ease;
border: 2px solid transparent;
}
.pdp-thumb:hover {
opacity: 0.8;
}
.pdp-thumb.active {
opacity: 1;
border-color: var(--color-heading);
}
/* PDP images */
.pdp-main-image {
background-color: #e8e4df;
background-size: cover;
background-position: center;
}
.pdp-thumb {
background-color: #e8e4df;
background-size: cover;
background-position: center;
}
.pdp-thumb[data-image*="fern/"] { background-image: url('https://picsum.photos/seed/fern/100/100'); }
.pdp-thumb[data-image*="fern-alt"] { background-image: url('https://picsum.photos/seed/fern-alt/100/100'); }
.pdp-thumb[data-image*="fern-detail"] { background-image: url('https://picsum.photos/seed/fern-detail/100/100'); }
.pdp-details {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.pdp-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-3xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin: 0;
}
.pdp-price {
font-family: var(--font-body);
font-size: var(--p-text-xl);
color: var(--color-heading);
font-variant-numeric: tabular-nums;
margin: 0;
}
.pdp-description {
font-family: var(--font-body);
font-size: var(--p-text-base);
color: var(--color-body);
line-height: 1.6;
}
.pdp-description p {
margin: 0;
}
.pdp-options {
display: flex;
flex-direction: column;
gap: var(--space-md);
padding: var(--space-md) 0;
border-top: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border);
}
.pdp-option-group {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.pdp-option-label {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
}
.pdp-option-buttons {
display: flex;
flex-wrap: wrap;
gap: var(--space-xs);
}
.pdp-option-btn {
padding: var(--space-xs) var(--space-sm);
border: 1px solid var(--color-border);
border-radius: var(--radius-button);
background: var(--t-surface-raised);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
cursor: pointer;
transition: all 0.15s ease;
}
.pdp-option-btn:hover {
border-color: var(--color-heading);
color: var(--color-heading);
}
.pdp-option-btn.active {
border-color: var(--color-heading);
background: var(--color-heading);
color: var(--t-text-inverse);
}
.pdp-add-btn {
width: 100%;
padding: var(--space-md);
font-size: var(--p-text-base);
}
/* PDP Expandable Details */
.pdp-details-sections {
display: flex;
flex-direction: column;
border-top: 1px solid var(--color-border);
}
.pdp-details {
border-bottom: 1px solid var(--color-border);
}
.pdp-details-summary {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-md) 0;
cursor: pointer;
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
list-style: none;
}
.pdp-details-summary::-webkit-details-marker {
display: none;
}
.pdp-details-summary::marker {
display: none;
}
.pdp-details-icon {
width: 18px;
height: 18px;
color: var(--color-caption);
transition: transform 0.2s ease;
}
.pdp-details[open] .pdp-details-icon {
transform: rotate(180deg);
}
.pdp-details-content {
padding-bottom: var(--space-md);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
line-height: 1.6;
}
.size-table {
width: 100%;
border-collapse: collapse;
font-size: var(--p-text-sm);
}
.size-table th,
.size-table td {
padding: var(--space-xs) var(--space-sm);
text-align: left;
border-bottom: 1px solid var(--color-border);
}
.size-table th {
font-weight: 500;
color: var(--color-heading);
background: var(--t-surface-sunken);
}
.size-table td {
color: var(--color-body);
}
.details-list {
margin: 0;
padding-left: var(--space-md);
}
.details-list li {
margin-bottom: var(--space-xs);
}
.details-list li:last-child {
margin-bottom: 0;
}
.pdp-meta {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding-top: var(--space-sm);
}
.pdp-meta-item {
display: flex;
align-items: center;
gap: var(--space-sm);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
}
.pdp-meta-icon {
width: 18px;
height: 18px;
color: var(--color-caption);
}
.pdp-trust-badges {
display: flex;
gap: var(--space-md);
padding-top: var(--space-md);
border-top: 1px solid var(--color-border);
flex-wrap: wrap;
}
.trust-badge {
display: flex;
align-items: center;
gap: var(--space-xs);
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
}
.trust-badge-icon {
width: 16px;
height: 16px;
}
.pdp-related {
padding: var(--space-xl) 0;
border-top: 1px solid var(--color-border);
margin-top: var(--space-xl);
}
/* Reviews Section */
.pdp-reviews {
padding: var(--space-xl) var(--space-lg);
background: var(--t-surface-base);
}
.reviews-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
flex-wrap: wrap;
gap: var(--space-md);
margin-bottom: var(--space-lg);
}
.reviews-summary {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.reviews-stars,
.review-stars {
display: flex;
gap: 2px;
}
.star {
width: 16px;
height: 16px;
color: var(--color-border);
}
.star.filled {
color: #f59e0b;
}
.reviews-count {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
}
.reviews-list {
display: flex;
flex-direction: column;
gap: var(--space-lg);
margin-bottom: var(--space-lg);
}
.review {
padding-bottom: var(--space-lg);
border-bottom: 1px solid var(--color-border);
}
.review:last-child {
border-bottom: none;
}
.review-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-xs);
}
.review-date {
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
}
.review-title {
font-family: var(--font-body);
font-size: var(--p-text-base);
font-weight: 600;
color: var(--color-heading);
margin: 0 0 var(--space-xs);
}
.review-text {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
line-height: 1.6;
margin: 0 0 var(--space-sm);
}
.review-author {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.review-name {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
}
.review-verified {
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
background: var(--t-surface-sunken);
padding: 2px 8px;
border-radius: var(--radius-button);
}
.reviews-load-more {
display: block;
margin: 0 auto;
}
.related-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-md);
}
/* Section CTA */
.section-cta {
text-align: center;
margin-top: var(--space-lg);
}
.btn-secondary {
background: transparent;
color: var(--color-heading);
border: 1px solid var(--color-heading);
}
.btn-secondary:hover {
background: var(--color-heading);
color: var(--t-text-inverse);
}
/* Home About Section */
.home-about {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-xl);
padding: var(--space-2xl) var(--space-lg);
background: var(--t-surface-base);
}
.home-about-image {
height: 300px;
border-radius: var(--radius-image);
background: url('https://picsum.photos/seed/studio/600/400') center/cover;
}
.home-about-content {
display: flex;
flex-direction: column;
justify-content: center;
}
.home-about-content h2 {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-2xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin: 0 0 var(--space-md);
}
.home-about-content p {
font-family: var(--font-body);
font-size: var(--p-text-base);
color: var(--color-body);
line-height: 1.7;
margin: 0 0 var(--space-md);
}
.text-link {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--t-accent);
text-decoration: none;
}
.text-link:hover {
text-decoration: underline;
}
/* Home Categories */
.home-categories {
padding: var(--space-xl) var(--space-lg);
background: var(--t-surface-base);
}
.category-links {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-md);
max-width: 800px;
margin: 0 auto;
}
.category-link {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-sm);
text-decoration: none;
padding: var(--space-md);
border-radius: var(--radius-card);
transition: all 0.2s ease;
}
.category-link:hover {
background: var(--t-surface-sunken);
}
.category-link:focus {
outline: 2px solid var(--t-accent);
outline-offset: 2px;
}
.category-image {
width: 100px;
height: 100px;
border-radius: 50%;
background-size: cover;
background-position: center;
transition: transform 0.2s ease;
}
.category-link:hover .category-image {
transform: scale(1.05);
}
.cat-img-1 { background-image: url('https://picsum.photos/seed/botanicals/200/200'); }
.cat-img-2 { background-image: url('https://picsum.photos/seed/florals/200/200'); }
.cat-img-3 { background-image: url('https://picsum.photos/seed/landscapes/200/200'); }
.category-name {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
}
/* Utility: visually hidden but accessible */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Collection Page */
.collection-header {
padding: var(--space-xl) var(--space-lg) var(--space-md);
background: var(--t-surface-base);
text-align: center;
}
.collection-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-3xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin: 0 0 var(--space-xs);
}
.collection-count {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
margin: 0;
}
.collection-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-lg);
gap: var(--space-md);
flex-wrap: wrap;
}
.collection-filter {
display: flex;
gap: var(--space-xs);
}
.filter-btn {
padding: var(--space-xs) var(--space-md);
border: 1px solid var(--color-border);
border-radius: var(--radius-button);
background: var(--t-surface-raised);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
cursor: pointer;
transition: all 0.15s ease;
}
.filter-btn:hover {
border-color: var(--color-heading);
color: var(--color-heading);
}
.filter-btn.active {
background: var(--color-heading);
border-color: var(--color-heading);
color: var(--t-text-inverse);
}
.sort-select {
padding: var(--space-xs) var(--space-md);
border: 1px solid var(--color-border);
border-radius: var(--radius-button);
background: var(--t-surface-raised);
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-heading);
cursor: pointer;
}
@media (max-width: 1000px) {
.controls-panel {
position: relative;
max-height: none;
border-right: none;
border-bottom: 1px solid #e5e5e5;
}
.preview-area {
padding: var(--p-space-4);
}
.product-grid[data-grid="4"] {
grid-template-columns: repeat(2, 1fr);
}
.pdp-layout {
grid-template-columns: 1fr;
}
.related-grid {
grid-template-columns: repeat(2, 1fr);
}
.footer-content {
grid-template-columns: 1fr;
gap: var(--space-lg);
}
.footer-links {
justify-content: flex-start;
}
.cart-layout {
grid-template-columns: 1fr;
}
.contact-layout {
grid-template-columns: 1fr;
}
.home-about {
grid-template-columns: 1fr;
}
.home-about-image {
height: 200px;
}
.category-links {
grid-template-columns: repeat(3, 1fr);
gap: var(--space-sm);
}
.category-image {
width: 70px;
height: 70px;
}
}
/* Cart Page */
.cart-container {
padding: var(--space-lg);
background: var(--t-surface-base);
min-height: 60vh;
}
.cart-header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-lg);
}
.cart-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-3xl);
color: var(--color-heading);
margin: 0;
}
.cart-state-toggle {
background: none;
border: none;
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
cursor: pointer;
text-decoration: underline;
padding: var(--space-xs);
}
.cart-state-toggle:hover {
color: var(--color-body);
}
.cart-state[hidden] {
display: none;
}
/* Empty State */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: var(--space-2xl) var(--space-lg);
min-height: 40vh;
}
.empty-state-illustration {
width: 120px;
height: 120px;
margin-bottom: var(--space-lg);
color: var(--color-caption);
}
.empty-state-illustration svg {
width: 100%;
height: 100%;
}
.empty-state-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-2xl);
color: var(--color-heading);
margin: 0 0 var(--space-sm);
}
.empty-state-message {
font-family: var(--font-body);
font-size: var(--p-text-base);
color: var(--color-body);
max-width: 400px;
margin: 0 0 var(--space-lg);
line-height: 1.6;
}
/* Error Page */
.error-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 70vh;
padding: var(--space-xl) var(--space-lg);
background: var(--t-surface-base);
}
.error-content {
text-align: center;
max-width: 500px;
}
.error-illustration {
width: 200px;
height: 160px;
margin: 0 auto var(--space-xl);
color: var(--t-accent);
}
.error-illustration svg {
width: 100%;
height: 100%;
}
.error-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-3xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin: 0 0 var(--space-sm);
}
.error-message {
font-family: var(--font-body);
font-size: var(--p-text-base);
color: var(--color-body);
line-height: 1.6;
margin: 0 0 var(--space-xl);
}
.error-actions {
display: flex;
gap: var(--space-sm);
justify-content: center;
flex-wrap: wrap;
}
.cart-layout {
display: grid;
grid-template-columns: 1fr 360px;
gap: var(--space-xl);
align-items: start;
}
.cart-items {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.cart-item {
display: flex;
align-items: center;
gap: var(--space-md);
padding: var(--space-md);
background: var(--t-surface-raised);
border-radius: var(--radius-card);
border: 1px solid var(--color-border);
}
.cart-item-image {
width: 80px;
height: 80px;
border-radius: var(--radius-image);
background-size: cover;
background-position: center;
flex-shrink: 0;
}
.cart-item-image.img-1 { background-image: url('https://picsum.photos/seed/fern/200/200'); }
.cart-item-image.img-2 { background-image: url('https://picsum.photos/seed/roses/200/200'); }
.cart-item-details {
flex: 1;
}
.cart-item-title {
font-family: var(--font-body);
font-weight: 500;
font-size: var(--p-text-base);
color: var(--color-heading);
margin: 0 0 4px;
}
.cart-item-variant {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
margin: 0 0 4px;
}
.cart-item-price {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-heading);
margin: 0;
font-variant-numeric: tabular-nums;
}
.cart-item-quantity {
display: flex;
align-items: center;
gap: var(--space-xs);
}
.qty-btn {
width: 32px;
height: 32px;
border: 1px solid var(--color-border);
border-radius: var(--radius-button);
background: var(--t-surface-raised);
color: var(--color-heading);
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s ease;
}
.qty-btn:hover {
border-color: var(--color-heading);
}
.qty-value {
font-family: var(--font-body);
font-size: var(--p-text-base);
color: var(--color-heading);
min-width: 24px;
text-align: center;
}
.cart-item-remove {
background: none;
border: none;
padding: var(--space-xs);
color: var(--color-caption);
cursor: pointer;
transition: color 0.15s ease;
}
.cart-item-remove:hover {
color: #dc2626;
}
.cart-item-remove svg {
width: 18px;
height: 18px;
}
.cart-summary {
padding: var(--space-lg);
background: var(--t-surface-sunken);
border-radius: var(--radius-card);
}
.cart-summary-row {
display: flex;
justify-content: space-between;
padding: var(--space-sm) 0;
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
border-bottom: 1px solid var(--color-border);
}
.cart-summary-row.cart-total {
font-weight: 600;
font-size: var(--p-text-base);
color: var(--color-heading);
border-bottom: none;
padding-top: var(--space-md);
}
.cart-checkout-btn {
width: 100%;
margin-top: var(--space-md);
padding: var(--space-md);
}
.cart-secure-note {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-xs);
margin-top: var(--space-md);
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
}
.cart-secure-note svg {
width: 14px;
height: 14px;
}
/* Content Pages (About/Contact) */
.content-page {
background: var(--t-surface-base);
}
.content-hero {
padding: var(--space-2xl) var(--space-lg);
text-align: center;
background: var(--t-surface-sunken);
}
.content-title {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-4xl);
letter-spacing: var(--tracking-heading);
color: var(--color-heading);
margin: 0 0 var(--space-xs);
}
.content-subtitle {
font-family: var(--font-body);
font-size: var(--p-text-lg);
color: var(--color-body);
margin: 0;
}
.content-body {
padding: var(--space-xl) var(--space-lg);
max-width: 800px;
margin: 0 auto;
}
.content-image {
width: 100%;
height: 300px;
border-radius: var(--radius-image);
margin-bottom: var(--space-lg);
background-size: cover;
background-position: center;
}
.about-image {
background-image: url('https://picsum.photos/seed/studio/800/400');
}
.content-text {
font-family: var(--font-body);
color: var(--color-body);
line-height: 1.7;
}
.content-text p {
margin: 0 0 var(--space-md);
}
.content-text .lead-text {
font-size: var(--p-text-lg);
color: var(--color-heading);
}
.content-text h2 {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-xl);
color: var(--color-heading);
margin: var(--space-lg) 0 var(--space-sm);
}
/* Contact Page */
.contact-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-xl);
padding: var(--space-xl) var(--space-lg);
max-width: 1000px;
margin: 0 auto;
}
.contact-info {
display: flex;
flex-direction: column;
gap: var(--space-lg);
}
.contact-block h3 {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-lg);
color: var(--color-heading);
margin: 0 0 var(--space-xs);
}
.contact-block p {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
margin: 0 0 var(--space-sm);
line-height: 1.5;
}
.contact-link {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--t-accent);
text-decoration: none;
}
.contact-link:hover {
text-decoration: underline;
}
.contact-social {
display: flex;
gap: var(--space-sm);
}
.contact-form {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.form-group {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.form-label {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
}
.form-input {
padding: var(--space-sm);
border: 1px solid var(--color-border);
border-radius: var(--radius-input);
font-family: var(--font-body);
font-size: var(--p-text-base);
background: var(--t-surface-raised);
color: var(--color-heading);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-input:focus {
outline: none;
border-color: var(--t-accent);
box-shadow: 0 0 0 3px var(--t-accent-ring);
}
.form-input::placeholder {
color: var(--color-caption);
}
.form-select {
cursor: pointer;
}
.form-textarea {
resize: vertical;
min-height: 120px;
}
.form-submit {
align-self: flex-start;
padding: var(--space-sm) var(--space-xl);
}
/* Cart Drawer */
.cart-drawer {
position: fixed;
top: 0;
right: -400px;
width: 400px;
max-width: 90vw;
height: 100%;
background: var(--t-surface-raised);
z-index: 1000;
display: flex;
flex-direction: column;
transition: right 0.3s ease;
box-shadow: -4px 0 20px rgba(0,0,0,0.15);
}
.cart-drawer.open {
right: 0;
}
.cart-drawer-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-md) var(--space-lg);
border-bottom: 1px solid var(--color-border);
}
.cart-drawer-header h2 {
font-family: var(--font-heading);
font-weight: var(--weight-heading);
font-size: var(--p-text-lg);
color: var(--color-heading);
margin: 0;
}
.cart-drawer-close {
background: none;
border: none;
padding: var(--space-xs);
cursor: pointer;
color: var(--color-body);
}
.cart-drawer-close svg {
width: 20px;
height: 20px;
}
.cart-drawer-items {
flex: 1;
overflow-y: auto;
padding: var(--space-md);
}
.cart-drawer-item {
display: flex;
gap: var(--space-sm);
padding: var(--space-sm) 0;
border-bottom: 1px solid var(--color-border);
}
.cart-drawer-item-image {
width: 60px;
height: 60px;
border-radius: var(--radius-image);
background-size: cover;
background-position: center;
flex-shrink: 0;
}
.cart-drawer-item-image.img-1 { background-image: url('https://picsum.photos/seed/fern/120/120'); }
.cart-drawer-item-image.img-2 { background-image: url('https://picsum.photos/seed/roses/120/120'); }
.cart-drawer-item-details h3 {
font-family: var(--font-body);
font-size: var(--p-text-sm);
font-weight: 500;
color: var(--color-heading);
margin: 0 0 2px;
}
.cart-drawer-item-details p {
font-family: var(--font-body);
font-size: var(--p-text-xs);
color: var(--color-caption);
margin: 0;
}
.cart-drawer-item-price {
color: var(--color-heading) !important;
font-weight: 500;
margin-top: 4px !important;
}
.cart-drawer-footer {
padding: var(--space-md) var(--space-lg);
border-top: 1px solid var(--color-border);
background: var(--t-surface-sunken);
}
.cart-drawer-total {
display: flex;
justify-content: space-between;
font-family: var(--font-body);
font-size: var(--p-text-base);
font-weight: 600;
color: var(--color-heading);
margin-bottom: var(--space-md);
}
.cart-drawer-checkout {
width: 100%;
margin-bottom: var(--space-sm);
}
.cart-drawer-link {
display: block;
text-align: center;
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-body);
text-decoration: underline;
}
.cart-drawer-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.4);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.cart-drawer-overlay.open {
opacity: 1;
visibility: visible;
}
/* Search Modal */
.search-modal {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: 1001;
display: flex;
align-items: flex-start;
justify-content: center;
padding-top: 100px;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
}
.search-modal.open {
opacity: 1;
visibility: visible;
}
.search-modal-content {
background: var(--t-surface-raised);
border-radius: var(--radius-card);
width: 100%;
max-width: 600px;
margin: 0 var(--space-md);
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
overflow: hidden;
}
.search-input-wrapper {
display: flex;
align-items: center;
padding: var(--space-md);
gap: var(--space-sm);
border-bottom: 1px solid var(--color-border);
}
.search-icon {
width: 20px;
height: 20px;
color: var(--color-caption);
flex-shrink: 0;
}
.search-input {
flex: 1;
border: none;
background: none;
font-family: var(--font-body);
font-size: var(--p-text-lg);
color: var(--color-heading);
outline: none;
}
.search-input::placeholder {
color: var(--color-caption);
}
.search-close {
background: none;
border: none;
padding: var(--space-xs);
cursor: pointer;
color: var(--color-caption);
}
.search-close:hover {
color: var(--color-heading);
}
.search-close svg {
width: 20px;
height: 20px;
}
.search-results {
padding: var(--space-lg);
}
.search-hint {
font-family: var(--font-body);
font-size: var(--p-text-sm);
color: var(--color-caption);
text-align: center;
margin: 0;
}
/* Zoom button on PDP image */
.pdp-main-image {
position: relative;
cursor: pointer;
}
.zoom-btn {
position: absolute;
bottom: var(--space-sm);
right: var(--space-sm);
width: 40px;
height: 40px;
background: var(--t-surface-raised);
border: none;
border-radius: var(--radius-button);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-heading);
box-shadow: var(--shadow-sm);
transition: all 0.15s ease;
opacity: 0;
}
.pdp-main-image:hover .zoom-btn,
.zoom-btn:focus {
opacity: 1;
}
.zoom-btn:hover {
background: var(--color-heading);
color: var(--t-text-inverse);
}
.zoom-btn svg {
width: 20px;
height: 20px;
}
/* Lightbox - using native dialog */
.lightbox {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
background: rgba(0, 0, 0, 0.95);
border: none;
padding: 0;
z-index: 1002;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox::backdrop {
background: rgba(0, 0, 0, 0.95);
}
.lightbox:not([open]) {
display: none;
}
.lightbox-content {
position: relative;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox-close {
position: absolute;
top: var(--space-md);
right: var(--space-md);
width: 44px;
height: 44px;
background: transparent;
border: none;
cursor: pointer;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-button);
transition: background 0.15s ease;
z-index: 1;
}
.lightbox-close:hover {
background: rgba(255, 255, 255, 0.1);
}
.lightbox-close svg {
width: 24px;
height: 24px;
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 50px;
height: 50px;
background: rgba(255, 255, 255, 0.1);
border: none;
cursor: pointer;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background 0.15s ease;
}
.lightbox-nav:hover {
background: rgba(255, 255, 255, 0.2);
}
.lightbox-nav svg {
width: 24px;
height: 24px;
}
.lightbox-prev {
left: var(--space-md);
}
.lightbox-next {
right: var(--space-md);
}
.lightbox-image-container {
max-width: 90vw;
max-height: 75vh;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox-image {
max-width: 100%;
max-height: 75vh;
object-fit: contain;
border-radius: var(--radius-image);
}
.lightbox-figure {
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-md);
}
.lightbox-caption {
color: rgba(255, 255, 255, 0.8);
font-family: var(--font-body);
font-size: var(--p-text-sm);
text-align: center;
max-width: 500px;
line-height: 1.5;
}
.lightbox-counter {
position: absolute;
bottom: var(--space-md);
left: 50%;
transform: translateX(-50%);
color: rgba(255, 255, 255, 0.7);
font-family: var(--font-body);
font-size: var(--p-text-sm);
}
</style>
</head>
<body>
<div class="page-layout">
<!-- Controls Panel -->
<div class="controls-panel">
<div class="controls-header">
<h1>Theme Studio</h1>
<p>One theme, infinite possibilities. Every combination is designed to work beautifully.</p>
</div>
<!-- Shop Name -->
<div class="control-section">
<label class="control-label">Shop name</label>
<input type="text" class="text-input" id="shop-name" value="Botanical Studio" placeholder="Your shop name">
</div>
<!-- Branding Section -->
<div class="branding-section">
<label class="control-label">Logo &amp; header</label>
<div class="logo-mode-options">
<label class="logo-mode-option active" data-mode="text-only">
<input type="radio" name="logo-mode" value="text-only" checked>
<span class="logo-mode-radio"></span>
<div class="logo-mode-content">
<div class="logo-mode-title">Shop name only</div>
<div class="logo-mode-desc">Your name in the heading font</div>
</div>
</label>
<label class="logo-mode-option" data-mode="logo-and-text">
<input type="radio" name="logo-mode" value="logo-and-text">
<span class="logo-mode-radio"></span>
<div class="logo-mode-content">
<div class="logo-mode-title">Logo + shop name</div>
<div class="logo-mode-desc">Your logo image with name beside it</div>
</div>
</label>
<label class="logo-mode-option" data-mode="logo-only">
<input type="radio" name="logo-mode" value="logo-only">
<span class="logo-mode-radio"></span>
<div class="logo-mode-content">
<div class="logo-mode-title">Logo only</div>
<div class="logo-mode-desc">Just your logo (with text built in)</div>
</div>
</label>
<label class="logo-mode-option" data-mode="header-image">
<input type="radio" name="logo-mode" value="header-image">
<span class="logo-mode-radio"></span>
<div class="logo-mode-content">
<div class="logo-mode-title">Header background</div>
<div class="logo-mode-desc">Full-width image with name overlay</div>
</div>
</label>
<label class="logo-mode-option" data-mode="logo-header-image">
<input type="radio" name="logo-mode" value="logo-header-image">
<span class="logo-mode-radio"></span>
<div class="logo-mode-content">
<div class="logo-mode-title">Logo + header background</div>
<div class="logo-mode-desc">Your logo (use white/light version) on a full-width image</div>
</div>
</label>
</div>
<div class="upload-section">
<!-- Logo upload (for logo-and-text and logo-only modes) -->
<div class="upload-row" id="logo-upload-row">
<span class="upload-label" id="logo-upload-label">Upload logo (SVG or PNG)</span>
<div class="upload-area">
<label class="upload-btn">
<span>Choose file...</span>
<input type="file" id="logo-upload" accept=".svg,.png,.jpg,.jpeg,.webp">
</label>
<div class="upload-preview" id="logo-preview">
<img id="logo-preview-img" src="" alt="Logo preview">
<button class="remove-upload" id="remove-logo">×</button>
</div>
</div>
<div class="size-control" id="logo-size-control">
<div class="size-control-header">
<span class="size-control-label">Logo size</span>
<span class="size-control-value" id="logo-size-value">36px</span>
</div>
<input type="range" class="size-slider" id="logo-size-slider" min="24" max="120" value="36">
</div>
<div class="logo-color-control" id="logo-color-control">
<div class="logo-color-toggle">
<label class="toggle-label">
<input type="checkbox" id="recolor-logo-checkbox">
<span class="toggle-switch"></span>
<span class="toggle-text">Recolour logo</span>
</label>
</div>
<div class="logo-color-picker-row" id="logo-color-picker-row">
<input type="color" class="color-picker color-picker-small" id="logo-color-picker" value="#171717">
<span class="color-value" id="logo-color-value">#171717</span>
</div>
</div>
</div>
<!-- Header background upload -->
<div class="upload-row" id="header-upload-row">
<span class="upload-label">Upload header image</span>
<div class="upload-area">
<label class="upload-btn">
<span>Choose file...</span>
<input type="file" id="header-upload" accept=".jpg,.jpeg,.png,.webp">
</label>
</div>
<div class="upload-preview upload-preview-wide" id="header-preview">
<img id="header-preview-img" src="" alt="Header preview">
<button class="remove-upload" id="remove-header">×</button>
</div>
<div class="header-image-controls" id="header-image-controls">
<div class="control-row">
<div class="size-control-header">
<span class="size-control-label">Zoom</span>
<span class="size-control-value" id="header-zoom-value">100%</span>
</div>
<input type="range" class="size-slider" id="header-zoom-slider" min="100" max="200" value="100">
</div>
<div class="control-row" id="header-position-x-row">
<div class="size-control-header">
<span class="size-control-label">Horizontal position</span>
<span class="size-control-value" id="header-position-x-value">50%</span>
</div>
<input type="range" class="size-slider" id="header-position-x-slider" min="0" max="100" value="50">
</div>
<div class="control-row">
<div class="size-control-header">
<span class="size-control-label">Vertical position</span>
<span class="size-control-value" id="header-position-value">50%</span>
</div>
<input type="range" class="size-slider" id="header-position-slider" min="0" max="100" value="50">
</div>
</div>
</div>
</div>
</div>
<!-- Presets -->
<div class="control-section">
<label class="control-label">Start with a preset</label>
<div class="preset-grid" id="preset-grid">
<button class="preset-button active" data-preset="gallery">
<div class="preset-name">Gallery</div>
<div class="preset-desc">Warm & spacious</div>
</button>
<button class="preset-button" data-preset="studio">
<div class="preset-name">Studio</div>
<div class="preset-desc">Clean & balanced</div>
</button>
<button class="preset-button" data-preset="boutique">
<div class="preset-name">Boutique</div>
<div class="preset-desc">Classic & refined</div>
</button>
<button class="preset-button" data-preset="bold">
<div class="preset-name">Bold</div>
<div class="preset-desc">Sharp & modern</div>
</button>
<button class="preset-button" data-preset="playful">
<div class="preset-name">Playful</div>
<div class="preset-desc">Friendly & round</div>
</button>
<button class="preset-button" data-preset="minimal">
<div class="preset-name">Minimal</div>
<div class="preset-desc">Cool & focused</div>
</button>
<button class="preset-button" data-preset="night">
<div class="preset-name">Night</div>
<div class="preset-desc">Dark & premium</div>
</button>
<button class="preset-button" data-preset="classic">
<div class="preset-name">Classic</div>
<div class="preset-desc">Timeless elegance</div>
</button>
<button class="preset-button" data-preset="impulse">
<div class="preset-name">Impulse</div>
<div class="preset-desc">Fashion editorial</div>
</button>
</div>
</div>
<!-- Accent Color - stays in essentials -->
<div class="control-section">
<label class="control-label">Accent colour</label>
<div class="color-picker-wrapper">
<input type="color" class="color-picker" id="accent-picker" value="#f97316">
<span class="color-value" id="color-value">#f97316</span>
</div>
</div>
<!-- Customise Section (collapsible) -->
<div class="customise-section" id="customise-section">
<div class="customise-header" id="customise-header">
<span class="customise-title">Customise</span>
<svg class="customise-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</div>
<div class="customise-content">
<!-- Typography Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 7 4 4 20 4 20 7"></polyline>
<line x1="9" y1="20" x2="15" y2="20"></line>
<line x1="12" y1="4" x2="12" y2="20"></line>
</svg>
<span class="control-group-title">Typography</span>
</div>
<div class="control-section">
<label class="control-label">Font style</label>
<div class="option-group" id="typography-options">
<button class="option-button active" data-typography="clean">Clean</button>
<button class="option-button" data-typography="editorial">Editorial</button>
<button class="option-button" data-typography="modern">Modern</button>
<button class="option-button" data-typography="classic">Classic</button>
<button class="option-button" data-typography="friendly">Friendly</button>
<button class="option-button" data-typography="minimal">Minimal</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Font size</label>
<div class="option-group" id="font-size-options">
<button class="option-button" data-font-size="small">Small</button>
<button class="option-button active" data-font-size="medium">Medium</button>
<button class="option-button" data-font-size="large">Large</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Heading weight</label>
<div class="option-group" id="heading-weight-options">
<button class="option-button" data-heading-weight="regular">Regular</button>
<button class="option-button" data-heading-weight="medium">Medium</button>
<button class="option-button active" data-heading-weight="bold">Bold</button>
</div>
</div>
</div>
<!-- Colours Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<span class="control-group-title">Colours</span>
</div>
<div class="control-section">
<label class="control-label">Colour mood</label>
<div class="option-group" id="mood-options">
<button class="option-button" data-mood="warm">Warm</button>
<button class="option-button active" data-mood="neutral">Neutral</button>
<button class="option-button" data-mood="cool">Cool</button>
<button class="option-button" data-mood="dark">Dark</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Hover colour</label>
<div class="color-picker-wrapper">
<input type="color" class="color-picker" id="secondary-accent-picker" value="#ea580c">
<span class="color-value" id="secondary-color-value">#ea580c</span>
</div>
</div>
<div class="control-section">
<label class="control-label">Sale badge colour</label>
<div class="color-picker-wrapper">
<input type="color" class="color-picker" id="sale-color-picker" value="#dc2626">
<span class="color-value" id="sale-color-value">#dc2626</span>
</div>
</div>
</div>
<!-- Layout Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
<line x1="9" y1="21" x2="9" y2="9"></line>
</svg>
<span class="control-group-title">Layout</span>
</div>
<div class="control-section">
<label class="control-label">Layout width</label>
<div class="option-group" id="layout-width-options">
<button class="option-button" data-layout-width="contained">Contained</button>
<button class="option-button active" data-layout-width="wide">Wide</button>
<button class="option-button" data-layout-width="full">Full width</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Density</label>
<div class="option-group" id="density-options">
<button class="option-button" data-density="spacious">Spacious</button>
<button class="option-button active" data-density="balanced">Balanced</button>
<button class="option-button" data-density="compact">Compact</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Corner style</label>
<div class="option-group" id="shape-options">
<button class="option-button" data-shape="sharp">Sharp</button>
<button class="option-button active" data-shape="soft">Soft</button>
<button class="option-button" data-shape="round">Round</button>
<button class="option-button" data-shape="pill">Pill</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Button style</label>
<div class="option-group" id="button-style-options">
<button class="option-button active" data-button-style="filled">Filled</button>
<button class="option-button" data-button-style="outline">Outline</button>
<button class="option-button" data-button-style="soft">Soft</button>
</div>
</div>
</div>
<!-- Product Cards Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
<line x1="8" y1="21" x2="16" y2="21"></line>
<line x1="12" y1="17" x2="12" y2="21"></line>
</svg>
<span class="control-group-title">Product cards</span>
</div>
<div class="control-section">
<label class="control-label">Products per row</label>
<div class="option-group" id="grid-options">
<button class="option-button" data-grid="2">2</button>
<button class="option-button" data-grid="3">3</button>
<button class="option-button active" data-grid="4">4</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Image ratio</label>
<div class="option-group" id="aspect-options">
<button class="option-button active" data-aspect="square">Square</button>
<button class="option-button" data-aspect="portrait">Portrait</button>
<button class="option-button" data-aspect="landscape">Landscape</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Text alignment</label>
<div class="option-group" id="product-text-options">
<button class="option-button active" data-product-text="left">Left</button>
<button class="option-button" data-product-text="center">Center</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Card shadow</label>
<div class="option-group" id="card-shadow-options">
<button class="option-button active" data-card-shadow="none">None</button>
<button class="option-button" data-card-shadow="subtle">Subtle</button>
<button class="option-button" data-card-shadow="pronounced">Pronounced</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Features</label>
<div class="toggle-list">
<label class="toggle-label">
<input type="checkbox" id="hover-image-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Second image on hover</span>
</label>
<label class="toggle-label">
<input type="checkbox" id="quick-add-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Quick add button</span>
</label>
<label class="toggle-label">
<input type="checkbox" id="show-prices-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Show prices</span>
</label>
</div>
</div>
</div>
<!-- Product Page Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
</svg>
<span class="control-group-title">Product page</span>
</div>
<div class="control-section">
<label class="control-label">Gallery position</label>
<div class="option-group" id="gallery-position-options">
<button class="option-button active" data-gallery-position="left">Left</button>
<button class="option-button" data-gallery-position="right">Right</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Sections</label>
<div class="toggle-list">
<label class="toggle-label">
<input type="checkbox" id="pdp-trust-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Trust badges</span>
</label>
<label class="toggle-label">
<input type="checkbox" id="pdp-reviews-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Reviews section</span>
</label>
<label class="toggle-label">
<input type="checkbox" id="pdp-related-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Related products</span>
</label>
</div>
</div>
</div>
<!-- Header Group -->
<div class="control-group">
<div class="control-group-header">
<svg class="control-group-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
</svg>
<span class="control-group-title">Header</span>
</div>
<div class="control-section">
<label class="control-label">Layout</label>
<div class="option-group" id="header-options">
<button class="option-button active" data-header="standard">Standard</button>
<button class="option-button" data-header="centered">Centered</button>
<button class="option-button" data-header="minimal">Minimal</button>
</div>
</div>
<div class="control-section">
<label class="control-label">Features</label>
<div class="toggle-list">
<label class="toggle-label">
<input type="checkbox" id="announcement-bar-toggle" checked>
<span class="toggle-switch"></span>
<span class="toggle-text">Announcement bar</span>
</label>
<label class="toggle-label">
<input type="checkbox" id="sticky-header-toggle">
<span class="toggle-switch"></span>
<span class="toggle-text">Sticky header</span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- Current combination -->
<div class="combo-display">
<div class="combo-label">Current combination</div>
<div class="combo-value" id="combo-value">Neutral · Clean · Soft · Balanced · 4-up · Standard</div>
<div class="combo-count">One of 100,000+ possible combinations</div>
</div>
</div>
<!-- Preview Area -->
<div class="preview-area">
<div class="preview-container">
<div class="page-toggle">
<button class="page-toggle-btn active" data-page="home">Home</button>
<button class="page-toggle-btn" data-page="collection">Collection</button>
<button class="page-toggle-btn" data-page="pdp">Product</button>
<button class="page-toggle-btn" data-page="cart">Cart</button>
<button class="page-toggle-btn" data-page="about">About</button>
<button class="page-toggle-btn" data-page="contact">Contact</button>
<button class="page-toggle-btn" data-page="error">Error</button>
</div>
<div class="browser-chrome">
<div class="browser-traffic-lights">
<span class="traffic-light red"></span>
<span class="traffic-light yellow"></span>
<span class="traffic-light green"></span>
</div>
<div class="browser-nav">
<button class="browser-nav-btn" aria-label="Back">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
</button>
<button class="browser-nav-btn" aria-label="Forward">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
</button>
</div>
<div class="browser-url-bar">
<svg class="browser-url-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
<div class="browser-favicon" id="browser-favicon">
<span class="favicon-letter" id="favicon-letter">B</span>
</div>
<span class="browser-url-text"><span class="domain" id="browser-domain">botanicalstudio</span>.simpleshop.uk</span>
</div>
<div class="browser-actions">
<button class="browser-action-btn" aria-label="Share">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/>
<polyline points="16 6 12 2 8 6"/>
<line x1="12" y1="2" x2="12" y2="15"/>
</svg>
</button>
</div>
</div>
<div class="preview-frame" id="preview-frame"
data-mood="neutral"
data-typography="clean"
data-shape="soft"
data-density="balanced">
<!-- Announcement Bar -->
<div class="announcement-bar" id="announcement-bar">
<p>Free UK shipping on orders over £50 ✨</p>
</div>
<!-- Shop Header -->
<header class="shop-header" id="shop-header" data-header="standard" data-logo-mode="text-only">
<div class="shop-logo" id="shop-logo">
<div class="shop-logo-image" id="shop-logo-image">
<img id="shop-logo-img" src="" alt="">
</div>
<span class="shop-logo-text" id="shop-logo-text">Botanical Studio</span>
</div>
<nav class="shop-nav">
<a href="#" data-nav="home">Home</a>
<a href="#" data-nav="collection">Shop All</a>
<a href="#" data-nav="about">About</a>
<a href="#" data-nav="contact">Contact</a>
</nav>
<div class="shop-cart">
<button class="header-icon-btn search-btn" id="search-btn" aria-label="Search">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="M21 21l-4.35-4.35"></path>
</svg>
</button>
<button class="header-icon-btn cart-btn" id="cart-btn" aria-label="Cart">
<svg class="icon cart-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"></path>
<line x1="3" y1="6" x2="21" y2="6"></line>
<path d="M16 10a4 4 0 01-8 0"></path>
</svg>
<span class="cart-count">2</span>
</button>
</div>
</header>
<!-- Home View -->
<div class="page-view home-view active" id="home-view">
<!-- Hero -->
<section class="shop-hero">
<h1 id="hero-title">Nature-inspired art prints</h1>
<p>Original botanical illustrations, printed on premium archival paper. Each piece brings a little bit of the outside, inside.</p>
<button class="btn btn-primary" id="shop-collection-btn" data-nav="collection">Shop the collection</button>
</section>
<!-- Categories -->
<section class="home-categories">
<nav class="category-links" aria-label="Product categories">
<a href="#" class="category-link" data-nav="collection">
<div class="category-image cat-img-1"></div>
<span class="category-name">Botanicals</span>
</a>
<a href="#" class="category-link" data-nav="collection">
<div class="category-image cat-img-2"></div>
<span class="category-name">Florals</span>
</a>
<a href="#" class="category-link" data-nav="collection">
<div class="category-image cat-img-3"></div>
<span class="category-name">Landscapes</span>
</a>
</nav>
</section>
<!-- Featured Products -->
<section class="product-section">
<h2 class="section-title">Featured prints</h2>
<div class="product-grid" id="product-grid" data-grid="4">
<article class="product-card">
<div class="product-image">
<span class="product-badge badge-new">New</span>
<div class="product-image-primary img-1"></div>
<div class="product-image-hover img-1-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Autumn Fern</h3>
<p class="product-price">£24.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<span class="product-badge badge-sale">Sale</span>
<div class="product-image-primary img-2"></div>
<div class="product-image-hover img-2-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Wild Roses</h3>
<p class="product-price"><span class="price-was">£35.00</span> £28.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-3"></div>
<div class="product-image-hover img-3-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Morning Dew</h3>
<p class="product-price">£24.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-5"></div>
<div class="product-image-hover img-5-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Spring Bloom</h3>
<p class="product-price">£28.00</p>
</div>
</article>
</div>
<div class="section-cta">
<button class="btn btn-secondary" data-nav="collection">View all products</button>
</div>
</section>
<!-- About Snippet -->
<section class="home-about">
<div class="home-about-image"></div>
<div class="home-about-content">
<h2>Made with care in Yorkshire</h2>
<p>Every illustration starts as a pencil sketch, inspired by the plants and flowers found in British woodlands, meadows, and gardens. Printed on museum-quality archival paper using pigment-based inks that will last a lifetime.</p>
<a href="#" class="text-link" data-nav="about">Learn more about the studio →</a>
</div>
</section>
<!-- Footer -->
<footer class="shop-footer" id="home-footer">
<div class="footer-content">
<div class="footer-newsletter">
<h3 class="footer-heading">Join the studio</h3>
<p class="footer-text">Get 10% off your first order and be the first to know about new prints.</p>
<form class="newsletter-form">
<input type="email" class="newsletter-input" placeholder="your@email.com">
<button type="submit" class="btn btn-primary newsletter-btn">Subscribe</button>
</form>
</div>
<div class="footer-links">
<div class="footer-column">
<h4 class="footer-column-title">Shop</h4>
<a href="#" data-nav="collection">All products</a>
<a href="#" data-nav="collection">New arrivals</a>
<a href="#" data-nav="collection">Best sellers</a>
</div>
<div class="footer-column">
<h4 class="footer-column-title">Help</h4>
<a href="#" data-nav="contact">Shipping</a>
<a href="#" data-nav="contact">Returns</a>
<a href="#" data-nav="contact">Contact</a>
</div>
</div>
</div>
<div class="footer-bottom">
<p id="footer-text">© 2025 Botanical Studio</p>
<div class="footer-social">
<a href="#" class="social-link" aria-label="Instagram">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
</svg>
</a>
<a href="#" class="social-link" aria-label="Pinterest">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
<line x1="12" y1="16" x2="9" y2="21"></line>
</svg>
</a>
</div>
</div>
</footer>
</div>
<!-- Collection View -->
<div class="page-view collection-view" id="collection-view">
<div class="collection-header">
<h1 class="collection-title">Shop All</h1>
<p class="collection-count">12 products</p>
</div>
<section class="product-section">
<div class="collection-toolbar">
<div class="collection-filter" role="group" aria-label="Filter by category">
<button class="filter-btn active">All</button>
<button class="filter-btn">Botanicals</button>
<button class="filter-btn">Florals</button>
<button class="filter-btn">Landscapes</button>
</div>
<div class="collection-sort">
<label for="sort-select" class="visually-hidden">Sort products</label>
<select id="sort-select" class="sort-select">
<option>Featured</option>
<option>Price: Low to high</option>
<option>Price: High to low</option>
<option>Newest</option>
</select>
</div>
</div>
<div class="product-grid" data-grid="4">
<article class="product-card">
<div class="product-image">
<span class="product-badge badge-new">New</span>
<div class="product-image-primary img-1"></div>
<div class="product-image-hover img-1-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Autumn Fern</h3>
<p class="product-price">£24.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<span class="product-badge badge-sale">Sale</span>
<div class="product-image-primary img-2"></div>
<div class="product-image-hover img-2-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Wild Roses</h3>
<p class="product-price"><span class="price-was">£35.00</span> £28.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-3"></div>
<div class="product-image-hover img-3-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Morning Dew</h3>
<p class="product-price">£24.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<span class="product-badge badge-sold">Sold out</span>
<div class="product-image-primary img-4"></div>
<div class="product-image-hover img-4-alt"></div>
</div>
<div class="product-info">
<h3 class="product-title">Oak Leaves</h3>
<p class="product-price">£32.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-5"></div>
<div class="product-image-hover img-5-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Spring Bloom</h3>
<p class="product-price">£28.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-6"></div>
<div class="product-image-hover img-6-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Lavender Fields</h3>
<p class="product-price">£24.00</p>
</div>
</article>
</div>
</section>
<footer class="shop-footer" id="collection-footer">
<div class="footer-bottom">
<p id="footer-text-collection">© 2025 Botanical Studio</p>
</div>
</footer>
</div>
<!-- PDP View -->
<div class="page-view pdp-view" id="pdp-view">
<div class="pdp-container">
<nav class="pdp-breadcrumb">
<a href="#" data-nav="home">Home</a>
<span class="breadcrumb-sep"></span>
<a href="#" data-nav="collection">Shop All</a>
<span class="breadcrumb-sep"></span>
<span>Autumn Fern</span>
</nav>
<div class="pdp-layout">
<div class="pdp-gallery">
<div class="pdp-main-image" id="pdp-main-image" style="background-image: url('https://picsum.photos/seed/fern/600/600')">
<button class="zoom-btn" id="zoom-btn" aria-label="View larger image">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="M21 21l-4.35-4.35"></path>
<line x1="11" y1="8" x2="11" y2="14"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
</button>
</div>
<div class="pdp-thumbnails">
<div class="pdp-thumb active"
data-image="https://picsum.photos/seed/fern/600/600"
data-alt="Autumn Fern botanical illustration - front view"
data-description="Delicate hand-drawn fern fronds in graphite and watercolour, showing the full composition"></div>
<div class="pdp-thumb"
data-image="https://picsum.photos/seed/fern-alt/600/600"
data-alt="Autumn Fern botanical illustration - detail view"
data-description="Close-up detail showing the intricate vein patterns and subtle colour gradations"></div>
<div class="pdp-thumb"
data-image="https://picsum.photos/seed/fern-detail/600/600"
data-alt="Autumn Fern botanical illustration - framed example"
data-description="Example of the print displayed in an oak frame, showing scale and presentation"></div>
</div>
</div>
<div class="pdp-details">
<h1 class="pdp-title">Autumn Fern</h1>
<p class="pdp-price">£24.00</p>
<div class="pdp-description">
<p>A delicate botanical illustration capturing the intricate fronds of an autumn fern. Each piece is printed on museum-quality 300gsm cotton rag paper using archival inks.</p>
</div>
<div class="pdp-options">
<div class="pdp-option-group">
<label class="pdp-option-label">Size</label>
<div class="pdp-option-buttons">
<button class="pdp-option-btn active">A5</button>
<button class="pdp-option-btn">A4</button>
<button class="pdp-option-btn">A3</button>
</div>
</div>
<div class="pdp-option-group">
<label class="pdp-option-label">Frame</label>
<div class="pdp-option-buttons">
<button class="pdp-option-btn active">Unframed</button>
<button class="pdp-option-btn">Oak</button>
<button class="pdp-option-btn">Black</button>
<button class="pdp-option-btn">White</button>
</div>
</div>
</div>
<div class="pdp-details-sections">
<details class="pdp-details">
<summary class="pdp-details-summary">
<span>Size guide</span>
<svg class="pdp-details-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</summary>
<div class="pdp-details-content">
<table class="size-table">
<thead>
<tr>
<th>Size</th>
<th>Dimensions</th>
<th>Best for</th>
</tr>
</thead>
<tbody>
<tr>
<td>A5</td>
<td>14.8 × 21 cm</td>
<td>Desks, shelves</td>
</tr>
<tr>
<td>A4</td>
<td>21 × 29.7 cm</td>
<td>Small wall spaces</td>
</tr>
<tr>
<td>A3</td>
<td>29.7 × 42 cm</td>
<td>Statement pieces</td>
</tr>
</tbody>
</table>
</div>
</details>
<details class="pdp-details">
<summary class="pdp-details-summary">
<span>Materials & quality</span>
<svg class="pdp-details-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</summary>
<div class="pdp-details-content">
<ul class="details-list">
<li>Printed on 300gsm museum-quality cotton rag paper</li>
<li>Archival pigment inks rated 100+ years</li>
<li>FSC-certified sustainable paper</li>
<li>Each print is hand-checked before shipping</li>
</ul>
</div>
</details>
<details class="pdp-details">
<summary class="pdp-details-summary">
<span>Shipping & returns</span>
<svg class="pdp-details-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</summary>
<div class="pdp-details-content">
<ul class="details-list">
<li>Free UK shipping on orders over £50</li>
<li>Dispatched within 2-3 business days</li>
<li>Plastic-free packaging</li>
<li>30-day returns for unused items</li>
</ul>
</div>
</details>
</div>
<button class="btn btn-primary pdp-add-btn">Add to basket</button>
<div class="pdp-meta">
<div class="pdp-meta-item">
<svg class="pdp-meta-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 22s-8-4.5-8-11.8A8 8 0 0 1 12 2a8 8 0 0 1 8 8.2c0 7.3-8 11.8-8 11.8z"/>
<circle cx="12" cy="10" r="3"/>
</svg>
<span>Printed in the UK</span>
</div>
<div class="pdp-meta-item">
<svg class="pdp-meta-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="1" y="3" width="15" height="13"></rect>
<polygon points="16 8 20 8 23 11 23 16 16 16 16 8"></polygon>
<circle cx="5.5" cy="18.5" r="2.5"></circle>
<circle cx="18.5" cy="18.5" r="2.5"></circle>
</svg>
<span>Free UK shipping over £50</span>
</div>
</div>
<div class="pdp-trust-badges">
<div class="trust-badge">
<svg class="trust-badge-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
<polyline points="9 12 11 14 15 10"></polyline>
</svg>
<span>Secure checkout</span>
</div>
<div class="trust-badge">
<svg class="trust-badge-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
<circle cx="12" cy="10" r="3"></circle>
</svg>
<span>UK based</span>
</div>
<div class="trust-badge">
<svg class="trust-badge-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
<span>Quality guaranteed</span>
</div>
</div>
</div>
</div>
<!-- Reviews Section -->
<div class="pdp-reviews">
<div class="reviews-header">
<h2 class="section-title">Customer reviews</h2>
<div class="reviews-summary">
<div class="reviews-stars">
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
</div>
<span class="reviews-count">Based on 24 reviews</span>
</div>
</div>
<div class="reviews-list">
<article class="review">
<div class="review-header">
<div class="review-stars">
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
</div>
<span class="review-date">2 weeks ago</span>
</div>
<h3 class="review-title">Absolutely beautiful</h3>
<p class="review-text">The quality exceeded my expectations. The colours are vibrant and the paper feels premium. It's now pride of place in my living room.</p>
<div class="review-author">
<span class="review-name">Sarah M.</span>
<span class="review-verified">Verified purchase</span>
</div>
</article>
<article class="review">
<div class="review-header">
<div class="review-stars">
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star filled" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
<svg class="star" viewBox="0 0 20 20"><path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" fill="currentColor"/></svg>
</div>
<span class="review-date">1 month ago</span>
</div>
<h3 class="review-title">Great gift</h3>
<p class="review-text">Bought this as a gift and it arrived beautifully packaged. Fast shipping too. Would definitely order again.</p>
<div class="review-author">
<span class="review-name">James T.</span>
<span class="review-verified">Verified purchase</span>
</div>
</article>
</div>
<button class="btn btn-secondary reviews-load-more">Load more reviews</button>
</div>
<!-- Related Products -->
<div class="pdp-related">
<h2 class="section-title">You might also like</h2>
<div class="related-grid">
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-2"></div>
<div class="product-image-hover img-2-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Wild Roses</h3>
<p class="product-price">£28.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-3"></div>
<div class="product-image-hover img-3-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Morning Dew</h3>
<p class="product-price">£24.00</p>
</div>
</article>
<article class="product-card">
<div class="product-image">
<div class="product-image-primary img-4"></div>
<div class="product-image-hover img-4-alt"></div>
<button class="quick-add-btn">Quick add</button>
</div>
<div class="product-info">
<h3 class="product-title">Oak Leaves</h3>
<p class="product-price">£32.00</p>
</div>
</article>
</div>
</div>
</div>
<!-- Footer -->
<footer class="shop-footer" id="pdp-footer">
<div class="footer-content">
<div class="footer-newsletter">
<h3 class="footer-heading">Join the studio</h3>
<p class="footer-text">Get 10% off your first order and be the first to know about new prints.</p>
<form class="newsletter-form">
<input type="email" class="newsletter-input" placeholder="your@email.com">
<button type="submit" class="btn btn-primary newsletter-btn">Subscribe</button>
</form>
</div>
<div class="footer-links">
<div class="footer-column">
<h4 class="footer-column-title">Shop</h4>
<a href="#">All prints</a>
<a href="#">New arrivals</a>
<a href="#">Best sellers</a>
</div>
<div class="footer-column">
<h4 class="footer-column-title">Help</h4>
<a href="#">Shipping</a>
<a href="#">Returns</a>
<a href="#">Contact</a>
</div>
</div>
</div>
<div class="footer-bottom">
<p id="footer-text-pdp">© 2025 Botanical Studio</p>
<div class="footer-social">
<a href="#" class="social-link" aria-label="Instagram">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
</svg>
</a>
<a href="#" class="social-link" aria-label="Pinterest">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
<line x1="12" y1="16" x2="9" y2="21"></line>
</svg>
</a>
</div>
</div>
</footer>
</div>
<!-- Cart Page -->
<div class="page-view cart-view" id="cart-view">
<div class="cart-container">
<div class="cart-header-row">
<h1 class="cart-title">Your basket</h1>
<button class="cart-state-toggle" id="cart-state-toggle">Preview empty state</button>
</div>
<!-- Full Cart State -->
<div class="cart-state cart-state-full" id="cart-full">
<div class="cart-layout">
<div class="cart-items">
<div class="cart-item">
<div class="cart-item-image img-1"></div>
<div class="cart-item-details">
<h3 class="cart-item-title">Autumn Fern</h3>
<p class="cart-item-variant">A4 / Unframed</p>
<p class="cart-item-price">£24.00</p>
</div>
<div class="cart-item-quantity">
<button class="qty-btn"></button>
<span class="qty-value">1</span>
<button class="qty-btn">+</button>
</div>
<button class="cart-item-remove" aria-label="Remove">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="cart-item">
<div class="cart-item-image img-2"></div>
<div class="cart-item-details">
<h3 class="cart-item-title">Wild Roses</h3>
<p class="cart-item-variant">A3 / Oak frame</p>
<p class="cart-item-price">£48.00</p>
</div>
<div class="cart-item-quantity">
<button class="qty-btn"></button>
<span class="qty-value">1</span>
<button class="qty-btn">+</button>
</div>
<button class="cart-item-remove" aria-label="Remove">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<div class="cart-summary">
<div class="cart-summary-row">
<span>Subtotal</span>
<span>£72.00</span>
</div>
<div class="cart-summary-row">
<span>Shipping</span>
<span>Calculated at checkout</span>
</div>
<div class="cart-summary-row cart-total">
<span>Total</span>
<span>£72.00</span>
</div>
<button class="btn btn-primary cart-checkout-btn">Checkout</button>
<p class="cart-secure-note">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
Secure checkout powered by Stripe
</p>
</div>
</div>
</div>
<!-- Empty Cart State -->
<div class="cart-state cart-state-empty" id="cart-empty" hidden>
<div class="empty-state">
<div class="empty-state-illustration">
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Soft background -->
<circle cx="60" cy="60" r="48" fill="currentColor" opacity="0.04"/>
<!-- Simple elegant shopping bag -->
<rect x="32" y="44" width="56" height="52" rx="4"
stroke="currentColor" stroke-width="2" fill="none" opacity="0.6"/>
<!-- Bag handles -->
<path d="M44 44 C44 44 44 32 60 32 C76 32 76 44 76 44"
stroke="currentColor" stroke-width="2" fill="none"
stroke-linecap="round" opacity="0.6"/>
<!-- Simple fold line -->
<line x1="32" y1="52" x2="88" y2="52"
stroke="currentColor" stroke-width="1" opacity="0.2"/>
</svg>
</div>
<h2 class="empty-state-title">Your basket is empty</h2>
<p class="empty-state-message">Looks like you haven't added anything yet. Start exploring our collection to find something you'll love.</p>
<button class="btn btn-primary" data-nav="collection">Continue shopping</button>
</div>
</div>
</div>
<footer class="shop-footer" id="cart-footer">
<div class="footer-bottom">
<p id="footer-text-cart">© 2025 Botanical Studio</p>
</div>
</footer>
</div>
<!-- About Page -->
<div class="page-view about-view" id="about-view">
<div class="content-page">
<div class="content-hero">
<h1 class="content-title">About the studio</h1>
<p class="content-subtitle">Nature-inspired art, made with care</p>
</div>
<div class="content-body">
<div class="content-image about-image"></div>
<div class="content-text">
<p class="lead-text">Botanical Studio was born from a love of the natural world and a desire to bring its beauty indoors.</p>
<p>Every illustration starts as a pencil sketch, inspired by the plants and flowers found in British woodlands, meadows, and gardens. These sketches are then refined and printed on museum-quality archival paper using pigment-based inks that will last a lifetime.</p>
<p>Based in the Yorkshire countryside, I work from a small garden studio surrounded by the very nature that inspires each piece. Every print is checked by hand before being carefully packaged and sent on its way.</p>
<h2>Sustainability</h2>
<p>I believe beautiful art shouldn't cost the earth. All prints are produced on FSC-certified paper, shipped in plastic-free packaging, and printed locally to reduce transport emissions.</p>
<h2>The process</h2>
<p>Each botanical illustration takes between 20-40 hours to complete, from initial field sketches through to the final digital refinement. I work primarily in graphite and watercolour, which are then scanned and carefully colour-corrected to ensure the prints match the original artwork.</p>
</div>
</div>
</div>
<footer class="shop-footer" id="about-footer">
<div class="footer-bottom">
<p id="footer-text-about">© 2025 Botanical Studio</p>
</div>
</footer>
</div>
<!-- Contact Page -->
<div class="page-view contact-view" id="contact-view">
<div class="content-page">
<div class="content-hero">
<h1 class="content-title">Get in touch</h1>
<p class="content-subtitle">I'd love to hear from you</p>
</div>
<div class="contact-layout">
<div class="contact-info">
<div class="contact-block">
<h3>General enquiries</h3>
<p>For questions about prints, shipping, or custom orders.</p>
<a href="mailto:hello@botanicalstudio.com" class="contact-link">hello@botanicalstudio.com</a>
</div>
<div class="contact-block">
<h3>Response time</h3>
<p>I typically respond within 1-2 business days. For urgent order queries, please include your order number.</p>
</div>
<div class="contact-block">
<h3>Follow along</h3>
<p>See works in progress and behind-the-scenes on Instagram.</p>
<div class="contact-social">
<a href="#" class="social-link" aria-label="Instagram">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
</svg>
</a>
<a href="#" class="social-link" aria-label="Pinterest">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
<line x1="12" y1="16" x2="9" y2="21"></line>
</svg>
</a>
</div>
</div>
</div>
<form class="contact-form">
<div class="form-group">
<label class="form-label" for="contact-name">Name</label>
<input type="text" id="contact-name" class="form-input" placeholder="Your name">
</div>
<div class="form-group">
<label class="form-label" for="contact-email">Email</label>
<input type="email" id="contact-email" class="form-input" placeholder="your@email.com">
</div>
<div class="form-group">
<label class="form-label" for="contact-subject">Subject</label>
<select id="contact-subject" class="form-input form-select">
<option>General enquiry</option>
<option>Order question</option>
<option>Custom order</option>
<option>Wholesale / Trade</option>
<option>Press / Collaboration</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="contact-message">Message</label>
<textarea id="contact-message" class="form-input form-textarea" rows="5" placeholder="How can I help?"></textarea>
</div>
<button type="submit" class="btn btn-primary form-submit">Send message</button>
</form>
</div>
</div>
<footer class="shop-footer" id="contact-footer">
<div class="footer-bottom">
<p id="footer-text-contact">© 2025 Botanical Studio</p>
</div>
</footer>
</div>
<!-- Error Page -->
<div class="page-view error-view" id="error-view">
<div class="error-container">
<div class="error-content">
<div class="error-illustration">
<svg viewBox="0 0 200 160" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Soft background -->
<circle cx="100" cy="75" r="55" fill="currentColor" opacity="0.04"/>
<!-- Magnifying glass - universal "not found" symbol -->
<circle cx="90" cy="70" r="32"
stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.5"/>
<line x1="113" y1="93" x2="140" y2="120"
stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
<!-- Question mark inside magnifying glass -->
<path d="M82 60 C82 52 88 48 95 48 C102 48 108 52 108 60 C108 66 102 68 95 72"
stroke="currentColor" stroke-width="2" fill="none"
stroke-linecap="round" opacity="0.4"/>
<circle cx="95" cy="82" r="2.5" fill="currentColor" opacity="0.4"/>
<!-- Small decorative dots suggesting scattered/lost -->
<circle cx="45" cy="45" r="3" fill="currentColor" opacity="0.15"/>
<circle cx="155" cy="55" r="2" fill="currentColor" opacity="0.1"/>
<circle cx="160" cy="100" r="2.5" fill="currentColor" opacity="0.12"/>
<circle cx="40" cy="110" r="2" fill="currentColor" opacity="0.1"/>
</svg>
</div>
<h1 class="error-title">Something went wrong</h1>
<p class="error-message">We couldn't find what you were looking for. The page may have moved, or perhaps it never existed in the first place.</p>
<div class="error-actions">
<button class="btn btn-primary" data-nav="home">Go to homepage</button>
<button class="btn btn-secondary" data-nav="collection">Browse products</button>
</div>
</div>
</div>
<footer class="shop-footer" id="error-footer">
<div class="footer-bottom">
<p id="footer-text-error">© 2025 Botanical Studio</p>
</div>
</footer>
</div>
<!-- Cart Drawer -->
<div class="cart-drawer" id="cart-drawer">
<div class="cart-drawer-header">
<h2>Your basket</h2>
<button class="cart-drawer-close" id="cart-drawer-close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="cart-drawer-items">
<div class="cart-drawer-item">
<div class="cart-drawer-item-image img-1"></div>
<div class="cart-drawer-item-details">
<h3>Autumn Fern</h3>
<p>A4 / Unframed</p>
<p class="cart-drawer-item-price">£24.00</p>
</div>
</div>
<div class="cart-drawer-item">
<div class="cart-drawer-item-image img-2"></div>
<div class="cart-drawer-item-details">
<h3>Wild Roses</h3>
<p>A3 / Oak frame</p>
<p class="cart-drawer-item-price">£48.00</p>
</div>
</div>
</div>
<div class="cart-drawer-footer">
<div class="cart-drawer-total">
<span>Subtotal</span>
<span>£72.00</span>
</div>
<button class="btn btn-primary cart-drawer-checkout">Checkout</button>
<a href="#" class="cart-drawer-link" id="view-cart-link">View basket</a>
</div>
</div>
<div class="cart-drawer-overlay" id="cart-drawer-overlay"></div>
<!-- Search Modal -->
<div class="search-modal" id="search-modal">
<div class="search-modal-content">
<div class="search-input-wrapper">
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="M21 21l-4.35-4.35"></path>
</svg>
<input type="text" class="search-input" placeholder="Search products..." autofocus>
<button class="search-close" id="search-close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="search-results">
<p class="search-hint">Try searching for "fern", "roses", or "botanical"</p>
</div>
</div>
</div>
<!-- Image Lightbox -->
<dialog class="lightbox" id="lightbox" aria-label="Product image gallery">
<div class="lightbox-content">
<button class="lightbox-close" id="lightbox-close" aria-label="Close gallery">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<button class="lightbox-nav lightbox-prev" id="lightbox-prev" aria-label="Previous image">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="15 18 9 12 15 6"></polyline>
</svg>
</button>
<figure class="lightbox-figure">
<div class="lightbox-image-container">
<img class="lightbox-image" id="lightbox-image" src="" alt="">
</div>
<figcaption class="lightbox-caption" id="lightbox-caption"></figcaption>
</figure>
<button class="lightbox-nav lightbox-next" id="lightbox-next" aria-label="Next image">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</button>
<div class="lightbox-counter" id="lightbox-counter" aria-live="polite">1 / 3</div>
</div>
</dialog>
</div>
</div>
</div>
<script>
// Presets configuration
const presets = {
gallery: {
mood: 'warm',
typography: 'editorial',
shape: 'soft',
density: 'spacious',
grid: '3',
header: 'centered',
accent: '#e85d04'
},
studio: {
mood: 'neutral',
typography: 'clean',
shape: 'soft',
density: 'balanced',
grid: '4',
header: 'standard',
accent: '#3b82f6'
},
boutique: {
mood: 'warm',
typography: 'classic',
shape: 'soft',
density: 'balanced',
grid: '3',
header: 'centered',
accent: '#b45309'
},
bold: {
mood: 'neutral',
typography: 'modern',
shape: 'sharp',
density: 'compact',
grid: '4',
header: 'standard',
accent: '#dc2626'
},
playful: {
mood: 'neutral',
typography: 'friendly',
shape: 'pill',
density: 'balanced',
grid: '4',
header: 'standard',
accent: '#8b5cf6'
},
minimal: {
mood: 'cool',
typography: 'clean',
shape: 'sharp',
density: 'spacious',
grid: '2',
header: 'minimal',
accent: '#171717'
},
night: {
mood: 'dark',
typography: 'modern',
shape: 'soft',
density: 'balanced',
grid: '4',
header: 'standard',
accent: '#f97316'
},
classic: {
mood: 'warm',
typography: 'classic',
shape: 'soft',
density: 'spacious',
grid: '3',
header: 'standard',
accent: '#166534'
},
impulse: {
mood: 'neutral',
typography: 'impulse',
shape: 'sharp',
density: 'spacious',
grid: '3',
header: 'centered',
accent: '#000000',
// Additional Impulse-specific settings
fontSize: 'medium',
headingWeight: 'regular',
layoutWidth: 'full',
buttonStyle: 'filled',
cardShadow: 'none',
productText: 'center'
}
};
// State
let currentSettings = {
mood: 'neutral',
typography: 'clean',
shape: 'soft',
density: 'balanced',
grid: '4',
header: 'standard',
accent: '#f97316'
};
let shopName = 'Botanical Studio';
let logoMode = 'text-only';
let logoUrl = null;
let logoSvgContent = null; // Store original SVG content
let logoIsSvg = false;
let headerImageUrl = null;
let logoSize = 36;
let headerPositionX = 50; // percentage 0-100
let headerPositionY = 50; // percentage 0-100
let headerZoom = 100;
let recolorLogo = false;
let logoColor = '#171717';
// Feature toggles
let showAnnouncementBar = true;
let stickyHeader = false;
let hoverImage = true;
let quickAdd = true;
let aspectRatio = 'square';
// DOM elements
const previewFrame = document.getElementById('preview-frame');
const shopHeader = document.getElementById('shop-header');
const productGrid = document.getElementById('product-grid');
const accentPicker = document.getElementById('accent-picker');
const colorValue = document.getElementById('color-value');
const comboValue = document.getElementById('combo-value');
const shopNameInput = document.getElementById('shop-name');
const logoUploadRow = document.getElementById('logo-upload-row');
const headerUploadRow = document.getElementById('header-upload-row');
const logoUpload = document.getElementById('logo-upload');
const headerUpload = document.getElementById('header-upload');
const logoPreview = document.getElementById('logo-preview');
const logoPreviewImg = document.getElementById('logo-preview-img');
const headerPreview = document.getElementById('header-preview');
const headerPreviewImg = document.getElementById('header-preview-img');
const shopLogoImage = document.getElementById('shop-logo-image');
const shopLogoImg = document.getElementById('shop-logo-img');
const shopLogoText = document.getElementById('shop-logo-text');
const logoSizeControl = document.getElementById('logo-size-control');
const logoSizeSlider = document.getElementById('logo-size-slider');
const logoSizeValue = document.getElementById('logo-size-value');
const logoColorControl = document.getElementById('logo-color-control');
const recolorLogoCheckbox = document.getElementById('recolor-logo-checkbox');
const logoColorPickerRow = document.getElementById('logo-color-picker-row');
const logoColorPicker = document.getElementById('logo-color-picker');
const logoColorValue = document.getElementById('logo-color-value');
const headerImageControls = document.getElementById('header-image-controls');
const headerPositionXRow = document.getElementById('header-position-x-row');
const headerPositionXSlider = document.getElementById('header-position-x-slider');
const headerPositionXValue = document.getElementById('header-position-x-value');
const headerPositionSlider = document.getElementById('header-position-slider');
const headerPositionValue = document.getElementById('header-position-value');
const headerZoomSlider = document.getElementById('header-zoom-slider');
const headerZoomValue = document.getElementById('header-zoom-value');
// Recolor SVG by replacing fill and stroke colors
function recolorSvg(svgContent, newColor) {
if (!svgContent) return svgContent;
// Replace fill attributes (but not fill="none")
let recolored = svgContent.replace(/fill="(?!none)[^"]*"/gi, `fill="${newColor}"`);
// Replace stroke attributes (but not stroke="none")
recolored = recolored.replace(/stroke="(?!none)[^"]*"/gi, `stroke="${newColor}"`);
// Also handle style attributes with fill/stroke
recolored = recolored.replace(/fill:\s*(?!none)[^;}"']+/gi, `fill: ${newColor}`);
recolored = recolored.replace(/stroke:\s*(?!none)[^;}"']+/gi, `stroke: ${newColor}`);
return recolored;
}
// Update the logo image in the preview
function updateLogoImage() {
if (logoIsSvg && logoSvgContent) {
let svgToUse = logoSvgContent;
if (recolorLogo) {
svgToUse = recolorSvg(logoSvgContent, logoColor);
}
logoUrl = 'data:image/svg+xml,' + encodeURIComponent(svgToUse);
// Also update the preview thumbnail
logoPreviewImg.src = logoUrl;
}
}
// Helper: Convert hex to HSL
function hexToHSL(hex) {
let r = parseInt(hex.slice(1, 3), 16) / 255;
let g = parseInt(hex.slice(3, 5), 16) / 255;
let b = parseInt(hex.slice(5, 7), 16) / 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
case g: h = ((b - r) / d + 2) / 6; break;
case b: h = ((r - g) / d + 4) / 6; break;
}
}
return {
h: Math.round(h * 360),
s: Math.round(s * 100),
l: Math.round(l * 100)
};
}
// Update logo/header mode display
function updateLogoDisplay() {
// Update upload row visibility
const needsLogo = logoMode === 'logo-and-text' || logoMode === 'logo-only' || logoMode === 'logo-header-image';
const needsHeader = logoMode === 'header-image' || logoMode === 'logo-header-image';
logoUploadRow.classList.toggle('visible', needsLogo);
headerUploadRow.classList.toggle('visible', needsHeader);
// Show size control only when logo is uploaded and mode uses a logo
const hasLogo = logoUrl || (logoIsSvg && logoSvgContent);
const showSizeControl = needsLogo && hasLogo;
logoSizeControl.classList.toggle('visible', showSizeControl);
// Show color control only for SVG logos
const showColorControl = needsLogo && logoIsSvg && logoSvgContent;
logoColorControl.classList.toggle('visible', showColorControl);
// Show header image controls when header image is uploaded
const showHeaderControls = needsHeader && headerImageUrl;
headerImageControls.classList.toggle('visible', showHeaderControls);
// Only show horizontal position when zoomed in
if (showHeaderControls) {
headerPositionXRow.classList.toggle('visible', headerZoom > 100);
}
// Update logo upload label based on mode
const logoUploadLabel = document.getElementById('logo-upload-label');
if (logoMode === 'logo-header-image') {
logoUploadLabel.textContent = 'Upload logo (use white/light version)';
} else {
logoUploadLabel.textContent = 'Upload logo (SVG or PNG)';
}
// Update preview header
shopHeader.dataset.logoMode = logoMode;
// Apply logo size
shopLogoImage.style.height = logoSize + 'px';
// Update logo visibility and header background
if (logoMode === 'text-only') {
shopLogoImage.classList.remove('visible');
shopLogoText.style.display = 'block';
shopHeader.style.backgroundImage = '';
shopHeader.style.backgroundPosition = '';
shopHeader.style.backgroundSize = '';
} else if (logoMode === 'logo-and-text') {
if (logoUrl) {
shopLogoImage.classList.add('visible');
shopLogoImg.src = logoUrl;
} else {
shopLogoImage.classList.remove('visible');
}
shopLogoText.style.display = 'block';
shopHeader.style.backgroundImage = '';
shopHeader.style.backgroundPosition = '';
shopHeader.style.backgroundSize = '';
} else if (logoMode === 'logo-only') {
if (logoUrl) {
shopLogoImage.classList.add('visible');
shopLogoImg.src = logoUrl;
} else {
shopLogoImage.classList.remove('visible');
}
shopLogoText.style.display = 'none';
shopHeader.style.backgroundImage = '';
shopHeader.style.backgroundPosition = '';
shopHeader.style.backgroundSize = '';
} else if (logoMode === 'header-image') {
shopLogoImage.classList.remove('visible');
shopLogoText.style.display = 'block';
if (headerImageUrl) {
shopHeader.style.backgroundImage = `url(${headerImageUrl})`;
shopHeader.style.backgroundPosition = `${headerPositionX}% ${headerPositionY}%`;
shopHeader.style.backgroundSize = `${headerZoom}% auto`;
} else {
// Default placeholder gradient
shopHeader.style.backgroundImage = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
shopHeader.style.backgroundPosition = 'center center';
shopHeader.style.backgroundSize = 'cover';
}
} else if (logoMode === 'logo-header-image') {
if (logoUrl) {
shopLogoImage.classList.add('visible');
shopLogoImg.src = logoUrl;
} else {
shopLogoImage.classList.remove('visible');
}
shopLogoText.style.display = 'none';
if (headerImageUrl) {
shopHeader.style.backgroundImage = `url(${headerImageUrl})`;
shopHeader.style.backgroundPosition = `${headerPositionX}% ${headerPositionY}%`;
shopHeader.style.backgroundSize = `${headerZoom}% auto`;
} else {
// Default placeholder gradient
shopHeader.style.backgroundImage = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
shopHeader.style.backgroundPosition = 'center center';
shopHeader.style.backgroundSize = 'cover';
}
}
}
// Apply settings to preview
function applySettings() {
// Apply data attributes
previewFrame.dataset.mood = currentSettings.mood;
previewFrame.dataset.typography = currentSettings.typography;
previewFrame.dataset.shape = currentSettings.shape;
previewFrame.dataset.density = currentSettings.density;
shopHeader.dataset.header = currentSettings.header;
productGrid.dataset.grid = currentSettings.grid;
// Apply Impulse-specific settings if present
if (currentSettings.fontSize) {
previewFrame.dataset.fontSize = currentSettings.fontSize;
document.querySelectorAll('#font-size-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.fontSize === currentSettings.fontSize);
});
}
if (currentSettings.headingWeight) {
previewFrame.dataset.headingWeight = currentSettings.headingWeight;
document.querySelectorAll('#heading-weight-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.headingWeight === currentSettings.headingWeight);
});
}
if (currentSettings.layoutWidth) {
previewFrame.dataset.layoutWidth = currentSettings.layoutWidth;
document.querySelectorAll('#layout-width-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.layoutWidth === currentSettings.layoutWidth);
});
}
if (currentSettings.buttonStyle) {
previewFrame.dataset.buttonStyle = currentSettings.buttonStyle;
document.querySelectorAll('#button-style-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.buttonStyle === currentSettings.buttonStyle);
});
}
if (currentSettings.cardShadow) {
previewFrame.dataset.cardShadow = currentSettings.cardShadow;
document.querySelectorAll('#card-shadow-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.cardShadow === currentSettings.cardShadow);
});
}
if (currentSettings.productText) {
previewFrame.dataset.productText = currentSettings.productText;
document.querySelectorAll('#product-text-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.productText === currentSettings.productText);
});
}
// Apply accent color
const hsl = hexToHSL(currentSettings.accent);
previewFrame.style.setProperty('--t-accent-h', hsl.h);
previewFrame.style.setProperty('--t-accent-s', hsl.s + '%');
previewFrame.style.setProperty('--t-accent-l', hsl.l + '%');
// Update color picker and display
accentPicker.value = currentSettings.accent;
colorValue.textContent = currentSettings.accent;
// Update shop name in preview
shopLogoText.textContent = shopName;
const footerTexts = ['footer-text', 'footer-text-collection', 'footer-text-pdp', 'footer-text-cart', 'footer-text-about', 'footer-text-contact', 'footer-text-error'];
footerTexts.forEach(id => {
const el = document.getElementById(id);
if (el) el.textContent = `© 2025 ${shopName}`;
});
// Update browser tab
document.getElementById('favicon-letter').textContent = shopName.charAt(0).toUpperCase();
document.getElementById('browser-domain').textContent = shopName.toLowerCase().replace(/\s+/g, '');
// Update logo display
updateLogoDisplay();
// Update combo display
const labels = {
mood: { warm: 'Warm', neutral: 'Neutral', cool: 'Cool', dark: 'Dark' },
typography: { clean: 'Clean', editorial: 'Editorial', modern: 'Modern', classic: 'Classic', friendly: 'Friendly', minimal: 'Minimal', impulse: 'Impulse' },
shape: { sharp: 'Sharp', soft: 'Soft', round: 'Round', pill: 'Pill' },
density: { spacious: 'Spacious', balanced: 'Balanced', compact: 'Compact' },
header: { standard: 'Standard', centered: 'Centered', minimal: 'Minimal' }
};
comboValue.textContent = [
labels.mood[currentSettings.mood],
labels.typography[currentSettings.typography],
labels.shape[currentSettings.shape],
labels.density[currentSettings.density],
currentSettings.grid + '-up',
labels.header[currentSettings.header]
].join(' · ');
updateActiveStates();
}
// Update active states on buttons
function updateActiveStates() {
document.querySelectorAll('#mood-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.mood === currentSettings.mood);
});
document.querySelectorAll('#typography-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.typography === currentSettings.typography);
});
document.querySelectorAll('#shape-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.shape === currentSettings.shape);
});
document.querySelectorAll('#density-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.density === currentSettings.density);
});
document.querySelectorAll('#grid-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.grid === currentSettings.grid);
});
document.querySelectorAll('#header-options .option-button').forEach(btn => {
btn.classList.toggle('active', btn.dataset.header === currentSettings.header);
});
}
// Preset buttons
document.querySelectorAll('.preset-button').forEach(btn => {
btn.addEventListener('click', () => {
const presetName = btn.dataset.preset;
const preset = presets[presetName];
currentSettings = { ...preset };
document.querySelectorAll('.preset-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
applySettings();
});
});
// Individual option buttons
function setupOptionGroup(groupId, settingKey) {
document.querySelectorAll(`#${groupId} .option-button`).forEach(btn => {
btn.addEventListener('click', () => {
currentSettings[settingKey] = btn.dataset[settingKey];
document.querySelectorAll('.preset-button').forEach(b => b.classList.remove('active'));
applySettings();
});
});
}
setupOptionGroup('mood-options', 'mood');
setupOptionGroup('typography-options', 'typography');
setupOptionGroup('shape-options', 'shape');
setupOptionGroup('density-options', 'density');
setupOptionGroup('grid-options', 'grid');
setupOptionGroup('header-options', 'header');
// Accent color picker
accentPicker.addEventListener('input', (e) => {
currentSettings.accent = e.target.value;
document.querySelectorAll('.preset-button').forEach(b => b.classList.remove('active'));
applySettings();
});
// Secondary accent (hover) color picker
const secondaryAccentPicker = document.getElementById('secondary-accent-picker');
const secondaryColorValue = document.getElementById('secondary-color-value');
secondaryAccentPicker.addEventListener('input', (e) => {
previewFrame.style.setProperty('--t-secondary-accent', e.target.value);
secondaryColorValue.textContent = e.target.value;
});
// Sale color picker
const saleColorPicker = document.getElementById('sale-color-picker');
const saleColorValue = document.getElementById('sale-color-value');
saleColorPicker.addEventListener('input', (e) => {
previewFrame.style.setProperty('--t-sale-color', e.target.value);
saleColorValue.textContent = e.target.value;
});
// Font size options
document.querySelectorAll('#font-size-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#font-size-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.fontSize = btn.dataset.fontSize;
});
});
// Heading weight options
document.querySelectorAll('#heading-weight-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#heading-weight-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.headingWeight = btn.dataset.headingWeight;
});
});
// Layout width options
document.querySelectorAll('#layout-width-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#layout-width-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.layoutWidth = btn.dataset.layoutWidth;
});
});
// Button style options
document.querySelectorAll('#button-style-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#button-style-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.buttonStyle = btn.dataset.buttonStyle;
});
});
// Card shadow options
document.querySelectorAll('#card-shadow-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#card-shadow-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.cardShadow = btn.dataset.cardShadow;
});
});
// Product text alignment options
document.querySelectorAll('#product-text-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#product-text-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.productText = btn.dataset.productText;
});
});
// Gallery position options
document.querySelectorAll('#gallery-position-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#gallery-position-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
previewFrame.dataset.galleryPosition = btn.dataset.galleryPosition;
});
});
// Show prices toggle
document.getElementById('show-prices-toggle').addEventListener('change', (e) => {
previewFrame.dataset.showPrices = e.target.checked;
});
// PDP toggles
document.getElementById('pdp-trust-toggle').addEventListener('change', (e) => {
previewFrame.dataset.pdpTrust = e.target.checked;
});
document.getElementById('pdp-reviews-toggle').addEventListener('change', (e) => {
previewFrame.dataset.pdpReviews = e.target.checked;
});
document.getElementById('pdp-related-toggle').addEventListener('change', (e) => {
previewFrame.dataset.pdpRelated = e.target.checked;
});
// Shop name input
shopNameInput.addEventListener('input', (e) => {
shopName = e.target.value || 'My Shop';
applySettings();
});
// Logo mode options
document.querySelectorAll('.logo-mode-option').forEach(option => {
option.addEventListener('click', () => {
const mode = option.dataset.mode;
logoMode = mode;
document.querySelectorAll('.logo-mode-option').forEach(opt => {
opt.classList.toggle('active', opt.dataset.mode === mode);
});
updateLogoDisplay();
});
});
// Logo upload
logoUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const browserFavicon = document.getElementById('browser-favicon');
logoIsSvg = file.type === 'image/svg+xml' || file.name.toLowerCase().endsWith('.svg');
if (logoIsSvg) {
// Read SVG as text so we can manipulate it
const textReader = new FileReader();
textReader.onload = (event) => {
logoSvgContent = event.target.result;
updateLogoImage();
logoPreviewImg.src = 'data:image/svg+xml,' + encodeURIComponent(logoSvgContent);
logoPreview.classList.add('has-image');
updateLogoDisplay();
// Update favicon with logo
browserFavicon.classList.add('has-logo');
let faviconImg = browserFavicon.querySelector('.favicon-logo');
if (!faviconImg) {
faviconImg = document.createElement('img');
faviconImg.className = 'favicon-logo';
browserFavicon.appendChild(faviconImg);
}
faviconImg.src = 'data:image/svg+xml,' + encodeURIComponent(logoSvgContent);
};
textReader.readAsText(file);
} else {
// Read as data URL for non-SVG images
logoSvgContent = null;
const reader = new FileReader();
reader.onload = (event) => {
logoUrl = event.target.result;
logoPreviewImg.src = logoUrl;
logoPreview.classList.add('has-image');
updateLogoDisplay();
// Update favicon with logo
browserFavicon.classList.add('has-logo');
let faviconImg = browserFavicon.querySelector('.favicon-logo');
if (!faviconImg) {
faviconImg = document.createElement('img');
faviconImg.className = 'favicon-logo';
browserFavicon.appendChild(faviconImg);
}
faviconImg.src = logoUrl;
};
reader.readAsDataURL(file);
}
});
// Header upload
headerUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
headerImageUrl = event.target.result;
headerPreviewImg.src = headerImageUrl;
headerPreview.classList.add('has-image');
updateLogoDisplay();
};
reader.readAsDataURL(file);
});
// Remove logo
document.getElementById('remove-logo').addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
logoUrl = null;
logoSvgContent = null;
logoIsSvg = false;
recolorLogo = false;
recolorLogoCheckbox.checked = false;
logoColorPickerRow.classList.remove('visible');
logoPreview.classList.remove('has-image');
logoUpload.value = '';
updateLogoDisplay();
});
// Remove header
document.getElementById('remove-header').addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
headerImageUrl = null;
headerPreview.classList.remove('has-image');
headerUpload.value = '';
updateLogoDisplay();
});
// Logo size slider
logoSizeSlider.addEventListener('input', (e) => {
logoSize = parseInt(e.target.value);
logoSizeValue.textContent = logoSize + 'px';
updateLogoDisplay();
});
// Recolor logo toggle
recolorLogoCheckbox.addEventListener('change', (e) => {
recolorLogo = e.target.checked;
logoColorPickerRow.classList.toggle('visible', recolorLogo);
updateLogoImage();
updateLogoDisplay();
});
// Logo color picker
logoColorPicker.addEventListener('input', (e) => {
logoColor = e.target.value;
logoColorValue.textContent = logoColor;
updateLogoImage();
updateLogoDisplay();
});
// Header horizontal position slider
headerPositionXSlider.addEventListener('input', (e) => {
headerPositionX = parseInt(e.target.value);
headerPositionXValue.textContent = headerPositionX + '%';
updateLogoDisplay();
});
// Header vertical position slider
headerPositionSlider.addEventListener('input', (e) => {
headerPositionY = parseInt(e.target.value);
headerPositionValue.textContent = headerPositionY + '%';
updateLogoDisplay();
});
// Header zoom slider
headerZoomSlider.addEventListener('input', (e) => {
headerZoom = parseInt(e.target.value);
headerZoomValue.textContent = headerZoom + '%';
// Only show horizontal position when zoomed in
headerPositionXRow.classList.toggle('visible', headerZoom > 100);
updateLogoDisplay();
});
// Initialize with Gallery preset
document.querySelector('[data-preset="gallery"]').click();
// Page view toggle
document.querySelectorAll('.page-toggle-btn').forEach(btn => {
btn.addEventListener('click', () => {
const page = btn.dataset.page;
document.querySelectorAll('.page-toggle-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.querySelectorAll('.page-view').forEach(view => view.classList.remove('active'));
document.getElementById(page + '-view').classList.add('active');
});
});
// Feature toggles
document.getElementById('announcement-bar-toggle').addEventListener('change', (e) => {
showAnnouncementBar = e.target.checked;
document.getElementById('announcement-bar').classList.toggle('hidden', !showAnnouncementBar);
});
document.getElementById('sticky-header-toggle').addEventListener('change', (e) => {
stickyHeader = e.target.checked;
previewFrame.dataset.stickyHeader = stickyHeader;
});
document.getElementById('hover-image-toggle').addEventListener('change', (e) => {
hoverImage = e.target.checked;
previewFrame.dataset.hoverImage = hoverImage;
});
document.getElementById('quick-add-toggle').addEventListener('change', (e) => {
quickAdd = e.target.checked;
previewFrame.dataset.quickAdd = quickAdd;
});
// Initialize feature data attributes
previewFrame.dataset.hoverImage = hoverImage;
previewFrame.dataset.quickAdd = quickAdd;
previewFrame.dataset.aspect = aspectRatio;
previewFrame.dataset.fontSize = 'medium';
previewFrame.dataset.headingWeight = 'bold';
previewFrame.dataset.layoutWidth = 'wide';
previewFrame.dataset.buttonStyle = 'filled';
previewFrame.dataset.cardShadow = 'none';
previewFrame.dataset.productText = 'left';
previewFrame.dataset.galleryPosition = 'left';
previewFrame.dataset.showPrices = 'true';
previewFrame.dataset.pdpTrust = 'true';
previewFrame.dataset.pdpReviews = 'true';
previewFrame.dataset.pdpRelated = 'true';
// Aspect ratio options
document.querySelectorAll('#aspect-options .option-button').forEach(btn => {
btn.addEventListener('click', () => {
aspectRatio = btn.dataset.aspect;
previewFrame.dataset.aspect = aspectRatio;
document.querySelectorAll('#aspect-options .option-button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
});
});
// Customise section toggle
const customiseSection = document.getElementById('customise-section');
const customiseHeader = document.getElementById('customise-header');
customiseHeader.addEventListener('click', () => {
customiseSection.classList.toggle('open');
});
// Cart drawer
const cartDrawer = document.getElementById('cart-drawer');
const cartDrawerOverlay = document.getElementById('cart-drawer-overlay');
const cartBtn = document.getElementById('cart-btn');
const cartDrawerClose = document.getElementById('cart-drawer-close');
const viewCartLink = document.getElementById('view-cart-link');
function openCartDrawer() {
cartDrawer.classList.add('open');
cartDrawerOverlay.classList.add('open');
}
function closeCartDrawer() {
cartDrawer.classList.remove('open');
cartDrawerOverlay.classList.remove('open');
}
cartBtn.addEventListener('click', openCartDrawer);
cartDrawerClose.addEventListener('click', closeCartDrawer);
cartDrawerOverlay.addEventListener('click', closeCartDrawer);
viewCartLink.addEventListener('click', (e) => {
e.preventDefault();
closeCartDrawer();
document.querySelector('[data-page="cart"]').click();
});
// Quick add buttons open cart drawer
document.querySelectorAll('.quick-add-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
openCartDrawer();
});
});
// Search modal
const searchModal = document.getElementById('search-modal');
const searchBtn = document.getElementById('search-btn');
const searchClose = document.getElementById('search-close');
searchBtn.addEventListener('click', () => {
searchModal.classList.add('open');
searchModal.querySelector('.search-input').focus();
});
searchClose.addEventListener('click', () => {
searchModal.classList.remove('open');
});
searchModal.addEventListener('click', (e) => {
if (e.target === searchModal) {
searchModal.classList.remove('open');
}
});
// Escape key closes modals (dialog handles its own escape)
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeCartDrawer();
searchModal.classList.remove('open');
}
});
// PDP thumbnail gallery
const pdpMainImage = document.getElementById('pdp-main-image');
document.querySelectorAll('.pdp-thumb').forEach(thumb => {
thumb.addEventListener('click', () => {
// Update main image
const imageUrl = thumb.dataset.image;
pdpMainImage.style.backgroundImage = `url('${imageUrl}')`;
// Update active state
document.querySelectorAll('.pdp-thumb').forEach(t => t.classList.remove('active'));
thumb.classList.add('active');
});
});
// Lightbox - using native dialog
const lightbox = document.getElementById('lightbox');
const lightboxImage = document.getElementById('lightbox-image');
const lightboxCaption = document.getElementById('lightbox-caption');
const lightboxCounter = document.getElementById('lightbox-counter');
const lightboxClose = document.getElementById('lightbox-close');
const lightboxPrev = document.getElementById('lightbox-prev');
const lightboxNext = document.getElementById('lightbox-next');
const zoomBtn = document.getElementById('zoom-btn');
// Get all product images with metadata from thumbnails
function getLightboxImages() {
return Array.from(document.querySelectorAll('.pdp-thumb')).map(thumb => ({
src: thumb.dataset.image,
alt: thumb.dataset.alt || 'Product image',
description: thumb.dataset.description || ''
}));
}
let currentLightboxIndex = 0;
function openLightbox(startIndex = 0) {
const images = getLightboxImages();
currentLightboxIndex = startIndex;
updateLightboxImage(images);
lightbox.showModal();
}
function closeLightbox() {
lightbox.close();
zoomBtn.focus();
}
function updateLightboxImage(images) {
const current = images[currentLightboxIndex];
lightboxImage.src = current.src;
lightboxImage.alt = current.alt;
lightboxCaption.textContent = current.description;
lightboxCounter.textContent = `${currentLightboxIndex + 1} / ${images.length}`;
}
function nextImage() {
const images = getLightboxImages();
currentLightboxIndex = (currentLightboxIndex + 1) % images.length;
updateLightboxImage(images);
}
function prevImage() {
const images = getLightboxImages();
currentLightboxIndex = (currentLightboxIndex - 1 + images.length) % images.length;
updateLightboxImage(images);
}
// Open lightbox from zoom button or clicking main image
zoomBtn.addEventListener('click', (e) => {
e.stopPropagation();
const activeThumb = document.querySelector('.pdp-thumb.active');
const thumbs = Array.from(document.querySelectorAll('.pdp-thumb'));
const startIndex = thumbs.indexOf(activeThumb);
openLightbox(startIndex >= 0 ? startIndex : 0);
});
pdpMainImage.addEventListener('click', () => {
const activeThumb = document.querySelector('.pdp-thumb.active');
const thumbs = Array.from(document.querySelectorAll('.pdp-thumb'));
const startIndex = thumbs.indexOf(activeThumb);
openLightbox(startIndex >= 0 ? startIndex : 0);
});
lightboxClose.addEventListener('click', closeLightbox);
lightboxNext.addEventListener('click', nextImage);
lightboxPrev.addEventListener('click', prevImage);
// Close on clicking backdrop (native dialog handles escape key)
lightbox.addEventListener('click', (e) => {
if (e.target === lightbox) {
closeLightbox();
}
});
// Arrow key navigation
lightbox.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') {
nextImage();
} else if (e.key === 'ArrowLeft') {
prevImage();
}
});
// Internal navigation links
function navigateToPage(pageId) {
document.querySelectorAll('.page-toggle-btn').forEach(b => b.classList.remove('active'));
document.querySelector(`[data-page="${pageId}"]`).classList.add('active');
document.querySelectorAll('.page-view').forEach(view => view.classList.remove('active'));
document.getElementById(pageId + '-view').classList.add('active');
}
document.querySelectorAll('[data-nav]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
navigateToPage(link.dataset.nav);
});
});
// Product cards link to PDP
document.querySelectorAll('.product-card').forEach(card => {
card.addEventListener('click', (e) => {
// Don't navigate if clicking quick-add button
if (e.target.closest('.quick-add-btn')) return;
navigateToPage('pdp');
});
});
// PDP Add to basket button opens cart drawer
document.querySelector('.pdp-add-btn').addEventListener('click', openCartDrawer);
// Cart state toggle (full/empty)
const cartStateToggle = document.getElementById('cart-state-toggle');
const cartFull = document.getElementById('cart-full');
const cartEmpty = document.getElementById('cart-empty');
let isCartEmpty = false;
cartStateToggle.addEventListener('click', () => {
isCartEmpty = !isCartEmpty;
cartFull.hidden = isCartEmpty;
cartEmpty.hidden = !isCartEmpty;
cartStateToggle.textContent = isCartEmpty ? 'Preview full cart' : 'Preview empty state';
});
</script>
</body>
</html>