${o.featured ? 'Featured' : ''}
${escapeHtml(o.title)}
$${Number(o.price_usd).toLocaleString()} · ${escapeHtml(o.duration)}
${escapeHtml(o.description)}
${o.includes_hardware ? 'Includes: ' + escapeHtml(o.includes_hardware) + '
' : ''}
By ${escapeHtml(o.expert_name)} · ${escapeHtml(o.legal_note)}
${(o.deliverables||[]).slice(0,4).map(d => '- '+escapeHtml(d)+'
').join('')}
`).join('');
oEl.querySelectorAll('[data-request]').forEach(btn => {
btn.addEventListener('click', async () => {
const offer_id = btn.getAttribute('data-request');
const title = btn.getAttribute('data-title') || offer_id;
const name = prompt('Your name') || '';
const email = prompt('Work email') || '';
if (!name || !email) return;
const note = prompt('Anything we should know? (optional)') || '';
btn.textContent = 'Sending…';
try {
const r = await fetch('/api/marketplace/request', {
method: 'POST', headers: {'content-type':'application/json'},
body: JSON.stringify({ offer_id, name, email, note })
});
const d = await r.json();
alert(d.message || d.error || 'Sent');
btn.textContent = 'Request engagement';
} catch (e) { alert(String(e)); btn.textContent = 'Request engagement'; }
});
});
}
if (eEl && experts.experts) {
eEl.innerHTML = experts.experts.map(e => `
${escapeHtml(e.assessment_badge)}
${escapeHtml(e.name)}
${escapeHtml(e.headline)}
Score ${e.assessment_score} · ${escapeHtml(e.tier)} · ${escapeHtml(e.availability)}
${(e.specialties||[]).map(escapeHtml).join(' · ')}
`).join('');
}
}
function escapeHtml(s) {
return String(s||'').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
}
loadMarket().catch(err => {
const oEl = document.getElementById('offers');
if (oEl) oEl.innerHTML = '