From 7fa743760d98d13b8b36dfc07003dc30184a1754 Mon Sep 17 00:00:00 2001 From: "DESKTOP-G4D78VI\\Oli" Date: Sat, 27 Sep 2025 23:46:54 +0100 Subject: [PATCH] initial --- EMAILJS_SETUP.md | 421 ++++++++++ EMAILJS_TEMPLATES.md | 1023 +++++++++++++++++++++++ README.md | 345 ++++++++ cake_inventory.csv | 21 + images/baker-portrait.jpg | 1 + images/chocolate-decadence.jpg | 1 + images/hero-cake.jpg | 1 + images/wedding-vanilla.jpg | 1 + index.html | 602 ++++++++++++++ script.js | 1017 +++++++++++++++++++++++ styles.css | 1423 ++++++++++++++++++++++++++++++++ 11 files changed, 4856 insertions(+) create mode 100644 EMAILJS_SETUP.md create mode 100644 EMAILJS_TEMPLATES.md create mode 100644 README.md create mode 100644 cake_inventory.csv create mode 100644 images/baker-portrait.jpg create mode 100644 images/chocolate-decadence.jpg create mode 100644 images/hero-cake.jpg create mode 100644 images/wedding-vanilla.jpg create mode 100644 index.html create mode 100644 script.js create mode 100644 styles.css diff --git a/EMAILJS_SETUP.md b/EMAILJS_SETUP.md new file mode 100644 index 0000000..bbfa6ee --- /dev/null +++ b/EMAILJS_SETUP.md @@ -0,0 +1,421 @@ +# EmailJS Setup Guide for Sweet Dreams Bakery + +This guide will walk you through setting up EmailJS to enable professional email functionality for order processing, contact forms, and customer communications. + +## ๐Ÿ“ง What is EmailJS? + +EmailJS allows you to send emails directly from your frontend application without needing a backend server. It's perfect for: +- Order confirmations +- Contact form submissions +- Newsletter subscriptions +- Business notifications + +## ๐Ÿš€ Quick Setup (5 minutes) + +### **Step 1: Create EmailJS Account** + +1. Go to [emailjs.com](https://www.emailjs.com) +2. Click "Sign Up" and create a free account +3. Verify your email address +4. Log in to your EmailJS dashboard + +### **Step 2: Set Up Email Service** + +1. **Add Email Service:** + - In your EmailJS dashboard, click "Email Services" + - Click "Add New Service" + - Choose your email provider: + - **Gmail** (recommended for personal/small business) + - **Outlook/Hotmail** + - **Yahoo Mail** + - **Other SMTP services** + +2. **Configure Gmail Service (Most Common):** + - Select "Gmail" + - Click "Connect Account" + - Sign in with your Gmail account + - Allow EmailJS permissions + - Your service will be created with an ID like `service_abc123` + +3. **Configure Custom SMTP (Business Email):** + - Select "Other" + - Enter your SMTP settings: + ``` + SMTP Server: mail.yourdomain.com + Port: 587 (or 465 for SSL) + Username: orders@yourbakery.com + Password: your-email-password + ``` + - Test the connection + - Save the service + +### **Step 3: Create Email Templates** + +You'll need to create these templates in your EmailJS dashboard: + +#### **Template 1: Customer Order Confirmation** + +1. Go to "Email Templates" โ†’ "Create New Template" +2. Template Name: `Customer Order Confirmation` +3. Template ID: `customer_order_confirmation` (you'll need this) +4. Configure the template (see detailed template code below) + +#### **Template 2: Business Order Notification** + +1. Create another template +2. Template Name: `Business Order Notification` +3. Template ID: `business_order_notification` +4. Configure for internal notifications + +#### **Template 3: Contact Form** + +1. Create a third template +2. Template Name: `Contact Form Inquiry` +3. Template ID: `contact_form_inquiry` +4. For general inquiries and consultations + +### **Step 4: Get Your Credentials** + +1. **Service ID**: Found in Email Services (e.g., `service_abc123`) +2. **Template IDs**: From your created templates +3. **User ID (Public Key)**: Account โ†’ API Keys โ†’ Public Key + +### **Step 5: Update Website Configuration** + +Edit `script.js` and update the EmailJS configuration: + +```javascript +// Update these values with your actual EmailJS credentials +const emailJSConfig = { + serviceID: 'service_abc123', // Your service ID + templateID: 'customer_order_confirmation', // Your main template ID + userID: 'user_xyz789' // Your public key +}; +``` + +## ๐Ÿ“ Email Template Configurations + +### **Customer Order Confirmation Template** + +**Template Settings:** +- **To Email**: `{{to_email}}` +- **From Name**: Sweet Dreams Bakery +- **From Email**: orders@sweetdreamsbakery.com (or your business email) +- **Subject**: Order Confirmation - Thank You {{to_name}}! + +**Email Template Body** (copy this HTML): +```html + + + + + + +
+

๐ŸŽ‚ Order Confirmation

+

Thank you for choosing Sweet Dreams Bakery!

+
+ +
+

Hello {{to_name}}!

+ +

We've received your order and we're excited to create something special for you! Here are your order details:

+ +
+

๐Ÿ“‹ Order Summary

+

Order Number: {{order_number}}

+

Event Date: {{event_date}}

+

Delivery Method: {{delivery_method}}

+ +

Items Ordered:

+
{{order_items}}
+ +

Total Amount: ${{order_total}}

