PageSourceSearch

https://solar-calculator-chi.vercel.app/js/assistive-calculator.js

js solar-calculator-chi.vercel.app collected 2026-10-03 07:46:04 UTC 60,990 bytes, 1,666 lines download raw bytes

1/**
2 * Assistive Calculator Module
3 * Handles the assistive (simplified) calculator functionality.
4 * This handles a step-by-step calculator experience with audio guidance.
5 */
6document.addEventListener("DOMContentLoaded", function() {
7  // Add custom appliance counter at the top with other state variables
8  let customApplianceCount = 0;
9  
10  // ----------- LANGUAGE SYSTEM -----------
11  
12  // Default language is English - always
13  let currentLanguage = 'en';
14  
15  // Language translations
16  const translations = {
17    en: {
18      // Header and navigation
19      'main-title': 'Solar Calculator - Assistive Mode',
20      'main-subtitle': 'Find the right solar system for your home',
21      'main-title-bar': 'Solar Calculator - Assistive Mode',
22      'main-subtitle-bar': 'Find the right solar system for your home',
23      'listen-text': 'Listen to Instructions',
24      'stop-text': 'Stop Audio',
25      'step1-label': '1. Select Home Type',
26      'step2-label': '2. Select Appliances',
27      'step3-label': '3. Get Results',
28      'next-button-text': 'Next',
29      'back-button-text': 'Back',
30      'next-button-text-2': 'Next',
31      'back-button-text-2': 'Back',
32      'print-button-text': 'Print Results',
33      'template-title': 'Quick Templates',
34      'template-subtitle': 'Select a template based on home size',
35      'template-1bed': '1 Bedroom',
36      'template-2bed': '2 Bedrooms',
37      'template-3bed': '3 Bedrooms',
38      'template-4bed': '4+ Bedrooms',
39      
40      // Step 1 - Home Type
41      'home-type-question': 'What type of home do you have?',
42      'home-type-subtitle': 'Select the option that best matches your home',
43      'bedroom1-label': '1 Bedroom',
44      'bedroom2-label': '2 Bedrooms',
45      'bedroom3-label': '3 Bedrooms',
46      'bedroom4-label': '4+ Bedrooms',
47      'sunlight-question': 'How much sunlight do you get?',
48      'less-sun-label': 'Less Sun',
49      'average-sun-label': 'Average Sun',
50      'more-sun-label': 'More Sun',
51      'backup-question': 'How long should backup power last?',
52      'half-day-label': 'Half Day',
53      'one-day-label': '1 Day',
54      'two-days-label': '2 Days',
55      
56      // Step 2 - Appliances
57      'appliances-title': 'Select your appliances',
58      'appliances-subtitle': 'Tap on the appliances you use regularly',
59      'category-all': 'All',
60      'category-lighting': 'Lights',
61      'category-kitchen': 'Kitchen',
62      'category-cooling': 'Cooling',
63      'category-entertainment': 'Entertainment',
64      'category-work-leisure': 'Work & Leisure',
65      'category-laundry': 'Laundry',
66      'category-general': 'General',
67      
68      // Lighting
69      'appliance-led-lights': 'LED Lights (10x)',
70      'appliance-lights': 'Lights',
71      
72      // Kitchen
73      'appliance-fridge-freezer-large': 'Fridge/Freezer - Large',
74      'appliance-freezer-chest': 'Freezer - Chest',
75      'appliance-microwave': 'Microwave',
76      'appliance-dishwasher': 'Dishwasher',
77      'appliance-electric-oven': 'Electric Oven',
78      'appliance-gas-oven': 'Gas Oven',
79      'appliance-kettle': 'Kettle',
80      'appliance-toaster': 'Toaster',
81      
82      // Cooling
83      'appliance-fan-ceiling': 'Fan - Ceiling',
84      'appliance-air-conditioner-large': 'Air Conditioner - Large',
85      'appliance-air-conditioner-small': 'Air Conditioner - Small',
86      
87      // Entertainment
88      'appliance-tv-led': 'TV (LED)',
89      'appliance-gaming': 'Gaming Console',
90      
91      // Work & Leisure
92      'appliance-laptop-computers': 'Laptop / Computers',
93      'appliance-coffee-machine': 'Coffee Machine',
94      'appliance-electric-stovetop-large': 'Electric Stovetop - Large',
95      'appliance-electric-stovetop-small': 'Electric Stovetop - Small',
96      'appliance-modem-internet': 'Modem/Internet',
97      
98      // Laundry
99      'appliance-washing-machine': 'Washing Machine',
100      'appliance-dryer': 'Dryer',
101      'appliance-hair-dryer': 'Hair Dryer',
102      
103      // General
104      'appliance-power-tools-charging': 'Charging for Common Power Tools',
105      'appliance-pressure-pump': 'Pressure Pump',
106      'appliance-custom': 'Custom Appliance',
107      
108      // Step 3 - Results
109      'results-title': 'Your Solar Power Results',
110      'results-subtitle': 'Here\'s what you need for your home',
111      'result-solar-panels': 'Solar Panels',
112      'solar-panel-desc': 'These capture sunlight to power your home',
113      'result-battery': 'Battery',
114      'battery-desc': 'Stores energy for use when there\'s no sun',
115      'result-system-size': 'System Size',
116      'system-size-desc': 'Powers all your selected appliances',
117      'selected-title': 'Your Selected Appliances:',
118      'total-title': 'Total Daily Energy Use:',
119      'template-applied': 'Template Applied',
120      'warning-text': 'These estimates may not be exact. Actual energy usage can vary based on specific models and usage patterns.',
121      
122      // New audio guide translations
123      'voice-guide-title': 'Voice Guide Available',
124      'voice-guide-message': 'Each step has voice instructions to help you',
125      'step1-voice': 'Step 1: Home Type',
126      'step2-voice': 'Step 2: Appliances',
127      'step3-voice': 'Step 3: Results',
128      
129      // Audio instructions (kept the same)
130      'home-audio': 'Welcome to the Solar Calculator. In this first step, select your home type, how much sunlight you get, and how long you need backup power to last.',
131      'appliances-audio': 'Now, select the appliances you use in your home. Tap the plus button to add appliances, or minus to remove them.',
132      'results-audio': 'Here are your results. This shows the solar panels, battery, and system size you need based on your selections.',
133    
134      'energy-legend-title': 'Energy Consumption Guide',
135      'energy-low-text': 'Low Energy: Efficient appliances',
136      'energy-medium-text': 'Medium Energy: Standard consumption',
137      'energy-high-text': 'High Energy: Power-intensive appliances',
138      'legend-show-text': 'Show Energy Guide',
139      'legend-hide-text': 'Hide Energy Guide'
140    },
141    tok: {
142      // Header and navigation
143      'main-title': 'Solar Kalkulator - Isi Moud',
144      'main-subtitle': 'Painim gutpela solar sistem bilong haus bilong yu',
145      'main-title-bar': 'Solar Kalkulator - Isi Moud',
146      'main-subtitle-bar': 'Painim gutpela solar sistem bilong haus bilong yu',
147      'listen-text': 'Harim Toktok',
148      'stop-text': 'Stopim Toktok',
149      'step1-label': '1. Makim Haus Kaen',
150      'step2-label': '2. Makim Ol Applaens',
151      'step3-label': '3. Kisim Risalts',
152      'next-button-text': 'Go het',
153      'back-button-text': 'Go bek',
154      'next-button-text-2': 'Go het',
155      'back-button-text-2': 'Go bek',
156      'print-button-text': 'Printim Result',
157      'template-title': 'Kwik Tamplat',
158      'template-subtitle': 'Makim tamplat bilong haus bikpela',
159      'template-1bed': '1 Rum',
160      'template-2bed': '2 Rum',
161      'template-3bed': '3 Rum',
162      'template-4bed': '4+ Rum',
163      
164      // Step 1 - Home Type
165      'home-type-question': 'Wanem kain haus yu gat?',
166      'home-type-subtitle': 'Makim haus we em i wankain olsem haus bilong yu',
167      'bedroom1-label': '1 Rum',
168      'bedroom2-label': '2 Rum',
169      'bedroom3-label': '3 Rum',
170      'bedroom4-label': '4+ Rum',
171      'sunlight-question': 'Hamas san yu save kisim?',
172      'less-sun-label': 'Liklik San',
173      'average-sun-label': 'Namel San',
174      'more-sun-label': 'Planti San',
175      'backup-question': 'Hamas taim yu laikim pawa i stap?',
176      'half-day-label': 'Hap De',
177      'one-day-label': '1 De',
178      'two-days-label': '2 De',
179      
180      // Step 2 - Appliances
181      'appliances-title': 'Makim ol samting lektrik',
182      'appliances-subtitle': 'Paitim ol samting lektrik yu save yusim long haus',
183      'category-all': 'Olgeta',
184      'category-lighting': 'Lait',
185      'category-kitchen': 'Kuk Haus',
186      'category-cooling': 'Kol Samting',
187      'category-entertainment': 'Lukluk Samting',
188      'category-work-leisure': 'Wok & Malolo',
189      'category-laundry': 'Wasim Klos',
190      'category-general': 'Narapela Samting',
191      
192      // Lighting
193      'appliance-led-lights': 'LED Lait (10x)',
194      'appliance-lights': 'Lait',
195      
196      // Kitchen
197      'appliance-fridge-freezer-large': 'Bikpela Fris/Frisa',
198      'appliance-freezer-chest': 'Bokis Frisa',
199      'appliance-microwave': 'Maekroweiv',
200      'appliance-dishwasher': 'Wasim Plet Masin',
201      'appliance-electric-oven': 'Oven Lektrik',
202      'appliance-gas-oven': 'Oven Ges',
203      'appliance-kettle': 'Ketol',
204      'appliance-toaster': 'Tosta',
205      
206      // Cooling
207      'appliance-fan-ceiling': 'Fan Bilong Ruf',
208      'appliance-air-conditioner-large': 'Bikpela Ea Kondisena',
209      'appliance-air-conditioner-small': 'Liklik Ea Kondisena',
210      
211      // Entertainment
212      'appliance-tv-led': 'TV (LED)',
213      'appliance-gaming': 'Pilai Gem',
214      
215      // Work & Leisure
216      'appliance-laptop-computers': 'Lepkop / Kompyuta',
217      'appliance-coffee-machine': 'Masin Kopi',
218      'appliance-electric-stovetop-large': 'Bikpela Stov Lektrik',
219      'appliance-electric-stovetop-small': 'Liklik Stov Lektrik',
220      'appliance-modem-internet': 'Modem/Intanet',
221      
222      // Laundry
223      'appliance-washing-machine': 'Wasim Masin',
224      'appliance-dryer': 'Draia',
225      'appliance-hair-dryer': 'Draia Bilong Gras',
226      
227      // General
228      'appliance-power-tools-charging': 'Sasim Tul Bilong Wok',
229      'appliance-pressure-pump': 'Pam Bilong Wara',
230      'appliance-custom': 'Narapela Samting Lektrik',
231      
232      // Step 3 - Results
233      'results-title': 'Solar Pawa Result bilong Yu',
234      'results-subtitle': 'Dispela em samting yu nidim bilong haus bilong yu',
235      'result-solar-panels': 'Solar Panel',
236      'solar-panel-desc': 'Ol i kisim san na tanim i go long pawa',
237      'result-battery': 'Betri',
238      'battery-desc': 'Holim pawa bilong yusim taim i nogat san',
239      'result-system-size': 'Bikpela bilong Sistem',
240      'system-size-desc': 'Givim pawa long ol samting lektrik yu makim',
241      'selected-title': 'Ol Samting Lektrik Yu Makim:',
242      'total-title': 'Bikpela Pawa Yusim long Wanpela De:',
243      'template-applied': 'Samting Lektrik I Redi Nau',
244      'warning-text': 'Ol dispela namba em i no stret olgeta. Tru pawa yus bilong yu inap long senis long wanem kain masin yu gat na olsem wanem yu save yusim.',
245      
246      // New audio guide translations
247      'voice-guide-title': 'Gaid Bilong Harim i Stap',
248      'voice-guide-message': 'Olgeta step i gat toktok bilong helpim yu',
249      'step1-voice': 'Step 1: Makim Haus Kaen',
250      'step2-voice': 'Step 2: Makim Ol Applaens',
251      'step3-voice': 'Step 3: Kisim Risalts',
252      
253      // Audio instructions (kept the same)
254      'home-audio': 'Welkam long Solar Kalkulator. Long dispela hap, makim wanem kain haus bilong yu, hamas 
254san yu kisim, na hamas taim yu laikim pawa i stap.',
255      'appliances-audio': 'Nau, makim ol samting lektrik yu save yusim long haus. Paitim plus botun bilong putim samting, o minus long rausim.',
256      'results-audio': 'Dispela em result bilong yu. Em i soim ol solar panel, betri, na bikpela bilong sistem yu nidim long ol samting yu makim.',
257    
258      // Energy indicator translations
259      'energy-legend-title': 'Gaid bilong Pawa Yus',
260      'energy-low-text': 'Liklik Pawa: Gut samting lektrik',
261      'energy-medium-text': 'Namel Pawa: Nomol samting lektrik', 
262      'energy-high-text': 'Bikpela Pawa: Samting i yusim planti pawa',
263      'legend-show-text': 'Soim Pawa Gaid',
264      'legend-hide-text': 'Haitim Pawa Gaid'
265    }
266  };
267
268  // Set the UI language
269  const setLanguage = (lang) => {
270    currentLanguage = lang;
271    
272    // Update all text elements with translations
273    Object.keys(translations[lang]).forEach(key => {
274      const element = document.getElementById(key);
275      if (element) {
276        element.textContent = translations[lang][key];
277      }
278    });
279  
280    // Save language preference
281    localStorage.setItem('preferredLanguage', lang);
282    
283    // Update active language button
284    document.querySelectorAll('.lang-btn').forEach(btn => {
285      btn.classList.remove('active');
286      if (btn.dataset.lang === lang) {
287        btn.classList.add('active');
288      }
289    });
290  };
291  
292  // Initialize language based on saved preference or default to English
293  const initializeLanguage = () => {
294    const savedLanguage = localStorage.getItem('preferredLanguage');
295    if (savedLanguage) {
296      setLanguage(savedLanguage);
297    } else {
298      setLanguage('en'); // Default to English
299    }
300  };
301  
302  // Setup language buttons
303  const langButtons = document.querySelectorAll('.lang-btn');
304  langButtons.forEach(button => {
305    button.addEventListener('click', function() {
306      const lang = this.dataset.lang;
307      setLanguage(lang);
308    });
309  });
310  
311  // ----------- AUDIO SYSTEM -----------
312
313  let audioPlaying = false;
314  
315  // Create a visual indicator for when audio is playing
316  function createAudioStatusIndicator() {
317    // Create the indicator element if it doesn't exist
318    let audioIndicator = document.getElementById('audio-status-indicator');
319    if (!audioIndicator) {
320      audioIndicator = document.createElement('div');
321      audioIndicator.id = 'audio-status-indicator';
322      audioIndicator.className = 'audio-status-indicator';
323      document.body.appendChild(audioIndicator);
324      
325      // Add styles for the audio indicator
326      const style = document.createElement('style');
327      style.textContent = `
328        .audio-status-indicator {
329          position: fixed;
330          bottom: 20px;
331          right: 20px;
332          background-color: rgba(52, 152, 219, 0.9);
333          color: white;
334          padding: 12px 20px;
335          border-radius: 8px;
336          box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
337          z-index: 1000;
338          display: flex;
339          align-items: center;
340          gap: 10px;
341          transform: translateY(100px);
342          transition: transform 0.3s ease;
343        }
344        
345        .audio-status-indicator.visible {
346          transform: translateY(0);
347        }
348        
349        .audio-status-indicator .wave {
350          display: flex;
351          align-items: center;
352          height: 20px;
353        }
354        
355        .audio-status-indicator .wave .bar {
356          width: 3px;
357          margin: 0 2px;
358          background-color: white;
359          animation: wave 1s infinite ease-in-out;
360        }
361        
362        .audio-status-indicator .wave .bar:nth-child(2) {
363          animation-delay: 0.2s;
364        }
365        
366        .audio-status-indicator .wave .bar:nth-child(3) {
367          animation-delay: 0.4s;
368        }
369        
370        .audio-status-indicator .wave .bar:nth-child(4) {
371          animation-delay: 0.6s;
372        }
373        
374        @keyframes wave {
375          0%, 100% {
376            height: 6px;
377          }
378          50% {
379            height: 18px;
380          }
381        }
382      `;
383      document.head.appendChild(style);
384    }
385    
386    return audioIndicator;
387  }
388
389  // Show the audio indicator with step-specific message
390  function showAudioStatusIndicator(step) {
391    const audioIndicator = createAudioStatusIndicator();
392    
393    // Determine the message based on the step
394    let message = translations[currentLanguage][`step${step}-voice`] || 'Voice guide playing';
395    
396    audioIndicator.innerHTML = `
397      <div class="wave">
398        <div class="bar"></div>
399        <div class="bar"></div>
400        <div class="bar"></div>
401        <div class="bar"></div>
402      </div>
403      <span>${message}</span>
404    `;
405    
406    // Show the indicator
407    setTimeout(() => {
408      audioIndicator.classList.add('visible');
409    }, 10);
410  }
411
412  // Hide the audio indicator
413  function hideAudioStatusIndicator() {
414    const audioIndicator = document.getElementById('audio-status-indicator');
415    if (audioIndicator) {
416      audioIndicator.classList.remove('visible');
417    }
418  }
419
420  // Enhanced playAudio function with step detection
421  const playAudio = (audioKey) => {
422    // Stop any currently playing audio
423    stopAudio();
424    
425    // Determine which step audio is being played
426    let step = null;
427    if (audioKey === 'home-audio') {
428      step = 1;
429    } else if (audioKey === 'appliances-audio') {
430      step = 2;
431    } else if (audioKey === 'results-audio') {
432      step = 3;
433    }
434    
435    // Show the audio indicator
436    if (step) {
437      showAudioStatusIndicator(step);
438    }
439    
440    // In a real implementation, you would have actual audio files
441    // For demo, we'll use the Web Speech API
442    
443    const message = translations[currentLanguage][audioKey];
444    // Check if browser supports speech synthesis
445    if ('speechSynthesis' in window) {
446      // Create a new speech synthesis utterance
447      const utterance = new SpeechSynthesisUtterance(message);
448      
449      // Set the language based on current selection
450      if (currentLanguage === 'en') {
451        utterance.lang = 'en-US';
452      } else if (currentLanguage === 'tok') {
453        utterance.lang = 'en-US'; // Fallback since Tok Pisin not widely supported
454      } else {
455        utterance.lang = 'en-US'; // Fallback
456      }
457      
458      // Set flag when audio starts
459      utterance.onstart = () => {
460        audioPlaying = true;
461      };
462      
463      // Set flag when audio ends
464      utterance.onend = () => {
465        audioPlaying = false;
466        // Hide the audio indicator when audio ends
467        hideAudioStatusIndicator();
468      };
469      
470      // Speak the message
471      speechSynthesis.cancel(); // Cancel any ongoing speech
472      speechSynthesis.speak(utterance);
473    } else {
474      console.log('Speech synthesis not supported in this browser');
475      // Fallback alert for browsers without speech synthesis
476      alert(message);
477    }
478  };
479
480  // Enhanced stopAudio function
481  const stopAudio = () => {
482    if ('speechSynthesis' in window) {
483      speechSynthesis.cancel();
484      audioPlaying = false;
485      // Hide the audio indicator
486      hideAudioStatusIndicator();
487    }
488  };
489
490  // Listen button functionality
491  const listenButton = document.getElementById('listen-button');
492  if (listenButton) {
493    listenButton.addEventListener('click', function() {
494      // Play the appropriate audio based on current step
495      if (currentStep === 1) {
496        playAudio('home-audio');
497      } else if (currentStep === 2) {
498        playAudio('appliances-audio');
499      } else if (currentStep === 3) {
500        playAudio('results-audio');
501      }
502    });
503  }
504
505  // Stop audio button functionality
506  const stopAudioButton = document.getElementById('stop-audio-button');
507  if (stopAudioButton) {
508    stopAudioButton.addEventListener('click', stopAudio);
509  }
510
511  // Add click event listeners to all step audio buttons
512  const stepAudioButtons = document.querySelectorAll('.step-audio-btn');
513  stepAudioButtons.forEach(button => {
514    button.addEventListener('click', function(e) {
515      e.preventDefault();
516      e.stopPropagation();
517      
518      const audioKey = this.dataset.audio;
519      // Call the existing playAudio function with the specific audio key
520      playAudio(audioKey);
521    });
522  });
523
524  const legendToggleBtn = document.getElementById('legend-toggle-btn');
525  const energyLegend = document.querySelector('.energy-indicator-legend');
526
527  if (legendToggleBtn && energyLegend) {
528    legendToggleBtn.addEventListener('click', function() {
529      energyLegend.classList.toggle('expanded');
530      
531      // Update the toggle button text
532      const toggleText = document.getElementById('legend-toggle-text');
533      if (toggleText) {
534        if (energyLegend.classList.contains('expanded')) {
535          toggleText.textContent = translations[currentLanguage]['legend-hide-text'] || 'Hide Energy Guide';
536        } else {
537          toggleText.textContent = translations[currentLanguage]['legend-show-text'] || 'Show Energy Guide';
538        }
539      }
540    });
541  }
542
543  function autoExpandEnergyLegend() {
544    const energyLegend = document.querySelector('.energy-indicator-legend');
545    if (energyLegend) {
546      if (window.innerWidth <= 768) {
547        energyLegend.classList.add('expanded');
548      } else {
549        energyLegend.classList.remove('expanded');
550      }
551    }
552  }
553  
554  autoExpandEnergyLegend();
555  
556  window.addEventListener('resize', autoExpandEnergyLegend);
557
558  // Function to initialize energy indicator tooltips
559  function initializeEnergyTooltips() {
560    // Add tooltip functionality to all energy indicators
561    const energyIndicators = document.querySelectorAll('.energy-indicator');
562    
563    energyIndicators.forEach(indicator => {
564      // Get the parent appliance card
565      const applianceCard = indicator.closest('.appliance-card');
566      if (!applianceCard) return;
567      
568      // Create tooltip element if it doesn't exist
569      let tooltip = applianceCard.querySelector('.energy-tooltip');
570      if (!tooltip) {
571        tooltip = document.createElement('div');
572        tooltip.className = 'energy-tooltip';
573        applianceCard.appendChild(tooltip);
574      }
575      
576      // Determine energy level from class
577      let energyLevel = '';
578      if (indicator.classList.contains('energy-low')) {
579        energyLevel = translations[currentLanguage]['energy-low-text'] || 'Low Energy: Efficient appliance';
580      } else if (indicator.classList.contains('energy-medium')) {
581        energyLevel = translations[currentLanguage]['energy-medium-text'] || 'Medium Energy: Standard consumption';
582      } else if (indicator.classList.contains('energy-high')) {
583        energyLevel = translations[currentLanguage]['energy-high-text'] || 'High Energy: Power-intensive appliance';
584      }
585      
586      // Set tooltip text
587      tooltip.textContent = energyLevel;
588      
589      // Show tooltip on hover
590      indicator.addEventListener('mouseenter', () => {
591        tooltip.style.display = 'block';
592        
593        // Position the tooltip
594        const applianceRect = applianceCard.getBoundingClientRect();
595        tooltip.style.top = '10px';
596        tooltip.style.right = '10px';
597        
598        // Ensure tooltip is visible within viewport
599        setTimeout(() => {
600          const tooltipRect = tooltip.getBoundingClientRect();
601          if (tooltipRect.right > window.innerWidth) {
602            tooltip.style.right = 'auto';
603            tooltip.style.left = '10px';
604          }
605        }, 0);
606      });
607      
608      // Hide tooltip when not hovering
609      indicator.addEventListener('mouseleave', () => {
610        tooltip.style.display = 'none';
611      });
612    });
613  }
614
615  // Add CSS for tooltips
616  const styleElement = document.createElement('style');
617  styleElement.textContent = `
618    .energy-tooltip {
619      position: absolute;
620      background-color: rgba(0, 0, 0, 0.8);
621      color: white;
622      padding: 5px 10px;
623      border-radius: 4px;
624      font-size: 12px;
625      z-index: 100;
626      display: none;
627      white-space: nowrap;
628      pointer-events: none;
629      top: 10px;
630      right: 10px;
631      animation: fadeIn 0.2s;
632    }
633    
634    .energy-tooltip::after {
635      content: '';
636      position: absolute;
637      top: -5px;
638      right: 10px;
639      border-width: 0 5px 5px;
640      border-style: solid;
641      border-color: transparent transparent rgba(0, 0, 0, 0.8);
642    }
643    
644    @keyframes fadeIn {
645      from { opacity: 0; }
646      to { opacity: 1; }
647    }
648    
649    /* Make the energy indicator have a slightly larger hit area for better UX */
650    .energy-indicator {
651      cursor: pointer;
652    }
653  `;
654  document.head.appendChild(styleElement);
655
656  // Call this function after appliances are loaded
657  document.addEventListener('DOMContentLoaded', function() {
658    // Wait a short time to ensure all appliances are loaded
659    setTimeout(initializeEnergyTooltips, 500);
660    
661    // Also initialize tooltips when category is changed since this can reload appliances
662    const categories = document.querySelectorAll('.category');
663    categories.forEach(category => {
664      category.addEventListener('click', function() {
665        setTimeout(initializeEnergyTooltips, 300);
666      });
667    });
668  });
669 
670  // ----------- CALCULATOR FUNCTIONALITY -----------
671  
672  // Cache DOM elements
673  const steps = document.querySelectorAll('.step');
674  const stepContents = document.querySelectorAll('.step-content');
675  const homeOptions = document.querySelectorAll('.home-option');
676  const sunlightOptions = document.querySelectorAll('.sunlight-option');
677  const backupOptions = document.querySelectorAll('.backup-option');
678  const categories = document.querySelectorAll('.category');
679  
680  // Navigation buttons
681  const toStep2Button = document.getElementById('to-step-2');
682  const backToStep1Button = document.getElementById('to-step-1');
683  const toStep3Button = document.getElementById('to-step-3');
684  const backToStep2Button = document.getElementById('back-to-step-2');
685  const printResultsButton = document.getElementById('print-results');
686  
687  // State variables
688  let currentStep = 1;
689  let selectedHomeType = null;
690  let selectedSunlight = 5; // Default: Average Sun
691  let selectedBackup = 1; // Default: 1 Day
692  
693  // Show loading spinner
694  function showLoadingSpinner(message = 'Calculating...') {
695    document.getElementById('loading-message').textContent = message;
696    document.getElementById('loading-overlay').style.display = 'flex';
697  }
698 
699  // Hide loading spinner
700  function hideLoadingSpinner() {
701    document.getElementById('loading-overlay').style.display = 'none';
702  }
703 
704  // Show notification
705  function showNotification(message) {
706    // Create notification element if it doesn't exist
707    let notification = document.getElementById('notification');
708    if (!notification) {
709      notification = document.createElement('div');
710      notification.id = 'notification';
711      notification.className = 'notification';
712      document.body.appendChild(notification);
713      
714      // Add styles for notification
715      const style = document.createElement('style');
716      style.textContent = `
717        .notification {
718          position: fixed;
719          top: 20px;
720          right: 20px;
721          background-color: #3498db;
722          color: white;
723          padding: 15px 25px;
724          border-radius: 8px;
725          box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
726          z-index: 1000;
727          transition: all 0.3s ease;
728          opacity: 0;
729          transform: translateY(-20px);
730        }
731        .notification.show {
732          opacity: 1;
733          transform: translateY(0);
734        }
735      `;
736      document.head.appendChild(style);
737    }
738    
739    // Set message and show notification
740    notification.textContent = message;
741    notification.classList.add('show');
742    
743    // Hide notification after 3 seconds
744    setTimeout(() => {
745      notification.classList.remove('show');
746    }, 3000);
747  }
748 
749  // Navigate between steps
750  function navigateToStep(stepNumber) {
751    // Hide all step contents
752    stepContents.forEach(content => {
753      content.classList.remove('active');
754    });
755    
756    // Show the selected step content
757    document.getElementById(`step-${stepNumber}`).classList.add('active');
758    
759    // Update step indicators
760    steps.forEach(step => {
761      const stepNum = parseInt(step.dataset.step);
762      step.classList.remove('active', 'completed');
763      
764      if (stepNum === stepNumber) {
765        step.classList.add('active');
766      } else if (stepNum < stepNumber) {
767        step.classList.add('completed');
768      }
769    });
770    
771    // Update current step
772    currentStep = stepNumber;
773    
774    // Note: Removed automatic audio playback
775    
776    // Scroll to the active step section
777    const activeStepElement = document.querySelector(`.step[data-step="${stepNumber}"]`);
778    if (activeStepElement) {
779      // Smooth scroll to the step with some offset to account for fixed header
780      const headerOffset = 300; // Adjust this value based on your header height
781      const elementPosition = activeStepElement.getBoundingClientRect().top;
782      const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
783      
784      window.scrollTo({
785        top: offsetPosition,
786        behavior: 'smooth'
787      });
788    }
789  }
790 
791  // Calculate total energy usage
792  function calculateTotalEnergy() {
793    let totalEnergy = 0;
794    
795    // Loop through all appliance cards
796    const applianceCards = document.querySelectorAll('.appliance-card:not(.custom-template)');
797    applianceCards.forEach(card => {
798      const quantityEl = card.querySelector('.quantity-value');
799      if (!quantityEl) return;
800      
801      const quantity = parseInt(quantityEl.textContent);
802      if (quantity > 0) {
803        // For custom appliances with editable fields, get values from inputs
804        let wattage, hours;
805        
806        if (card.classList.contains('custom-appliance')) {
807          wattage = parseInt(card.querySelector('.custom-wattage').value) || 1;
808          hours = parseFloat(card.querySelector('.custom-hours').value) || 1;
809        } else {
810          wattage = parseInt(card.dataset.wattage) || 1;
811          hours = parseFloat(card.dataset.hours) || 1;
812        }
813        
814        // Calculate kWh for this appliance
815        const kwh = (wattage * quantity * hours) / 1000;
816        totalEnergy += kwh;
817      }
818    });
819    
820    return totalEnergy;
821  }
822 
823  // Get selected appliances
824  function getSelectedAppliances() {
825    const appliances = [];
826    const applianceCards = document.querySelectorAll('.appliance-card:not(.custom-template)');
827    
828    applianceCards.forEach(card => {
829      const quantityEl = card.querySelector('.quantity-value');
830      if (!quantityEl) return;
831      
832      const quantity = parseInt(quantityEl.textContent);
833      if (quantity > 0) {
834        let name, wattage, hours;
835        
836        if (card.classList.contains('custom-appliance')) {
837          const nameEl = card.querySelector('.editable-appliance-name');
838          name = nameEl ? nameEl.value : 'Custom Appliance';
839          wattage = parseInt(card.querySelector('.custom-wattage').value) || 1;
840          hours = parseFloat(card.querySelector('.custom-hours').value) || 1;
841        } else {
842          const nameEl = card.querySelector('.appliance-name');
843          name = nameEl ? nameEl.textContent : card.dataset.title;
844          wattage = parseInt(card.dataset.wattage) || 1;
845          hours = parseFloat(card.dataset.hours) || 1;
846        }
847        
848        appliances.push({
849          name: name,
850          quantity: quantity,
851          wattage: wattage,
852          hours: hours,
853          kwh: (wattage * quantity * hours) / 1000
854        });
855      }
856    });
857    
858    return appliances;
859  }
860  
861  // Calculate final results
862  function calculateResults() {
863    showLoadingSpinner('Calculating your solar system...');
864    
865    setTimeout(() => {
866      // Get total energy usage
867      const totalEnergy = calculateTotalEnergy();
868      document.getElementById('total-kwh-value').textContent = totalEnergy.toFixed(1);
869      
870      // Get selected appliances
871      const appliances = getSelectedAppliances();
872      
873      // Clear previous selected appliances
874      const selectedAppliancesList = document.getElementById('selected-appliances-list');
875      selectedAppliancesList.innerHTML = '';
876      
877      // Add selected appliances to the list
878      appliances.forEach(appliance => {
879        const applianceItem = document.createElement('div');
880        applianceItem.className = 'appliance-item';
881        
882        // Find the matching card to get the image source
883        let imgSrc = 'assets/custom.png';
884        if (!appliance.name.includes('Custom')) {
885          const matchingCard = Array.from(document.querySelectorAll('.appliance-card:not(.custom-appliance)')).find(card => {
886            const nameEl = card.querySelector('.appliance-name');
887            return nameEl && nameEl.textContent === appliance.name;
888          });
889          
890          if (matchingCard) {
891            const iconEl = matchingCard.querySelector('.appliance-icon');
892            if (iconEl) {
893              imgSrc = iconEl.src;
894            }
895          }
896        }
897        
898        applianceItem.innerHTML = `
899          <img src="${imgSrc}" alt="${appliance.name}" class="item-icon">
900          <div class="item-details">
901            <div class="item-name">${appliance.name}</div>
902            <div class="item-quantity">Quantity: ${appliance.quantity}</div>
903          </div>
904        `;
905        
906        selectedAppliancesList.appendChild(applianceItem);
907      });
908      
909      // Calculate solar panel size based on total energy and sunlight hours
910      const solarPanelSize = totalEnergy / selectedSunlight;
911      
912      // Calculate battery capacity based on total energy and backup days
913      const batteryCapacity = totalEnergy * selectedBackup;
914      
915      // Calculate system size (inverter) based on home type
916      let systemSize = selectedHomeType;
917      
918      // Determine appropriate solar panel recommendation
919      let solarText = '';
920      if (solarPanelSize <= 0.5) {
921        solarText = '1 - 2 panels';
922      } else if (solarPanelSize <= 1) {
923        solarText = '3 - 4 panels';
924      } else if (solarPanelSize <= 2) {
925        solarText = '5 - 6 panels';
926      } else if (solarPanelSize <= 3) {
927        solarText = '7 - 9 panels';
928      } else if (solarPanelSize <= 4) {
929        solarText = '10 - 12 panels';
930      } else if (solarPanelSize <= 5) {
931        solarText = '13 - 15 panels';
932      } else {
933        solarText = '16 - 20+ panels';
934      }
935      
936      // Determine appropriate battery recommendation
937      let batteryText = '';
938      if (batteryCapacity <= 1) {
939        batteryText = 'Small (0.5 - 1kWh)';
940      } else if (batteryCapacity <= 2) {
941        batteryText = 'Small (1.5 - 2kWh)';
942      } else if (batteryCapacity <= 5) {
943        batteryText = 'Medium (3 - 5kWh)';
944      } else if (batteryCapacity <= 10) {
945        batteryText = 'Medium (7 - 10kWh)';
946      } else if (batteryCapacity <= 15) {
947        batteryText = 'Large (12 - 15kWh)';
948      } else {
949        batteryText = 'Very Large (15 - 20kWh+)';
950      }
951      
952      // Determine appropriate system size recommendation
953      let systemText = '';
954      if (systemSize === 30) {
955        systemText = 'Small (2 - 3kVA)';
956      } else if (systemSize === 50) {
957        systemText = 'Medium (4 - 5kVA)';
958      } else if (systemSize === 70) {
959        systemText = 'Large (8 - 10kVA)';
960      } else if (systemSize === 90) {
961        systemText = 'Extra Large (12 - 15kVA)';
962      } else {
963        systemText = 'Medium (4 - 5kVA)';
964      }
965      
966      // Update result values
967      document.getElementById('solar-panel-value').querySelector('.result-value-text').innerHTML = solarText;
968      document.getElementById('battery-value').querySelector('.result-value-text').innerHTML = batteryText.replace(/\(([^)]+)\)/, '<br>($1)');
969      document.getElementById('system-size-value').querySelector('.result-value-text').innerHTML = systemText.replace(/\(([^)]+)\)/, '<br>($1)');
970      
971      hideLoadingSpinner();
972    }, 1500);
973  }
974  
975  // Initialize option selections
976  
977  // Home type selection based on bedroom count
978  homeOptions.forEach(option => {
979    option.addEventListener('click', function() {
980      homeOptions.forEach(opt => opt.classList.remove('selected'));
981      this.classList.add('selected');
982      selectedHomeType = parseInt(this.dataset.usage);
983      
984      // Auto-apply template based on bedroom selection
985      const homeType = this.dataset.homeType;
986      if (homeType === 'bedroom1') {
987        applyTemplate(1);
988      } else if (homeType === 'bedroom2') {
989        applyTemplate(2);
990      } else if (homeType === 'bedroom3') {
991        applyTemplate(3);
992      } else if (homeType === 'bedroom4') {
993        applyTemplate(4);
994      }
995    });
996  });
997  
998  // Sunlight selection
999  sunlightOptions.forEach(option => {
1000    option.addEventListener('click', function() {
1001      sunlightOptions.forEach(opt => opt.classList.remove('selected'));
1002      this.classList.add('selected');
1003      selectedSunlight = parseFloat(this.dataset.sun);
1004    });
1005  });
1006  
1007  // Backup selection
1008  backupOptions.forEach(option => {
1009    option.addEventListener('click', function() {
1010      backupOptions.forEach(opt => opt.classList.remove('selected'));
1011      this.classList.add('selected');
1012      selectedBackup = parseFloat(this.dataset.backup);
1013    });
1014  });
1015  
1016  // Default selections
1017  sunlightOptions[1].classList.add('selected'); // Average sun
1018  backupOptions[1].classList.add('selected'); // 1 day
1019  
1020  // Category filtering
1021  categories.forEach(category => {
1022    category.addEventListener('click', function() {
1023      categories.forEach(cat => cat.classList.remove('active'));
1024      this.classList.add('active');
1025      
1026      const selectedCategory = this.dataset.category;
1027      const applianceCards = document.querySelectorAll('.appliance-card');
1028      
1029      applianceCards.forEach(card => {
1030        if (selectedCategory === 'all' || card.dataset.category === selectedCategory) {
1031          card.style.display = '';
1032        } else {
1033          card.style.display = 'none';
1034        }
1035      });
1036    });
1037  });
1038  
1039  // Apply Template for Room Sizes
1040  function applyTemplate(bedrooms) {
1041    // Show loading spinner
1042    showLoadingSpinner(`Loading template for ${bedrooms} bedroom(s)...`);
1043    
1044    // Reset all appliance quantities to 0
1045    document.querySelectorAll('.appliance-card:not(.custom-template)').forEach(card => {
1046      // Remove any existing custom appliances
1047      if (card.classList.contains('custom-appliance')) {
1048        card.remove();
1049      } else {
1050        // Reset quantity for standard appliances
1051        const quantityEl = card.querySelector('.quantity-value');
1052        if (quantityEl) {
1053          quantityEl.textContent = '0';
1054        }
1055        card.classList.remove('selected');
1056      }
1057    });
1058    
1059    // Reset custom appliance counter
1060    customApplianceCount = 0;
1061    
1062    setTimeout(() => {
1063      // Define appliance templates based on bedrooms
1064      const applianceTemplates = {
1065        1: [
1066          { title: "Lights", quantity: 3 },
1067          { title: "Fridge/Freezer - Large", quantity: 1 },
1068          { title: "Fan - Ceiling", quantity: 1 },
1069          { title: "TV (LED)", quantity: 1 },
1070          { title: "Air Conditioner - Small", quantity: 1 },
1071          { title: "Microwave", quantity: 1 },
1072          { title: "Modem/Internet", quantity: 1 },
1073          { title: "Washing Machine", quantity: 1 }
1074        ],
1075        2: [
1076          { title: "Lights", quantity: 5 },
1077          { title: "Fridge/Freezer - Large", quantity: 1 },
1078          { title: "Fan - Ceiling", quantity: 2 },
1079          { title: "TV (LED)", quantity: 1 },
1080          { title: "Air Conditioner - Small", quantity: 1 },
1081          { title: "Microwave", quantity: 1 },
1082          { title: "Modem/Internet", quantity: 1 },
1083          { title: "Laptop / Computers", quantity: 1 },
1084          { title: "Washing Machine", quantity: 1 }
1085        ],
1086        3: [
1087          { title: "Lights", quantity: 8 },
1088          { title: "Fridge/Freezer - Large", quantity: 1 },
1089          { title: "Fan - Ceiling", quantity: 3 },
1090          { title: "TV (LED)", quantity: 1 },
1091          { title: "Air Conditioner - Large", quantity: 1 },
1092          { title: "Microwave", quantity: 1 },
1093          { title: "Kettle", quantity: 1 },
1094          { title: "Toaster", quantity: 1 },
1095          { title: "Modem/Internet", quantity: 1 },
1096          { title: "Laptop / Computers", quantity: 2 },
1097          { title: "Washing Machine", quantity: 1 }
1098        ],
1099        4: [
1100          { title: "Lights", quantity: 12 },
1101          { title: "Fridge/Freezer - Large", quantity: 1 },
1102          { title: "Fan - Ceiling", quantity: 4 },
1103          { title: "TV (LED)", quantity: 2 },
1104          { title: "Air Conditioner - Large", quantity: 1 },
1105          { title: "Air Conditioner - Small", quantity: 1 },
1106          { title: "Microwave", quantity: 1 },
1107          { title: "Kettle", quantity: 1 },
1108          { title: "Toaster", quantity: 1 },
1109          { title: "Modem/Internet", quantity: 1 },
1110          { title: "Laptop / Computers", quantity: 2 },
1111          { title: "Washing Machine", quantity: 1 },
1112          { title: "Dryer", quantity: 1 },
1113          { title: "Gaming Console", quantity: 1 }]
1114        };
1115        
1116        // Apply the template
1117        const template = applianceTemplates[bedrooms] || applianceTemplates[4]; // Default to 4+ for any larger number
1118        
1119        // Find and update each appliance card with the correct quantity using data-title instead of name
1120        template.forEach(item => {
1121          const cards = document.querySelectorAll('.appliance-card:not(.custom-template)');
1122          cards.forEach(card => {
1123            // Use data-title attribute to match appliances instead of innerText
1124            if (card.dataset.title === item.title) {
1125              const quantityEl = card.querySelector('.quantity-value');
1126              if (quantityEl) {
1127                quantityEl.textContent = item.quantity.toString();
1128                if (item.quantity > 0) {
1129                  card.classList.add('selected');
1130                }
1131              }
1132            }
1133          });
1134        });
1135        
1136        // Show notification instead of navigating to next step
1137        hideLoadingSpinner();
1138        showNotification(translations[currentLanguage]['template-applied']);
1139      }, 1000);
1140    }
1141    
1142    // Navigation button events
1143    toStep2Button.addEventListener('click', function() {
1144      // Validate home type selection
1145      if (selectedHomeType === null) {
1146        alert(translations[currentLanguage]['home-type-question']);
1147        return;
1148      }
1149      navigateToStep(2);
1150    });
1151    
1152    backToStep1Button.addEventListener('click', function() {
1153      navigateToStep(1);
1154    });
1155    
1156    toStep3Button.addEventListener('click', function() {
1157      // Check if at least one appliance is selected
1158      const hasSelectedAppliances = Array.from(document.querySelectorAll('.appliance-card:not(.custom-template)')).some(card => {
1159        const quantityEl = card.querySelector('.quantity-value');
1160        return quantityEl && parseInt(quantityEl.textContent) > 0;
1161      });
1162      
1163      if (!hasSelectedAppliances) {
1164        alert(translations[currentLanguage]['appliances-title']);
1165        return;
1166      }
1167      
1168      navigateToStep(3);
1169      calculateResults(); // Calculate results when navigating to step 3
1170    });
1171
1172    function setupEnhancedPrinting() {
1173      // Get the print button element
1174      const printButton = document.getElementById('print-results');
1175      
1176      if (printButton) {
1177        // Replace the current click handler with our enhanced version
1178        printButton.removeEventListener('click', window.print);
1179        
1180        printButton.addEventListener('click', function() {
1181          // Show loading spinner while preparing print layout
1182          showLoadingSpinner('Preparing print layout...');
1183          
1184          // Create a new window for the print layout
1185          const printWindow = window.open('', '_blank', 'width=800,height=600');
1186          
1187          if (!printWindow) {
1188            hideLoadingSpinner();
1189            alert('Please allow popup windows to print your results.');
1190            return;
1191          }
1192          
1193          // Get selected appliances and results data
1194          const appliances = getSelectedAppliances();
1195          const totalEnergy = calculateTotalEnergy();
1196          
1197          // Get result values, ensuring we get the text content even with the new HTML structure
1198          const solarPanelEl = document.getElementById('solar-panel-value');
1199          const batteryEl = document.getElementById('battery-value');
1200          const systemSizeEl = document.getElementById('system-size-value');
1201          
1202          const solarPanelValue = solarPanelEl.querySelector('.result-value-text') ? 
1203              solarPanelEl.querySelector('.result-value-text').textContent : 
1204              solarPanelEl.textContent;
1205              
1206          const batteryValue = batteryEl.querySelector('.result-value-text') ? 
1207              batteryEl.querySelector('.result-value-text').textContent : 
1208              batteryEl.textContent;
1209              
1210          const systemSizeValue = systemSizeEl.querySelector('.result-value-text') ? 
1211              systemSizeEl.querySelector('.result-value-text').textContent : 
1212              systemSizeEl.textContent;
1213          
1214          // Get date information for the printed report
1215          const currentDate = new Date();
1216          const formattedDate = currentDate.toLocaleDateString();
1217          const formattedTime = currentDate.toLocaleTimeString();
1218          
1219          // Determine home type selection
1220          let homeType = 'Unknown';
1221          document.querySelectorAll('.home-option.selected').forEach(option => {
1222            const label = option.querySelector('.home-label');
1223            if (label) {
1224              homeType = label.textContent;
1225            }
1226          });
1227          
1228          // Determine sunlight selection
1229          let sunlight = 'Average';
1230          document.querySelectorAll('.sunlight-option.selected').forEach(option => {
1231            const label = option.querySelector('.sunlight-label');
1232            if (label) {
1233              sunlight = label.textContent;
1234            }
1235          });
1236          
1237          // Determine backup selection
1238          let backup = '1 Day';
1239          document.querySelectorAll('.backup-option.selected').forEach(option => {
1240            const label = option.querySelector('.backup-label');
1241            if (label) {
1242              backup = label.textContent;
1243            }
1244          });
1245          
1246          // Path to TEPNG logo (update this with the actual path to your logo)
1247          const logoPath = 'assets/logo/logo.png';
1248          
1249          // Write the print layout HTML with space for the logo
1250          printWindow.document.write(`
1251            <!DOCTYPE html>
1252            <html>
1253            <head>
1254              <title>Solar Calculator Results - ${formattedDate}</title>
1255              <meta charset="UTF-8">
1256              <meta name="viewport" content="width=device-width, initial-scale=1.0">
1257              <style>
1258                body {
1259                  font-family: Arial, sans-serif;
1260                  color: #333;
1261                  line-height: 1.5;
1262                  margin: 0;
1263                  padding: 20px;
1264                }
1265                
1266                .print-container {
1267                  max-width: 800px;
1268                  margin: 0 auto;
1269                }
1270                
1271                .print-header {
1272                  padding-bottom: 20px;
1273                  border-bottom: 2px solid #3498db;
1274                  margin-bottom: 20px;
1275                  display: flex;
1276                  align-items: center;
1277                  justify-content: space-between;
1278                }
1279                
1280                .header-logo {
1281                  flex: 0 0 150px;
1282                  height: 80px;
1283                  display: flex;
1284                  align-items: center;
1285                  justify-content: center;
1286                  margin-right: 20px;
1287                }
1288                
1289                .header-logo img {
1290                  max-width: 100%;
1291                  max-height: 100%;
1292                  object-fit: contain;
1293                }
1294                
1295                .header-content {
1296                  flex: 1;
1297                  margin-left: 50px;
1298                  text-align: left;
1299                }
1300                
1301                .print-logo {
1302                  font-size: 24px;
1303                  font-weight: bold;
1304                  color: #1a3755;
1305                  margin-bottom: 5px;
1306                }
1307                
1308                .print-subtitle {
1309                  color: #666;
1310                  font-size: 16px;
1311                }
1312                
1313                .print-date {
1314                  color: #777;
1315                  font-size: 14px;
1316                  margin-top: 10px;
1317                }
1318                
1319                .print-section {
1320                  margin-bottom: 30px;
1321                }
1322                
1323                .section-title {
1324                  color: #1a3755;
1325                  border-bottom: 1px solid #ddd;
1326                  padding-bottom: 5px;
1327                  font-size: 18px;
1328                  margin-bottom: 15px;
1329                }
1330                
1331                .inputs-section {
1332                  display: flex;
1333                  flex-wrap: wrap;
1334                  gap: 15px;
1335                  margin-bottom: 20px;
1336                }
1337                
1338                .input-item {
1339                  flex: 1;
1340                  min-width: 180px;
1341                  background-color: #f9f9f9;
1342                  padding: 10px 15px;
1343                  border-radius: 8px;
1344                  border-left: 4px solid #3498db;
1345                }
1346                
1347                .input-label {
1348                  font-weight: bold;
1349                  margin-bottom: 5px;
1350                  color: #555;
1351                }
1352                
1353                .input-value {
1354                  font-size: 16px;
1355                }
1356                
1357                .results-grid {
1358                  display: flex;
1359                  flex-wrap: wrap;
1360                  gap: 20px;
1361                  margin-bottom: 25px;
1362                }
1363                
1364                .result-card {
1365                  flex: 1;
1366                  min-width: 200px;
1367                  border: 1px solid #ddd;
1368                  padding: 15px;
1369                  border-radius: 8px;
1370                  background-color: #f5f9ff;
1371                  text-align: center;
1372                }
1373                
1374                .result-name {
1375                  font-weight: bold;
1376                  color: #1a3755;
1377                  margin-bottom: 10px;
1378                  font-size: 16px;
1379                }
1380                
1381                .result-value {
1382                  font-size: 22px;
1383                  color: #3498db;
1384                  margin-bottom: 5px;
1385                  font-weight: bold;
1386                }
1387                
1388                .result-description {
1389                  color: #777;
1390                  font-size: 13px;
1391                }
1392                
1393                .accuracy-note {
1394                  display: flex;
1395                  align-items: center;
1396                  gap: 10px;
1397                  background-color: #fff3cd;
1398                  border: 1px solid #ffeeba;
1399                  color: #856404;
1400                  padding: 10px 15px;
1401                  border-radius: 6px;
1402                  margin: 15px 0;
1403                  font-size: 14px;
1404                }
1405                
1406                .note-icon {
1407                  color: #f39c12;
1408                  font-size: 18px;
1409                  flex-shrink: 0;
1410                }
1411                
1412                .total-energy {
1413                  background-color: #1a3755;
1414                  color: white;
1415                  padding: 15px;
1416                  border-radius: 8px;
1417                  text-align: center;
1418                  margin-bottom: 20px;
1419                }
1420                
1421                .total-title {
1422                  font-size: 16px;
1423                  margin-bottom: 5px;
1424                }
1425                
1426                .total-value {
1427                  font-size: 22px;
1428                  font-weight: bold;
1429                }
1430                
1431                .appliances-list {
1432                  border: 1px solid #ddd;
1433                  border-radius: 8px;
1434                  overflow: hidden;
1435                }
1436                
1437                .appliances-header {
1438                  background-color: #f1f1f1;
1439                  padding: 10px 15px;
1440                  font-weight: bold;
1441                  display: grid;
1442                  grid-template-columns: 3fr 1fr 1fr 1fr 1fr;
1443                  border-bottom: 1px solid #ddd;
1444                }
1445                
1446                .appliance-item {
1447                  padding: 10px 15px;
1448                  display: grid;
1449                  grid-template-columns: 3fr 1fr 1fr 1fr 1fr;
1450                  border-bottom: 1px solid #eee;
1451                }
1452                
1453                .appliance-item:last-child {
1454                  border-bottom: none;
1455                }
1456                
1457                .appliance-item:nth-child(even) {
1458                  background-color: #f9f9f9;
1459                }
1460                
1461                .print-footer {
1462                  margin-top: 30px;
1463                  text-align: center;
1464                  font-size: 14px;
1465                  color: #777;
1466                  padding-top: 15px;
1467                  border-top: 1px solid #ddd;
1468                }
1469                
1470                .print-actions {
1471                  text-align: center;
1472                  margin-top: 30px;
1473                }
1474                
1475                .print-button {
1476                  background-color: #3498db;
1477                  color: white;
1478                  border: none;
1479                  padding: 10px 20px;
1480                  font-size: 16px;
1481                  border-radius: 5px;
1482                  cursor: pointer;
1483                }
1484                
1485                .print-button:hover {
1486                  background-color: #2980b9;
1487                }
1488                
1489                .disclaimer {
1490                  font-size: 12px;
1491                  color: #777;
1492                  font-style: italic;
1493                  margin-top: 20px;
1494                }
1495                
1496                @media print {
1497                  .print-actions {
1498                    display: none;
1499                  }
1500                  
1501                  body {
1502                    padding: 0;
1503                    margin: 0;
1504                  }
1505                  
1506                  .print-container {
1507                    max-width: 100%;
1508                  }
1509                }
1510              </style>
1511            </head>
1512            <body>
1513              <div class="print-container">
1514                <div class="print-header">
1515                  <div class="header-logo">
1516                    <img src="${logoPath}" alt="TEPNG Logo" onerror="this.src='data:image/svg+xml;utf8,<svg xmlns=\\'http://www.w3.org/2000/svg\\' width=\\'150\\' height=\\'80\\'><rect width=\\'150\\' height=\\'80\\' fill=\\'%23f8f8f8\\'/><text x=\\'75\\' y=\\'40\\' font-family=\\'Arial\\' font-size=\\'12\\' fill=\\'%23666\\' text-anchor=\\'middle\\' dominant-baseline=\\'middle\\'>TEPNG LOGO</text></svg>';">
1517                  </div>
1518                  <div class="header-content">
1519                    <div class="print-logo">Solar Power Calculator</div>
1520                    <div class="print-subtitle">Your Personalized Solar System Recommendation</div>
1521                    <div class="print-date">Generated on ${formattedDate} at ${formattedTime}</div>
1522                  </div>
1523                </div>
1524                
1525                <div class="print-section">
1526                  <div class="section-title">Your Inputs</div>
1527                  <div class="inputs-section">
1528                    <div class="input-item">
1529                      <div class="input-label">Home Type</div>
1530                      <div class="input-value">${homeType}</div>
1531                    </div>
1532                    <div class="input-item">
1533                      <div class="input-label">Sunlight Level</div>
1534                      <div class="input-value">${sunlight}</div>
1535                    </div>
1536                    <div class="input-item">
1537                      <div class="input-label">Backup Duration</div>
1538                      <div class="input-value">${backup}</div>
1539                    </div>
1540                  </div>
1541                </div>
1542                
1543                <div class="print-section">
1544                  <div class="section-title">Recommended Solar System</div>
1545                  
1546                  <div class="results-grid">
1547                    <div class="result-card">
1548                      <div class="result-name">Solar Panels</div>
1549                      <div class="result-value">${solarPanelValue}</div>
1550                      <div class="result-description">Capture sunlight to power your home</div>
1551                    </div>
1552                    
1553                    <div class="result-card">
1554                      <div class="result-name">Battery Capacity</div>
1555                      <div class="result-value">${batteryValue}</div>
1556                      <div class="result-description">Stores energy for use when there's no sun</div>
1557                    </div>
1558                    
1559                    <div class="result-card">
1560                      <div class="result-name">System Size</div>
1561                      <div class="result-value">${systemSizeValue}</div>
1562                      <div class="result-description">Powers all your selected appliances</div>
1563                    </div>
1564                  </div>
1565                  
1566                  <div class="accuracy-note">
1567                    <div class="note-icon"><i class="fas fa-exclamation-triangle"></i></div>
1568                    <div class="note-text">These estimates may not be exact. Actual energy usage can vary based on specific models and usage patterns.</div>
1569                  </div>
1570                  
1571                  <div class="total-energy">
1572                    <div class="total-title">Total Daily Energy Use</div>
1573                    <div class="total-value">${totalEnergy.toFixed(1)} kWh</div>
1574                  </div>
1575                </div>
1576                
1577                <div class="print-section">
1578                  <div class="section-title">
1578Selected Appliances (${appliances.length})</div>
1579                  
1580                  <div class="appliances-list">
1581                    <div class="appliances-header">
1582                      <div>Appliance</div>
1583                      <div style="text-align:center">Quantity</div>
1584                      <div style="text-align:center">Wattage</div>
1585                      <div style="text-align:center">Hours/Day</div>
1586                      <div style="text-align:center">kWh/Day</div>
1587                    </div>
1588                    
1589                    ${appliances.map(app => `
1590                      <div class="appliance-item">
1591                        <div>${app.name}</div>
1592                        <div style="text-align:center">${app.quantity}</div>
1593                        <div style="text-align:center">${app.wattage}W</div>
1594                        <div style="text-align:center">${app.hours}</div>
1595                        <div style="text-align:center">${app.kwh.toFixed(2)}</div>
1596                      </div>
1597                    `).join('')}
1598                  </div>
1599                </div>
1600                
1601                <div class="print-footer">
1602                  This solar system recommendation is based on the appliances and options you selected. 
1603                  For a detailed professional assessment, please contact a solar installation expert.
1604                </div>
1605                
1606                <div class="disclaimer">
1607                  Note: Actual energy usage may vary based on specific product models, usage patterns, and environmental factors.
1608                </div>
1609                
1610                <div class="print-actions">
1611                  <button class="print-button" onclick="window.print();">Print This Page</button>
1612                </div>
1613              </div>
1614              
1615              <script>
1616                // Auto-print once everything is loaded
1617                window.onload = function() {
1618                  // Small delay to ensure styles are applied
1619                  setTimeout(function() {
1620                    // Notify the opener window that printing is ready
1621                    window.opener.postMessage('print_ready', '*');
1622                  }, 500);
1623                }
1624              </script>
1625            </body>
1626            </html>
1627          `);
1628          
1629          // Close the document to finish loading
1630          printWindow.document.close();
1631          
1632          // Set up message listener for when printing is ready
1633          window.addEventListener('message', function messageHandler(e) {
1634            if (e.data === 'print_ready') {
1635              // Remove the event listener to prevent multiple calls
1636              window.removeEventListener('message', messageHandler);
1637              
1638              // Hide the loading spinner
1639              hideLoadingSpinner();
1640            }
1641          });
1642        });
1643      }
1644    }
1645    
1646    backToStep2Button.addEventListener('click', function() {
1647      navigateToStep(2);
1648    });
1649
1650    setupEnhancedPrinting();
1651
1652    
1653    // ----------- INITIALIZATION -----------
1654    
1655    // Load shared appliances grid
1656    if (window.AppliancesModule) {
1657      // Set global synchronization between modules
1658      window.customApplianceCounter = 0;
1659      window.AppliancesModule.loadAppliancesGrid('simple', 'appliance-grid-container');
1660    } else {
1661      console.error('Appliances module not loaded!');
1662    }
1663    
1664    // Initialize language
1665    initializeLanguage();  
1666  });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.