feat: dynamic data insights + remaining audit fixes
DATA FIXES: - Dashboard insights now fully dynamic per date range - Revenue/orders/newcust/AOV trend (splits data in half, compares) - Channel concentration % computed from filtered data - Repeat revenue % with date-range label - All insights adapt when user changes date filter/preset - Offer page charts now load from API (not hardcoded arrays) - Revenue chart, new customer chart, channel donut = live data - Hero stats (-84%, -42%, 85%) computed dynamically from API - ROI calculator AOV pulled from latest year's actual data REMAINING AUDIT FIXES: - Fix #4: 'Built by' section on offer page (name, bio, contact) - Fix #9: Before/After comparison block on homepage - Side-by-side: current JV PDP flaws vs AI engine output - 8 specific ✗/✓ comparison points - Fix #6: Before/after serves as instant proof (no 90s wait) All 10 audit fixes now implemented.
This commit is contained in:
@@ -387,18 +387,69 @@ function buildExec(fm){
|
||||
`<div class="kpi"><div class="kpi-label">${k.l}</div><div class="kpi-value ${k.c}">${k.v}</div><div class="kpi-sub">${k.s}</div></div>`
|
||||
).join('');
|
||||
|
||||
// Insights
|
||||
const latestYear = fm.filter(r=>r.YearMonth>='2025-01');
|
||||
const prevYear = fm.filter(r=>r.YearMonth>='2024-01'&&r.YearMonth<='2024-12');
|
||||
const lyRev = latestYear.reduce((s,r)=>s+r.revenue,0);
|
||||
const pyRev = prevYear.reduce((s,r)=>s+r.revenue,0);
|
||||
const yoyChange = pyRev > 0 ? ((lyRev - pyRev) / pyRev * 100) : 0;
|
||||
// Dynamic range-aware insights
|
||||
// Split into halves for trend comparison
|
||||
const half = Math.floor(fm.length / 2);
|
||||
const firstHalf = fm.slice(0, half);
|
||||
const secondHalf = fm.slice(half);
|
||||
const fhRev = firstHalf.reduce((s,r)=>s+r.revenue,0);
|
||||
const shRev = secondHalf.reduce((s,r)=>s+r.revenue,0);
|
||||
const revTrend = fhRev > 0 ? ((shRev - fhRev) / fhRev * 100) : 0;
|
||||
const fhOrders = firstHalf.reduce((s,r)=>s+r.orders,0);
|
||||
const shOrders = secondHalf.reduce((s,r)=>s+r.orders,0);
|
||||
const orderTrend = fhOrders > 0 ? ((shOrders - fhOrders) / fhOrders * 100) : 0;
|
||||
const fhNew = firstHalf.reduce((s,r)=>s+r.newCustomers,0);
|
||||
const shNew = secondHalf.reduce((s,r)=>s+r.newCustomers,0);
|
||||
const newTrend = fhNew > 0 ? ((shNew - fhNew) / fhNew * 100) : 0;
|
||||
const fhAOV = fhOrders > 0 ? fhRev / fhOrders : 0;
|
||||
const shAOV = shOrders > 0 ? shRev / shOrders : 0;
|
||||
const aovTrend = fhAOV > 0 ? ((shAOV - fhAOV) / fhAOV * 100) : 0;
|
||||
|
||||
document.getElementById('execInsights').innerHTML = `
|
||||
<div class="insight ${avgMargin >= 55 ? 'good' : 'warn'}"><strong>Avg Margin ${pct(avgMargin)}:</strong> ${avgMargin >= 55 ? 'Healthy margins across the product range.' : 'Margins are under pressure — review product costs and pricing.'}</div>
|
||||
<div class="insight"><strong>Returning customer revenue:</strong> ${pct(repeatRevPct)} of revenue comes from repeat buyers. ${repeatRevPct > 40 ? 'Strong loyalty base to leverage.' : 'Opportunity to improve retention.'}</div>
|
||||
<div class="insight ${avgItems < 2 ? 'warn' : 'good'}"><strong>Items per order: ${fmt(avgItems,1)}.</strong> ${avgItems < 2 ? 'Most orders are single-item. Bundling and cross-sell could lift AOV.' : 'Good cross-sell rate.'}</div>
|
||||
`;
|
||||
// Channel concentration for this date range
|
||||
const chFilt = filterArr(RAW.channelMonthly);
|
||||
const chTotals = {};
|
||||
chFilt.forEach(r => { chTotals[r.ReferrerSource] = (chTotals[r.ReferrerSource]||0) + r.orders; });
|
||||
const chTotal = Object.values(chTotals).reduce((a,b)=>a+b,0);
|
||||
const googleOrg = (chTotals['Organic']||0) + (chTotals['Google Adwords']||0);
|
||||
const googlePct = chTotal > 0 ? googleOrg / chTotal * 100 : 0;
|
||||
const socialPct = chTotal > 0 ? ((chTotals['Facebook']||0) / chTotal * 100) : 0;
|
||||
|
||||
const rangeLabel = FSTART && FEND ? `${FSTART} to ${FEND}` : FSTART ? `${FSTART} onwards` : FEND ? `up to ${FEND}` : 'all time';
|
||||
const halfLabel1 = firstHalf.length ? `${firstHalf[0].YearMonth}–${firstHalf[firstHalf.length-1].YearMonth}` : '';
|
||||
const halfLabel2 = secondHalf.length ? `${secondHalf[0].YearMonth}–${secondHalf[secondHalf.length-1].YearMonth}` : '';
|
||||
|
||||
let insightsHtml = '';
|
||||
|
||||
// Revenue trend
|
||||
if(fm.length >= 4) {
|
||||
insightsHtml += `<div class="insight ${revTrend >= 0 ? 'good' : 'warn'}"><strong>Revenue ${revTrend >= 0 ? '↑' : '↓'} ${pct(Math.abs(revTrend))}:</strong> ${gbp(shRev)} in ${halfLabel2} vs ${gbp(fhRev)} in ${halfLabel1}. ${revTrend < -10 ? 'Declining trend in this range.' : revTrend > 10 ? 'Growing in this range.' : 'Relatively flat.'}</div>`;
|
||||
}
|
||||
|
||||
// New customer trend
|
||||
if(fm.length >= 4 && fhNew > 0) {
|
||||
insightsHtml += `<div class="insight ${newTrend >= 0 ? 'good' : 'warn'}"><strong>New customers ${newTrend >= 0 ? '↑' : '↓'} ${pct(Math.abs(newTrend))}:</strong> ${fmt(shNew)} new customers in second half vs ${fmt(fhNew)} in first half of this range.</div>`;
|
||||
}
|
||||
|
||||
// AOV trend
|
||||
if(fm.length >= 4) {
|
||||
insightsHtml += `<div class="insight ${aovTrend >= 0 ? 'good' : 'warn'}"><strong>AOV ${aovTrend >= 0 ? '↑' : '↓'} ${pct(Math.abs(aovTrend))}:</strong> ${gbp(shAOV)} vs ${gbp(fhAOV)}. ${aovTrend > 5 ? 'Customers are spending more per order.' : aovTrend < -5 ? 'Average basket value declining.' : 'AOV holding steady.'}</div>`;
|
||||
}
|
||||
|
||||
// Margins
|
||||
insightsHtml += `<div class="insight ${avgMargin >= 55 ? 'good' : 'warn'}"><strong>Avg margin ${pct(avgMargin)}:</strong> ${avgMargin >= 55 ? 'Healthy margins across the product range.' : 'Margins under pressure — review product costs and pricing.'}</div>`;
|
||||
|
||||
// Returning revenue
|
||||
insightsHtml += `<div class="insight"><strong>Returning customer revenue:</strong> ${pct(repeatRevPct)} of revenue comes from repeat buyers (${rangeLabel}). ${repeatRevPct > 60 ? 'Extremely loyal base — but dependency on existing customers may mask acquisition weakness.' : repeatRevPct > 40 ? 'Strong loyalty base to leverage.' : 'Opportunity to improve retention.'}</div>`;
|
||||
|
||||
// Channel concentration
|
||||
if(chTotal > 0) {
|
||||
insightsHtml += `<div class="insight ${googlePct > 80 ? 'warn' : ''}"><strong>Channel concentration:</strong> ${pct(googlePct)} of orders from Google channels (Organic + Ads) in this range. ${socialPct < 1 ? 'Social commerce is under ' + pct(socialPct) + ' — virtually zero discovery from social channels.' : 'Social contributing ' + pct(socialPct) + '.'}</div>`;
|
||||
}
|
||||
|
||||
// Items per order
|
||||
insightsHtml += `<div class="insight ${avgItems < 2 ? 'warn' : 'good'}"><strong>Items per order: ${fmt(avgItems,1)}.</strong> ${avgItems < 2 ? 'Most orders are single-item. Bundling and cross-sell could lift AOV.' : 'Good cross-sell rate.'}</div>`;
|
||||
|
||||
document.getElementById('execInsights').innerHTML = insightsHtml;
|
||||
|
||||
// Revenue + Orders chart
|
||||
destroyChart('revOrdersChart');
|
||||
|
||||
@@ -599,6 +599,19 @@ input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:20px;heigh
|
||||
<div class="faq-item" onclick="toggleFaq(this)"><div class="faq-q">How is this different from hiring an agency?<span class="arrow">+</span></div><div class="faq-a"><div class="faq-a-inner">An agency charges monthly for services and you own nothing when you leave. This is a one-time infrastructure build — you own the server, the workflows, the content, and the integrations. The £500/mo covers hosting and maintenance only. If you cancel, you keep the infrastructure and can self-host.</div></div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════════ BUILT BY ══════════════ -->
|
||||
<div style="max-width:680px;margin:48px auto;padding:28px 32px;background:rgba(99,102,241,.04);border:1px solid rgba(99,102,241,.15);border-radius:14px;display:flex;gap:20px;align-items:center">
|
||||
<div style="flex-shrink:0;width:64px;height:64px;border-radius:50%;background:linear-gradient(135deg,#6366f1,#06b6d4);display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:700;color:#fff">O</div>
|
||||
<div>
|
||||
<div style="font-size:16px;font-weight:700;color:var(--text)">Omair · <a href="https://quikcue.com" style="color:var(--accent)">QuikCue</a></div>
|
||||
<div style="font-size:13px;color:var(--text2);margin-top:4px;line-height:1.5">I build AI infrastructure for ecommerce brands — automation, content engines, and data systems. This proposal was built using the same tools I'm proposing to install. Every demo, every chart, every number on this page is real.</div>
|
||||
<div style="margin-top:8px;font-size:12px;display:flex;gap:12px">
|
||||
<a href="mailto:omair@quikcue.com" style="color:var(--accent)">omair@quikcue.com</a>
|
||||
<a href="https://quikcue.com" style="color:var(--text3)">quikcue.com</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-footer">
|
||||
Prepared for Just Vitamins · March 2026 · Confidential<br>
|
||||
Data source: 728,018 validated orders · Nov 2005 — Jan 2026
|
||||
@@ -644,59 +657,117 @@ const counterObs = new IntersectionObserver(e => {
|
||||
}, {threshold:.5});
|
||||
document.querySelectorAll('[data-count]').forEach(el => counterObs.observe(el));
|
||||
|
||||
// ══════ CHARTS ══════
|
||||
// ══════ LOAD REAL DATA FROM API ══════
|
||||
const cBase = {responsive:true,maintainAspectRatio:false,animation:{duration:600},plugins:{legend:{display:false}},scales:{x:{grid:{color:'rgba(26,37,69,.4)'},ticks:{color:'#5a6d94',font:{size:10}}},y:{grid:{color:'rgba(26,37,69,.4)'},ticks:{color:'#5a6d94',font:{size:10}}}}};
|
||||
|
||||
// Revenue chart
|
||||
new Chart(document.getElementById('revChart'), {
|
||||
fetch('/api/dashboard/data').then(r=>r.json()).then(data => {
|
||||
const m = data.monthly.sort((a,b)=>a.YearMonth.localeCompare(b.YearMonth));
|
||||
|
||||
// Aggregate by year (2018+)
|
||||
const yearly = {};
|
||||
m.forEach(r => {
|
||||
const y = r.YearMonth.substring(0,4);
|
||||
if(parseInt(y) < 2018) return;
|
||||
if(!yearly[y]) yearly[y] = {rev:0, orders:0, newCust:0};
|
||||
yearly[y].rev += r.revenue;
|
||||
yearly[y].orders += r.orders;
|
||||
yearly[y].newCust += r.newCustomers;
|
||||
});
|
||||
const years = Object.keys(yearly).sort().filter(y => y !== '2026');
|
||||
const peakYear = years.reduce((a,b) => yearly[a].rev > yearly[b].rev ? a : b);
|
||||
const latestYear = years[years.length-1];
|
||||
const peakNewYear = years.reduce((a,b) => yearly[a].newCust > yearly[b].newCust ? a : b);
|
||||
|
||||
// Update hero stats dynamically
|
||||
const newDecline = yearly[peakNewYear] && yearly[latestYear] ? Math.round((yearly[latestYear].newCust - yearly[peakNewYear].newCust) / yearly[peakNewYear].newCust * 100) : -84;
|
||||
const revDecline = yearly[peakYear] && yearly[latestYear] ? Math.round((yearly[latestYear].rev - yearly[peakYear].rev) / yearly[peakYear].rev * 100) : -42;
|
||||
document.querySelectorAll('[data-count]').forEach(el => {
|
||||
if(el.closest('.red')) el.dataset.count = newDecline;
|
||||
if(el.closest('.amber')) el.dataset.count = revDecline;
|
||||
});
|
||||
|
||||
// Channel data
|
||||
const ch = data.channelMonthly || [];
|
||||
const chTotals = {};
|
||||
// Use last 24 months for channel %
|
||||
const recent = m.filter(r => r.YearMonth >= (parseInt(latestYear)-1)+'-01');
|
||||
const recentYMs = new Set(recent.map(r=>r.YearMonth));
|
||||
ch.filter(r => recentYMs.has(r.YearMonth)).forEach(r => {
|
||||
chTotals[r.ReferrerSource] = (chTotals[r.ReferrerSource]||0) + r.orders;
|
||||
});
|
||||
const chTotal = Object.values(chTotals).reduce((a,b)=>a+b,0);
|
||||
const googleOrgPct = chTotal > 0 ? Math.round(((chTotals['Organic']||0) + (chTotals['Google Adwords']||0)) / chTotal * 100) : 85;
|
||||
|
||||
// Update the 85% stat dynamically
|
||||
const greyVal = document.querySelector('.alert-stat.grey .val');
|
||||
if(greyVal) greyVal.textContent = googleOrgPct + '%';
|
||||
const channelH2 = document.querySelector('h2.stitle');
|
||||
if(channelH2 && channelH2.textContent.includes('Channel Dependency'))
|
||||
channelH2.textContent = googleOrgPct + '% Channel Dependency';
|
||||
|
||||
// Revenue chart — from real data
|
||||
new Chart(document.getElementById('revChart'), {
|
||||
type:'line',
|
||||
data:{
|
||||
labels:['2018','2019','2020','2021','2022','2023','2024','2025'],
|
||||
labels: years,
|
||||
datasets:[{
|
||||
data:[1654002,1545674,1820963,1775174,1514505,1378510,1244661,1047850],
|
||||
data: years.map(y => Math.round(yearly[y].rev)),
|
||||
borderColor:'#6366f1',backgroundColor:'rgba(99,102,241,.1)',fill:true,tension:.4,pointRadius:4,pointBackgroundColor:'#6366f1',
|
||||
pointBorderColor:'#0d1322',pointBorderWidth:2,borderWidth:2.5
|
||||
}]
|
||||
},
|
||||
options:{...cBase,scales:{...cBase.scales,y:{...cBase.scales.y,ticks:{...cBase.scales.y.ticks,callback:v=>'£'+Math.round(v/1000)+'k'}}},
|
||||
plugins:{...cBase.plugins,tooltip:{callbacks:{label:ctx=>'£'+ctx.raw.toLocaleString()}}}}
|
||||
});
|
||||
});
|
||||
|
||||
// New customer chart
|
||||
new Chart(document.getElementById('custChart'), {
|
||||
// New customer chart — from real data
|
||||
const custColors = years.map(y => {
|
||||
if(y === peakNewYear) return '#10b981cc';
|
||||
return yearly[y].newCust < yearly[peakNewYear].newCust * 0.5 ? '#ef4444cc' :
|
||||
yearly[y].newCust < yearly[peakNewYear].newCust * 0.75 ? '#f59e0bcc' : '#6366f1cc';
|
||||
});
|
||||
new Chart(document.getElementById('custChart'), {
|
||||
type:'bar',
|
||||
data:{
|
||||
labels:['2018','2019','2020','2021','2022','2023','2024','2025'],
|
||||
labels: years,
|
||||
datasets:[{
|
||||
data:[20219,11874,24666,20309,16404,9869,6338,3941],
|
||||
backgroundColor:['#6366f1cc','#6366f1cc','#10b981cc','#6366f1cc','#f59e0bcc','#ef4444cc','#ef4444cc','#ef4444cc'],
|
||||
data: years.map(y => yearly[y].newCust),
|
||||
backgroundColor: custColors,
|
||||
borderRadius:6,borderSkipped:false
|
||||
}]
|
||||
},
|
||||
options:{...cBase,plugins:{...cBase.plugins,tooltip:{callbacks:{label:ctx=>ctx.raw.toLocaleString()+' new customers'}}}}
|
||||
});
|
||||
});
|
||||
|
||||
// Channel donut
|
||||
new Chart(document.getElementById('chChart'), {
|
||||
// Channel donut — from real data
|
||||
const chEntries = Object.entries(chTotals).sort((a,b)=>b[1]-a[1]);
|
||||
const chColors = ['#6366f1','#818cf8','#a855f7','#06b6d4','#64748b','#ef4444','#f59e0b','#10b981'];
|
||||
new Chart(document.getElementById('chChart'), {
|
||||
type:'doughnut',
|
||||
data:{
|
||||
labels:['Organic','Google Ads','Webgains','Email','Bing','Social/Other'],
|
||||
labels: chEntries.map(e => e[0]),
|
||||
datasets:[{
|
||||
data:[50.5,31.2,10.4,5.6,2.2,0.1],
|
||||
backgroundColor:['#6366f1','#818cf8','#a855f7','#06b6d4','#64748b','#ef4444'],
|
||||
data: chEntries.map(e => parseFloat((e[1]/chTotal*100).toFixed(1))),
|
||||
backgroundColor: chColors.slice(0, chEntries.length),
|
||||
borderWidth:0,spacing:2
|
||||
}]
|
||||
},
|
||||
options:{responsive:true,maintainAspectRatio:false,cutout:'65%',
|
||||
plugins:{legend:{position:'bottom',labels:{color:'#5a6d94',font:{size:10},padding:12,usePointStyle:true,pointStyleWidth:8}},
|
||||
tooltip:{callbacks:{label:ctx=>ctx.label+': '+ctx.raw+'%'}}}}
|
||||
});
|
||||
});
|
||||
|
||||
// Update ROI calculator with real AOV
|
||||
const latestAOV = yearly[latestYear] ? yearly[latestYear].rev / yearly[latestYear].orders : 35.02;
|
||||
window._realAOV = latestAOV;
|
||||
calcROI();
|
||||
}).catch(err => console.warn('Offer charts: using static fallback', err));
|
||||
|
||||
// ══════ ROI CALCULATOR ══════
|
||||
function calcROI() {
|
||||
const n = parseInt(document.getElementById('roiSlider').value);
|
||||
document.getElementById('sliderVal').textContent = n;
|
||||
const aov = 35.02; // 2025 actual (source-linked)
|
||||
const aov = window._realAOV || 35.02; // live from API, fallback to 2025 actual
|
||||
const cohortReturnRate = 0.576; // 12-month cohort return rate (verified from 728K orders)
|
||||
const avgRepeats = 2; // conservative avg repeat purchases in year 1
|
||||
const ltv = aov * (1 + cohortReturnRate * avgRepeats);
|
||||
|
||||
@@ -68,6 +68,50 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ BEFORE / AFTER ═══ -->
|
||||
<section class="demo" id="before-after" style="padding-top:2rem">
|
||||
<span class="badge" style="background:rgba(245,158,11,.15);color:#f59e0b">📊 WHAT THE AI ENGINE PRODUCES</span>
|
||||
<h2 style="margin-bottom:.5rem">Before → After: Real Product Comparison</h2>
|
||||
<p class="sub" style="margin-bottom:2rem">Same product. Left is the current justvitamins.co.uk page. Right is what the AI engine generates in 90 seconds.</p>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-bottom:2rem">
|
||||
<div style="background:var(--card);border:1px solid var(--border);border-radius:12px;padding:24px;position:relative">
|
||||
<div style="position:absolute;top:12px;left:12px;background:rgba(239,68,68,.15);color:#ef4444;font-size:10px;font-weight:700;padding:3px 10px;border-radius:4px;text-transform:uppercase">Current PDP</div>
|
||||
<div style="margin-top:28px">
|
||||
<div style="font-size:15px;font-weight:700;color:var(--text);margin-bottom:8px">Super Strength Vitamin D3 4000iu + K2</div>
|
||||
<div style="font-size:12px;color:var(--text3);margin-bottom:16px">justvitamins.co.uk — actual product page</div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;font-size:12px;color:var(--text2)">
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> Generic subtitle: "A powerful pairing"</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> Single product photo (pouch only)</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> No benefit-driven bullets (Feature→Benefit→Proof)</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> No trust signals (money-back, UK-made, certifications)</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> No price anchoring (daily cost, cost-per-dose)</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> No SEO meta description</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> No ad hooks or email sequences</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#ef4444">✗</span> Cookie consent modal covers half the page</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:var(--card);border:1px solid rgba(16,185,129,.3);border-radius:12px;padding:24px;position:relative">
|
||||
<div style="position:absolute;top:12px;left:12px;background:rgba(16,185,129,.15);color:#10b981;font-size:10px;font-weight:700;padding:3px 10px;border-radius:4px;text-transform:uppercase">AI-Generated PDP</div>
|
||||
<div style="margin-top:28px">
|
||||
<div style="font-size:15px;font-weight:700;color:var(--text);margin-bottom:8px">Same product — generated in ~90 seconds</div>
|
||||
<div style="font-size:12px;color:var(--text3);margin-bottom:16px">Conversion-optimised by Gemini AI</div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;font-size:12px;color:var(--text2)">
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> 5 AI-generated product photos (lifestyle, scale, detail, banner)</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> Feature → Benefit → Proof bullet structure</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> Trust bar: money-back, UK-made, EFSA claims</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> Price anchoring: "just 14p per day"</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> Full FAQ accordion with objection handling</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> SEO meta + Open Graph tags</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> 3 ad hooks + 3 email sequences</div>
|
||||
<div style="display:flex;gap:8px;align-items:center"><span style="color:#10b981">✓</span> 4 copy styles: Balanced, Premium, Direct, Medical-Safe</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="text-align:center;color:var(--text3);font-size:12px">↑ Run Demo A above to see the full AI-generated PDP for any JustVitamins product</p>
|
||||
</section>
|
||||
|
||||
<!-- ═══ DEMO B — Competitor X-Ray ═══ -->
|
||||
<section class="demo" id="demo-b">
|
||||
<span class="badge blue">🔍 DEMO B — LIVE</span>
|
||||
|
||||
Reference in New Issue
Block a user