+ + {{#special_requests}} +

Special Requests: {{special_requests}}

+ {{/special_requests}} +
+ +

๐ŸŽฏ What's Next?

+ + +

Have questions? Reply to this email or call us at (555) 123-CAKE

+ + Contact Us +
+ + + + +``` + +### **Business Order Notification Template** + +**Template Settings:** +- **To Email**: orders@sweetdreamsbakery.com (your business email) +- **From Name**: Website Orders +- **Subject**: ๐Ÿšจ NEW ORDER: {{customer_name}} - ${{order_total}} + +**Email Template Body:** +```html + + + + + + +
+

๐ŸŽ‚ NEW CAKE ORDER RECEIVED!

+

Order Time: {{order_time}}

+
+ +
+

๐Ÿ‘ค Customer Information

+

Name: {{customer_name}}

+

Email: {{customer_email}}

+

Phone: {{customer_phone}}

+
+ +
+

๐Ÿ›๏ธ Complete Order Details

+
{{order_details}}
+
+ +

โšก Action Required: Contact customer within 24 hours to confirm order details and arrange payment.

+ + +``` + +### **Contact Form Template** + +**Template Settings:** +- **To Email**: info@sweetdreamsbakery.com +- **From Name**: {{from_name}} +- **From Email**: {{from_email}} +- **Subject**: Website Inquiry: {{inquiry_type}} + +**Email Template Body:** +```html + + + +

๐Ÿฐ New Website Inquiry

+ +

From: {{from_name}} ({{from_email}})

+

Phone: {{phone}}

+

Inquiry Type: {{inquiry_type}}

+ +

Message:

+
+ {{message}} +
+ +

Sent from Sweet Dreams Bakery website contact form

+ + +``` + +## โš™๏ธ Advanced Configuration + +### **Multiple Template Setup** + +If you want different templates for different order types: + +```javascript +// In script.js, you can configure multiple templates +const emailTemplates = { + customerConfirmation: 'customer_order_confirmation', + businessNotification: 'business_order_notification', + contactInquiry: 'contact_form_inquiry', + newsletterWelcome: 'newsletter_welcome' +}; + +// Use different templates based on context +await emailjs.send( + emailJSConfig.serviceID, + emailTemplates.customerConfirmation, + emailData +); +``` + +### **Custom Domain Email** + +For professional appearance, use your own domain: + +1. **Set up business email** (e.g., orders@yourbakery.com) +2. **Configure SMTP** in EmailJS with your business email settings +3. **Update templates** to use your business email as sender + +### **Email Deliverability** + +To ensure emails don't go to spam: + +1. **SPF Record**: Add EmailJS to your domain's SPF record +2. **DKIM**: Enable DKIM signing in EmailJS settings +3. **Reply-To**: Set up proper reply-to addresses +4. **Test thoroughly**: Send test emails to different providers + +## ๐Ÿงช Testing Your Setup + +### **Test Mode (No Real Emails)** + +The website includes demo mode when EmailJS isn't configured: + +```javascript +// This runs when EmailJS credentials aren't set up +console.log('Demo mode: Order would be processed via EmailJS'); +showNotification('Demo mode: Order would be sent via EmailJS', 'info'); +``` + +### **Send Test Emails** + +1. **Use EmailJS Test Mode:** + - Go to your EmailJS dashboard + - Select your template + - Click "Test Template" + - Fill in sample data + - Send test email + +2. **Test Through Website:** + - Fill out contact form with your email + - Place a test order + - Check both customer and business emails + +### **Debug Common Issues** + +```javascript +// Add this to script.js for debugging +emailjs.send(serviceID, templateID, emailData) + .then(function(response) { + console.log('SUCCESS!', response.status, response.text); + }, function(error) { + console.log('FAILED...', error); + // Common error codes: + // 400: Bad request (check template variables) + // 403: Forbidden (check service configuration) + // 412: Template not found + }); +``` + +## ๐Ÿ”’ Security Best Practices + +### **Public Key Security** + +- EmailJS public keys are safe to include in frontend code +- They only allow sending emails, not accessing your account +- Rate limiting is automatically applied + +### **Template Validation** + +- Always validate form data before sending +- Use template variables to prevent email injection +- Never include sensitive data in email templates + +### **Spam Prevention** + +- Implement client-side rate limiting +- Add honeypot fields to forms +- Consider adding basic captcha for high-traffic sites + +## ๐Ÿ“Š Monitoring & Analytics + +### **EmailJS Dashboard** + +Monitor your email activity: +- **Sent emails count** +- **Success/failure rates** +- **Monthly usage limits** +- **Template performance** + +### **Usage Limits** + +**Free Plan:** +- 200 emails/month +- Basic templates +- Standard support + +**Paid Plans:** +- Higher email limits +- Advanced features +- Priority support + +## โ“ Troubleshooting + +### **Common Issues** + +**"Service not found" Error:** +```javascript +// Check your service ID is correct +const emailJSConfig = { + serviceID: 'service_XXXXXXX', // Must match EmailJS dashboard + // ... +}; +``` + +**"Template not found" Error:** +```javascript +// Verify template ID matches exactly +templateID: 'customer_order_confirmation', // Case-sensitive! +``` + +**Emails going to spam:** +- Check sender email reputation +- Verify SPF/DKIM setup +- Use professional from addresses +- Avoid spam trigger words + +**Template variables not working:** +```javascript +// Ensure variable names match exactly +const emailData = { + to_name: customerName, // Must match {{to_name}} in template + to_email: customerEmail, // Must match {{to_email}} in template + // ... +}; +``` + +### **Getting Help** + +1. **EmailJS Documentation**: [docs.emailjs.com](https://www.emailjs.com/docs/) +2. **EmailJS Support**: Available through your dashboard +3. **Community Forums**: Stack Overflow with `emailjs` tag + +## ๐ŸŽ‰ Success! + +Once configured, your bakery website will: +- โœ… Send professional order confirmations to customers +- โœ… Notify you immediately of new orders +- โœ… Handle contact form inquiries automatically +- โœ… Support newsletter subscriptions +- โœ… Work without any backend infrastructure + +**Your customers will receive beautiful, professional emails that match your bakery's branding!** + +--- + +*Need help? Check the troubleshooting section above or refer to the main README.md file.* \ No newline at end of file diff --git a/EMAILJS_TEMPLATES.md b/EMAILJS_TEMPLATES.md new file mode 100644 index 0000000..e709866 --- /dev/null +++ b/EMAILJS_TEMPLATES.md @@ -0,0 +1,1023 @@ +# EmailJS Template Code for Sweet Dreams Bakery + +This document contains the complete email template code for your bakery website's EmailJS integration. Copy and paste these templates directly into your EmailJS dashboard. + +## ๐Ÿ“ง Template Overview + +You'll need to create these 4 templates in your EmailJS dashboard: + +1. **Customer Order Confirmation** - Sent to customers after placing orders +2. **Business Order Notification** - Internal notification for new orders +3. **Contact Form Auto-Reply** - Response to contact form submissions +4. **Newsletter Welcome** - Welcome email for newsletter subscribers + +--- + +## ๐Ÿ›๏ธ Template 1: Customer Order Confirmation + +**Template ID:** `customer_order_confirmation` + +### Template Settings: +- **To Email:** `{{to_email}}` +- **From Name:** `Sweet Dreams Bakery` +- **From Email:** `orders@sweetdreamsbakery.com` +- **Subject:** `๐ŸŽ‚ Order Confirmation #{{order_number}} - Thank You {{to_name}}!` + +### HTML Template: +```html + + + + + + Order Confirmation - Sweet Dreams Bakery + + + +
+
+

๐ŸŽ‚ Order Confirmation

+

Your sweet dreams are coming true!

+
+ +
+
+ Hello {{to_name}}! ๐Ÿ‘‹ +
+ +

Thank you for choosing Sweet Dreams Bakery! We've received your order and our talented bakers are excited to create something truly special for your upcoming event.

+ +
+

๐Ÿ“‹ Your Order Details

+ +
+

Order Number: {{order_number}}

+

Event Date: {{event_date}}

+

Event Time: {{event_time}}

+

Delivery Method: {{delivery_method}}

+ {{#delivery_address}} +

Delivery Address: {{delivery_address}}

+ {{/delivery_address}} +
+ +

๐Ÿฐ Items Ordered:

+
+
{{order_items}}
+
+ +
+ Total: ${{order_total}} +
+ + {{#special_requests}} +
+ โœจ Special Requests:
+ {{special_requests}} +
+ {{/special_requests}} +
+ +
+

๐ŸŽฏ What Happens Next?

+
    +
  • Within 24 hours: Our team will contact you to confirm all order details and discuss any customizations
  • +
  • Design Consultation: We'll review your cake design preferences and make suggestions if needed
  • +
  • Payment Arrangement: We'll arrange convenient payment options that work for you
  • +
  • Production Schedule: Your cake will be freshly made close to your event date
  • +
  • Final Confirmation: We'll confirm pickup/delivery details 48 hours before your event
  • +
+
+ +
+

Questions about your order?

+

We're here to help! Contact us anytime:

+

๐Ÿ“ž (555) 123-CAKE

+

โœ‰๏ธ orders@sweetdreamsbakery.com

+ + Email Us + Call Us +
+ +

+ "Thank you for letting us be part of your special celebration. We can't wait to create something beautiful for you!" +

+ - The Sweet Dreams Bakery Team ๐Ÿฐ +

+
+ + +
+ + +``` + +--- + +## ๐Ÿšจ Template 2: Business Order Notification + +**Template ID:** `business_order_notification` + +### Template Settings: +- **To Email:** `orders@sweetdreamsbakery.com` (your business email) +- **From Name:** `Website Orders` +- **From Email:** `noreply@sweetdreamsbakery.com` +- **Subject:** `๐Ÿšจ NEW ORDER: {{customer_name}} - ${{order_total}} | Event: {{event_date}}` + +### HTML Template: +```html + + + + + + New Order Alert - Sweet Dreams Bakery + + + +
+
+

๐ŸŽ‚ NEW CAKE ORDER RECEIVED!

+

A customer has placed an order through your website

+
+ +
+ ๐Ÿ“… Order received: {{order_date}} at {{order_time}} +
+ +
+
+

๐Ÿ‘ค Customer Information

+
+
+ Name: + {{customer_name}} +
+
+ Email: + + {{customer_email}} + +
+
+ Phone: + + {{customer_phone}} + +
+
+ Event Date: + {{event_date}} {{#event_time}}at {{event_time}}{{/event_time}} +
+
+ Delivery: + {{delivery_method}} +
+ {{#delivery_address}} +
+ Address: + {{delivery_address}} +
+ {{/delivery_address}} +
+
+ +
+

๐Ÿ›๏ธ Order Details

+ +
+ Order Total: ${{order_total}} +
+ +

๐Ÿ“ Complete Order Information:

+
{{order_details}}
+ + {{#special_requests}} +
+ โœจ Special Requests:
+ {{special_requests}} +
+ {{/special_requests}} +
+ +
+

โšก ACTION REQUIRED

+

Contact the customer within 24 hours to:

+
    +
  • Confirm order details and availability
  • +
  • Discuss customization requirements
  • +
  • Arrange payment method and schedule
  • +
  • Finalize delivery/pickup logistics
  • +
+ + +
+ +
+

This order was placed through your Sweet Dreams Bakery website.
+ The customer has received an automatic confirmation email.

+
+
+
+ + +``` + +--- + +## ๐Ÿ’ฌ Template 3: Contact Form Auto-Reply + +**Template ID:** `contact_form_auto_reply` + +### Template Settings: +- **To Email:** `{{from_email}}` +- **From Name:** `Sweet Dreams Bakery` +- **From Email:** `info@sweetdreamsbakery.com` +- **Subject:** `Thank you for contacting Sweet Dreams Bakery! ๐Ÿฐ` + +### HTML Template: +```html + + + + + + Thank You - Sweet Dreams Bakery + + + +
+
+

๐Ÿฐ Thank You for Contacting Us!

+

We've received your message and will get back to you soon

+
+ +
+

Hello {{from_name}},

+ +

Thank you for reaching out to Sweet Dreams Bakery! We've received your inquiry about {{inquiry_type}} and our team will respond within 24 hours.

+ +
+

๐Ÿ“ Your Message Summary:

+

Inquiry Type: {{inquiry_type}}

+

Your Message:

+
+ {{message}} +
+
+ +

In the meantime, feel free to:

+
    +
  • Browse our cake gallery on our website
  • +
  • Check out our latest creations on social media
  • +
  • Read about our custom cake process
  • +
+ +
+

Need immediate assistance?

+

๐Ÿ“ž (555) 123-CAKE

+

๐Ÿ•’ Business Hours: Tue-Sat 8AM-6PM, Sun 9AM-4PM

+ + Call Us + Visit Website +
+ +

We're excited to help make your sweet dreams come true!

+ +

The Sweet Dreams Bakery Team ๐ŸŽ‚

+
+ + +
+ + +``` + +--- + +## ๐Ÿ“ฐ Template 4: Newsletter Welcome + +**Template ID:** `newsletter_welcome` + +### Template Settings: +- **To Email:** `{{subscriber_email}}` +- **From Name:** `Sweet Dreams Bakery` +- **From Email:** `newsletter@sweetdreamsbakery.com` +- **Subject:** `๐Ÿฐ Welcome to Sweet Dreams! Here's 10% off your first order` + +### HTML Template: +```html + + + + + + Welcome to Sweet Dreams Newsletter + + + +
+
+

๐Ÿฐ Welcome to Sweet Dreams!

+

Thank you for joining our delicious newsletter family

+
+ +
+ ๐ŸŽ‰ WELCOME GIFT: Use code SWEET10 for 10% off your first order! +
+ +
+
+

Hello Sweet Friend! ๐Ÿ‘‹

+

We're thrilled to have you join our Sweet Dreams Bakery newsletter! You've just unlocked access to exclusive offers, baking tips, and first looks at our latest cake creations.

+
+ +
+

What to expect in your inbox:

+
    +
  • Exclusive discount codes and special offers
  • +
  • First access to new cake designs and flavors
  • +
  • Seasonal baking tips and recipes
  • +
  • Behind-the-scenes bakery stories
  • +
  • Early booking for holiday cake slots
  • +
  • Birthday month surprises ๐ŸŽ‚
  • +
+
+ +
+

Ready to place your first order?

+

Browse our delicious collection of handcrafted cakes and use your welcome discount!

+ + Shop Cakes Now + +

+ Discount Code: SWEET10
+ Valid until: {{expiry_date}}
+ Minimum order: $25 +

+
+ +
+

Follow us for daily cake inspiration!

+ +
+ +

+ "We can't wait to be part of your special celebrations!"
+ - Sarah & The Sweet Dreams Team +

+
+ + +
+ + +``` + +--- + +## ๐Ÿ“‹ Template Variables Reference + +### Customer Order Confirmation Variables: +- `{{to_name}}` - Customer's name +- `{{to_email}}` - Customer's email +- `{{order_number}}` - Generated order number +- `{{event_date}}` - Event date +- `{{event_time}}` - Event time (optional) +- `{{delivery_method}}` - Pickup or Delivery +- `{{delivery_address}}` - Address (if delivery) +- `{{order_items}}` - Formatted list of items +- `{{order_total}}` - Total amount +- `{{special_requests}}` - Custom requests + +### Business Order Notification Variables: +- `{{customer_name}}` - Customer's full name +- `{{customer_email}}` - Customer's email +- `{{customer_phone}}` - Customer's phone +- `{{order_date}}` - Order placement date +- `{{order_time}}` - Order placement time +- `{{order_total}}` - Total amount +- `{{order_details}}` - Complete order JSON +- `{{event_date}}` - Event date +- `{{delivery_method}}` - Delivery method +- `{{special_requests}}` - Special requests + +### Contact Form Variables: +- `{{from_name}}` - Sender's name +- `{{from_email}}` - Sender's email +- `{{phone}}` - Phone number (optional) +- `{{inquiry_type}}` - Type of inquiry +- `{{message}}` - Message content + +### Newsletter Variables: +- `{{subscriber_email}}` - Subscriber's email +- `{{expiry_date}}` - Discount expiry date + +--- + +## ๐ŸŽฏ Implementation Steps + +1. **Create Service** in EmailJS dashboard +2. **Copy each template** above into EmailJS +3. **Test each template** with sample data +4. **Update script.js** with your service and template IDs +5. **Customize branding** (colors, business info, social links) +6. **Test complete workflow** from website + +## โšก Quick Tips + +- **Always test templates** before going live +- **Use descriptive template names** for easy management +- **Keep mobile users in mind** - templates are responsive +- **Update business information** in all templates +- **Add your actual social media links** +- **Customize colors** to match your brand + +Your professional bakery email system is now ready! ๐ŸŽ‰ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0e07a3 --- /dev/null +++ b/README.md @@ -0,0 +1,345 @@ +# Sweet Dreams Bakery - E-Commerce Website + +A professional, fully-featured bakery e-commerce website built with pure HTML, CSS, and JavaScript. Features CSV-based product management, EmailJS integration for order processing, and a complete shopping cart system. + +![Sweet Dreams Bakery](images/hero-cake.jpg) + +## ๐ŸŒŸ Features + +### **Frontend-Only Architecture** +- Pure HTML5, CSS3, and JavaScript (ES6+) +- No backend required - runs entirely in the browser +- CSV-based product inventory for easy management +- EmailJS integration for professional order processing +- Local storage for cart persistence + +### **E-Commerce Functionality** +- โœ… Dynamic product catalog loaded from CSV +- โœ… Advanced product filtering and search +- โœ… Shopping cart with quantity management +- โœ… Professional checkout process +- โœ… Email order confirmation system +- โœ… Stock quantity tracking +- โœ… Custom product options support + +### **Professional Design** +- โœ… Bakery-themed color palette and typography +- โœ… Responsive design (mobile-first approach) +- โœ… Smooth animations and transitions +- โœ… Professional product photography integration +- โœ… Accessible and SEO-friendly structure + +### **Business Features** +- โœ… Custom cake consultation forms +- โœ… Wedding cake specialization +- โœ… Dietary options support (gluten-free, vegan) +- โœ… Event date scheduling +- โœ… Pickup and delivery options +- โœ… Baker portfolio and process showcase + +## ๐Ÿš€ Quick Start + +### **1. Download and Setup** +```bash +# Clone or download the repository +git clone sweet-dreams-bakery +cd sweet-dreams-bakery + +# Or simply download and extract the ZIP file +``` + +### **2. Configure EmailJS (Optional)** +1. Follow the detailed guide in [`EMAILJS_SETUP.md`](EMAILJS_SETUP.md) +2. Update the configuration in `script.js`: + ```javascript + const emailJSConfig = { + serviceID: 'your_service_id', + templateID: 'your_template_id', + userID: 'your_user_id' + }; + ``` + +### **3. Start Local Server** +Choose one of these methods to run the website locally: + +**Option A: Python HTTP Server** +```bash +# Python 3 +python -m http.server 8000 + +# Python 2 +python -m SimpleHTTPServer 8000 + +# Then visit: http://localhost:8000 +``` + +**Option B: Node.js HTTP Server** +```bash +# Install http-server globally +npm install -g http-server + +# Run server +http-server -p 8000 + +# Then visit: http://localhost:8000 +``` + +**Option C: VS Code Live Server** +1. Install "Live Server" extension in VS Code +2. Right-click `index.html` โ†’ "Open with Live Server" + +## ๐Ÿ“ Project Structure + +``` +sweet-dreams-bakery/ +โ”œโ”€โ”€ index.html # Main website file +โ”œโ”€โ”€ styles.css # Complete responsive styling +โ”œโ”€โ”€ script.js # All interactive functionality +โ”œโ”€โ”€ cake_inventory.csv # Product database (20 sample cakes) +โ”œโ”€โ”€ images/ # Product images directory +โ”‚ โ”œโ”€โ”€ hero-cake.jpg # Main hero image +โ”‚ โ”œโ”€โ”€ baker-portrait.jpg # About section image +โ”‚ โ”œโ”€โ”€ gallery-*.jpg # Portfolio gallery images +โ”‚ โ””โ”€โ”€ product-*.jpg # Individual product images +โ”œโ”€โ”€ README.md # This file +โ”œโ”€โ”€ EMAILJS_SETUP.md # EmailJS configuration guide +โ”œโ”€โ”€ EMAILJS_TEMPLATES.md # Email template code +โ””โ”€โ”€ sw.js # Service worker (optional) +``` + +## ๐Ÿ›๏ธ Product Management + +### **Adding New Products** +Edit `cake_inventory.csv` with the following columns: + +| Column | Description | Example | +|--------|-------------|---------| +| `id` | Unique product ID | `21` | +| `name` | Product name | `"Summer Berry Tart"` | +| `description` | Product description | `"Fresh seasonal berries..."` | +| `price` | Price in dollars | `45.99` | +| `category` | Product category | `"Specialty Desserts"` | +| `size_inches` | Cake diameter | `8` | +| `serves_people` | Number of servings | `10` | +| `weight_kg` | Weight in kilograms | `1.5` | +| `flavor` | Primary flavor | `"Mixed Berry"` | +| `image_url` | Image path/URL | `"images/berry-tart.jpg"` | +| `image_alt` | Alt text for accessibility | `"Fresh berry tart with cream"` | +| `stock_quantity` | Available quantity | `5` | +| `featured` | Featured product flag | `true/false` | +| `custom_available` | Custom orders available | `true/false` | +| `dietary_options` | Special dietary info | `"gluten-free available"` | +| `baker_name` | Baker who creates it | `"Sarah Mitchell"` | +| `date_created` | Creation date | `"2024-01-15"` | +| `sku` | Stock keeping unit | `"BERRY-TART-021"` | +| `occasion_type` | Suitable occasions | `"summer, birthday"` | + +### **Product Categories** +- Wedding Cakes +- Birthday Cakes +- Celebration Cakes +- Cupcakes & Minis +- Specialty Desserts +- Seasonal Items + +### **Image Requirements** +- **Recommended size**: 1000x1000px minimum +- **Format**: JPG, PNG, or WebP +- **Aspect ratio**: Square (1:1) preferred +- **File naming**: Descriptive names (e.g., `chocolate-wedding-cake.jpg`) +- **Alt text**: Always include descriptive alt text for accessibility + +## โš™๏ธ Configuration + +### **EmailJS Configuration** +See [`EMAILJS_SETUP.md`](EMAILJS_SETUP.md) for detailed setup instructions. + +### **Color Customization** +Update CSS variables in `styles.css`: +```css +:root { + --color-primary: #F4B8C3; /* Soft pink frosting */ + --color-secondary: #FFF5E6; /* Cream/vanilla */ + --color-accent: #8B4B73; /* Rich berry */ + --color-chocolate: #4A2C2A; /* Dark chocolate */ + /* ... more variables */ +} +``` + +### **Typography Customization** +Change fonts by updating the Google Fonts import in `index.html`: +```html + +``` + +## ๐ŸŽจ Customization Guide + +### **Branding** +1. **Logo**: Replace the cake icon in the header with your logo +2. **Business Name**: Update "Sweet Dreams Bakery" throughout the site +3. **Contact Information**: Update phone, email, and address in the contact section +4. **Social Media**: Add your social media links in the footer + +### **Content** +1. **About Section**: Replace baker information and story +2. **Hero Message**: Update the main headline and description +3. **Process Steps**: Customize the 4-step process description +4. **Gallery Images**: Add photos of your actual work + +### **Functionality** +1. **Payment Processing**: The system uses a "pay later" approach - collect orders first, then arrange payment +2. **Delivery Areas**: Customize delivery options in the checkout form +3. **Lead Times**: Adjust minimum order advance notice requirements +4. **Business Hours**: Update operating hours in the contact section + +## ๐Ÿ“ฑ Responsive Design + +The website is fully responsive with breakpoints at: +- **Mobile**: 480px and below +- **Tablet**: 768px and below +- **Desktop**: 1024px and above +- **Large screens**: 1200px and above + +## ๐Ÿ”ง Browser Compatibility + +**Supported Browsers:** +- Chrome 60+ โœ… +- Firefox 55+ โœ… +- Safari 12+ โœ… +- Edge 79+ โœ… + +**Required Features:** +- CSS Grid and Flexbox +- JavaScript ES6+ (arrow functions, async/await) +- Local Storage API +- Fetch API + +## ๐Ÿš€ Deployment Options + +### **Static Hosting Services** +Perfect for this frontend-only website: + +**Netlify (Recommended)** +1. Drag and drop your project folder to [netlify.com](https://netlify.com) +2. Automatic HTTPS and CDN included +3. Custom domain support available + +**Vercel** +1. Sign up at [vercel.com](https://vercel.com) +2. Import from Git or upload files +3. Instant deployment with preview URLs + +**GitHub Pages** +1. Create a GitHub repository +2. Enable GitHub Pages in repository settings +3. Upload your files to the repository + +### **Traditional Web Hosting** +Upload all files to your web hosting provider's public directory (usually `public_html` or `www`). + +## ๐Ÿ›ก๏ธ Security & Privacy + +### **Data Handling** +- All form data is processed client-side +- Cart data stored in browser's local storage +- No personal data stored on servers +- EmailJS handles email transmission securely + +### **HTTPS Requirements** +- Required for production deployment +- Most static hosting services provide this automatically +- Necessary for some browser features to work properly + +## ๐Ÿ› Troubleshooting + +### **Products Not Loading** +1. Check browser console for errors +2. Ensure `cake_inventory.csv` is in the root directory +3. Verify CSV format matches expected columns +4. Check file permissions and CORS settings + +### **EmailJS Not Working** +1. Verify EmailJS configuration in `script.js` +2. Check EmailJS dashboard for service status +3. Ensure email templates are properly configured +4. Review browser console for API errors + +### **Images Not Displaying** +1. Check image file paths in CSV +2. Verify images exist in the `images/` directory +3. Ensure proper file extensions (.jpg, .png, .webp) +4. Check browser console for 404 errors + +### **Cart Not Persisting** +1. Ensure local storage is enabled in browser +2. Check for JavaScript errors in console +3. Verify domain consistency (don't mix http/https) + +## ๐Ÿ“ˆ Performance Optimization + +### **Image Optimization** +1. Compress images before uploading +2. Use appropriate formats (WebP when supported) +3. Implement lazy loading (already included) +4. Consider using a CDN for images + +### **Code Optimization** +1. Minify CSS and JavaScript for production +2. Enable gzip compression on server +3. Use browser caching headers +4. Consider implementing a service worker + +## ๐Ÿ”„ Updates & Maintenance + +### **Regular Tasks** +1. **Update Product Inventory**: Modify `cake_inventory.csv` as needed +2. **Add New Images**: Upload to `images/` directory +3. **Update Content**: Modify HTML content for seasonal changes +4. **Monitor Orders**: Check EmailJS dashboard regularly + +### **Seasonal Updates** +1. Update featured products for holidays +2. Add seasonal items to inventory +3. Update hero images for special occasions +4. Modify color scheme for seasonal themes + +## ๐Ÿ“ง Email Templates + +See [`EMAILJS_TEMPLATES.md`](EMAILJS_TEMPLATES.md) for: +- Customer order confirmation template +- Business notification template +- Newsletter subscription template +- Contact form auto-reply template + +## ๐Ÿค Support & Contribution + +### **Getting Help** +1. Check this README first +2. Review browser console for errors +3. Verify EmailJS configuration +4. Check CSV file format + +### **Feature Requests** +This is a complete, production-ready bakery website. Common customization requests: +- Online payment integration +- Inventory management system +- Customer account system +- Advanced booking calendar + +## ๐Ÿ“„ License + +This project is provided as-is for educational and commercial use. You may modify and distribute it according to your needs. + +## ๐ŸŽฏ Credits + +- **Design**: Custom bakery-themed design system +- **Icons**: Font Awesome 6.4.0 +- **Fonts**: Google Fonts (Playfair Display + Inter) +- **Images**: Unsplash (placeholder images) +- **Email Service**: EmailJS + +--- + +**Made with โค๏ธ for Sweet Dreams Bakery** + +For questions or support, please refer to the documentation files included in this project. \ No newline at end of file diff --git a/cake_inventory.csv b/cake_inventory.csv new file mode 100644 index 0000000..63af059 --- /dev/null +++ b/cake_inventory.csv @@ -0,0 +1,21 @@ +id,name,description,price,category,size_inches,serves_people,weight_kg,flavor,image_url,image_alt,stock_quantity,featured,custom_available,dietary_options,baker_name,date_created,sku,occasion_type +1,Classic Vanilla Wedding Cake,"Elegant three-tier vanilla sponge with buttercream roses and pearl details. Perfect centerpiece for your special day.",299.99,Wedding Cakes,10,50,3.5,Vanilla,https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Three-tier vanilla wedding cake with white buttercream roses,2,true,true,"gluten-free available, vegan available",Sarah Mitchell,2024-01-15,WED-VAN-001,wedding +2,Chocolate Decadence Birthday Cake,"Rich chocolate cake layered with dark chocolate ganache and fresh berries. A chocolate lover's dream.",89.99,Birthday Cakes,8,12,2.2,Dark Chocolate,https://images.unsplash.com/photo-1606313564200-e75d5e30476c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Dark chocolate birthday cake with ganache and berries,5,true,true,"gluten-free available",Sarah Mitchell,2024-01-20,BDAY-CHOC-002,birthday +3,Red Velvet Anniversary Cake,"Moist red velvet layers with cream cheese frosting and elegant white chocolate decorations.",125.00,Celebration Cakes,9,18,2.8,Red Velvet,https://images.unsplash.com/photo-1621303837174-89787a7d4729?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Red velvet anniversary cake with cream cheese frosting,3,false,true,"none available",Sarah Mitchell,2024-02-01,ANNIV-RV-003,anniversary +4,Lemon Bliss Cupcakes (Dozen),"Fresh lemon cupcakes topped with lemon buttercream and candied lemon zest. Light and refreshing.",36.00,Cupcakes & Minis,3,12,0.8,Lemon,https://images.unsplash.com/photo-1614707267537-b85aaf00c4b7?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Dozen lemon cupcakes with buttercream frosting,15,false,false,"gluten-free available, vegan available",Emma Thompson,2024-02-10,CUP-LEM-004,any +5,Strawberry Shortcake Supreme,"Traditional vanilla sponge layered with fresh strawberries and whipped cream. Summer perfection.",75.50,Specialty Desserts,7,8,1.5,Vanilla Berry,https://images.unsplash.com/photo-1565958011703-44f9829ba187?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Strawberry shortcake with fresh berries and cream,4,true,false,"gluten-free available",Sarah Mitchell,2024-02-15,SPEC-STRAW-005,summer +6,Custom Graduation Cake,"Personalized graduation cake with school colors and custom message. Choice of vanilla, chocolate, or funfetti.",95.00,Celebration Cakes,8,15,2.1,Custom Choice,https://images.unsplash.com/photo-1571115764595-644a1f56a55c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Custom graduation cake with cap and diploma decorations,0,false,true,"gluten-free available, vegan available",Emma Thompson,2024-03-01,GRAD-CUST-006,graduation +7,Funfetti Birthday Surprise,"Colorful funfetti cake with vanilla buttercream and rainbow sprinkles. Perfect for kids' parties.",65.00,Birthday Cakes,6,10,1.4,Funfetti,https://images.unsplash.com/photo-1563729784474-d77dbb933a9e?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Funfetti birthday cake with colorful sprinkles,8,false,true,"gluten-free available",Emma Thompson,2024-03-05,BDAY-FUN-007,birthday +8,Elegant Rose Garden Wedding Cake,"Four-tier masterpiece with hand-piped sugar roses and cascading pearl details.",450.00,Wedding Cakes,12,75,5.2,Vanilla Almond,https://images.unsplash.com/photo-1535254973040-607b474cb50d?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Four-tier wedding cake with sugar roses and pearls,1,true,true,"vegan available",Sarah Mitchell,2024-03-10,WED-ROSE-008,wedding +9,Carrot Cake with Cream Cheese,"Moist spiced carrot cake with walnuts and smooth cream cheese frosting. A classic favorite.",55.00,Specialty Desserts,6,8,1.6,Spiced Carrot,https://images.unsplash.com/photo-1621303837174-89787a7d4729?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Carrot cake slice with cream cheese frosting and walnuts,6,false,false,"gluten-free available",Sarah Mitchell,2024-03-15,SPEC-CAR-009,any +10,Mini Cheesecake Assortment (12),"Assorted mini cheesecakes: classic, chocolate, strawberry, and blueberry flavors.",48.00,Cupcakes & Minis,2,12,1.0,Assorted Cheesecake,https://images.unsplash.com/photo-1567306226416-28f0efdc88ce?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Assortment of twelve mini cheesecakes in various flavors,10,false,false,"gluten-free available",Emma Thompson,2024-03-20,MINI-CHEESE-010,any +11,Chocolate Ganache Tart,"Rich chocolate tart with smooth ganache filling and gold leaf accents. Sophisticated indulgence.",42.00,Specialty Desserts,5,6,0.9,Dark Chocolate,https://images.unsplash.com/photo-1551024506-0bccd828d307?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Dark chocolate ganache tart with gold leaf decoration,7,false,false,"gluten-free available, vegan available",Sarah Mitchell,2024-03-25,SPEC-TART-011,any +12,Seasonal Pumpkin Spice Cake,"Warm pumpkin spice cake with cinnamon cream cheese frosting and candied pecans.",70.00,Seasonal Items,7,10,1.8,Pumpkin Spice,https://images.unsplash.com/photo-1571115764595-644a1f56a55c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Pumpkin spice cake with cinnamon frosting and pecans,3,false,true,"gluten-free available",Emma Thompson,2024-04-01,SEAS-PUMP-012,fall +13,Baby Shower Buttercream Cake,"Delicate pastel cake with buttercream flowers and baby-themed decorations.",85.00,Celebration Cakes,8,12,2.0,Vanilla Strawberry,https://images.unsplash.com/photo-1488477304112-4944851de03d?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Pink and blue baby shower cake with buttercream flowers,4,false,true,"gluten-free available, vegan available",Emma Thompson,2024-04-05,BABY-SHOW-013,baby shower +14,Tiramisu Layer Cake,"Italian-inspired coffee-soaked layers with mascarpone cream and cocoa dusting.",95.00,Specialty Desserts,8,12,2.3,Coffee Mascarpone,https://images.unsplash.com/photo-1571877227200-a0d98ea607e9?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Tiramisu layer cake with mascarpone and coffee flavoring,2,true,false,"none available",Sarah Mitchell,2024-04-10,SPEC-TIRA-014,any +15,Valentine's Heart Cake,"Heart-shaped red velvet cake with romantic rose decorations and gold accents.",78.00,Seasonal Items,8,10,1.9,Red Velvet,https://images.unsplash.com/photo-1518047601542-79f18c655718?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Heart-shaped red velvet cake with roses and gold details,5,false,true,"gluten-free available",Sarah Mitchell,2024-04-15,SEAS-VAL-015,valentine +16,Coconut Cream Paradise,"Tropical coconut cake layers with coconut cream filling and toasted coconut flakes.",68.00,Specialty Desserts,7,10,1.7,Coconut,https://images.unsplash.com/photo-1464349095431-e9a21285b5f3?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Coconut cake with cream filling and toasted coconut,6,false,false,"gluten-free available, vegan available",Emma Thompson,2024-04-20,SPEC-COC-016,any +17,Birthday Number Cake,"Custom number-shaped cake for milestone birthdays. Choice of flavors and decorations.",120.00,Birthday Cakes,10,20,2.5,Custom Choice,https://images.unsplash.com/photo-1557925923-cd4648e211a0?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Large number-shaped birthday cake with custom decorations,1,false,true,"gluten-free available, vegan available",Sarah Mitchell,2024-04-25,BDAY-NUM-017,birthday +18,Luxury Chocolate Tower,"Five-tier chocolate masterpiece with gold details and fresh berries. Ultimate indulgence.",580.00,Wedding Cakes,14,100,7.8,Premium Chocolate,https://images.unsplash.com/photo-1464349095431-e9a21285b5f3?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Five-tier luxury chocolate wedding cake with gold and berries,1,true,true,"gluten-free available",Sarah Mitchell,2024-05-01,WED-LUX-018,wedding +19,Spring Lemon Elderflower,"Light lemon cake with elderflower buttercream and fresh flower decorations.",82.00,Seasonal Items,7,12,1.8,Lemon Elderflower,https://images.unsplash.com/photo-1486427944299-d1955d23e34d?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Spring cake with lemon elderflower flavor and fresh flowers,4,true,true,"gluten-free available, vegan available",Emma Thompson,2024-05-05,SEAS-SPRING-019,spring +20,Macaron Tower Centerpiece,"Elegant tower of assorted French macarons in pastel colors. Perfect wedding alternative.",185.00,Wedding Cakes,6,40,2.0,Assorted Macaron,https://images.unsplash.com/photo-1578662996442-48f60103fc96?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80,Elegant tower of colorful French macarons,2,false,false,"gluten-free available",Emma Thompson,2024-05-10,WED-MAC-020,wedding \ No newline at end of file diff --git a/images/baker-portrait.jpg b/images/baker-portrait.jpg new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/images/baker-portrait.jpg @@ -0,0 +1 @@ +placeholder diff --git a/images/chocolate-decadence.jpg b/images/chocolate-decadence.jpg new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/images/chocolate-decadence.jpg @@ -0,0 +1 @@ +placeholder diff --git a/images/hero-cake.jpg b/images/hero-cake.jpg new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/images/hero-cake.jpg @@ -0,0 +1 @@ +placeholder diff --git a/images/wedding-vanilla.jpg b/images/wedding-vanilla.jpg new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/images/wedding-vanilla.jpg @@ -0,0 +1 @@ +placeholder diff --git a/index.html b/index.html new file mode 100644 index 0000000..bd79428 --- /dev/null +++ b/index.html @@ -0,0 +1,602 @@ + + + + + + Sweet Dreams Bakery - Artisan Cakes & Desserts + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+

Artisan Cakes Made with Love

+

+ Creating unforgettable moments with handcrafted cakes and desserts. + From elegant wedding cakes to delightful birthday treats, every creation + is made with premium ingredients and artistic passion. +

+ +
+
+ Beautiful artisan wedding cake with roses +
+
+
+ + +
+
+
+

Our Signature Cakes

+

Discover our collection of handcrafted cakes and desserts

+
+ + +
+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+
+

Loading delicious cakes...

+
+ + +
+ +
+ + + +
+
+ + +
+
+
+
+

About Sweet Dreams Bakery

+

+ Founded in 2018 by master baker Sarah Mitchell, Sweet Dreams Bakery has been + creating extraordinary cakes and desserts that turn special moments into + unforgettable memories. With over 15 years of experience in fine pastry arts, + our team combines traditional techniques with innovative flavors. +

+
+
+ +

Award-Winning Quality

+

Recognized for excellence in cake design and taste

+
+
+ +

Premium Ingredients

+

Only the finest, locally-sourced ingredients

+
+
+ +

Custom Designs

+

Personalized creations for your special occasions

+
+
+
+
+ Sarah Mitchell, master baker +
+
+
+
+ + +
+
+
+

Our Baking Process

+

From consultation to delivery, we ensure perfection at every step

+
+ +
+
+
1
+
+

Consultation

+

We discuss your vision, dietary needs, and event details to create the perfect cake design.

+
+
+
+
2
+
+

Design & Planning

+

Our team creates detailed sketches and plans, selecting the finest ingredients for your cake.

+
+
+
+
3
+
+

Handcrafted Creation

+

Every element is carefully crafted by hand, from baking to decorating with artistic precision.

+
+
+
+
4
+
+

Quality Check & Delivery

+

Final quality inspection and professional delivery or pickup arranged at your convenience.

+
+
+
+
+
+ + + + + +
+
+
+
+

Get In Touch

+

+ Ready to create something special? Contact us for consultations, + custom orders, or any questions about our cakes and services. +

+ +
+
+ +
+

Address

+

123 Baker Street
Sweet Valley, CA 90210

+
+
+
+ +
+

Phone

+

(555) 123-CAKE

+
+
+
+ +
+

Email

+

orders@sweetdreamsbakery.com

+
+
+
+ +
+

Hours

+

Tue-Sat: 8AM-6PM
Sun: 9AM-4PM
Closed Mondays

+
+
+
+
+ +
+

Send us a message

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+
+
+
+ + + + + + + + + + + + + + + +
+
+ + +
+
+ + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..659a0c8 --- /dev/null +++ b/script.js @@ -0,0 +1,1017 @@ +// ===== GLOBAL VARIABLES ===== +let products = []; +let cart = JSON.parse(localStorage.getItem('sweetDreamsCart')) || []; +let filteredProducts = []; + +// EmailJS Configuration +const emailJSConfig = { + serviceID: 'YOUR_SERVICE_ID', // Replace with actual EmailJS service ID + templateID: 'YOUR_TEMPLATE_ID', // Replace with actual EmailJS template ID + userID: 'YOUR_USER_ID' // Replace with actual EmailJS user ID +}; + +// ===== INITIALIZATION ===== +document.addEventListener('DOMContentLoaded', function() { + initializeApp(); +}); + +function initializeApp() { + // Initialize EmailJS + if (typeof emailjs !== 'undefined') { + emailjs.init(emailJSConfig.userID); + } + + // Load products + loadProducts(); + + // Initialize event listeners + initializeEventListeners(); + + // Update cart UI + updateCartUI(); + + // Initialize smooth scrolling + initializeSmoothScrolling(); + + // Initialize header scroll effect + initializeHeaderEffects(); +} + +// ===== PRODUCT LOADING ===== +async function loadProducts() { + try { + showLoading(); + + const response = await fetch('cake_inventory.csv'); + const csvText = await response.text(); + + products = parseCSV(csvText); + filteredProducts = [...products]; + + hideLoading(); + renderProducts(filteredProducts); + + } catch (error) { + console.error('Error loading products:', error); + hideLoading(); + showError('Failed to load products. Using demo data.'); + + // Fallback to demo data if CSV fails to load + products = getDemoProducts(); + filteredProducts = [...products]; + renderProducts(filteredProducts); + } +} + +function parseCSV(csvText) { + const lines = csvText.trim().split('\n'); + const headers = lines[0].split(','); + const products = []; + + for (let i = 1; i < lines.length; i++) { + const values = parseCSVLine(lines[i]); + const product = {}; + + headers.forEach((header, index) => { + const key = header.trim(); + let value = values[index] ? values[index].trim() : ''; + + // Convert numeric fields + if (['id', 'price', 'size_inches', 'serves_people', 'weight_kg', 'stock_quantity'].includes(key)) { + value = parseFloat(value) || 0; + } + + // Convert boolean fields + if (['featured', 'custom_available'].includes(key)) { + value = value.toLowerCase() === 'true'; + } + + product[key] = value; + }); + + products.push(product); + } + + return products; +} + +function parseCSVLine(line) { + const result = []; + let current = ''; + let inQuotes = false; + + for (let i = 0; i < line.length; i++) { + const char = line[i]; + + if (char === '"') { + inQuotes = !inQuotes; + } else if (char === ',' && !inQuotes) { + result.push(current); + current = ''; + } else { + current += char; + } + } + + result.push(current); + return result; +} + +function getDemoProducts() { + // Fallback demo data in case CSV loading fails + return [ + { + id: 1, + name: "Classic Vanilla Wedding Cake", + description: "Elegant three-tier vanilla sponge with buttercream roses and pearl details. Perfect centerpiece for your special day.", + price: 299.99, + category: "Wedding Cakes", + size_inches: 10, + serves_people: 50, + weight_kg: 3.5, + flavor: "Vanilla", + image_url: "https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80", + image_alt: "Three-tier vanilla wedding cake with white buttercream roses", + stock_quantity: 2, + featured: true, + custom_available: true, + dietary_options: "gluten-free available, vegan available", + baker_name: "Sarah Mitchell", + occasion_type: "wedding" + }, + { + id: 2, + name: "Chocolate Decadence Birthday Cake", + description: "Rich chocolate cake layered with dark chocolate ganache and fresh berries. A chocolate lover's dream.", + price: 89.99, + category: "Birthday Cakes", + size_inches: 8, + serves_people: 12, + weight_kg: 2.2, + flavor: "Dark Chocolate", + image_url: "https://images.unsplash.com/photo-1606313564200-e75d5e30476c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80", + image_alt: "Dark chocolate birthday cake with ganache and berries", + stock_quantity: 5, + featured: true, + custom_available: true, + dietary_options: "gluten-free available", + baker_name: "Sarah Mitchell", + occasion_type: "birthday" + } + ]; +} + +// ===== PRODUCT RENDERING ===== +function renderProducts(productsToRender) { + const grid = document.getElementById('products-grid'); + const noResults = document.getElementById('no-results'); + + if (productsToRender.length === 0) { + grid.innerHTML = ''; + noResults.style.display = 'block'; + return; + } + + noResults.style.display = 'none'; + + const html = productsToRender.map(product => createProductCard(product)).join(''); + grid.innerHTML = html; + + // Add event listeners to product cards + addProductEventListeners(); +} + +function createProductCard(product) { + const isOutOfStock = product.stock_quantity === 0; + const featuredBadge = product.featured ? '
Featured
' : ''; + + return ` +
+
+ ${product.image_alt} + ${featuredBadge} +
+
+
${product.category}
+

${product.name}

+

${product.description}

+
+ Serves ${product.serves_people} + ${product.size_inches}" +
+ +
+
+ `; +} + +function addProductEventListeners() { + // Product card click to show details + document.querySelectorAll('.product__card').forEach(card => { + card.addEventListener('click', function(e) { + if (!e.target.closest('.add-to-cart')) { + const productId = parseInt(this.dataset.productId); + showProductDetails(productId); + } + }); + }); + + // Add to cart buttons + document.querySelectorAll('.add-to-cart').forEach(button => { + button.addEventListener('click', function(e) { + e.stopPropagation(); + const productId = parseInt(this.dataset.productId); + addToCart(productId); + }); + }); +} + +// ===== PRODUCT FILTERING & SEARCH ===== +function initializeFiltering() { + const searchInput = document.getElementById('search-input'); + const categoryFilter = document.getElementById('category-filter'); + const sortSelect = document.getElementById('sort-select'); + + searchInput.addEventListener('input', debounce(filterProducts, 300)); + categoryFilter.addEventListener('change', filterProducts); + sortSelect.addEventListener('change', filterProducts); +} + +function filterProducts() { + const searchTerm = document.getElementById('search-input').value.toLowerCase(); + const category = document.getElementById('category-filter').value; + const sortBy = document.getElementById('sort-select').value; + + // Filter by search term + filteredProducts = products.filter(product => { + const searchFields = [ + product.name, + product.description, + product.flavor, + product.category, + product.occasion_type + ].join(' ').toLowerCase(); + + return searchFields.includes(searchTerm); + }); + + // Filter by category + if (category !== 'all') { + filteredProducts = filteredProducts.filter(product => product.category === category); + } + + // Sort products + filteredProducts.sort((a, b) => { + switch (sortBy) { + case 'price-low': + return a.price - b.price; + case 'price-high': + return b.price - a.price; + case 'name': + return a.name.localeCompare(b.name); + case 'featured': + default: + return (b.featured ? 1 : 0) - (a.featured ? 1 : 0); + } + }); + + renderProducts(filteredProducts); +} + +// ===== SHOPPING CART ===== +function addToCart(productId, quantity = 1) { + const product = products.find(p => p.id === productId); + if (!product) return; + + if (product.stock_quantity === 0) { + showNotification('This item is currently out of stock', 'error'); + return; + } + + const existingItem = cart.find(item => item.id === productId); + + if (existingItem) { + const newQuantity = existingItem.quantity + quantity; + if (newQuantity <= product.stock_quantity) { + existingItem.quantity = newQuantity; + showNotification(`Updated ${product.name} quantity in cart`, 'success'); + } else { + showNotification(`Only ${product.stock_quantity} items available`, 'warning'); + return; + } + } else { + cart.push({ + id: product.id, + name: product.name, + price: product.price, + image_url: product.image_url, + quantity: quantity, + max_quantity: product.stock_quantity + }); + showNotification(`Added ${product.name} to cart`, 'success'); + } + + saveCart(); + updateCartUI(); +} + +function removeFromCart(productId) { + cart = cart.filter(item => item.id !== productId); + saveCart(); + updateCartUI(); + renderCartItems(); +} + +function updateCartQuantity(productId, quantity) { + const item = cart.find(item => item.id === productId); + if (!item) return; + + if (quantity <= 0) { + removeFromCart(productId); + return; + } + + if (quantity > item.max_quantity) { + showNotification(`Only ${item.max_quantity} items available`, 'warning'); + return; + } + + item.quantity = quantity; + saveCart(); + updateCartUI(); + renderCartItems(); +} + +function saveCart() { + localStorage.setItem('sweetDreamsCart', JSON.stringify(cart)); +} + +function updateCartUI() { + const cartCount = document.getElementById('cart-count'); + const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0); + cartCount.textContent = totalItems; + cartCount.style.display = totalItems > 0 ? 'flex' : 'none'; +} + +function getCartTotal() { + return cart.reduce((sum, item) => sum + (item.price * item.quantity), 0); +} + +// ===== MODAL MANAGEMENT ===== +function initializeModals() { + // Cart modal + const cartBtn = document.getElementById('cart-btn'); + const cartModal = document.getElementById('cart-modal'); + const cartClose = document.getElementById('cart-modal-close'); + + cartBtn.addEventListener('click', showCartModal); + cartClose.addEventListener('click', () => hideModal('cart-modal')); + + // Product modal + const productModal = document.getElementById('product-modal'); + const productClose = document.getElementById('product-modal-close'); + productClose.addEventListener('click', () => hideModal('product-modal')); + + // Checkout modal + const checkoutBtn = document.getElementById('checkout-btn'); + const checkoutModal = document.getElementById('checkout-modal'); + const checkoutClose = document.getElementById('checkout-modal-close'); + + checkoutBtn.addEventListener('click', showCheckoutModal); + checkoutClose.addEventListener('click', () => hideModal('checkout-modal')); + + // Close modals on backdrop click + [cartModal, productModal, checkoutModal].forEach(modal => { + modal.addEventListener('click', function(e) { + if (e.target === this) { + hideModal(this.id); + } + }); + }); + + // Close modals on Escape key + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + const activeModal = document.querySelector('.modal.active'); + if (activeModal) { + hideModal(activeModal.id); + } + } + }); +} + +function showModal(modalId) { + const modal = document.getElementById(modalId); + modal.classList.add('active'); + document.body.style.overflow = 'hidden'; +} + +function hideModal(modalId) { + const modal = document.getElementById(modalId); + modal.classList.remove('active'); + document.body.style.overflow = ''; +} + +function showCartModal() { + renderCartItems(); + showModal('cart-modal'); +} + +function renderCartItems() { + const cartItems = document.getElementById('cart-items'); + const cartEmpty = document.getElementById('cart-empty'); + const cartFooter = document.getElementById('cart-footer'); + const cartTotal = document.getElementById('cart-total'); + + if (cart.length === 0) { + cartItems.innerHTML = ''; + cartEmpty.style.display = 'block'; + cartFooter.style.display = 'none'; + return; + } + + cartEmpty.style.display = 'none'; + cartFooter.style.display = 'block'; + + const html = cart.map(item => ` +
+ ${item.name} +
+
${item.name}
+
$${item.price.toFixed(2)} each
+
+ + + + +
+
+
+ `).join(''); + + cartItems.innerHTML = html; + cartTotal.textContent = `$${getCartTotal().toFixed(2)}`; +} + +function showProductDetails(productId) { + const product = products.find(p => p.id === productId); + if (!product) return; + + const modalTitle = document.getElementById('product-modal-title'); + const productDetail = document.getElementById('product-detail'); + + modalTitle.textContent = product.name; + + const isOutOfStock = product.stock_quantity === 0; + + productDetail.innerHTML = ` +
+
+ ${product.image_alt} +
+
+
${product.category}
+

${product.name}

+

${product.description}

+ +
+

Specifications

+
    +
  • Size: ${product.size_inches}" diameter
  • +
  • Serves: ${product.serves_people} people
  • +
  • Weight: ${product.weight_kg} kg
  • +
  • Flavor: ${product.flavor}
  • +
  • Baker: ${product.baker_name}
  • +
+
+ + ${product.dietary_options && product.dietary_options !== 'none available' ? ` +
+

Dietary Options

+

${product.dietary_options}

+
+ ` : ''} + + ${product.custom_available ? ` +
+ + Custom designs available - contact us for personalization +
+ ` : ''} + +
+
$${product.price.toFixed(2)}
+ +
+ +
+ ${product.stock_quantity > 0 ? + ` ${product.stock_quantity} available` : + ' Currently out of stock' + } +
+
+
+ `; + + showModal('product-modal'); +} + +// ===== CHECKOUT ===== +function showCheckoutModal() { + if (cart.length === 0) { + showNotification('Your cart is empty', 'warning'); + return; + } + + renderOrderSummary(); + calculateOrderTotal(); + hideModal('cart-modal'); + showModal('checkout-modal'); +} + +function renderOrderSummary() { + const orderSummary = document.getElementById('order-summary'); + + const html = cart.map(item => ` +
+ ${item.name} ร— ${item.quantity} + $${(item.price * item.quantity).toFixed(2)} +
+ `).join(''); + + orderSummary.innerHTML = html; +} + +function calculateOrderTotal() { + const deliverySelect = document.getElementById('checkout-delivery'); + const subtotal = getCartTotal(); + const deliveryFee = deliverySelect.value === 'delivery' ? 15 : 0; + const total = subtotal + deliveryFee; + + document.getElementById('order-subtotal').textContent = `$${subtotal.toFixed(2)}`; + document.getElementById('order-delivery').textContent = `$${deliveryFee.toFixed(2)}`; + document.getElementById('order-total').textContent = `$${total.toFixed(2)}`; +} + +// ===== FORM HANDLING ===== +function initializeForms() { + // Contact form + const contactForm = document.getElementById('contact-form'); + contactForm.addEventListener('submit', handleContactForm); + + // Checkout form + const checkoutForm = document.getElementById('checkout-form'); + checkoutForm.addEventListener('submit', handleCheckoutForm); + + // Newsletter form + const newsletterForm = document.getElementById('newsletter-form'); + newsletterForm.addEventListener('submit', handleNewsletterForm); + + // Delivery method change + const deliverySelect = document.getElementById('checkout-delivery'); + deliverySelect.addEventListener('change', function() { + const deliveryAddress = document.getElementById('delivery-address'); + const isDelivery = this.value === 'delivery'; + + deliveryAddress.style.display = isDelivery ? 'block' : 'none'; + + // Update required attributes + const addressInputs = deliveryAddress.querySelectorAll('input'); + addressInputs.forEach(input => { + input.required = isDelivery; + }); + + calculateOrderTotal(); + }); +} + +async function handleContactForm(e) { + e.preventDefault(); + + const form = e.target; + const submitBtn = form.querySelector('button[type="submit"]'); + const formData = new FormData(form); + + // Show loading state + submitBtn.classList.add('loading'); + + try { + // Prepare email data + const emailData = { + from_name: formData.get('name'), + from_email: formData.get('email'), + phone: formData.get('phone') || 'Not provided', + inquiry_type: formData.get('inquiry_type'), + message: formData.get('message') + }; + + // Send email via EmailJS + if (typeof emailjs !== 'undefined' && emailJSConfig.serviceID !== 'YOUR_SERVICE_ID') { + await emailjs.send(emailJSConfig.serviceID, emailJSConfig.templateID, emailData); + showNotification('Message sent successfully! We\'ll get back to you soon.', 'success'); + } else { + // Demo mode - simulate success + await new Promise(resolve => setTimeout(resolve, 1000)); + showNotification('Demo mode: Message would be sent via EmailJS', 'info'); + console.log('Contact form data:', emailData); + } + + form.reset(); + + } catch (error) { + console.error('Error sending message:', error); + showNotification('Failed to send message. Please try again.', 'error'); + } finally { + submitBtn.classList.remove('loading'); + } +} + +async function handleCheckoutForm(e) { + e.preventDefault(); + + const form = e.target; + const submitBtn = form.querySelector('button[type="submit"]'); + const formData = new FormData(form); + + // Validate form + if (!validateCheckoutForm(formData)) { + return; + } + + // Show loading state + submitBtn.classList.add('loading'); + + try { + // Prepare order data + const orderData = { + customer: { + firstName: formData.get('first_name'), + lastName: formData.get('last_name'), + email: formData.get('email'), + phone: formData.get('phone') + }, + delivery: { + method: formData.get('delivery_method'), + address: formData.get('address') || 'Pickup at bakery', + city: formData.get('city') || '', + zip: formData.get('zip') || '' + }, + event: { + date: formData.get('event_date'), + time: formData.get('event_time') || 'Flexible', + specialRequests: formData.get('special_requests') || 'None' + }, + items: cart, + totals: { + subtotal: getCartTotal(), + delivery: formData.get('delivery_method') === 'delivery' ? 15 : 0, + total: getCartTotal() + (formData.get('delivery_method') === 'delivery' ? 15 : 0) + }, + orderDate: new Date().toISOString() + }; + + // Send order via EmailJS + if (typeof emailjs !== 'undefined' && emailJSConfig.serviceID !== 'YOUR_SERVICE_ID') { + await sendOrderEmails(orderData); + showNotification('Order placed successfully! Check your email for confirmation.', 'success'); + } else { + // Demo mode - simulate success + await new Promise(resolve => setTimeout(resolve, 2000)); + showNotification('Demo mode: Order would be processed via EmailJS', 'info'); + console.log('Order data:', orderData); + } + + // Clear cart and close modal + cart = []; + saveCart(); + updateCartUI(); + hideModal('checkout-modal'); + + // Show success message + showOrderConfirmation(orderData); + + } catch (error) { + console.error('Error processing order:', error); + showNotification('Failed to process order. Please try again.', 'error'); + } finally { + submitBtn.classList.remove('loading'); + } +} + +async function handleNewsletterForm(e) { + e.preventDefault(); + + const form = e.target; + const email = form.querySelector('input[type="email"]').value; + + try { + // In a real application, this would be sent to your email service + console.log('Newsletter subscription:', email); + showNotification('Successfully subscribed to newsletter!', 'success'); + form.reset(); + } catch (error) { + showNotification('Failed to subscribe. Please try again.', 'error'); + } +} + +function validateCheckoutForm(formData) { + const requiredFields = ['first_name', 'last_name', 'email', 'phone', 'delivery_method', 'event_date']; + + for (const field of requiredFields) { + if (!formData.get(field)) { + showNotification(`Please fill in the ${field.replace('_', ' ')} field`, 'warning'); + return false; + } + } + + // Validate email + const email = formData.get('email'); + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + showNotification('Please enter a valid email address', 'warning'); + return false; + } + + // Validate event date (should be in the future) + const eventDate = new Date(formData.get('event_date')); + const today = new Date(); + today.setHours(0, 0, 0, 0); + + if (eventDate < today) { + showNotification('Event date must be in the future', 'warning'); + return false; + } + + return true; +} + +// ===== EMAIL INTEGRATION ===== +async function sendOrderEmails(orderData) { + // Prepare email templates + const customerEmailData = { + to_name: `${orderData.customer.firstName} ${orderData.customer.lastName}`, + to_email: orderData.customer.email, + order_number: generateOrderNumber(), + order_items: formatOrderItems(orderData.items), + order_total: orderData.totals.total.toFixed(2), + event_date: orderData.event.date, + delivery_method: orderData.delivery.method, + special_requests: orderData.event.specialRequests + }; + + const businessEmailData = { + customer_name: `${orderData.customer.firstName} ${orderData.customer.lastName}`, + customer_email: orderData.customer.email, + customer_phone: orderData.customer.phone, + order_details: JSON.stringify(orderData, null, 2) + }; + + // Send customer confirmation email + await emailjs.send(emailJSConfig.serviceID, 'customer_confirmation', customerEmailData); + + // Send business notification email + await emailjs.send(emailJSConfig.serviceID, 'business_notification', businessEmailData); +} + +function generateOrderNumber() { + const timestamp = Date.now().toString().slice(-6); + const random = Math.random().toString(36).substr(2, 3).toUpperCase(); + return `SD${timestamp}${random}`; +} + +function formatOrderItems(items) { + return items.map(item => + `${item.name} (Quantity: ${item.quantity}) - $${(item.price * item.quantity).toFixed(2)}` + ).join('\n'); +} + +// ===== NAVIGATION & UI ===== +function initializeNavigation() { + const navToggle = document.getElementById('nav-toggle'); + const navClose = document.getElementById('nav-close'); + const navMenu = document.getElementById('nav-menu'); + const navLinks = document.querySelectorAll('.nav__link'); + + // Mobile menu toggle + navToggle.addEventListener('click', () => { + navMenu.classList.add('show-menu'); + }); + + navClose.addEventListener('click', () => { + navMenu.classList.remove('show-menu'); + }); + + // Close menu on link click + navLinks.forEach(link => { + link.addEventListener('click', () => { + navMenu.classList.remove('show-menu'); + }); + }); + + // Active link highlighting + updateActiveLink(); + window.addEventListener('scroll', updateActiveLink); +} + +function updateActiveLink() { + const sections = document.querySelectorAll('section[id]'); + const navLinks = document.querySelectorAll('.nav__link'); + + let current = ''; + + sections.forEach(section => { + const sectionTop = section.offsetTop - 100; + const sectionHeight = section.offsetHeight; + + if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) { + current = section.getAttribute('id'); + } + }); + + navLinks.forEach(link => { + link.classList.remove('active-link'); + if (link.getAttribute('href') === `#${current}`) { + link.classList.add('active-link'); + } + }); +} + +function initializeSmoothScrolling() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function(e) { + e.preventDefault(); + const target = document.querySelector(this.getAttribute('href')); + if (target) { + const headerHeight = document.querySelector('.header').offsetHeight; + const targetPosition = target.offsetTop - headerHeight; + + window.scrollTo({ + top: targetPosition, + behavior: 'smooth' + }); + } + }); + }); +} + +function initializeHeaderEffects() { + const header = document.getElementById('header'); + + window.addEventListener('scroll', () => { + if (window.scrollY > 100) { + header.style.background = 'rgba(250, 248, 245, 0.98)'; + header.style.boxShadow = '0 2px 20px rgba(61, 53, 48, 0.1)'; + } else { + header.style.background = 'rgba(250, 248, 245, 0.95)'; + header.style.boxShadow = 'none'; + } + }); +} + +// ===== UTILITY FUNCTIONS ===== +function showLoading() { + document.getElementById('products-loading').style.display = 'block'; +} + +function hideLoading() { + document.getElementById('products-loading').style.display = 'none'; +} + +function showNotification(message, type = 'info') { + const notification = document.getElementById('notification'); + const icon = notification.querySelector('.notification__icon'); + const messageElement = notification.querySelector('.notification__message'); + + // Set icon based on type + const icons = { + success: 'fas fa-check-circle', + error: 'fas fa-exclamation-circle', + warning: 'fas fa-exclamation-triangle', + info: 'fas fa-info-circle' + }; + + icon.className = `notification__icon ${icons[type]}`; + messageElement.textContent = message; + notification.className = `notification ${type} show`; + + // Auto-hide after 5 seconds + setTimeout(() => { + notification.classList.remove('show'); + }, 5000); +} + +function showError(message) { + showNotification(message, 'error'); +} + +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +function showOrderConfirmation(orderData) { + const confirmationModal = document.createElement('div'); + confirmationModal.className = 'modal active'; + confirmationModal.innerHTML = ` + + `; + + document.body.appendChild(confirmationModal); + + // Auto-remove after user interaction + confirmationModal.addEventListener('click', function(e) { + if (e.target === this || e.target.closest('.modal__close')) { + this.remove(); + } + }); +} + +// ===== EVENT LISTENERS INITIALIZATION ===== +function initializeEventListeners() { + initializeNavigation(); + initializeModals(); + initializeForms(); + initializeFiltering(); + + // Close notifications + document.addEventListener('click', function(e) { + if (e.target.closest('.notification')) { + e.target.closest('.notification').classList.remove('show'); + } + }); +} + +// ===== ERROR HANDLING ===== +window.addEventListener('error', function(e) { + console.error('Application error:', e.error); + showNotification('An unexpected error occurred. Please refresh the page.', 'error'); +}); + +// ===== SERVICE WORKER (OPTIONAL) ===== +if ('serviceWorker' in navigator) { + window.addEventListener('load', function() { + navigator.serviceWorker.register('/sw.js') + .then(function(registration) { + console.log('ServiceWorker registration successful'); + }, function(err) { + console.log('ServiceWorker registration failed'); + }); + }); +} \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..cb5a104 --- /dev/null +++ b/styles.css @@ -0,0 +1,1423 @@ +/* ===== CSS VARIABLES ===== */ +:root { + /* Bakery Color Palette */ + --color-primary: #F4B8C3; /* Soft pink frosting */ + --color-primary-dark: #E8A2AE; /* Deeper pink */ + --color-secondary: #FFF5E6; /* Cream/vanilla */ + --color-accent: #8B4B73; /* Rich berry */ + --color-accent-light: #A65D8A; + --color-chocolate: #4A2C2A; /* Dark chocolate brown */ + --color-caramel: #D4A574; /* Golden caramel */ + --color-mint: #B8D4C2; /* Soft mint green */ + + /* Neutral Colors */ + --color-white: #FFFFFF; + --color-cream: #FAF8F5; + --color-light-gray: #F8F6F3; + --color-gray: #E5E1DC; + --color-dark-gray: #8B8680; + --color-text: #3D3530; /* Warm dark brown */ + --color-text-light: #6B6560; + + /* Status Colors */ + --color-success: #7FB069; + --color-error: #E07A5F; + --color-warning: #F4A261; + --color-info: #457B9D; + + /* Gradients */ + --gradient-primary: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%); + --gradient-hero: linear-gradient(135deg, var(--color-secondary) 0%, var(--color-cream) 50%, #FDF4E8 100%); + --gradient-accent: linear-gradient(135deg, var(--color-accent) 0%, var(--color-accent-light) 100%); + + /* Typography */ + --font-display: 'Playfair Display', serif; + --font-body: 'Inter', sans-serif; + --font-size-xs: 0.75rem; + --font-size-sm: 0.875rem; + --font-size-base: 1rem; + --font-size-lg: 1.125rem; + --font-size-xl: 1.25rem; + --font-size-2xl: 1.5rem; + --font-size-3xl: 1.875rem; + --font-size-4xl: 2.25rem; + --font-size-5xl: 3rem; + --font-weight-light: 300; + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + /* Spacing */ + --spacing-xs: 0.25rem; + --spacing-sm: 0.5rem; + --spacing-md: 1rem; + --spacing-lg: 1.5rem; + --spacing-xl: 2rem; + --spacing-2xl: 3rem; + --spacing-3xl: 4rem; + + /* Layout */ + --container-max-width: 1200px; + --header-height: 80px; + --border-radius-sm: 0.5rem; + --border-radius-md: 0.75rem; + --border-radius-lg: 1rem; + --border-radius-xl: 1.5rem; + + /* Shadows */ + --shadow-sm: 0 2px 8px rgba(61, 53, 48, 0.08); + --shadow-md: 0 4px 16px rgba(61, 53, 48, 0.12); + --shadow-lg: 0 8px 32px rgba(61, 53, 48, 0.16); + --shadow-xl: 0 16px 64px rgba(61, 53, 48, 0.2); + + /* Transitions */ + --transition-fast: 0.2s ease; + --transition-normal: 0.3s ease; + --transition-slow: 0.5s ease; + + /* Z-index */ + --z-modal: 1000; + --z-header: 100; + --z-dropdown: 50; +} + +/* ===== RESET & BASE ===== */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; + font-size: 16px; +} + +body { + font-family: var(--font-body); + font-size: var(--font-size-base); + font-weight: var(--font-weight-normal); + line-height: 1.6; + color: var(--color-text); + background-color: var(--color-cream); + overflow-x: hidden; +} + +/* ===== TYPOGRAPHY ===== */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-display); + font-weight: var(--font-weight-semibold); + line-height: 1.2; + margin-bottom: var(--spacing-md); + color: var(--color-chocolate); +} + +h1 { + font-size: var(--font-size-5xl); + font-weight: var(--font-weight-bold); +} + +h2 { + font-size: var(--font-size-4xl); +} + +h3 { + font-size: var(--font-size-3xl); +} + +h4 { + font-size: var(--font-size-2xl); +} + +p { + margin-bottom: var(--spacing-md); + line-height: 1.7; +} + +a { + color: var(--color-accent); + text-decoration: none; + transition: color var(--transition-fast); +} + +a:hover { + color: var(--color-accent-light); +} + +/* ===== UTILITY CLASSES ===== */ +.container { + max-width: var(--container-max-width); + margin: 0 auto; + padding: 0 var(--spacing-lg); +} + +.section__header { + text-align: center; + margin-bottom: var(--spacing-3xl); +} + +.section__title { + font-size: var(--font-size-4xl); + margin-bottom: var(--spacing-md); + position: relative; +} + +.section__title::after { + content: ''; + position: absolute; + bottom: -0.5rem; + left: 50%; + transform: translateX(-50%); + width: 60px; + height: 3px; + background: var(--gradient-primary); + border-radius: 2px; +} + +.section__subtitle { + font-size: var(--font-size-lg); + color: var(--color-text-light); + max-width: 600px; + margin: 0 auto; +} + +/* ===== BUTTONS ===== */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: var(--spacing-md) var(--spacing-xl); + font-family: var(--font-body); + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + text-decoration: none; + border: none; + border-radius: var(--border-radius-md); + cursor: pointer; + transition: all var(--transition-normal); + position: relative; + overflow: hidden; + min-height: 48px; +} + +.btn--primary { + background: var(--gradient-primary); + color: var(--color-white); + box-shadow: var(--shadow-sm); +} + +.btn--primary:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-md); + color: var(--color-white); +} + +.btn--secondary { + background: transparent; + color: var(--color-accent); + border: 2px solid var(--color-accent); +} + +.btn--secondary:hover { + background: var(--color-accent); + color: var(--color-white); + transform: translateY(-2px); +} + +.btn--full { + width: 100%; +} + +.btn__loading { + display: none; +} + +.btn.loading .btn__text { + display: none; +} + +.btn.loading .btn__loading { + display: flex; +} + +/* ===== HEADER ===== */ +.header { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: var(--header-height); + background: rgba(250, 248, 245, 0.95); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--color-gray); + z-index: var(--z-header); + transition: all var(--transition-normal); +} + +.nav { + display: flex; + align-items: center; + justify-content: space-between; + height: 100%; +} + +.nav__logo { + display: flex; + align-items: center; + gap: var(--spacing-sm); + font-family: var(--font-display); + font-size: var(--font-size-xl); + font-weight: var(--font-weight-bold); + color: var(--color-chocolate); +} + +.nav__logo i { + font-size: var(--font-size-2xl); + color: var(--color-primary); +} + +.nav__menu { + display: flex; + align-items: center; +} + +.nav__list { + display: flex; + list-style: none; + gap: var(--spacing-xl); + margin: 0; +} + +.nav__link { + font-weight: var(--font-weight-medium); + color: var(--color-text); + transition: color var(--transition-fast); + position: relative; +} + +.nav__link::after { + content: ''; + position: absolute; + bottom: -4px; + left: 0; + width: 0; + height: 2px; + background: var(--gradient-primary); + transition: width var(--transition-fast); +} + +.nav__link:hover::after, +.nav__link.active-link::after { + width: 100%; +} + +.nav__actions { + display: flex; + align-items: center; + gap: var(--spacing-md); +} + +.nav__cart { + position: relative; + background: none; + border: none; + font-size: var(--font-size-xl); + color: var(--color-accent); + cursor: pointer; + transition: color var(--transition-fast); + padding: var(--spacing-sm); +} + +.nav__cart:hover { + color: var(--color-accent-light); +} + +.cart-count { + position: absolute; + top: -4px; + right: -4px; + background: var(--color-accent); + color: var(--color-white); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-bold); + padding: 2px 6px; + border-radius: 50px; + min-width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; +} + +.nav__toggle, +.nav__close { + display: none; + background: none; + border: none; + font-size: var(--font-size-xl); + color: var(--color-text); + cursor: pointer; +} + +/* ===== HERO SECTION ===== */ +.hero { + background: var(--gradient-hero); + padding: calc(var(--header-height) + var(--spacing-3xl)) 0 var(--spacing-3xl); + min-height: 100vh; + display: flex; + align-items: center; +} + +.hero__container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-3xl); + align-items: center; +} + +.hero__title { + font-size: var(--font-size-5xl); + margin-bottom: var(--spacing-lg); + background: linear-gradient(135deg, var(--color-chocolate), var(--color-accent)); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.hero__description { + font-size: var(--font-size-lg); + color: var(--color-text-light); + margin-bottom: var(--spacing-xl); + line-height: 1.8; +} + +.hero__buttons { + display: flex; + gap: var(--spacing-lg); + flex-wrap: wrap; +} + +.hero__image { + position: relative; +} + +.hero__image img { + width: 100%; + height: auto; + border-radius: var(--border-radius-xl); + box-shadow: var(--shadow-lg); +} + +/* ===== PRODUCTS SECTION ===== */ +.products { + padding: var(--spacing-3xl) 0; + background: var(--color-white); +} + +.products__controls { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: var(--spacing-lg); + margin-bottom: var(--spacing-2xl); + align-items: end; +} + +.search__container { + position: relative; +} + +.search__input { + width: 100%; + padding: var(--spacing-md) var(--spacing-md) var(--spacing-md) var(--spacing-3xl); + border: 2px solid var(--color-gray); + border-radius: var(--border-radius-md); + font-size: var(--font-size-base); + background: var(--color-white); + transition: border-color var(--transition-fast); +} + +.search__input:focus { + outline: none; + border-color: var(--color-primary); +} + +.search__icon { + position: absolute; + left: var(--spacing-md); + top: 50%; + transform: translateY(-50%); + color: var(--color-dark-gray); +} + +.filter__select, +.sort__select { + width: 100%; + padding: var(--spacing-md); + border: 2px solid var(--color-gray); + border-radius: var(--border-radius-md); + font-size: var(--font-size-base); + background: var(--color-white); + cursor: pointer; + transition: border-color var(--transition-fast); +} + +.filter__select:focus, +.sort__select:focus { + outline: none; + border-color: var(--color-primary); +} + +.loading { + text-align: center; + padding: var(--spacing-3xl); +} + +.loading__spinner { + width: 40px; + height: 40px; + border: 4px solid var(--color-gray); + border-top: 4px solid var(--color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto var(--spacing-md); +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.products__grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-xl); +} + +.product__card { + background: var(--color-white); + border-radius: var(--border-radius-lg); + box-shadow: var(--shadow-sm); + overflow: hidden; + transition: all var(--transition-normal); + cursor: pointer; +} + +.product__card:hover { + transform: translateY(-8px); + box-shadow: var(--shadow-lg); +} + +.product__image { + position: relative; + overflow: hidden; + height: 250px; +} + +.product__image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform var(--transition-slow); +} + +.product__card:hover .product__image img { + transform: scale(1.05); +} + +.product__badge { + position: absolute; + top: var(--spacing-md); + left: var(--spacing-md); + background: var(--gradient-accent); + color: var(--color-white); + padding: var(--spacing-xs) var(--spacing-sm); + border-radius: var(--border-radius-sm); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); +} + +.product__content { + padding: var(--spacing-lg); +} + +.product__category { + font-size: var(--font-size-sm); + color: var(--color-accent); + font-weight: var(--font-weight-medium); + margin-bottom: var(--spacing-xs); +} + +.product__name { + font-size: var(--font-size-xl); + font-weight: var(--font-weight-semibold); + margin-bottom: var(--spacing-sm); + color: var(--color-chocolate); +} + +.product__description { + color: var(--color-text-light); + font-size: var(--font-size-sm); + margin-bottom: var(--spacing-md); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.product__meta { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--spacing-md); + font-size: var(--font-size-sm); + color: var(--color-text-light); +} + +.product__footer { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--spacing-md); +} + +.product__price { + font-family: var(--font-display); + font-size: var(--font-size-2xl); + font-weight: var(--font-weight-bold); + color: var(--color-accent); +} + +.add-to-cart { + background: var(--gradient-primary); + color: var(--color-white); + border: none; + padding: var(--spacing-sm) var(--spacing-md); + border-radius: var(--border-radius-md); + font-weight: var(--font-weight-medium); + cursor: pointer; + transition: all var(--transition-fast); + display: flex; + align-items: center; + gap: var(--spacing-xs); +} + +.add-to-cart:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-sm); +} + +.no-results { + text-align: center; + padding: var(--spacing-3xl); + color: var(--color-text-light); +} + +.no-results i { + font-size: var(--font-size-4xl); + margin-bottom: var(--spacing-lg); + color: var(--color-dark-gray); +} + +/* ===== ABOUT SECTION ===== */ +.about { + padding: var(--spacing-3xl) 0; + background: var(--color-light-gray); +} + +.about__container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-3xl); + align-items: center; +} + +.about__description { + font-size: var(--font-size-lg); + line-height: 1.8; + margin-bottom: var(--spacing-xl); +} + +.about__features { + display: grid; + gap: var(--spacing-lg); +} + +.feature { + display: flex; + gap: var(--spacing-md); + align-items: flex-start; +} + +.feature i { + font-size: var(--font-size-2xl); + color: var(--color-primary); + margin-top: var(--spacing-xs); +} + +.feature h3 { + font-size: var(--font-size-lg); + margin-bottom: var(--spacing-xs); +} + +.feature p { + color: var(--color-text-light); + margin: 0; +} + +.about__image { + position: relative; +} + +.about__image img { + width: 100%; + height: auto; + border-radius: var(--border-radius-xl); + box-shadow: var(--shadow-lg); +} + +/* ===== PROCESS SECTION ===== */ +.process { + padding: var(--spacing-3xl) 0; + background: var(--color-white); +} + +.process__steps { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-xl); +} + +.step { + text-align: center; + padding: var(--spacing-xl); + border-radius: var(--border-radius-lg); + background: var(--color-light-gray); + position: relative; +} + +.step__number { + display: inline-flex; + align-items: center; + justify-content: center; + width: 60px; + height: 60px; + background: var(--gradient-primary); + color: var(--color-white); + border-radius: 50%; + font-family: var(--font-display); + font-size: var(--font-size-2xl); + font-weight: var(--font-weight-bold); + margin-bottom: var(--spacing-lg); +} + +.step h3 { + font-size: var(--font-size-xl); + margin-bottom: var(--spacing-md); +} + +.step p { + color: var(--color-text-light); + margin: 0; +} + +/* ===== GALLERY SECTION ===== */ +.gallery { + padding: var(--spacing-3xl) 0; + background: var(--color-light-gray); +} + +.gallery__grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-lg); +} + +.gallery__item { + position: relative; + overflow: hidden; + border-radius: var(--border-radius-lg); + aspect-ratio: 1; + cursor: pointer; +} + +.gallery__item img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform var(--transition-slow); +} + +.gallery__item:hover img { + transform: scale(1.05); +} + +/* ===== CONTACT SECTION ===== */ +.contact { + padding: var(--spacing-3xl) 0; + background: var(--color-white); +} + +.contact__container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-3xl); +} + +.contact__description { + font-size: var(--font-size-lg); + margin-bottom: var(--spacing-xl); +} + +.contact__info { + display: grid; + gap: var(--spacing-lg); +} + +.contact__item { + display: flex; + gap: var(--spacing-md); + align-items: flex-start; +} + +.contact__item i { + font-size: var(--font-size-xl); + color: var(--color-primary); + margin-top: var(--spacing-xs); + min-width: 24px; +} + +.contact__item h4 { + font-size: var(--font-size-lg); + margin-bottom: var(--spacing-xs); +} + +.contact__item p { + color: var(--color-text-light); + margin: 0; +} + +/* ===== FORMS ===== */ +.contact__form, +.checkout__form { + background: var(--color-light-gray); + padding: var(--spacing-xl); + border-radius: var(--border-radius-lg); +} + +.form__group { + position: relative; + margin-bottom: var(--spacing-lg); +} + +.form__input { + width: 100%; + padding: var(--spacing-md); + border: 2px solid var(--color-gray); + border-radius: var(--border-radius-md); + font-size: var(--font-size-base); + font-family: var(--font-body); + background: var(--color-white); + transition: all var(--transition-fast); +} + +.form__input:focus { + outline: none; + border-color: var(--color-primary); +} + +.form__input:focus + .form__label, +.form__input:not(:placeholder-shown) + .form__label { + transform: translateY(-100%) scale(0.85); + color: var(--color-primary); +} + +.form__label { + position: absolute; + left: var(--spacing-md); + top: 50%; + transform: translateY(-50%); + color: var(--color-dark-gray); + font-size: var(--font-size-base); + pointer-events: none; + transition: all var(--transition-fast); + background: var(--color-white); + padding: 0 var(--spacing-xs); +} + +.form__textarea { + min-height: 120px; + resize: vertical; +} + +.form__row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-lg); +} + +/* ===== FOOTER ===== */ +.footer { + background: var(--color-chocolate); + color: var(--color-white); + padding: var(--spacing-3xl) 0 var(--spacing-xl); +} + +.footer__container { + display: grid; + gap: var(--spacing-xl); +} + +.footer__content { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-xl); +} + +.footer__logo { + display: flex; + align-items: center; + gap: var(--spacing-sm); + font-family: var(--font-display); + font-size: var(--font-size-xl); + font-weight: var(--font-weight-bold); + margin-bottom: var(--spacing-lg); +} + +.footer__logo i { + font-size: var(--font-size-2xl); + color: var(--color-primary); +} + +.footer__description { + color: rgba(255, 255, 255, 0.8); + margin-bottom: var(--spacing-lg); +} + +.footer__social { + display: flex; + gap: var(--spacing-md); +} + +.footer__social-link { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + background: rgba(255, 255, 255, 0.1); + border-radius: 50%; + color: var(--color-white); + transition: all var(--transition-fast); +} + +.footer__social-link:hover { + background: var(--color-primary); + transform: translateY(-2px); +} + +.footer__title { + font-size: var(--font-size-lg); + margin-bottom: var(--spacing-md); + color: var(--color-white); +} + +.footer__links { + list-style: none; +} + +.footer__links li { + margin-bottom: var(--spacing-sm); +} + +.footer__links a { + color: rgba(255, 255, 255, 0.8); + transition: color var(--transition-fast); +} + +.footer__links a:hover { + color: var(--color-primary); +} + +.newsletter__form { + display: flex; + margin-top: var(--spacing-md); +} + +.newsletter__input { + flex: 1; + padding: var(--spacing-sm) var(--spacing-md); + border: none; + border-radius: var(--border-radius-md) 0 0 var(--border-radius-md); + background: var(--color-white); +} + +.newsletter__btn { + padding: var(--spacing-sm) var(--spacing-md); + background: var(--gradient-primary); + border: none; + border-radius: 0 var(--border-radius-md) var(--border-radius-md) 0; + color: var(--color-white); + cursor: pointer; + transition: all var(--transition-fast); +} + +.newsletter__btn:hover { + background: var(--color-accent); +} + +.footer__bottom { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: var(--spacing-xl); + border-top: 1px solid rgba(255, 255, 255, 0.2); + color: rgba(255, 255, 255, 0.8); +} + +.footer__legal { + display: flex; + gap: var(--spacing-lg); +} + +.footer__legal a { + color: rgba(255, 255, 255, 0.6); + font-size: var(--font-size-sm); +} + +/* ===== MODALS ===== */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: none; + align-items: center; + justify-content: center; + z-index: var(--z-modal); + padding: var(--spacing-lg); +} + +.modal.active { + display: flex; +} + +.modal__content { + background: var(--color-white); + border-radius: var(--border-radius-lg); + max-width: 500px; + width: 100%; + max-height: 90vh; + overflow-y: auto; + animation: modalSlideIn 0.3s ease; +} + +.modal__content--large { + max-width: 800px; +} + +@keyframes modalSlideIn { + from { + transform: scale(0.8); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +.modal__header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-lg); + border-bottom: 1px solid var(--color-gray); +} + +.modal__title { + margin: 0; + font-size: var(--font-size-xl); +} + +.modal__close { + background: none; + border: none; + font-size: var(--font-size-xl); + color: var(--color-text); + cursor: pointer; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all var(--transition-fast); +} + +.modal__close:hover { + background: var(--color-gray); +} + +.modal__body { + padding: var(--spacing-lg); +} + +.modal__footer { + padding: var(--spacing-lg); + border-top: 1px solid var(--color-gray); +} + +/* ===== CART ===== */ +.cart__items { + max-height: 400px; + overflow-y: auto; +} + +.cart__item { + display: flex; + gap: var(--spacing-md); + padding: var(--spacing-md) 0; + border-bottom: 1px solid var(--color-gray); +} + +.cart__item:last-child { + border-bottom: none; +} + +.cart__item-image { + width: 80px; + height: 80px; + border-radius: var(--border-radius-md); + object-fit: cover; +} + +.cart__item-content { + flex: 1; +} + +.cart__item-name { + font-weight: var(--font-weight-medium); + margin-bottom: var(--spacing-xs); +} + +.cart__item-price { + color: var(--color-accent); + font-weight: var(--font-weight-semibold); +} + +.cart__item-controls { + display: flex; + align-items: center; + gap: var(--spacing-sm); + margin-top: var(--spacing-sm); +} + +.quantity-btn { + width: 30px; + height: 30px; + border: 1px solid var(--color-gray); + background: var(--color-white); + border-radius: var(--border-radius-sm); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-fast); +} + +.quantity-btn:hover { + background: var(--color-primary); + color: var(--color-white); + border-color: var(--color-primary); +} + +.quantity-input { + width: 50px; + text-align: center; + border: 1px solid var(--color-gray); + border-radius: var(--border-radius-sm); + padding: var(--spacing-xs); +} + +.remove-item { + background: var(--color-error); + color: var(--color-white); + border: none; + padding: var(--spacing-xs) var(--spacing-sm); + border-radius: var(--border-radius-sm); + font-size: var(--font-size-xs); + cursor: pointer; + transition: all var(--transition-fast); +} + +.remove-item:hover { + background: #d4624a; +} + +.cart__total { + display: flex; + justify-content: space-between; + align-items: center; + font-size: var(--font-size-lg); + font-weight: var(--font-weight-semibold); + margin-bottom: var(--spacing-md); +} + +.cart__empty { + text-align: center; + padding: var(--spacing-3xl); + color: var(--color-text-light); +} + +.cart__empty i { + font-size: var(--font-size-4xl); + margin-bottom: var(--spacing-md); +} + +/* ===== CHECKOUT ===== */ +.checkout__section { + margin-bottom: var(--spacing-xl); + padding-bottom: var(--spacing-lg); + border-bottom: 1px solid var(--color-gray); +} + +.checkout__section:last-child { + border-bottom: none; + margin-bottom: 0; +} + +.checkout__section h4 { + margin-bottom: var(--spacing-md); + color: var(--color-chocolate); +} + +.order__summary { + margin-bottom: var(--spacing-lg); +} + +.order__item { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-sm) 0; + border-bottom: 1px solid var(--color-gray); +} + +.order__item:last-child { + border-bottom: none; +} + +.order__total { + background: var(--color-light-gray); + padding: var(--spacing-md); + border-radius: var(--border-radius-md); +} + +.total__row { + display: flex; + justify-content: space-between; + margin-bottom: var(--spacing-sm); +} + +.total__final { + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-lg); + border-top: 1px solid var(--color-gray); + padding-top: var(--spacing-sm); + margin-bottom: 0; +} + +.checkout__note { + text-align: center; + font-size: var(--font-size-sm); + color: var(--color-text-light); + margin-top: var(--spacing-md); + display: flex; + align-items: center; + justify-content: center; + gap: var(--spacing-sm); +} + +/* ===== NOTIFICATIONS ===== */ +.notification { + position: fixed; + top: 20px; + right: 20px; + background: var(--color-white); + padding: var(--spacing-md) var(--spacing-lg); + border-radius: var(--border-radius-md); + box-shadow: var(--shadow-lg); + display: none; + align-items: center; + gap: var(--spacing-sm); + z-index: calc(var(--z-modal) + 1); + max-width: 400px; + animation: slideInRight 0.3s ease; +} + +.notification.show { + display: flex; +} + +.notification.success { + border-left: 4px solid var(--color-success); +} + +.notification.error { + border-left: 4px solid var(--color-error); +} + +.notification.warning { + border-left: 4px solid var(--color-warning); +} + +.notification.info { + border-left: 4px solid var(--color-info); +} + +@keyframes slideInRight { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +/* ===== RESPONSIVE DESIGN ===== */ +@media (max-width: 1024px) { + .hero__container { + grid-template-columns: 1fr; + text-align: center; + } + + .hero__image { + order: -1; + } + + .about__container { + grid-template-columns: 1fr; + } + + .contact__container { + grid-template-columns: 1fr; + } + + .products__controls { + grid-template-columns: 1fr; + } +} + +@media (max-width: 768px) { + :root { + --font-size-5xl: 2.5rem; + --font-size-4xl: 2rem; + --font-size-3xl: 1.5rem; + } + + .container { + padding: 0 var(--spacing-md); + } + + .nav__menu { + position: fixed; + top: var(--header-height); + left: -100%; + width: 100%; + height: calc(100vh - var(--header-height)); + background: var(--color-white); + transition: left var(--transition-normal); + flex-direction: column; + justify-content: flex-start; + padding: var(--spacing-xl); + } + + .nav__menu.show-menu { + left: 0; + } + + .nav__list { + flex-direction: column; + gap: var(--spacing-lg); + width: 100%; + } + + .nav__toggle, + .nav__close { + display: block; + } + + .hero { + padding: calc(var(--header-height) + var(--spacing-xl)) 0 var(--spacing-xl); + } + + .hero__buttons { + justify-content: center; + } + + .products__grid { + grid-template-columns: 1fr; + } + + .process__steps { + grid-template-columns: 1fr; + } + + .gallery__grid { + grid-template-columns: repeat(2, 1fr); + } + + .form__row { + grid-template-columns: 1fr; + } + + .footer__content { + grid-template-columns: 1fr; + text-align: center; + } + + .footer__bottom { + flex-direction: column; + gap: var(--spacing-md); + text-align: center; + } + + .modal { + padding: var(--spacing-md); + } + + .modal__content { + max-height: 95vh; + } +} + +@media (max-width: 480px) { + .hero__buttons { + flex-direction: column; + align-items: center; + } + + .btn { + width: 100%; + max-width: 280px; + } + + .gallery__grid { + grid-template-columns: 1fr; + } + + .cart__item { + flex-direction: column; + align-items: flex-start; + } + + .cart__item-controls { + justify-content: space-between; + width: 100%; + } +} \ No newline at end of file