Aesthetic Advisor
/* --------------------------------------------------
Basic Reset and Desktop Defaults (Large Screens)
-------------------------------------------------- */
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: Arial, sans-serif; background: #f8f8f8; color: #333; }
.recommender-container {
display: flex;
flex-direction: row;
max-width: 1200px;
margin: 20px auto;
background: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
.model-column, .selection-column { flex: 1; position: relative; }
.model-column { border-right: 1px solid #eee; }
/* Model Wrapper & Images */
.model-wrapper {
position: relative;
width: 100%;
height: 700px;
background: #f0f0f0;
overflow: hidden;
}
.body-model {
position: absolute;
top: 0; left: 0;
width: 100%;
height: 100%;
object-fit: contain;
display: none;
}
.body-model.active { display: block; }
/* Gender Toggle Button */
.gender-toggle-btn {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
padding: 0.5rem 1rem;
background: #333;
color: #fff;
border: none;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s ease;
z-index: 2; /* Ensure above model, below overlay */
}
.gender-toggle-btn:hover { background: #555; }
/* Hotspots */
.hotspot {
position: absolute;
width: 30px;
height: 30px;
background-color: #4AC1D5;
border-radius: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
box-shadow: 0 0 0 4px rgba(74, 193, 213, 0.3); /* Adjusted alpha for subtlety */
transition: transform 0.2s ease, box-shadow 0.2s ease;
z-index: 1; /* Lower than the overlay */
}
.hotspot::before {
content: "+";
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
font-size: 1.2em;
}
.hotspot:hover {
transform: translate(-50%, -50%) scale(1.2);
box-shadow: 0 0 0 6px rgba(74, 193, 213, 0.5); /* Enhanced hover shadow */
}
/* Back Button */
.back-btn {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
padding: 0.5rem 1rem;
background: #f3f4f6;
border: 1px solid #e5e7eb;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: background 0.2s ease;
z-index: 2; /* Ensure above model, below overlay */
}
.back-btn:hover { background: #e5e7eb; }
/* Cover Overlays */
.cover-overlay {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 100; /* Sits above hotspots */
cursor: pointer;
transition: opacity 0.5s ease, visibility 0s 0.5s;
opacity: 1;
visibility: visible;
}
.cover-overlay.left-cover { background: rgba(0, 0, 0, 0.85); }
.cover-overlay.right-cover { background: #fff; color: #333; }
.cover-overlay.hidden {
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 0.5s ease, visibility 0s 0.5s;
}
.cover-content { text-align: center; padding: 20px; }
.left-cover .cover-content { transform: translateY(-70%); }
.pulsing-arrow {
font-size: 2.5rem;
color: #fff;
position: relative;
animation: pulse 1.5s infinite;
z-index: 2;
}
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.1); opacity: 0.7; }
100% { transform: scale(1); opacity: 1; }
}
.pulsing-arrow:before,
.pulsing-arrow:after {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 2px solid #fff;
border-radius: 50%;
opacity: 0.6;
}
.pulsing-arrow:before { width: 60px; height: 60px; z-index: -1; animation: pulse-ring 1.5s infinite ease-out; }
.pulsing-arrow:after { width: 80px; height: 80px; z-index: -2; animation: pulse-ring 1.5s 0.3s infinite ease-out; }
@keyframes pulse-ring {
0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.6; }
100% { transform: translate(-50%, -50%) scale(1.2); opacity: 0; }
}
.click-to-begin { color: #fff; margin-top: 50px; font-size: 1rem; }
/* Right Cover Overlay (Desktop Version) */
.cover-overlay.right-cover .cover-content { text-align: center; }
.welcome-header { font-size: 2.0rem; margin-bottom: 100px; line-height: 1.9; }
.logo-placeholder { margin-bottom: 10px; }
.logo-placeholder img {
max-width: 100%;
height: auto;
transform: translateY(-40px);
max-height: 140px;
}
.steps {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px;
}
.step {
background: #4AC1D5;
padding: 10px 15px;
border-radius: 50px;
display: inline-flex;
align-items: center;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.step-number {
background: #fff;
color: #4AC1D5;
border-radius: 50%;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 10px;
flex-shrink: 0;
font-weight: bold;
}
.step-text { font-size: 1rem; color: #fff; }
/* Panels and Selection Column (Desktop) */
.selection-column {
display: flex; /* Default: visible on desktop */
flex-direction: column;
padding: 20px;
gap: 20px;
background: #fff;
position: relative; /* Needed for cover overlay */
}
.panel { display: none; transition: opacity 0.3s ease; }
.panel.active { display: block; opacity: 1;}
#introPanel, #concernPanel, #planPanel {
background: #fafafa;
border: 1px solid #eee;
border-radius: 8px;
padding: 20px;
}
#concernAreaTitle { margin-bottom: 15px; font-size: 1.25rem; font-weight: bold; }
.concern-list {
display: flex;
flex-direction: column;
gap: 10px;
max-height: 400px; /* Prevent excessive height */
overflow-y: auto; /* Add scroll if needed */
}
.concern-item {
padding: 12px 15px; /* Slightly more padding */
border-radius: 6px;
border: 1px solid #ddd;
cursor: pointer;
transition: background-color 0.2s, border-color 0.2s;
background-color: #fff; /* Default background */
font-size: 0.95rem;
}
.concern-item:hover { background-color: #f0f0f0; }
.concern-item.selected {
border-color: #4AC1D5;
background-color: #e0f7fa; /* Lighter blue background for selected */
font-weight: 500;
}
.plan-panel { display: flex; flex-direction: column; }
.plan-panel h3 { margin-bottom: 10px; }
.treatment-plan-items {
flex: 1;
overflow-y: auto;
margin-bottom: 15px; /* More space before buttons */
max-height: 350px; /* Limit height */
border-top: 1px solid #eee; /* Separator */
border-bottom: 1px solid #eee; /* Separator */
padding: 10px 0; /* Padding for items */
}
.plan-item {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
/* border: 1px solid #ddd; */ /* Removed border for cleaner look */
border-radius: 6px;
padding: 10px;
margin-bottom: 5px;
font-size: 0.9rem;
}
.plan-item:hover { background: #f9f9f9; }
.remove-btn {
background: none;
border: none;
color: #cc0000; /* Brighter red */
font-weight: bold;
cursor: pointer;
font-size: 1.2em; /* Make X slightly larger */
padding: 0 5px; /* Add padding for easier click */
}
.remove-btn:hover { color: #990000; /* Darker red on hover */ }
.empty-plan-text {
color: #999;
font-style: italic;
text-align: center;
margin-top: 20px;
padding: 20px;
}
.plan-buttons {
display: flex;
justify-content: space-between;
margin-top: 10px; /* Added margin */
}
.primary-btn, .secondary-btn {
border: none;
border-radius: 20px;
padding: 10px 20px;
cursor: pointer;
transition: background 0.3s ease, opacity 0.3s ease;
font-weight: bold;
}
.primary-btn { background: #4AC1D5; color: #fff; }
.primary-btn:hover { background: #3b9eaa; } /* Slightly darker hover */
.secondary-btn { background: #eee; color: #333; }
.secondary-btn:hover { background: #ddd; }
.primary-btn:disabled { background: #a0dbe4; opacity: 0.7; cursor: not-allowed; }
/* Generic Modal Styles */
.modal {
position: fixed;
top: 0; left: 0;
width: 100%;
height: 100%;
display: none; /* Hidden by default */
background: rgba(0,0,0,0.6); /* Slightly darker overlay */
justify-content: center;
align-items: center;
z-index: 1000; /* High z-index */
padding: 15px; /* Padding for smaller screens */
}
.modal.show { display: flex; } /* Use flex to center content */
.modal-content {
background: #fff;
padding: 25px 30px; /* More padding */
border-radius: 8px;
max-width: 500px;
width: 100%;
position: relative;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
max-height: 90vh; /* Limit height */
display: flex; /* Use flex for internal layout */
flex-direction: column;
}
/* Form Modal Specifics */
#formModal .modal-content h2 {
margin-bottom: 15px;
font-size: 1.3rem;
color: #333;
}
.form-group { margin-bottom: 15px; }
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
font-size: 0.9rem;
}
.form-group label span { color: red; } /* Required asterisk */
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px; /* More padding */
border: 1px solid #ccc; /* Slightly darker border */
border-radius: 4px;
font-size: 1rem;
}
.form-group textarea { min-height: 80px; } /* Ensure textarea is usable */
.form-disclaimer { font-size: 0.85rem; color: #666; margin-bottom: 20px; line-height: 1.4;}
#formModal .primary-btn { width: 100%; padding: 12px; font-size: 1rem; } /* Full width submit */
/* Generic Close Button */
.close-modal-btn {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
cursor: pointer;
color: #888; /* Lighter color */
font-size: 1.8rem; /* Larger */
line-height: 1;
padding: 5px;
transition: color 0.3s ease;
}
.close-modal-btn:hover { color: #333; }
/* --- NEW: Mobile Concern Modal Styles --- */
.mobile-concern-modal .modal-content {
max-width: 90%; /* Use more width on mobile */
padding: 20px;
}
.mobile-concern-modal h2 {
font-size: 1.2rem;
margin-bottom: 15px;
text-align: center;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
.mobile-concern-modal .concern-list {
max-height: 60vh; /* Limit height on mobile */
overflow-y: auto;
margin-bottom: 15px; /* Space before close button */
}
/* Re-use concern-item styles */
.mobile-concern-modal .concern-item {
font-size: 1rem; /* Slightly larger text for mobile */
padding: 15px;
}
.mobile-concern-modal .modal-close-footer {
text-align: center;
margin-top: 15px;
}
.mobile-concern-modal .secondary-btn { /* Style a close button if needed */
padding: 8px 25px;
}
/* --- END NEW --- */
/* Toast Notification */
.toast {
position: fixed;
bottom: 20px;
left: 50%; /* Center horizontally */
transform: translateX(-50%); /* Actual centering */
background: #333;
color: #fff;
padding: 12px 25px;
border-radius: 6px;
opacity: 0;
/* transform: translateY(50px); */ /* Removed Y transform for simple fade */
transition: opacity 0.4s ease;
z-index: 1010; /* Above modals */
pointer-events: none; /* Don't intercept clicks */
}
.toast.show {
opacity: 1;
/* transform: translateY(0); */
}
/* Back button inside concern panel */
#closeConcernsBtn {
background: none;
border: none;
cursor: pointer;
color: #555;
font-size: 0.9rem;
margin-bottom: 10px; /* Space below button */
display: inline-block; /* Allow margin */
padding: 5px 0;
transition: color 0.2s ease;
}
#closeConcernsBtn:hover { color: #000; }
/* --- *** CSS FIX *** --- */
/* --- Mobile Submit Button Area --- */
.mobile-submit-area {
/* display: block; REMOVED THIS LINE */
padding: 15px;
background-color: #f8f8f8;
text-align: center;
border-top: 1px solid #eee;
display: none; /* HIDE BY DEFAULT (for desktop) - ADDED THIS LINE */
}
.mobile-submit-area .primary-btn {
width: 80%;
max-width: 300px;
padding: 12px 20px;
font-size: 1rem;
}
/* --- *** END CSS FIX *** --- */
/* --------------------------------------------------
Mobile Adjustments – Reordering for Mobile Layout
-------------------------------------------------- */
/* Hide mobile-specific elements on desktop */
.mobile-welcome-header,
.mobile-logo-buttons { display: none; }
@media (max-width: 768px) {
/* Stack the overall layout vertically */
.recommender-container {
flex-direction: column;
margin: 0; /* Remove margin for full width */
border-radius: 0; /* Remove radius for full width */
box-shadow: none; /* Remove shadow */
}
.model-column, .selection-column { width: 100%; }
.model-column {
border-right: none;
border-bottom: 1px solid #eee;
min-height: 400px; /* Ensure minimum height */
}
.model-wrapper {
height: auto; /* Let content determine height */
min-height: 400px; /* Match column height */
}
.body-model {
position: relative; /* Change positioning for natural flow */
object-fit: contain; /* Keep contain */
max-height: 400px; /* Limit image height */
}
.gender-toggle-btn { bottom: 10px; }
.back-btn { bottom: 10px; }
/* Hide the original right cover overlay and selection column */
.cover-overlay.right-cover,
.selection-column { display: none !important; } /* Keep this! */
/* Show mobile welcome header */
.mobile-welcome-header {
display: block;
background: #fff;
padding: 1rem;
text-align: center;
border-bottom: 1px solid #eee;
box-shadow: 0 2px 4px rgba(0,0,0,0.05); /* Subtle shadow */
}
.mobile-welcome-header .welcome-header {
font-size: 1.4rem; /* Adjust size */
margin: 0;
line-height: 1.4;
}
/* Show mobile logo/buttons */
.mobile-logo-buttons {
display: block;
background: #fff;
padding: 1.5rem 1rem; /* More padding */
text-align: center;
border-top: 1px solid #eee; /* Use border instead of margin */
}
.mobile-logo-buttons .logo-placeholder {
margin-bottom: 1.5rem; /* More space */
}
.mobile-logo-buttons .logo-placeholder img {
max-width: 60%; /* Adjust logo size */
max-height: 100px;
height: auto;
transform: none; /* Reset desktop transform */
}
.mobile-logo-buttons .steps {
display: flex;
flex-direction: column;
gap: 0.8rem; /* Adjust gap */
align-items: flex-start; /* left align items */
text-align: left; /* ensure text is left aligned */
max-width: 400px; /* Limit width for better readability */
margin: 0 auto; /* Center the steps block */
}
.mobile-logo-buttons .step {
padding: 0.6rem 1rem; /* Adjust padding */
border-radius: 30px; /* Adjust radius */
background: #4AC1D5;
color: #fff;
display: flex;
align-items: center;
width: 100%; /* Make steps full width */
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.mobile-logo-buttons .step-number {
margin-right: 0.8rem; /* Adjust spacing */
width: 28px; /* Adjust size */
height: 28px;
font-size: 0.9rem;
}
.mobile-logo-buttons .step-text {
font-size: 0.9rem; /* Adjust text size */
}
/* Adjust Hotspot size for mobile */
.hotspot {
width: 25px;
height: 25px;
}
.hotspot::before { font-size: 1em; }
/* Make left cover content centered better on mobile */
.left-cover .cover-content { transform: none; }
.pulsing-arrow { font-size: 2rem; }
.pulsing-arrow:before { width: 50px; height: 50px; }
.pulsing-arrow:after { width: 70px; height: 70px; }
.click-to-begin { margin-top: 30px; }
/* --- *** CSS FIX *** --- */
/* --- Explicitly show mobile submit area --- */
.mobile-submit-area {
display: block; /* SHOW ONLY ON MOBILE */
}
/* --- *** END CSS FIX *** --- */
} /* End @media (max-width: 768px) */
/* --- *** CSS FIX *** --- */
/* REMOVED the @media (min-width: 769px) rule that previously tried to hide .mobile-submit-area */
/* --- *** END CSS FIX *** --- */
Welcome to your 360 Aesthetic Advisor
Switch to Male
Back to Body
↖
click to begin
Welcome to your 360 Aesthetic Advisor
1
Click on body parts to view concerns.
2
Select your concerns.
3
Submit & receive your personalized treatment recommendations.
Welcome!
Click on a body area to begin building your treatment plan.
← Back to Plan
Area Concerns
Your Selections (0)
No selections yet. Click a body area to begin.
Clear All
Finish & Get Results
1
Click on body parts to view concerns.
2
Select one or multiple concerns.
3
Submit to receive personalized treatment recommendations.
Finish & Get Results (0)
×
Area Concerns
×
Enter your contact information to receive your customized treatment plan!
First Name *
Email *
Additional Information
All of your information will be kept private and only shared with your provider.
Submit
Message goes here
document.addEventListener('DOMContentLoaded', function() {
// --- DOM Element References ---
const toggleGenderBtn = document.getElementById('toggleGenderBtn');
const femaleModel = document.getElementById('femaleModel');
const maleModel = document.getElementById('maleModel');
const bodyModelContainer = document.getElementById('bodyModelContainer');
const faceModelContainer = document.getElementById('faceModelContainer');
const backToBodyBtn = document.getElementById('backToBodyBtn');
const leftCover = document.querySelector('.cover-overlay.left-cover');
const rightCover = document.querySelector('.cover-overlay.right-cover');
const introPanel = document.getElementById('introPanel');
const concernPanel = document.getElementById('concernPanel');
const planPanel = document.getElementById('planPanel');
const concernAreaTitle = document.getElementById('concernAreaTitle');
const concernList = document.getElementById('concernList');
const closeConcernsBtn = document.getElementById('closeConcernsBtn');
const planCountDesktop = document.getElementById('planCount');
const treatmentPlanItems = document.getElementById('treatmentPlanItems');
const clearPlanBtn = document.getElementById('clearPlanBtn');
const finishPlanBtnDesktop = document.getElementById('finishPlanBtnDesktop');
const formModal = document.getElementById('formModal');
const treatmentPlanDataInput = document.getElementById('treatment_plan_data');
const contactForm = document.getElementById('contactForm');
const toast = document.getElementById('toast');
// Mobile Specific Elements
const mobileConcernModal = document.getElementById('mobileConcernModal');
const mobileConcernAreaTitle = document.getElementById('mobileConcernAreaTitle');
const mobileConcernList = document.getElementById('mobileConcernList');
const finishPlanBtnMobile = document.getElementById('finishPlanBtnMobile');
const mobilePlanCount = document.getElementById('mobilePlanCount');
let isFemale = true;
let treatmentPlan = []; // Stores { area: string, id: string, label: string }
// --- Data ---
const AREA_CONCERNS = {
face: [
{ id: 'fine-lines', label: 'Fine lines & wrinkles' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }, { id: 'dull-skin', label: 'Dull skin' }, { id: 'sagging-skin', label: 'Sagging skin' }, { id: 'enlarged-pores', label: 'Enlarged pores' }
],
forehead: [
{ id: 'fine-lines', label: 'Fine lines & wrinkles' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }, { id: 'dull-skin', label: 'Dull skin' }, { id: 'sagging-skin', label: 'Sagging skin' }, { id: 'enlarged-pores', label: 'Enlarged pores' }, { id: 'hair-thinning', label: 'Hair thinning or hair loss' }
],
eyes: [
{ id: 'dark-circles', label: 'Dark circles' }, { id: 'fine-lines', label: 'Fine lines (crow’s feet)' }, { id: 'puffiness', label: 'Puffiness' }, { id: 'thin-skin', label: 'Thin or crepey skin' }, { id: 'lash-enhancement', label: 'Lash enhancement' }
],
cheeks: [
{ id: 'acne', label: 'Acne & acne scars' }, { id: 'dark-spots', label: 'Dark spots & melasma' }, { id: 'dull-skin', label: 'Dull skin' }, { id: 'redness', label: 'Redness or rosacea' }, { id: 'sensitive-skin', label: 'Sensitive skin' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }, { id: 'enlarged-pores', label: 'Enlarged pores & blackheads' }
],
nose: [
{ id: 'oily-skin', label: 'Oily skin' }, { id: 'blackheads', label: 'Blackheads' }, { id: 'redness', label: 'Redness' }, { id: 'enlarged-pores', label: 'Visible/enlarged pores' }
],
lips: [
{ id: 'lip-shape', label: 'Lip shape or volume' }, { id: 'fine-lines', label: 'Fine lines around lips' }, { id: 'dry-lips', label: 'Dry or cracked lips' }
],
jaw: [
{ id: 'sagging-skin', label: 'Sagging skin' }, { id: 'jowls', label: 'Jowls' }, { id: 'jawline-definition', label: 'Jawline definition' }, { id: 'acne', label: 'Acne or breakouts' }, { id: 'enlarged-pores', label: 'Enlarged pores' }
],
neck: [
{ id: 'sagging-skin', label: 'Sagging / crepey skin' }, { id: 'fine-lines', label: 'Fine lines' }, { id: 'dull-skin', label: 'Dull skin' }, { id: 'dark-spots', label: 'Dark spots & sun damage' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }, { id: 'decolletage-rejuvenation', label: 'Decolletage rejuvenation' }
],
underarms: [ { id: 'excessive-sweating', label: 'Excessive sweating (hyperhidrosis)' } ],
abdomen: [
{ id: 'stretch-marks', label: 'Stretch marks' }, { id: 'cellulite', label: 'Cellulite' }, { id: 'sagging-skin', label: 'Sagging skin' }, { id: 'uneven-texture', label: 'Uneven skin texture' }, { id: 'medical-weight-loss', label: 'Medical weight loss' }
],
hips: [
{ id: 'stretch-marks', label: 'Stretch marks' }, { id: 'cellulite', label: 'Cellulite' }, { id: 'sagging-skin', label: 'Sagging or loose skin' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }
],
hands: [
{ id: 'thin-skin', label: 'Thin or aging skin' }, { id: 'dry-skin', label: 'Dry skin' }, { id: 'uneven-skin-tone', label: 'Uneven skin tone' }, { id: 'volume-loss', label: 'Volume loss' }, { id: 'hands-rejuvenation', label: 'Hands rejuvenation' }
]
};
// --- Utility Functions ---
function capitalize(str) {
return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
}
function isMobileView() {
// Use window.matchMedia for reliable detection based on CSS breakpoint
return window.matchMedia("(max-width: 768px)").matches;
}
function showToast(message) {
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
function openModal(modalElement) {
if(modalElement) modalElement.classList.add('show');
}
function closeModal(modalElement) {
if(modalElement) modalElement.classList.remove('show');
}
// --- Core Logic Functions ---
// Updates both desktop plan panel and mobile submit button state
function renderPlanItems() {
const count = treatmentPlan.length;
// Update Desktop Plan Panel (only if it exists)
if (treatmentPlanItems && finishPlanBtnDesktop && planCountDesktop && introPanel && planPanel) {
treatmentPlanItems.innerHTML = ""; // Clear previous items
if (count === 0) {
treatmentPlanItems.innerHTML = '
No selections yet. Click a body area to begin.
'; finishPlanBtnDesktop.disabled = true; if (planPanel.classList.contains('active') && !isMobileView()) { planPanel.classList.remove('active'); introPanel.classList.add('active'); // Show intro if plan becomes empty } } else { finishPlanBtnDesktop.disabled = false; if (introPanel.classList.contains('active') && !isMobileView()) { introPanel.classList.remove('active'); planPanel.classList.add('active'); // Ensure plan panel is visible if items exist } treatmentPlan.forEach((item, index) => { const row = document.createElement("div"); row.className = "plan-item"; row.innerHTML = `${capitalize(item.area)}: ${item.label}
`;
row.querySelector('.remove-btn').addEventListener("click", function() {
const itemToRemove = treatmentPlan[index]; // Get item before removing
treatmentPlan.splice(index, 1);
renderPlanItems(); // Update plan display
// Update selection state in the currently visible concern list (if any)
if (!isMobileView() && concernPanel && concernPanel.classList.contains('active')) {
renderConcernSelection(itemToRemove.area, concernList); // Update desktop list
}
showToast(`Removed: ${itemToRemove.label}`);
});
treatmentPlanItems.appendChild(row);
});
}
planCountDesktop.textContent = `(${count})`;
}
// Update Mobile Submit Button (only if it exists)
if(mobilePlanCount && finishPlanBtnMobile) {
mobilePlanCount.textContent = count;
finishPlanBtnMobile.disabled = (count === 0);
}
}
// Renders the selection state (highlighting) for concerns in a given list element
function renderConcernSelection(area, listElement) {
if (!listElement) return; // Guard against null listElement
const items = listElement.querySelectorAll(".concern-item");
items.forEach(item => {
const concernId = item.getAttribute('data-id'); // Use data-id for reliable matching
const inPlan = treatmentPlan.some(tp => tp.area === area && tp.id === concernId);
item.classList.toggle("selected", inPlan);
});
}
// Handles showing concerns either in Desktop Panel or Mobile Modal
function showConcerns(area) {
const concerns = AREA_CONCERNS[area] || [];
const areaTitleText = capitalize(area) + " Concerns";
if (isMobileView()) {
// --- Mobile Logic: Use Modal ---
if (!mobileConcernModal || !mobileConcernAreaTitle || !mobileConcernList) return; // Guard clauses
mobileConcernAreaTitle.textContent = areaTitleText;
mobileConcernList.innerHTML = ""; // Clear previous items
concerns.forEach(concern => {
const div = document.createElement("div");
div.className = "concern-item";
div.textContent = concern.label;
div.setAttribute('data-id', concern.id); // Store ID for matching
div.setAttribute('data-area', area); // Store area for context
// Add click listener to toggle selection and close modal
div.addEventListener("click", function() {
toggleConcern(area, concern);
// Toggle class immediately for visual feedback before modal closes
this.classList.toggle("selected", treatmentPlan.some(tp => tp.area === area && tp.id === concern.id));
// Close modal after a short delay for visual feedback
setTimeout(() => closeModal(mobileConcernModal), 150);
});
mobileConcernList.appendChild(div);
});
// Update selection state for the newly added items
renderConcernSelection(area, mobileConcernList);
openModal(mobileConcernModal);
} else {
// --- Desktop Logic: Use Panel ---
if (!concernAreaTitle || !concernList || !introPanel || !planPanel || !concernPanel) return; // Guard clauses
concernAreaTitle.textContent = areaTitleText;
concernList.innerHTML = ""; // Clear previous items
concerns.forEach(concern => {
const div = document.createElement("div");
div.className = "concern-item";
div.textContent = concern.label;
div.setAttribute('data-id', concern.id); // Store ID for matching
div.setAttribute('data-area', area); // Store area for context
div.addEventListener("click", function() {
toggleConcern(area, concern);
// Re-render selection state for the desktop list after toggle
renderConcernSelection(area, concernList);
});
concernList.appendChild(div);
});
// Update selection state for the newly added items
renderConcernSelection(area, concernList);
// Switch panels
introPanel.classList.remove('active');
planPanel.classList.remove('active'); // Hide plan panel when showing concerns
concernPanel.classList.add('active');
}
}
// Toggles a concern in the treatment plan
function toggleConcern(area, concern) {
const index = treatmentPlan.findIndex(item => item.area === area && item.id === concern.id);
if (index > -1) {
// Remove concern
treatmentPlan.splice(index, 1);
showToast(`Removed: ${concern.label}`);
} else {
// Add concern
treatmentPlan.push({ area: area, id: concern.id, label: concern.label });
showToast(`Added: ${concern.label}`);
}
// Update the main plan display (both desktop and mobile button state)
renderPlanItems();
}
// Prepares and shows the final submission form
function initiateFinishPlan() {
if (treatmentPlan.length === 0) return; // Should be disabled, but double-check
if (!treatmentPlanDataInput || !formModal) return; // Guard clauses
// Format plan for hidden input
const planText = treatmentPlan.map(item => `${capitalize(item.area)}: ${item.label}`).join('\n');
treatmentPlanDataInput.value = planText;
// Show the form modal
openModal(formModal);
}
// --- Event Listeners ---
// Gender Toggle
if (toggleGenderBtn) {
toggleGenderBtn.addEventListener('click', () => {
isFemale = !isFemale;
if (femaleModel) femaleModel.classList.toggle('active', isFemale);
if (maleModel) maleModel.classList.toggle('active', !isFemale);
toggleGenderBtn.textContent = isFemale ? 'Switch to Male' : 'Switch to Female';
});
}
// Hotspot Clicks (using event delegation on containers)
if (bodyModelContainer) {
bodyModelContainer.addEventListener('click', function(e) {
if (e.target.classList.contains('hotspot')) {
e.stopPropagation();
const area = e.target.getAttribute('data-area');
if (area === "face") {
if (faceModelContainer) {
bodyModelContainer.style.display = "none";
faceModelContainer.style.display = "block";
}
} else {
showConcerns(area);
}
}
});
}
if (faceModelContainer) {
faceModelContainer.addEventListener('click', function(e) {
if (e.target.classList.contains('hotspot')) {
e.stopPropagation();
const area = e.target.getAttribute('data-area');
showConcerns(area);
}
});
}
// Back from Face to Body
if (backToBodyBtn) {
backToBodyBtn.addEventListener('click', () => {
if (faceModelContainer) faceModelContainer.style.display = "none";
if (bodyModelContainer) bodyModelContainer.style.display = "block";
// Decide if we should show intro or plan panel on desktop
if (!isMobileView()) {
if (concernPanel) concernPanel.classList.remove('active'); // Hide concerns if user goes back
if (treatmentPlan.length > 0) {
if (planPanel) planPanel.classList.add('active');
if (introPanel) introPanel.classList.remove('active');
} else {
if (planPanel) planPanel.classList.remove('active');
if (introPanel) introPanel.classList.add('active');
}
}
});
}
// Hide Cover Overlays
function hideCovers() {
if(leftCover) leftCover.classList.add('hidden');
if (rightCover) rightCover.classList.add('hidden'); // Only hide right if it exists
// Show initial panel(s) after covers hide
if (!isMobileView()) {
// Desktop: show intro or plan panel based on selections
if (treatmentPlan.length === 0) {
if(introPanel) introPanel.classList.add('active');
if(planPanel) planPanel.classList.remove('active');
} else {
if(introPanel) introPanel.classList.remove('active');
if(planPanel) planPanel.classList.add('active');
}
}
// No specific action needed for mobile after cover hide, interaction starts with hotspots.
}
if(leftCover) leftCover.addEventListener('click', hideCovers);
if (rightCover) rightCover.addEventListener('click', hideCovers);
// Back button inside Desktop Concern Panel
if (closeConcernsBtn) {
closeConcernsBtn.addEventListener('click', () => {
if (concernPanel) concernPanel.classList.remove('active');
// Show plan panel if it has items, otherwise intro
if (treatmentPlan.length > 0) {
if (planPanel) planPanel.classList.add('active');
if (introPanel) introPanel.classList.remove('active');
} else {
if (planPanel) planPanel.classList.remove('active');
if (introPanel) introPanel.classList.add('active');
}
});
}
// Clear All Selections Button (Desktop)
if (clearPlanBtn) {
clearPlanBtn.addEventListener('click', () => {
if (treatmentPlan.length > 0) {
treatmentPlan = [];
renderPlanItems(); // Update UI
// If concern panel was active, switch back to intro on desktop
if (!isMobileView() && concernPanel && concernPanel.classList.contains('active')) {
concernPanel.classList.remove('active');
if (introPanel) introPanel.classList.add('active');
}
showToast("All selections cleared.");
}
});
}
// Finish & Get Results Buttons (Desktop and Mobile)
if(finishPlanBtnDesktop) finishPlanBtnDesktop.addEventListener('click', initiateFinishPlan);
if(finishPlanBtnMobile) finishPlanBtnMobile.addEventListener('click', initiateFinishPlan);
// Modal Closing (Generic Handler for Close Buttons and Backdrop)
document.addEventListener('click', function(e) {
// Check for close buttons with data-close-modal attribute
if (e.target.matches('[data-close-modal]')) {
const modalId = e.target.getAttribute('data-close-modal');
const modalToClose = document.getElementById(modalId);
if (modalToClose) {
closeModal(modalToClose);
}
}
// Check for backdrop clicks (target is the modal container itself)
else if (e.target.classList.contains('modal')) {
closeModal(e.target);
}
});
// Form submission (optional: add validation or confirmation)
// if(contactForm) {
// contactForm.addEventListener('submit', function(e) {
// // Optional: Add client-side validation here if needed
// console.log("Form submitted with plan:", treatmentPlanDataInput.value);
// });
// }
// --- Initial Setup ---
renderPlanItems(); // Initialize plan display (counts, button states)
// Hide covers if they shouldn't show initially (e.g., deep link, testing)
// hideCovers(); // Uncomment this line if you want covers hidden by default
});