<!DOCTYPE html>
<html lang="en">
...
<!--
Phill Good Skin & Hair - Single-file demo website
- Replace /assets/logo.png with your current Phill Good, Inc logo file
- Replace placeholder product images in /assets/products/
- This file includes:
• Product catalog with categories and status (Market Ready / In Production)
• Product detail modal with ingredient & benefits
• Ordering form (stores orders locally; replace with real payment/DB)
• Reviews system (stored locally; replace with server-side storage)
• Simple Admin panel to add/edit products & keep info organized
- To make production-ready:
• Hook order submission to a payment gateway (Stripe/PayPal)
• Move product & review data to a backend (Firebase, Supabase, custom API)
• Protect admin routes and add authentication
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Phill Good Skin & Hair Products</title>
<meta name="description" content="Handcrafted low-water body butters, hair serums, and balms from Phill Good, Inc — smooth texture, great scent, skin benefits in every jar." />
<style>
/* --- Basic Reset --- */
:root{
--bg:#0f0f13; --card:#111217; --muted:#9aa0a6; --accent:#7b4cff; --accent-2:#ff8a00;
--glass: rgba(255,255,255,0.04);
--max-width:1100px;
--radius:12px;
font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
color-scheme: dark;
}
*{box-sizing:border-box}
html,body{height:100%; margin:0; background:linear-gradient(180deg,#081018 0%, #081218 60%); color:#fff}
a{color:var(--accent); text-decoration:none}
.wrap{max-width:var(--max-width); margin:28px auto; padding:20px}
header{display:flex; gap:16px; align-items:center; margin-bottom:18px}
.logo{display:flex; gap:12px; align-items:center}
.logo img{height:56px; width:auto; border-radius:8px; background:#fff1; padding:6px}
.brand-title{font-weight:700; font-size:1.25rem}
.tagline{color:var(--muted); font-size:0.9rem}
nav{margin-left:auto; display:flex; gap:12px; align-items:center}
/* --- Controls --- */
.controls{display:flex; gap:10px; flex-wrap:wrap; margin:16px 0}
.btn{background:var(--accent); color:#fff; padding:10px 12px; border-radius:999px; border:none; cursor:pointer; font-weight:600}
.btn.secondary{background:transparent; border:1px solid rgba(255,255,255,0.06); padding:8px 10px}
.filter{background:var(--glass); padding:8px 10px; border-radius:10px; border:1px solid rgba(255,255,255,0.03)}
.search{flex:1; min-width:180px}
input[type="search"], input[type="text"], select { background:transparent; color:inherit; border:1px solid rgba(255,255,255,0.05); padding:8px 10px; border-radius:8px; width:100%;}
/* --- Grid --- */
.grid{display:grid; grid-template-columns: repeat(auto-fill,minmax(230px,1fr)); gap:16px; margin-top:12px}
.card{background:linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)); padding:14px; border-radius:12px; border:1px solid rgba(255,255,255,0.03); display:flex; flex-direction:column; gap:10px}
.product-img{height:160px; background:#0003; border-radius:10px; display:flex; align-items:center; justify-content:center; overflow:hidden}
.product-img img{width:100%; height:100%; object-fit:cover}
.meta{display:flex; justify-content:space-between; align-items:center}
.product-title{font-weight:700}
.badges{display:flex; gap:6px; flex-wrap:wrap}
.badge{padding:6px 8px; border-radius:999px; font-size:0.75rem; background:#ffffff12}
.status-in{background:linear-gradient(90deg,#1b8a56,#1fb97b); color:white}
.status-prod{background:linear-gradient(90deg,#ffb347,#ffcc33); color:#111}
.price{font-weight:800}
.excerpt{color:var(--muted); font-size:0.9rem}
/* --- Modal & panels --- */
.overlay{position:fixed; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0.7), rgba(0,0,0,0.8)); display:none; align-items:center; justify-content:center; z-index:80}
.modal{background: #07070a; width:95%; max-width:880px; border-radius:12px; padding:18px; border:1px solid rgba(255,255,255,0.04)}
.modal-body{display:grid; grid-template-columns: 1fr 340px; gap:14px}
.modal-body img{width:100%; height:320px; object-fit:cover; border-radius:10px}
.ingredients{background:#0b0b0f; padding:10px; border-radius:10px; border:1px solid rgba(255,255,255,0.02)}
/* --- Orders & reviews --- */
form.order-form{display:flex; flex-direction:column; gap:10px}
.form-row{display:flex; gap:8px}
.form-row > *{flex:1}
textarea{min-height:80px; border-radius:8px; padding:10px; border:1px solid rgba(255,255,255,0.04)}
.reviews{margin-top:12px; display:flex; flex-direction:column; gap:8px}
.review{background:#050507; padding:10px; border-radius:8px; border:1px solid rgba(255,255,255,0.02)}
.small{font-size:0.85rem; color:var(--muted)}
/* --- Admin panel --- */
.admin-panel{margin-top:18px; background:#071021; padding:12px; border-radius:10px; border:1px dashed rgba(255,255,255,0.03)}
.row{display:flex; gap:12px; align-items:center}
.product-list{display:flex; flex-direction:column; gap:8px; margin-top:12px}
/* --- Footer --- */
footer{margin-top:28px; padding:20px; text-align:center; color:var(--muted); font-size:0.92rem}
/* --- Responsive tweaks --- */
@media (max-width:880px){
.modal-body{grid-template-columns:1fr; }
.modal-body img{height:220px}
}
</style>
</head>
<body>
<div class="wrap" id="app">
<header>
<div class="logo">
<img src="/assets/logo.png" alt="Phill Good, Inc logo (replace with your logo)" id="brandLogo" />
<div>
<div class="brand-title">Phill Good Skin & Hair</div>
<div class="tagline">Low-water butters • Smooth texture • Signature scents • Real skin benefits</div>
</div>
</div>
<nav>
<button class="btn" id="viewCatalogBtn">Shop</button>
<button class="btn secondary" id="viewOrdersBtn">Orders</button>
<button class="btn secondary" id="adminToggleBtn">Admin</button>
</nav>
</header>
<!-- Controls -->
<div class="controls" aria-hidden="false">
<div style="min-width:220px;">
<input id="query" type="search" placeholder="Search products, ingredients, benefits..." aria-label="Search products" class="search"/>
</div>
<div class="filter">
<label class="small">Filter</label>
<div style="display:flex; gap:8px; margin-top:6px;">
<select id="filterStatus" aria-label="Filter by status">
<option value="all">All statuses</option>
<option value="market-ready">Market Ready</option>
<option value="in-production">In Production</option>
</select>
<select id="filterCategory" aria-label="Filter by category">
<option value="all">All categories</option>
<option value="body">Body Butter</option>
<option value="beard">Beard & Hair</option>
<option value="serum">Serums</option>
</select>
</div>
</div>
<div style="margin-left:auto; display:flex; gap:8px;">
<button class="btn" id="newArrivalBtn">New Arrival</button>
<button class="btn secondary" id="clearFiltersBtn">Clear</button>
</div>
</div>
<!-- Product grid -->
<section aria-label="Product catalog">
<div id="productGrid" class="grid" role="list" aria-live="polite">
<!-- Product cards injected by JS -->
</div>
</section>
<!-- Modal overlay -->
<div class="overlay" id="overlay" role="dialog" aria-modal="true" aria-hidden="true">
<div class="modal" role="document" aria-label="Product details">
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px; margin-bottom:8px;">
<div style="font-weight:800; font-size:1.1rem" id="modalTitle">Product name</div>
<div style="display:flex; gap:8px;">
<button class="btn secondary" id="closeModalBtn">Close</button>
<button class="btn" id="openOrderBtn">Order</button>
</div>
</div>
<div class="modal-body">
<div>
<img id="modalImage" src="/assets/products/placeholder.jpg" alt="Product image"/>
<div style="display:flex; gap:10px; margin-top:10px;">
<div style="flex:1">
<div class="small">Description</div>
<div id="modalDesc" style="margin-top:6px; color:var(--muted)"></div>
</div>
<div style="width:260px;">
<div class="ingredients">
<div style="font-weight:700">Ingredients & Benefits</div>
<div id="modalIngredients" class="small" style="margin-top:8px"></div>
</div>
<div style="margin-top:10px;">
<div class="small">Status</div>
<div id="modalStatus" style="margin-top:6px" class="badge"></div>
</div>
<div style="margin-top:10px;">
<div class="small">Price</div>
<div id="modalPrice" style="font-weight:900; margin-top:6px"></div>
</div>
</div>
</div>
<div style="margin-top:14px;">
<div style="display:flex; justify-content:space-between; align-items:center;">
<div style="font-weight:800">Customer Reviews</div>
<div class="small" id="reviewsCount"></div>
</div>
<div id="reviewsContainer" class="reviews"></div>
<div style="margin-top:10px;">
<div style="font-weight:700">Leave a Review</div>
<div style="margin-top:8px; display:flex; gap:8px;">
<input id="reviewerName" placeholder="Name" />
<select id="reviewRating" style="width:120px;">
<option value="5">5 ★</option><option value="4">4 ★</option><option value="3">3 ★</option>
<option value="2">2 ★</option><option value="1">1 ★</option>
</select>
</div>
<textarea id="reviewText" placeholder="Tell others why you love it..."></textarea>
<div style="display:flex; gap:8px; justify-content:flex-end;">
<button class="btn" id="submitReviewBtn">Submit Review</button>
</div>
</div>
</div>
</div>
<!-- Order / quick cart panel -->
<aside>
<div style="font-weight:800; margin-bottom:6px">Order</div>
<div style="background:#05060a; padding:10px; border-radius:8px;">
<div class="small">Selected</div>
<div id="orderProductName" style="font-weight:800; margin:6px 0"></div>
<form class="order-form" id="orderForm" onsubmit="return false;">
<label class="small">Quantity</label>
<input id="orderQty" type="number" min="1" value="1"/>
<label class="small">Full name</label>
<input id="orderName" type="text" required />
<label class="small">Email or phone</label>
<input id="orderContact" type="text" required />
<label class="small">Shipping address</label>
<input id="orderAddress" type="text" />
<label class="small">Notes (gift/scent preference)</label>
<textarea id="orderNotes"></textarea>
<div style="display:flex; gap:8px; margin-top:8px;">
<button class="btn" id="placeOrderBtn">Place Order</button>
<button class="btn secondary" id="saveCartBtn">Save Cart</button>
</div>
<div id="orderMsg" class="small" style="margin-top:8px;color:var(--muted)"></div>
</form>
</div>
<div style="margin-top:12px;">
<div class="small">Why choose our butters?</div>
<ul class="small" style="margin-top:8px">
<li>Ultra-low water content — slower dilution, longer hydration</li>
<li>Velvety texture — melts into skin, not greasy</li>
<li>Clean, signature scents — balanced & not overpowering</li>
<li>Ingredients with purpose — repair, protect, brighten</li>
</ul>
</div>
</aside>
</div>
</div>
</div>
<!-- Admin / Orders panels -->
<section id="panels" style="margin-top:18px;">
<div id="ordersPanel" style="display:none;">
<div style="display:flex; justify-content:space-between; align-items:center;">
<div style="font-weight:800">Orders</div>
<div class="small" id="ordersSummary"></div>
</div>
<div id="ordersList" class="product-list"></div>
</div>
<div id="adminPanel" class="admin-panel" style="display:none;">
<div style="display:flex; justify-content:space-between; align-items:center;">
<div><strong>Admin Panel</strong> — quick product & catalog management</div>
<div class="small">Local demo admin (no auth)</div>
</div>
<div style="margin-top:10px">
<form id="addProductForm" onsubmit="return false;" style="display:flex; gap:8px; flex-wrap:wrap; align-items:center;">
<input id="pName" placeholder="Product name" required style="min-width:180px"/>
<select id="pCategory"><option value="body">Body Butter</option><option value="beard">Beard & Hair</option><option value="serum">Serum</option></select>
<select id="pStatus"><option value="market-ready">Market Ready</option><option value="in-production">In Production</option></select>
<input id="pPrice" placeholder="Price (e.g., 14.99)" />
<input id="pImage" placeholder="/assets/products/..." />
<button class="btn" id="addProductBtn">Add / Update Product</button>
</form>
</div>
<div class="product-list" id="adminProductList" aria-live="polite"></div>
</div>
</section>
<footer>
<div>Handcrafted by <strong>Phill Good, Inc.</strong> — Clean ingredients, powerful results. Replace this with real footer content and links.</div>
<div style="margin-top:8px;" class="small">Want shipping & wholesale integration? Connect payments and inventory on the backend.</div>
</footer>
</div>
<script>
/* ---------------------
Demo data (replace with backend)
--------------------- */
const STORAGE_KEYS = {
products: 'pg_products_v1',
reviews: 'pg_reviews_v1',
orders: 'pg_orders_v1'
};
const sampleProducts = [
{
id: 'pg-butter-001',
name: 'Ultra Melt Body Butter - Citrus Cedar',
category: 'body',
status: 'market-ready',
price: 14.99,
image: '/assets/products/butter-citrus.jpg',
excerpt: 'Low-water whipped butter — melts into skin, non-greasy finish.',
description: 'A rich, whipped body butter crafted for deep hydration without water. Uses cocoa butter, mango butter, and jojoba to seal moisture.',
ingredients: [
{name:'Mango Butter', benefit:'softens & smooths'},
{name:'Cocoa Butter', benefit:'helps barrier repair'},
{name:'Jojoba Oil', benefit:'absorbs like skin oil'},
{name:'Essential Oils (Citrus & Cedar)', benefit:'clean, long-lasting scent'}
]
},
{
id: 'pg-balm-002',
name: 'Beard Butter - Orange Cedarwood',
category: 'beard',
status: 'market-ready',
price: 12.5,
image: '/assets/products/beard-orange.jpg',
excerpt: 'Lightweight butters for beard softness & shine.',
description: 'Lanolin + cocoa butter blend for beard manageability and scalp health.',
ingredients: [
{name:'Lanolin', benefit:'deep conditioning'},
{name:'Cocoa Butter', benefit:'nourishes hair'},
{name:'Argan Oil', benefit:'adds shine & strength'},
]
},
{
id: 'pg-serum-003',
name: 'Scalp Serum - Herb & Peppermint',
category: 'serum',
status: 'in-production',
price: 18.00,
image: '/assets/products/scalp-serum.jpg',
excerpt: 'Light, non-greasy serum to soothe scalp and boost hair health.',
description: 'An experimental blend with peppermint and niacinamide for circulation & scalp comfort.',
ingredients: [
{name:'Hempseed Oil', benefit:'rich in omega fatty acids'},
{name:'Peppermint Oil', benefit:'stimulates circulation'},
{name:'Niacinamide', benefit:'supports scalp barrier'}
]
}
];
/* ---------------------
Utilities & storage
--------------------- */
function loadOrInit(key, fallback){
const raw = localStorage.getItem(key);
if(raw) try { return JSON.parse(raw); } catch(e){}
localStorage.setItem(key, JSON.stringify(fallback));
return fallback;
}
function save(key, val){ localStorage.setItem(key, JSON.stringify(val)); }
// Initialize data
let products = loadOrInit(STORAGE_KEYS.products, sampleProducts);
let reviews = loadOrInit(STORAGE_KEYS.reviews, {}); // { productId: [ {name, rating, text, date} ] }
let orders = loadOrInit(STORAGE_KEYS.orders, []);
/* ---------------------
Rendering functions
--------------------- */
const productGrid = document.getElementById('productGrid');
const queryEl = document.getElementById('query');
const filterStatus = document.getElementById('filterStatus');
const filterCategory = document.getElementById('filterCategory');
const overlay = document.getElementById('overlay');
let currentProduct = null;
function renderProducts(list=products){
productGrid.innerHTML = '';
if(!list.length){ productGrid.innerHTML = '<div class="small" style="grid-column:1/-1">No products found.</div>'; return; }
list.forEach(p => {
const card = document.createElement('article');
card.className = 'card';
card.setAttribute('role','listitem');
card.innerHTML = `
<div class="product-img"><img src="${p.image || '/assets/products/placeholder.jpg'}" alt="${escapeHtml(p.name)}"></div>
<div class="meta">
<div><div class="product-title">${escapeHtml(p.name)}</div><div class="small">${escapeHtml(p.excerpt || '')}</div></div>
<div style="text-align:right">
<div class="price">$${Number(p.price).toFixed(2)}</div>
<div class="badges">
<div class="badge ${p.status === 'market-ready' ? 'status-in' : 'status-prod'}">${p.status === 'market-ready' ? 'Market Ready' : 'In Production'}</div>
<div class="badge">${p.category}</div>
</div>
</div>
</div>
<div style="display:flex; gap:8px; margin-top:8px;">
<button class="btn" data-action="view" data-id="${p.id}">View</button>
<button class="btn secondary" data-action="quick" data-id="${p.id}">Quick Order</button>
</div>
`;
productGrid.appendChild(card);
});
}
function escapeHtml(s=''){ return String(s).replace(/[&<>"']/g, m=>({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[m])); }
// Filtering & searching
function getFiltered(){
const q = (queryEl.value || '').trim().toLowerCase();
const status = filterStatus.value;
const cat = filterCategory.value;
return products.filter(p => {
if(status !== 'all' && (status === 'market-ready' ? p.status !== 'market-ready': p.status !== 'in-production')) return false;
if(cat !== 'all' && p.category !== cat) return false;
if(!q) return true;
const hay = (p.name + ' ' + p.excerpt + ' ' + p.description + ' ' + p.ingredients.map(i=>i.name + ' ' + i.benefit).join(' ')).toLowerCase();
return hay.includes(q);
});
}
// Modal population
function openModal(productId){
currentProduct = products.find(x => x.id === productId);
if(!currentProduct) return;
document.getElementById('modalTitle').textContent = currentProduct.name;
document.getElementById('modalImage').src = currentProduct.image || '/assets/products/placeholder.jpg';
document.getElementById('modalDesc').textContent = currentProduct.description || currentProduct.excerpt || '';
const ingrEl = document.getElementById('modalIngredients');
ingrEl.innerHTML = currentProduct.ingredients.map(i => `• <strong>${i.name}</strong>: ${i.benefit}`).join('<br>');
document.getElementById('modalStatus').textContent = currentProduct.status === 'market-ready' ? 'Market Ready' : 'In Production';
document.getElementById('modalPrice').textContent = `$${Number(currentProduct.price).toFixed(2)}`;
document.getElementById('orderProductName').textContent = currentProduct.name;
document.getElementById('orderQty').value = 1;
renderReviewsFor(currentProduct.id);
overlay.style.display = 'flex';
overlay.setAttribute('aria-hidden','false');
}
function closeModal(){
overlay.style.display = 'none';
overlay.setAttribute('aria-hidden','true');
currentProduct = null;
}
// Reviews
function renderReviewsFor(productId){
const container = document.getElementById('reviewsContainer');
const list = (reviews[productId] || []).slice().reverse();
container.innerHTML = '';
document.getElementById('reviewsCount').textContent = `${list.length} review${list.length !== 1 ? 's':''}`;
if(!list.length) container.innerHTML = '<div class="small">No reviews yet — be the first to leave one.</div>';
list.forEach(r => {
const el = document.createElement('div');
el.className = 'review';
el.innerHTML = `<div style="display:flex; justify-content:space-between; align-items:center;"><div><strong>${escapeHtml(r.name)}</strong> <span class="small">• ${r.rating} ★</span></div><div class="small">${new Date(r.date).toLocaleDateString()}</div></div><div style="margin-top:6px">${escapeHtml(r.text)}</div>`;
container.appendChild(el);
});
}
document.getElementById('submitReviewBtn').addEventListener('click', () => {
if(!currentProduct) return;
const name = document.getElementById('reviewerName').value.trim() || 'Anonymous';
const rating = Number(document.getElementById('reviewRating').value);
const text = document.getElementById('reviewText').value.trim();
if(!text){ alert('Please write a short review.'); return; }
const rv = { name, rating, text, date: new Date().toISOString() };
reviews[currentProduct.id] = reviews[currentProduct.id] || [];
reviews[currentProduct.id].push(rv);
save(STORAGE_KEYS.reviews, reviews);
document.getElementById('reviewerName').value=''; document.getElementById('reviewText').value='';
renderReviewsFor(currentProduct.id);
});
// Orders: local storage (demo)
document.getElementById('placeOrderBtn').addEventListener('click', () => {
if(!currentProduct) return;
const qty = Number(document.getElementById('orderQty').value) || 1;
const name = document.getElementById('orderName').value.trim();
const contact = document.getElementById('orderContact').value.trim();
if(!name || !contact){ alert('Please enter name and contact info.'); return; }
const address = document.getElementById('orderAddress').value.trim();
const notes = document.getElementById('orderNotes').value.trim();
const order = {
id: 'ord_' + Date.now(),
productId: currentProduct.id,
productName: currentProduct.name,
qty, name, contact, address, notes,
total: Number(currentProduct.price) * qty,
date: new Date().toISOString(),
status: 'new'
};
orders.unshift(order);
save(STORAGE_KEYS.orders, orders);
document.getElementById('orderMsg').textContent = 'Order saved locally (demo). For production, integrate payments & backend.';
renderOrdersList();
});
// Admin product add/edit
document.getElementById('addProductBtn').addEventListener('click', () => {
const id = (document.getElementById('pName').value || '').trim();
if(!id){ alert('Name required'); return; }
const name = id;
const cat = document.getElementById('pCategory').value;
const status = document.getElementById('pStatus').value;
const price = Number(document.getElementById('pPrice').value) || 0;
const image = document.getElementById('pImage').value || '/assets/products/placeholder.jpg';
// If exists, update
let prod = products.find(p => p.name.toLowerCase() === name.toLowerCase());
if(prod){
prod.category = cat; prod.status = status; prod.price = price; prod.image = image;
} else {
prod = { id: 'pg_' + Date.now(), name, category: cat, status, price, image, excerpt:'', description:'', ingredients:[] };
products.push(prod);
}
save(STORAGE_KEYS.products, products);
document.getElementById('pName').value=''; document.getElementById('pPrice').value=''; document.getElementById('pImage').value='';
refreshUI();
});
// Orders list render
function renderOrdersList(){
const container = document.getElementById('ordersList');
container.innerHTML = '';
if(!orders.length){ container.innerHTML = '<div class="small">No orders yet.</div>'; return; }
orders.forEach(o => {
const el = document.createElement('div');
el.className = 'card';
el.innerHTML = `<div style="display:flex; justify-content:space-between; align-items:center;"><div><strong>${escapeHtml(o.productName)}</strong><div class="small">${new Date(o.date).toLocaleString()}</div></div><div style="text-align:right"><div style="font-weight:800">$${Number(o.total).toFixed(2)}</div><div class="small">${o.status}</div></div></div>
<div class="small">${escapeHtml(o.name)} • ${escapeHtml(o.contact)}</div>
<div class="small" style="margin-top:8px">Address: ${escapeHtml(o.address || '—')}</div>
<div style="display:flex; gap:8px; margin-top:8px;"><button class="btn" data-action="mark" data-id="${o.id}">Mark Shipped</button><button class="btn secondary" data-action="remove" data-id="${o.id}">Remove</button></div>`;
container.appendChild(el);
});
}
productGrid.addEventListener('click', (e) => {
const btn = e.target.closest('button');
if(!btn) return;
const action = btn.dataset.action;
const id = btn.dataset.id;
if(action === 'view') openModal(id);
if(action === 'quick'){
openModal(id);
// prefill qty 1 for quick ordering
document.getElementById('orderQty').value = 1;
}
});
// Orders panel actions
document.getElementById('ordersList').addEventListener('click', (e) => {
const btn = e.target.closest('button'); if(!btn) return;
const id = btn.dataset.id; const action = btn.dataset.action;
if(action === 'mark'){
const idx = orders.findIndex(x => x.id === id); if(idx >= 0){ orders[idx].status = 'shipped'; save(STORAGE_KEYS.orders, orders); renderOrdersList(); renderOrdersSummary(); }
}
if(action === 'remove'){
orders = orders.filter(x => x.id !== id); save(STORAGE_KEYS.orders, orders); renderOrdersList(); renderOrdersSummary();
}
});
// Admin product list
function renderAdminProducts(){
const list = document.getElementById('adminProductList');
list.innerHTML = '';
products.forEach(p => {
const div = document.createElement('div');
div.className = 'card';
div.innerHTML = `<div style="display:flex; justify-content:space-between; align-items:center;"><div><strong>${escapeHtml(p.name)}</strong><div class="small">${escapeHtml(p.category)} • ${p.status}</div></div><div style="text-align:right"><div class="small">$${Number(p.price).toFixed(2)}</div><div style="display:flex; gap:8px; margin-top:6px;"><button class="btn" data-action="edit" data-id="${p.id}">Edit</button><button class="btn secondary" data-action="delete" data-id="${p.id}">Delete</button></div></div></div>`;
list.appendChild(div);
});
}
document.getElementById('adminProductList').addEventListener('click', (e) => {
const btn = e.target.closest('button'); if(!btn) return;
const action = btn.dataset.action; const id = btn.dataset.id;
if(action === 'edit'){
const p = products.find(x => x.id === id); if(!p) return;
document.getElementById('pName').value = p.name;
document.getElementById('pCategory').value = p.category;
document.getElementById('pStatus').value = p.status;
document.getElementById('pPrice').value = p.price;
document.getElementById('pImage').value = p.image;
}
if(action === 'delete'){
if(!confirm('Delete this product?')) return;
products = products.filter(x => x.id !== id);
save(STORAGE_KEYS.products, products);
refreshUI();
}
});
/* ---------------------
UI helpers & events
--------------------- */
function refreshUI(){
renderProducts(getFiltered());
renderAdminProducts();
renderOrdersList();
renderOrdersSummary();
}
function renderOrdersSummary(){
document.getElementById('ordersSummary').textContent = `${orders.length} order${orders.length !== 1 ? 's':''}`;
document.getElementById('ordersPanel').style.display = orders.length ? 'block' : 'none';
}
document.getElementById('viewCatalogBtn').addEventListener('click', ()=>{ window.scrollTo({top:0, behavior:'smooth'}); });
document.getElementById('viewOrdersBtn').addEventListener('click', ()=>{ document.getElementById('ordersPanel').style.display = 'block'; document.getElementById('adminPanel').style.display='none'; window.scrollTo({top:document.getElementById('ordersPanel').offsetTop, behavior:'smooth'}); });
document.getElementById('adminToggleBtn').addEventListener('click', ()=>{ const el = document.getElementById('adminPanel'); el.style.display = el.style.display === 'none' || !el.style.display ? 'block' : 'none'; window.scrollTo({top:el.offsetTop, behavior:'smooth'}); });
document.getElementById('closeModalBtn').addEventListener('click', closeModal);
document.getElementById('openOrderBtn').addEventListener('click', ()=>{ document.getElementById('orderName').focus(); });
document.getElementById('clearFiltersBtn').addEventListener('click', () => {
queryEl.value=''; filterStatus.value='all'; filterCategory.value='all'; refreshUI();
});
document.getElementById('newArrivalBtn').addEventListener('click', () => {
// Demo: toggle showing in-production only
filterStatus.value = (filterStatus.value === 'in-production') ? 'all' : 'in-production';
refreshUI();
});
// Live search
queryEl.addEventListener('input', () => refreshUI());
filterStatus.addEventListener('change', () => refreshUI());
filterCategory.addEventListener('change', () => refreshUI());
// Overlay click to close
overlay.addEventListener('click', (e) => {
if(e.target === overlay) closeModal();
});
// Orders panel initially hidden unless orders exist
document.getElementById('ordersPanel').style.display = orders.length ? 'block' : 'none';
// Initial render
refreshUI();
/* ---------------------
Small helpers for UX & organization
--------------------- */
function findProductById(id){ return products.find(p=>p.id===id); }
// Expose a global quick-add for testing (dev)
window.PG = {
addSample: () => { products.push({id:'pg_'+Date.now(), name:'Test '+Date.now(), category:'body', status:'in-production', price:9.99, image:'/assets/products/placeholder.jpg', excerpt:'', description:'', ingredients:[]}); save(STORAGE_KEYS.products, products); refreshUI(); }
};
// Helpful: clicking on product image not required; allow keyboard navigation - add key events
document.addEventListener('keydown', (e) => {
if(e.key === 'Escape') closeModal();
});
</script>
</body>
</html>