Shop :root{ –paper:#EEEAE1; –surface-raised:#FFFFFF; –ink:#1C2621; –ink-soft:#5B6459; –ink-faint:#8A8578; –border:#DCD5C5; –border-strong:#C7BEA8; –gold:#B9862E; –gold-ink:#7A5A1E; –gold-tint:#F4E8D2; –teal:#2E6E63; –shadow-card: 0 1px 2px rgba(28,38,33,0.06), 0 1px 0 rgba(28,38,33,0.04); } *{box-sizing:border-box;} html,body{margin:0;padding:0;} body{background:var(–paper);color:var(–ink);font-family:’Inter’,system-ui,sans-serif;font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;} h1,h2,h3{font-family:’Fraunces’,serif;font-weight:600;margin:0;} button{font-family:inherit;cursor:pointer;} input,select,textarea{font-family:inherit;font-size:13.5px;} /* ———- Header ———- */ header{ position:sticky;top:0;z-index:30;background:var(–surface-raised); border-bottom:1px solid var(–border);padding:14px 28px; display:flex;justify-content:space-between;align-items:center;gap:14px; } .brandbtn{display:flex;align-items:center;gap:9px;background:none;border:none;padding:2px;} .mark{width:30px;height:30px;border-radius:7px;background:var(–ink);color:var(–gold);display:flex;align-items:center;justify-content:center;font-family:’Fraunces’,serif;font-style:italic;font-weight:600;font-size:15px;flex:none;} .brandbtn .word{font-family:’Fraunces’,serif;font-weight:600;font-size:17px;text-align:left;} header .actions{display:flex;gap:8px;} .btn{display:inline-flex;align-items:center;gap:6px;padding:9px 15px;border-radius:20px;border:1px solid var(–border-strong);background:#fff;color:var(–ink);font-size:13px;font-weight:600;} .btn:hover{border-color:var(–ink-soft);} .btn-dark{background:var(–ink);color:#F4F1E8;border-color:var(–ink);} .btn-dark:hover{background:#2A362F;} .btn-gold{background:var(–gold);color:#fff;border-color:var(–gold);} .btn-gold:hover{background:var(–gold-ink);} .btn-sm{padding:6px 12px;font-size:12px;} .btn-ghost{background:none;border:none;color:var(–ink-soft);padding:4px 6px;} .btn-ghost:hover{color:var(–rust,#AE5039);text-decoration:underline;} /* ———- Hero ———- */ .hero{max-width:760px;margin:44px auto 30px;padding:0 24px;text-align:center;} .hero .tag{font-size:11.5px;color:var(–gold-ink);font-weight:700;margin-bottom:10px;} .hero h1{font-size:38px;} .hero p{color:var(–ink-soft);font-size:14px;max-width:480px;margin:10px auto 22px;} .search-wrap{max-width:420px;margin:0 auto 18px;} .search-wrap input{width:100%;padding:12px 16px;border:1px solid var(–border-strong);border-radius:26px;background:#fff;font-size:13.5px;} .search-wrap input:focus{outline:2px solid var(–gold);border-color:var(–gold);} .chips{display:flex;flex-wrap:wrap;gap:7px;justify-content:center;} .chip{border:1px solid var(–border-strong);background:#fff;border-radius:20px;padding:6px 14px;font-size:12px;font-weight:600;color:var(–ink-soft);} .chip.active{background:var(–ink);color:#F4F1E8;border-color:var(–ink);} /* ———- Grid ———- */ main{max-width:1180px;margin:0 auto;padding:0 28px 70px;} .toolbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;} .count{font-size:12.5px;color:var(–ink-soft);} .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:20px;} .card{background:var(–surface-raised);border:1px solid var(–border);border-radius:12px;overflow:hidden;box-shadow:var(–shadow-card);cursor:pointer;transition:transform .12s ease, box-shadow .12s ease;} .card:hover{transform:translateY(-2px);box-shadow:0 10px 22px rgba(28,38,33,0.11);} .cimg{height:150px;display:flex;align-items:center;justify-content:center;position:relative;} .mono{font-family:’Fraunces’,serif;font-size:44px;font-weight:500;color:rgba(255,255,255,0.92);} .ribbon{position:absolute;top:10px;left:10px;background:var(–gold);color:#fff;font-size:10.5px;font-weight:700;padding:4px 10px;border-radius:20px;} .cbody{padding:14px 15px 16px;} .ccat{font-size:10.5px;color:var(–ink-faint);font-weight:600;margin-bottom:3px;} .cname{font-weight:600;font-size:15px;line-height:1.3;margin-bottom:8px;} .feats{list-style:none;margin:0 0 12px;padding:0;} .feats li{font-size:11.5px;color:var(–ink-soft);padding-left:14px;position:relative;margin-bottom:3px;} .feats li::before{content:”✓”;position:absolute;left:0;color:var(–teal);font-weight:700;font-size:11px;} .cfoot{display:flex;justify-content:space-between;align-items:center;} .price{font-family:’Fraunces’,serif;font-weight:600;font-size:17px;} .cta{background:var(–ink);color:#F4F1E8;font-size:11.5px;font-weight:700;padding:8px 13px;border-radius:20px;text-decoration:none;} .cta:hover{background:var(–gold-ink);} .cta.disabled{background:#EDE9DC;color:var(–ink-faint);pointer-events:none;} .empty{border:1.5px dashed var(–border-strong);border-radius:12px;padding:44px 24px;text-align:center;color:var(–ink-soft);grid-column:1/-1;} .empty h3{margin-bottom:6px;color:var(–ink);} .empty p{max-width:360px;margin:0 auto 16px;font-size:13px;} /* ———- Modals / overlays ———- */ .overlay{position:fixed;inset:0;background:rgba(28,38,33,0.5);display:none;align-items:center;justify-content:center;z-index:60;padding:22px;} .overlay.open{display:flex;} .modal{background:var(–paper);border-radius:14px;max-width:640px;width:100%;max-height:88vh;overflow-y:auto;box-shadow:0 20px 50px rgba(0,0,0,0.3);} .qhero{height:190px;display:flex;align-items:center;justify-content:center;border-radius:14px 14px 0 0;position:relative;} .qhero .mono{font-size:60px;} .qclose{position:absolute;top:12px;right:14px;background:rgba(255,255,255,0.85);border:none;border-radius:50%;width:30px;height:30px;font-size:16px;} .qbody{padding:26px 28px 28px;} .qcat{font-size:11.5px;color:var(–gold-ink);font-weight:700;margin-bottom:4px;} .qbody h3{font-size:23px;margin-bottom:4px;} .qprice{font-family:’Fraunces’,serif;font-size:19px;margin-bottom:14px;} .qsec{margin-bottom:14px;} .qsec .lbl{font-size:11.5px;font-weight:700;color:var(–ink-soft);margin-bottom:4px;} .qsec p{margin:0;font-size:13.5px;} .qactions{margin-top:16px;} .qdisc{font-size:11px;color:var(–ink-faint);margin-top:16px;border-top:1px solid var(–border);padding-top:12px;} /* side drawer (manage) */ .drawer-overlay{position:fixed;inset:0;background:rgba(28,38,33,0.45);display:none;justify-content:flex-end;z-index:60;} .drawer-overlay.open{display:flex;} .drawer{width:440px;max-width:92vw;background:var(–paper);height:100vh;overflow-y:auto;padding:24px 26px 40px;box-shadow:-8px 0 24px rgba(0,0,0,0.15);} .drawer-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;} .drawer-head h3{font-size:19px;} .xbtn{background:none;border:none;font-size:19px;color:var(–ink-soft);} .row{display:flex;justify-content:space-between;align-items:center;padding:11px 2px;border-bottom:1px solid var(–border);gap:10px;} .row:last-child{border-bottom:none;} .row .rname{font-weight:600;font-size:13.5px;} .row .rmeta{color:var(–ink-soft);font-size:11.5px;margin-top:2px;} .row .racts{display:flex;gap:4px;flex:none;} .field{margin-bottom:13px;} .field label{display:block;font-size:12px;font-weight:600;color:var(–ink-soft);margin-bottom:5px;} .field input,.field select,.field textarea{width:100%;padding:9px 10px;border:1px solid var(–border-strong);border-radius:6px;background:#fff;color:var(–ink);} .field textarea{min-height:58px;resize:vertical;} .field input:focus,.field select:focus,.field textarea:focus{outline:2px solid var(–gold);border-color:var(–gold);} .field .hint{font-size:11px;color:var(–ink-faint);margin-top:3px;} .drawer-foot{display:flex;gap:8px;margin-top:16px;padding-top:14px;border-top:1px solid var(–border);} #toast{position:fixed;bottom:22px;right:26px;display:flex;flex-direction:column;gap:8px;z-index:100;} .toast-msg{background:var(–ink);color:#F4F1E8;padding:10px 16px;border-radius:7px;font-size:13px;box-shadow:0 6px 18px rgba(0,0,0,0.25);max-width:320px;} footer{max-width:1180px;margin:0 auto;padding:20px 28px 40px;text-align:center;color:var(–ink-faint);font-size:11.5px;} @media (max-width: 640px){ header{padding:12px 16px;} .hero{margin:30px auto 22px;} .hero h1{font-size:29px;} main{padding:0 16px 60px;} }
CURATED PICKS

Your Shop

Add your products to fill this page — every card can carry a deal, key features, and a buy link.

Manage products

/* ===================== STATE ===================== */ let BRAND = {name:””, tag:””, loc:””, disc:””}; let PRODUCTS = []; let ACTIVE_CATEGORY = ‘All’; const CATEGORY_STYLE = { “Home and kitchen”: “linear-gradient(135deg,#2E6E63,#1F4E45)”, “Beauty and personal care”: “linear-gradient(135deg,#6E4C63,#4E3547)”, “Health and wellness”: “linear-gradient(135deg,#5C6B3E,#404B2B)”, “Fashion”: “linear-gradient(135deg,#AE5039,#7E392A)”, “Technology”: “linear-gradient(135deg,#3E6E8E,#2B4E66)”, “Outdoor and travel”: “linear-gradient(135deg,#A65A3C,#7C4229)”, “Pet products”: “linear-gradient(135deg,#B9862E,#8A651F)”, “Seasonal products”: “linear-gradient(135deg,#4B5A66,#333F49)”, “Gifts”: “linear-gradient(135deg,#6E4C63,#B9862E)”, “Deals and comparisons”: “linear-gradient(135deg,#B9862E,#AE5039)” }; /* ===================== STORAGE ===================== */ async function storeGet(key, fallback){ try{ const r = await window.storage.get(key, false); return r ? JSON.parse(r.value) : fallback; } catch(e){ return fallback; } } async function storeSet(key, value){ try{ await window.storage.set(key, JSON.stringify(value), false); } catch(e){ toast(“Couldn’t save — storage error.”); } } function esc(s){ return (s||””).toString().replace(/[&”‘]/g, c=>({‘&’:’&’,”:’>’,'”‘:’"’,”‘”:’'’}[c])); } function toast(msg){ const box = document.getElementById(‘toast’); const el = document.createElement(‘div’); el.className = ‘toast-msg’; el.textContent = msg; box.appendChild(el); setTimeout(()=>el.remove(), 3200); } /* ===================== INIT ===================== */ async function init(){ BRAND = await storeGet(‘brand-info-simple’, BRAND); PRODUCTS = await storeGet(‘products-simple’, []); renderHero(); renderGrid(); } init(); /* ===================== HERO / BRAND ===================== */ function renderHero(){ const name = BRAND.name || “Your Shop”; document.getElementById(‘hdr-name’).textContent = name; document.getElementById(‘hero-name’).textContent = name; document.getElementById(‘mark-letter’).textContent = name.trim().charAt(0).toUpperCase() || ‘S’; document.getElementById(‘hero-tag’).textContent = BRAND.loc ? BRAND.loc.toUpperCase()+” · CURATED PICKS” : “CURATED PICKS”; document.getElementById(‘hero-sub’).textContent = BRAND.tag || “Add your products to fill this page — every card can carry a deal, key features, and a buy link.”; const foot = document.getElementById(‘footer’); if(BRAND.disc){ foot.style.display=’block’; foot.textContent = BRAND.disc; } else foot.style.display=’none’; } function openBrandModal(){ document.getElementById(‘bm-name’).value = BRAND.name||””; document.getElementById(‘bm-tag’).value = BRAND.tag||””; document.getElementById(‘bm-loc’).value = BRAND.loc||””; document.getElementById(‘bm-disc’).value = BRAND.disc||””; document.getElementById(‘brand-overlay’).classList.add(‘open’); } function closeBrandModal(){ document.getElementById(‘brand-overlay’).classList.remove(‘open’); } async function saveBrandModal(){ BRAND = { name: document.getElementById(‘bm-name’).value.trim(), tag: document.getElementById(‘bm-tag’).value.trim(), loc: document.getElementById(‘bm-loc’).value.trim(), disc: document.getElementById(‘bm-disc’).value.trim() }; await storeSet(‘brand-info-simple’, BRAND); renderHero(); closeBrandModal(); toast(“Page updated.”); } /* ===================== GRID ===================== */ function featureList(text){ return (text||””).split(/\\n|,/).map(s=>s.trim()).filter(Boolean).slice(0,3); } function renderChips(){ const present = […new Set(PRODUCTS.map(p=>p.category))]; document.getElementById(‘chips’).innerHTML = [‘All’, …present].map(c=> `` ).join(”); } function setCategory(c){ ACTIVE_CATEGORY = c; renderGrid(); } function renderGrid(){ renderChips(); const q = (document.getElementById(‘search-input’).value||”).toLowerCase().trim(); const list = PRODUCTS.filter(p=>{ const okCat = ACTIVE_CATEGORY===’All’ || p.category===ACTIVE_CATEGORY; const okQ = !q || (p.name||”).toLowerCase().includes(q) || (p.category||”).toLowerCase().includes(q); return okCat && okQ; }); document.getElementById(‘count’).textContent = PRODUCTS.length ? `${list.length} of ${PRODUCTS.length} product${PRODUCTS.length>1?’s’:”}` : ”; const grid = document.getElementById(‘grid’); if(PRODUCTS.length===0){ grid.innerHTML = `

This shop is empty

Add your first product and it’ll show up here as a shoppable card with its price, features, and buy link.

`; return; } if(list.length===0){ grid.innerHTML = `

No matches

Try a different search or category.

`; return; } grid.innerHTML = list.map(p=>{ const bg = CATEGORY_STYLE[p.category] || CATEGORY_STYLE[“Home and kitchen”]; const initial = (p.name||’?’).trim().charAt(0).toUpperCase() || ‘?’; const feats = featureList(p.features); const hasLink = !!(p.link && p.link.trim()); return `
${esc(initial)} ${p.promo ? `${esc(p.promo.length>20 ? ‘Deal’ : p.promo)}` : ”}
${esc(p.category)}
${esc(p.name)||'(untitled)’}
${feats.length ? `
    ${feats.map(f=>`
  • ${esc(f)}
  • `).join(”)}
` : ”}
${esc(p.price)||’—’} ${hasLink ? `Shop now →` : `Link needed`}
`; }).join(”); } /* ===================== QUICK VIEW ===================== */ function openQV(id){ const p = PRODUCTS.find(x=>x.id===id); if(!p) return; const bg = CATEGORY_STYLE[p.category] || CATEGORY_STYLE[“Home and kitchen”]; const initial = (p.name||’?’).trim().charAt(0).toUpperCase() || ‘?’; const feats = featureList(p.features); const hasLink = !!(p.link && p.link.trim()); const disc = p.disclosure || BRAND.disc || ”; document.getElementById(‘qv-modal’).innerHTML = `
${esc(initial)}
${esc(p.category)}

${esc(p.name)||'(untitled)’}

${esc(p.price)||’Price: information needed’}
${feats.length ? `
    ${feats.map(f=>`
  • ${esc(f)}
  • `).join(”)}
` : ”}
Why buyers want it

${esc(p.problem)||’Information needed’}

${p.promo ? `
Current deal

${esc(p.promo)}

` : ”}
${hasLink ? `Shop now →` : `Add a product link to enable buying`}
${disc ? `
${esc(disc)}
` : ”}
`; document.getElementById(‘qv-overlay’).classList.add(‘open’); } function closeQV(){ document.getElementById(‘qv-overlay’).classList.remove(‘open’); } /* ===================== MANAGE ===================== */ function openManage(){ document.getElementById(‘manage-overlay’).classList.add(‘open’); backToList(); } function closeManage(){ document.getElementById(‘manage-overlay’).classList.remove(‘open’); } function backToList(){ document.getElementById(‘manage-list-view’).style.display=’block’; document.getElementById(‘manage-form-view’).style.display=’none’; renderManageList(); } function renderManageList(){ const box = document.getElementById(‘manage-list’); if(PRODUCTS.length===0){ box.innerHTML = `

No products yet — add your first one above.

`; return; } box.innerHTML = PRODUCTS.map(p=>`
${esc(p.name)||'(untitled)’}
${esc(p.category)} · ${esc(p.price)||’price needed’}
`).join(”); } function emptyProduct(){ return {id:’p_’+Date.now(), name:””,link:””,category:”Home and kitchen”,price:””,features:””,problem:””,promo:””,disclosure:””}; } function showForm(id){ const p = id ? PRODUCTS.find(x=>x.id===id) : emptyProduct(); document.getElementById(‘form-title’).textContent = id ? “Edit product” : “Add product”; document.getElementById(‘f-id’).value = p.id; document.getElementById(‘f-name’).value = p.name; document.getElementById(‘f-price’).value = p.price; document.getElementById(‘f-link’).value = p.link; document.getElementById(‘f-category’).value = p.category; document.getElementById(‘f-features’).value = p.features; document.getElementById(‘f-problem’).value = p.problem; document.getElementById(‘f-promo’).value = p.promo; document.getElementById(‘f-disclosure’).value = p.disclosure || (id ? “” : (BRAND.disc||””)); document.getElementById(‘f-delete’).style.display = id ? ‘inline-flex’ : ‘none’; document.getElementById(‘manage-list-view’).style.display=’none’; document.getElementById(‘manage-form-view’).style.display=’block’; } async function saveProduct(){ const id = document.getElementById(‘f-id’).value; const idx = PRODUCTS.findIndex(x=>x.id===id); const p = { id: id || (‘p_’+Date.now()), name: document.getElementById(‘f-name’).value.trim(), price: document.getElementById(‘f-price’).value.trim(), link: document.getElementById(‘f-link’).value.trim(), category: document.getElementById(‘f-category’).value, features: document.getElementById(‘f-features’).value.trim(), problem: document.getElementById(‘f-problem’).value.trim(), promo: document.getElementById(‘f-promo’).value.trim(), disclosure: document.getElementById(‘f-disclosure’).value.trim() }; if(!p.name){ toast(“Give the product a name first.”); return; } if(idx>-1) PRODUCTS[idx]=p; else PRODUCTS.push(p); await storeSet(‘products-simple’, PRODUCTS); renderGrid(); backToList(); toast(“Product saved.”); } async function deleteFromForm(){ const id = document.getElementById(‘f-id’).value; if(!id) return; if(!confirm(“Remove this product from the shop?”)) return; PRODUCTS = PRODUCTS.filter(x=>x.id!==id); await storeSet(‘products-simple’, PRODUCTS); renderGrid(); backToList(); toast(“Product removed.”); }