' + t.slice(i, i + q.length) + '' + hl(t.slice(i + q.length), q);
}
function renderTable() {
if (activeTab === 'shop' || activeTab === 'planner') return;
const rows = filtered();
const q = document.getElementById('search').value.trim().toLowerCase();
if (sortKey) rows.sort((a, b) => ((a[sortKey] || '').localeCompare(b[sortKey] || '')) * sortDir);
var cse=document.getElementById('cShown'); if(cse) cse.textContent=rows.length;
var cte=document.getElementById('cTotal'); if(cte) cte.textContent=D.length;
var tb = document.getElementById('tbody');
if (!tb) {
document.body.insertAdjacentHTML('afterbegin','
ERROR: tbody not found
');
return;
}
if (!rows.length) {
tb.innerHTML = '
DEBUG: D.length=' + D.length + ' activeTab=' + activeTab + ' rows=' + filtered().length + ' ';
return;
}
tb.innerHTML = rows.map((r, i) => {
const nw = r.src === 'peptidedosages' ? '
NEW ' : '';
const ns = r.nasal ? '
▲ nasal ' : '';
return '
' +
'' + hl(r.name, q) + nw + ns + ' ' +
'' + hl(r.purpose, q) + ' ' +
'' + hl(r.vial, q) + ' ' + r.bac + ' ' +
'' + hl(r.dose, q) + ' ' +
'' + r.units + ' ' +
'' + hl(r.timing, q) + ' ' +
'' + hl(r.frequency, q) + ' ' +
'' + hl(r.duration, q) + ' ';
}).join('');
}
function srt(k) {
if (sortKey === k) sortDir *= -1; else { sortKey = k; sortDir = 1; }
document.querySelectorAll('th').forEach(t => t.classList.remove('th-asc', 'th-desc'));
const idx = {name:0,purpose:1,vial:2,bac:3,dose:4,units:5,timing:6,frequency:7,duration:8}[k];
const th = document.querySelectorAll('th')[idx];
if (th) th.classList.add(sortDir === 1 ? 'th-asc' : 'th-desc');
renderTable();
}
function resetAll() {
document.getElementById('search').value = '';
['fPurpose','fTiming'].forEach(id => { const el=document.getElementById(id); if(el) el.value=''; });
sortKey = ''; sortDir = 1;
document.querySelectorAll('th').forEach(t => t.classList.remove('th-asc', 'th-desc'));
setTab(document.querySelector('.tab[data-tab="all"]'));
}
// ─── DETAIL MODAL ────────────────────────────────────────────────────────────
function openDetail(idx) {
const r = D[idx];
currentDetailRow = r;
const hn = r.nasal;
const srcLine = r.src === 'peptidedosages'
? '
NEW PeptideDosages.com '
: '
Hunter Williams Cheat Sheet ';
const sqGrid = '
' +
'
Vial Amount
' + r.vial + '
' +
'
' +
'
' +
'
Syringe Units
' + r.units + '
' +
'
' +
'
Frequency
' + r.frequency + '
' +
'
Duration / Cycle
' + r.duration + '
' +
'
';
const nasalGrid = hn ? '
' +
'
Nasal Spray Dose
' + (r.nasalDose || 'See notes') + '
' +
'
' +
'
Frequency
' + r.frequency + '
' +
'
Duration
' + r.duration + '
' +
'
Nasal Protocol Notes
' + (r.nasalNote || '') + '
' +
'
' : '';
const toggle = hn
? `
`
: '';
const noteHtml = r.note ? '
Note: ' + r.note + '
' : '';
const urlHtml = r.url ? '
' : '';
const discHtml = '
Your responsibility: Research this compound independently and work with a qualified practitioner before starting any protocol.
';
document.getElementById('detailContent').innerHTML =
'
' + r.name + ' ' +
'
' +
'' + r.purpose + ' ' + srcLine +
'
' +
toggle +
'
' + sqGrid + '
' +
(hn ? '
' + nasalGrid + '
' : '') +
buildPricePanel(r) +
buildMiniSyringe(r) +
noteHtml + urlHtml + discHtml;
openOverlay('detailOverlay');
setTimeout(() => renderMiniSyringe(r), 50);
}
function swR(mode) {
const sq = document.getElementById('pSQ'), n = document.getElementById('pN');
const tSQ = document.getElementById('rtSQ'), tN = document.getElementById('rtN');
if (mode === 'sq') {
if (sq) sq.classList.add('active'); if (n) n.classList.remove('active');
if (tSQ) { tSQ.classList.add('active'); tSQ.classList.remove('nasal-active'); }
if (tN) tN.classList.remove('active', 'nasal-active');
} else {
if (n) n.classList.add('active'); if (sq) sq.classList.remove('active');
if (tN) { tN.classList.add('active', 'nasal-active'); }
if (tSQ) tSQ.classList.remove('active');
}
}
// ─── RECONSTITUTION MATHS ────────────────────────────────────────────────────
function toBase(val, unit) {
if (unit === 'mg') return val * 1000;
if (unit === 'mcg') return val;
return val;
}
function fmtConc(val, unit) {
const u = (unit || 'mcg').toLowerCase();
if (u === 'mg' && val < 0.01) return (val * 1000).toFixed(2) + ' mcg/ml';
if (u === 'mcg' && val >= 1000) return (val / 1000).toFixed(3) + ' mg/ml';
return val.toFixed(val >= 100 ? 1 : val >= 10 ? 2 : 3) + ' ' + u + '/ml';
}
function parseDoseStr(str) {
if (!str || str === 'N/A' || str === '—') return null;
str = str.split('/')[0].trim();
const range = str.match(/([\d.]+)\s*[–\-]\s*[\d.]+\s*(mg|mcg|iu)/i);
if (range) return { val: parseFloat(range[1]), unit: range[2].toLowerCase() };
const simple = str.match(/([\d.]+)\s*(mg|mcg|iu)/i);
if (simple) return { val: parseFloat(simple[1]), unit: simple[2].toLowerCase() };
return null;
}
function parseBacStr(str) {
if (!str || str === 'N/A') return null;
const m = str.match(/([\d.]+)/);
return m ? parseFloat(m[1]) : null;
}
function calcDose(pv, pu, wml, dv, du) {
const pb = toBase(pv, pu), db = toBase(dv, du);
const concBase = pb / wml, volMl = db / concBase;
return { volMl, concVal: pv / wml, concUnit: pu, totalReconMl: wml, dosesInVial: isFinite(pb/db) ? Math.floor(pb/db) : 0 };
}
function maxMlForCap(cap) { return cap === 100 ? 1.0 : cap === 50 ? 0.5 : 0.3; }
// ─── SYRINGE DRAWING ─────────────────────────────────────────────────────────
function drawSyringe(svgEl, fillMl, maxMl, capacity) {
if (!svgEl) return;
const frac = Math.min(1, Math.max(0, isFinite(fillMl / maxMl) ? fillMl / maxMl : 0));
const fillUnits = fillMl * capacity;
const isOver = fillMl > maxMl && fillMl > 0;
const VW = 520, VH = 140;
const bX = 60, bY = 40, bW = 360, bH = 60;
const tipX = bX + bW, nW = 80, nH = 8;
const tc = capacity === 100 ? 10 : 10;
const me = capacity === 100 ? 10 : 5;
const fw = frac * bW;
const fc = isOver ? '#ff6b6b' : '#00e5c3';
const mc = isOver ? '#ff6b6b' : '#f5c800';
let s = '
';
s += '
';
s += '
';
if (fw > 3) s += '
';
for (let i = 0; i <= tc; i++) {
const x = bX + (i / tc) * bW;
const uv = Math.round(i * (capacity / tc));
const maj = uv % me === 0;
s += '
';
if (maj) {
const ml = (i / tc) * maxMl;
s += '
' + (ml > 0 ? ml.toFixed(maxMl < 0.5 ? 2 : 1) : '0') + ' ';
s += '
' + uv + ' ';
}
}
s += '
ml ';
s += '
' + (capacity === 100 ? 'U-100 · 1 ml' : capacity === 50 ? 'U-50 · 0.5 ml' : 'U-30 · 0.3 ml') + ' ';
s += '
';
const px = bX - 38;
s += '
';
s += '
';
s += '
';
if (frac > 0.005 && !isOver && isFinite(fillMl)) {
const ax = bX + fw;
s += '
';
s += '
▼ ' + fillMl.toFixed(3) + ' ml = ' + fillUnits.toFixed(1) + ' units ';
}
if (isOver) s += '
⚠ EXCEEDS SYRINGE — split or use larger ';
svgEl.setAttribute('viewBox', '0 0 ' + VW + ' ' + VH);
svgEl.innerHTML = s;
}
// ─── STANDALONE SYRINGE MODAL ─────────────────────────────────────────────────
function setSyrType(el, cap) {
document.querySelectorAll('.syr-type-btn').forEach(b => b.classList.remove('active'));
el.classList.add('active'); syringeCapacity = cap; updateSyringe();
}
function updateSyringe() {
const p = parseFloat(document.getElementById('svPeptide').value);
const pu = document.getElementById('svPUnit').value;
const w = parseFloat(document.getElementById('svWater').value);
const d = parseFloat(document.getElementById('svDose').value);
const du = document.getElementById('svDUnit').value;
const custom = parseFloat(document.getElementById('svCustom').value);
const svgEl = document.getElementById('mainSyrSVG');
const maxMl = maxMlForCap(syringeCapacity);
const warn = document.getElementById('svWarn');
if (!isNaN(custom) && custom > 0) {
const units = custom * syringeCapacity;
document.getElementById('svConc').textContent = '—';
document.getElementById('svVol').textContent = custom.toFixed(3) + ' ml';
document.getElementById('svRecon').textContent = '—';
document.getElementById('svUnits').textContent = units.toFixed(1) + ' units';
drawSyringe(svgEl, custom, maxMl, syringeCapacity);
warn.className = 'syr-warn' + (custom > maxMl ? ' show' : '');
return;
}
if (isNaN(p) || isNaN(w) || isNaN(d) || w <= 0 || d <= 0 || p <= 0) {
drawSyringe(svgEl, 0, maxMl, syringeCapacity);
['svConc','svVol','svRecon','svUnits'].forEach(id => document.getElementById(id).textContent = '—');
warn.className = 'syr-warn'; return;
}
const res = calcDose(p, pu, w, d, du);
const fu = res.volMl * syringeCapacity;
document.getElementById('svConc').textContent = fmtConc(res.concVal, res.concUnit);
document.getElementById('svVol').textContent = isFinite(res.volMl) ? res.volMl.toFixed(3) + ' ml' : '—';
document.getElementById('svRecon').textContent = res.totalReconMl.toFixed(1) + ' ml · ' + res.dosesInVial + ' doses';
document.getElementById('svUnits').textContent = isFinite(fu) ? fu.toFixed(1) + ' units' : '—';
drawSyringe(svgEl, isFinite(res.volMl) ? res.volMl : 0, maxMl, syringeCapacity);
const isOver = res.volMl > maxMl;
warn.className = 'syr-warn' + (isOver ? ' show' : '');
if (isOver) warn.textContent = '⚠ Volume exceeds syringe capacity. Use larger or split.';
}
function initMainSyringe() {
const el = document.getElementById('mainSyrSVG');
if (el) { el.setAttribute('viewBox','0 0 520 140'); drawSyringe(el, 0, 1.0, 100); }
}
// ─── MINI SYRINGE (inside detail modal) ──────────────────────────────────────
function buildMiniSyringe(r) {
return '
💉 Syringe Fill Guide ' +
'
Syringe: ' +
'' +
'U-100 (1 ml) U-50 (0.5 ml) U-30 (0.3 ml) ' +
'Override (ml): ' +
'
' +
'
' +
'
' +
'
' +
'
' +
'
' +
'
' +
'
';
}
function renderMiniSyringe(r) {
if (!r) return;
currentDetailRow = r;
const svgEl = document.getElementById('miniSyrSVG');
if (!svgEl) return;
const cap = parseInt(document.getElementById('miniSyrType')?.value || '100');
const maxMl = maxMlForCap(cap);
const custom = parseFloat(document.getElementById('miniCustomMl')?.value);
if (!isNaN(custom) && custom > 0) {
const units = custom * cap;
document.getElementById('miniVol').textContent = custom.toFixed(3) + ' ml';
document.getElementById('miniUnits').textContent = units.toFixed(1) + ' units';
document.getElementById('miniConc').textContent = '—';
document.getElementById('miniDoses').textContent = '—';
drawSyringe(svgEl, custom, maxMl, cap); return;
}
const di = parseDoseStr(r.dose), bml = parseBacStr(r.bac), vi = parseDoseStr(r.vial);
if (!di || !bml || !vi || bml <= 0) {
drawSyringe(svgEl, 0, maxMl, cap);
['miniVol','miniUnits','miniConc','miniDoses'].forEach(id => document.getElementById(id).textContent = '—');
return;
}
const res = calcDose(vi.val, vi.unit, bml, di.val, di.unit);
const fu = res.volMl * cap;
document.getElementById('miniVol').textContent = isFinite(res.volMl) ? res.volMl.toFixed(3) + ' ml' : '—';
document.getElementById('miniUnits').textContent = isFinite(fu) ? fu.toFixed(1) + ' units' : '—';
document.getElementById('miniConc').textContent = isFinite(res.concVal) ? fmtConc(res.concVal, res.concUnit) : '—';
document.getElementById('miniDoses').textContent = res.dosesInVial > 0 ? res.dosesInVial : '—';
drawSyringe(svgEl, isFinite(res.volMl) ? res.volMl : 0, maxMl, cap);
}
// ─── PRICE DATA ───────────────────────────────────────────────────────────────
const PRICES = {
'5-amino-1mq': [{"code": "5AM", "qty": "10 x 5mg vials", "price": 90, "desc": "NNMT inhibitor; may increase NAD+ levels, support metabolic health and fat loss", "rawName": "5-amino-1mq"}, {"code": "10AM", "qty": "10 x 10mg vials", "price": 130, "desc": "NNMT inhibitor; may increase NAD+ levels, support metabolic health and fat loss", "rawName": "5-amino-1mq"}, {"code": "50AM", "qty": "10 x 50mg vials", "price": 190, "desc": "NNMT inhibitor; may increase NAD+ levels, support metabolic health and fat loss", "rawName": "5-amino-1mq"}],
'acu': [{"code": "ACU50", "qty": "10 x 50mg vials", "price": 100, "desc": "Research peptide blend; specific applications under investigation", "rawName": "ACU"}, {"code": "ACU100", "qty": "10 x 100mg vials", "price": 130, "desc": "Research peptide blend; specific applications under investigation", "rawName": "ACU"}],
'adamax': [{"code": "ADA5", "qty": "10 x 5mg vials", "price": 160, "desc": "Peptide bioregulator; may support cellular metabolism and tissue-specific regeneration", "rawName": "Admax"}, {"code": "ADA10", "qty": "10 x 10mg vials", "price": 240, "desc": "Peptide bioregulator; may support cellular metabolism and tissue-specific regeneration", "rawName": "Admax"}],
'adipotide': [{"code": "AP2", "qty": "10 x 2mg vials", "price": 140, "desc": "Proapoptotic peptide; targets adipose tissue vasculature, investigational for obesity", "rawName": "Adipotide"}, {"code": "AP5", "qty": "10 x 5mg vials", "price": 240, "desc": "Proapoptotic peptide; targets adipose tissue vasculature, investigational for obesity", "rawName": "Adipotide"}],
'aicar': [{"code": "AR50", "qty": "10 x 50mg vials", "price": 120, "desc": "AMPK activator; enhances glucose uptake and fat oxidation, investigational metabolic agent", "rawName": "AICAR"}],
'aod-9604': [{"code": "5AD", "qty": "10 x 10mg vials", "price": 180, "desc": "AOD-9604; HGH fragment analog, may promote fat metabolism without affecting blood sugar", "rawName": "AOD"}, {"code": "10AD", "qty": "10 x 10mg vials", "price": 280, "desc": "AOD-9604; HGH fragment analog, may promote fat metabolism without affecting blood sugar", "rawName": "AOD"}],
'ara-290': [{"code": "RA10", "qty": "10 x 10mg vials", "price": 120, "desc": "Erythropoietin derivative; investigational for neuropathy, tissue protection, and anti-inflammatory effects", "rawName": "Ara-290"}],
'bac water': [{"code": "BA3", "qty": "10 x 3ml vials", "price": 16, "desc": "Bacteriostatic water; sterile diluent for reconstituting lyophilized peptides and medications", "rawName": "bacwater"}, {"code": "BA10", "qty": "10 x 10ml vials", "price": 20, "desc": "Bacteriostatic water; sterile diluent for reconstituting lyophilized peptides and medications", "rawName": "bacwater"}],
'botulinum toxin': [{"code": "XT100", "qty": "10 x 100IU vials", "price": 280, "desc": "Neurotoxin; blocks nerve signals to muscles, used for cosmetic wrinkle reduction and medical conditions", "rawName": "Botulinum toxin"}],
'bpc-157': [{"code": "BC5", "qty": "10 x 5mg vials", "price": 80, "desc": "Body Protection Compound; promotes tissue healing, gut repair, and anti-inflammatory effects", "rawName": "BPC157"}, {"code": "BC10", "qty": "10 x 10mg vials", "price": 130, "desc": "Body Protection Compound; promotes tissue healing, gut repair, and anti-inflammatory effects", "rawName": "BPC157"}],
'bpc-157 / tb-500 blend': [{"code": "BB10", "qty": "10 x 10(5+5)mg vials", "price": 180, "desc": "Synergistic blend of BPC-157 and TB-500 for enhanced tissue regeneration and recovery", "rawName": "bpc157+tb500"}, {"code": "BB20", "qty": "10 x 20(10+10)mg vials", "price": 300, "desc": "Synergistic blend of BPC-157 and TB-500 for enhanced tissue regeneration and recovery", "rawName": "bpc157+tb500"}, {"code": "BB30", "qty": "10 x 30(15+15)mg vials", "price": 420, "desc": "Synergistic blend of BPC-157 and TB-500 for enhanced tissue regeneration and recovery", "rawName": "bpc157+tb500"}],
'cagrilintide': [{"code": "CGL5", "qty": "10 x 5mg vials", "price": 200, "desc": "Long-acting amylin analog; investigational for weight management and appetite control", "rawName": "cagrilintide"}, {"code": "CGL10", "qty": "10 x 10mg vials", "price": 320, "desc": "Long-acting amylin analog; investigational for weight management and appetite control", "rawName": "cagrilintide"}],
'cagrisema (cagrilintide + semaglutide)': [{"code": "CS10", "qty": "10 x 10mg vials", "price": 240, "desc": "Dual amylin/GLP-1 blend; combined appetite suppression and metabolic support", "rawName": "cagrilintide5mg+semaglutide5mg"}, {"code": "CS20", "qty": "10 x 20mg vials", "price": 360, "desc": "Dual amylin/GLP-1 blend; combined appetite suppression and metabolic support", "rawName": "cagrilintide5mg+semaglutide5mg"}],
'cartalax': [{"code": "CTL20", "qty": "10 x 20mg vials", "price": 280, "desc": "Cartilage peptide bioregulator; may support joint health and cartilage tissue repair", "rawName": "Cartalax"}],
'cerebrolysin': [{"code": "CBL60", "qty": "10 x 60mg vials", "price": 140, "desc": "Cerebrolysin; porcine brain-derived peptide mixture; neuroprotective and cognitive support", "rawName": "Cerbroysin"}],
'cjc-1295 dac': [{"code": "CD5", "qty": "10 x 5mg vials", "price": 260, "desc": "GHRH analog with drug affinity complex; extended half-life for sustained GH release", "rawName": "CJC-1295 with DAC"}],
'cjc-1295 no dac': [{"code": "CND5", "qty": "10 x 5mg vials", "price": 140, "desc": "GHRH analog; stimulates GH release with shorter half-life than with DAC", "rawName": "CJC-1295 without DAC"}, {"code": "CND10", "qty": "10 x 10mg vials", "price": 240, "desc": "GHRH analog; stimulates GH release with shorter half-life than with DAC", "rawName": "CJC-1295 without DAC"}],
'crystagen': [{"code": "", "qty": "10 x 20mg vials", "price": 170, "desc": "Immune peptide bioregulator; may support immune system function and cellular defense", "rawName": "Crystagen"}],
'dermorphin': [{"code": "DR5", "qty": "10 x 5mg vials", "price": 100, "desc": "Opioid peptide; potent mu-opioid agonist with analgesic properties (research use only)", "rawName": "Dermorphin"}],
'dihexa': [{"code": "DI5", "qty": "10 x 5mg vials", "price": 160, "desc": "Angiotensin IV analog; investigational nootropic, may enhance synaptogenesis and cognitive function", "rawName": "dihexa"}, {"code": "DI10", "qty": "10 x 10mg vials", "price": 220, "desc": "Angiotensin IV analog; investigational nootropic, may enhance synaptogenesis and cognitive function", "rawName": "dihexa"}],
'dsip': [{"code": "DS5", "qty": "10 x 5mg vials", "price": 80, "desc": "Delta sleep-inducing peptide; may promote deep sleep, reduce stress, and modulate endocrine function", "rawName": "DSIP"}, {"code": "DS10", "qty": "10 x 10mg vials", "price": 140, "desc": "Delta sleep-inducing peptide; may promote deep sleep, reduce stress, and modulate endocrine function", "rawName": "DSIP"}],
'epithalon': [{"code": "ET10", "qty": "10 x 10mg vials", "price": 80, "desc": "Synthetic pineal tetrapeptide; may activate telomerase, support anti-aging and cellular longevity", "rawName": "Epithalon"}, {"code": "ET50", "qty": "10 x 50mg vials", "price": 250, "desc": "Synthetic pineal tetrapeptide; may activate telomerase, support anti-aging and cellular longevity", "rawName": "Epithalon"}],
'epo': [{"code": "", "qty": "10 x 3000IU vials", "price": 310, "desc": "Erythropoietin; stimulates red blood cell production, used for anemia and athletic performance", "rawName": "EPO"}],
'foxo4-dri': [{"code": "F410", "qty": "10 x 10mg vials", "price": 540, "desc": "Senolytic peptide; selectively induces apoptosis of senescent cells, investigational for aging", "rawName": "FOXO4-DRI"}],
'ghk-cu': [{"code": "CU50", "qty": "10 x 50mg vials", "price": 80, "desc": "Copper peptide; promotes collagen synthesis, wound healing, skin rejuvenation, and anti-aging", "rawName": "GHK-CU"}, {"code": "CU100", "qty": "10 x 100mg vials", "price": 110, "desc": "Copper peptide; promotes collagen synthesis, wound healing, skin rejuvenation, and anti-aging", "rawName": "GHK-CU"}],
'ghrp-2': [{"code": "G25", "qty": "10 x 5mg vials", "price": 60, "desc": "Growth hormone releasing peptide; stimulates GH secretion with less appetite effect than GHRP-6", "rawName": "GHRP-2"}, {"code": "G210", "qty": "10 x 10mg vials", "price": 100, "desc": "Growth hormone releasing peptide; stimulates GH secretion with less appetite effect than GHRP-6", "rawName": "GHRP-2"}, {"code": "G215", "qty": "10 x 15mg vials", "price": 140, "desc": "Growth hormone releasing peptide; stimulates GH secretion with less appetite effect than GHRP-6", "rawName": "GHRP-2"}],
'ghrp-6': [{"code": "G65", "qty": "10 x 5mg vials", "price": 80, "desc": "Growth hormone releasing peptide; stimulates GH secretion, increases appetite, supports muscle growth", "rawName": "GHRP-6"}, {"code": "G610", "qty": "10 x 10mg vials", "price": 120, "desc": "Growth hormone releasing peptide; stimulates GH secretion, increases appetite, supports muscle growth", "rawName": "GHRP-6"}],
'glow blend (ghk-cu, bpc-157, tb-500)': [{"code": "BBG", "qty": "10 x 70(50+10+10) vials", "price": 360, "desc": "Custom peptide blend (70mg total); combined metabolic and rejuvenation support formula", "rawName": "Glow"}],
'glutathione': [{"code": "GTT", "qty": "10 x 600mg vials", "price": 120, "desc": "Master antioxidant; supports detoxification, immune function, and skin brightening", "rawName": "Gluthathione"}, {"code": "GTT", "qty": "10 x 1500mg vials", "price": 160, "desc": "Master antioxidant; supports detoxification, immune function, and skin brightening", "rawName": "Gluthathione"}],
'hcg': [{"code": "HC5000", "qty": "10 x 5000IU vials", "price": 130, "desc": "Human chorionic gonadotropin; supports fertility, testosterone production, and weight loss protocols", "rawName": "HCG"}, {"code": "HC10000", "qty": "10 x 10000iu vials", "price": 240, "desc": "Human chorionic gonadotropin; supports fertility, testosterone production, and weight loss protocols", "rawName": "HCG"}],
'hexarelin': [{"code": "HX2", "qty": "10 x 2mg vials", "price": 90, "desc": "GH secretagogue; stimulates GH and IGF-1 release, may support cardiac function", "rawName": "Hexarelin"}, {"code": "HX5", "qty": "10 x 5ml vials", "price": 140, "desc": "GH secretagogue; stimulates GH and IGF-1 release, may support cardiac function", "rawName": "Hexarelin"}, {"code": "HX10", "qty": "10 x 10mg vials", "price": 220, "desc": "GH secretagogue; stimulates GH and IGF-1 release, may support cardiac function", "rawName": "Hexarelin"}],
'hgh 176-191': [{"code": "FR2", "qty": "10 x 2mg vials", "price": 120, "desc": "HGH fragment; may promote fat loss without affecting insulin sensitivity or IGF-1", "rawName": "HGH Fragment 176-191"}, {"code": "FR5", "qty": "10 x 5mg vials", "price": 170, "desc": "HGH fragment; may promote fat loss without affecting insulin sensitivity or IGF-1", "rawName": "HGH Fragment 176-191"}],
'hgh 191aa': [{"code": "H6", "qty": "10 x 6iu vials", "price": 100, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}, {"code": "H10", "qty": "10 x 10iu vials", "price": 120, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}, {"code": "H12", "qty": "10 x 12iu vials", "price": 140, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}, {"code": "H15", "qty": "10 x 15iu vials", "price": 160, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}, {"code": "H24", "qty": "10 x 24iu vials", "price": 240, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}, {"code": "H36", "qty": "10 x 36iu vials", "price": 360, "desc": "Recombinant human growth hormone; supports muscle growth, recovery, anti-aging, and metabolism", "rawName": "hgh-191"}],
'hmg': [{"code": "G75", "qty": "10 x 75iu vials", "price": 120, "desc": "Human menopausal gonadotropin; supports fertility by stimulating ovarian/testicular function", "rawName": "HMG"}],
'igf-1 lr3': [{"code": "IG01", "qty": "10 x 0.1mg vials", "price": 100, "desc": "Insulin-like growth factor-1 LR3; promotes muscle growth, cell proliferation, and tissue repair", "rawName": "IGF-LR3/1"}, {"code": "IG1", "qty": "10 x 1mg vials", "price": 330, "desc": "Insulin-like growth factor-1 LR3; promotes muscle growth, cell proliferation, and tissue repair", "rawName": "IGF-LR3/1"}],
'ipamorelin': [{"code": "IP5", "qty": "10 x 5mg vials", "price": 80, "desc": "Growth hormone secretagogue; selective GH release with minimal cortisol/prolactin elevation", "rawName": "ipamorelin"}, {"code": "IP10", "qty": "10 x 10mg vials", "price": 120, "desc": "Growth hormone secretagogue; selective GH release with minimal cortisol/prolactin elevation", "rawName": "ipamorelin"}],
'ipamorelin / cjc-1295 no dac blend': [{"code": "CP10", "qty": "10 x 10(5 + 5) vials", "price": 180, "desc": "Combined GHRH and GHRP for synergistic growth hormone stimulation", "rawName": "CJC-1295 without DAC + IPA"}],
'kisspeptin': [{"code": "KS5", "qty": "10 x 5mg vials", "price": 110, "desc": "Reproductive peptide; stimulates GnRH release, supports fertility and hormone regulation", "rawName": "Kisspeptin-10"}, {"code": "KS10", "qty": "10 x 10mg vials", "price": 170, "desc": "Reproductive peptide; stimulates GnRH release, supports fertility and hormone regulation", "rawName": "Kisspeptin-10"}],
'klow blend (ghk-cu, bpc-157, tb-500, kpv)': [{"code": "BBGK", "qty": "10 x 80(50+10+10+10) vials", "price": 400, "desc": "Custom peptide blend (80mg total); combined metabolic and performance support formula", "rawName": "Klow"}],
'kpv': [{"code": "KP5", "qty": "10 x 5mg vials", "price": 80, "desc": "Tripeptide (Lys-Pro-Val); anti-inflammatory, may support gut health and wound healing", "rawName": "KPV"}, {"code": "KP10", "qty": "10 x 10mg vials", "price": 110, "desc": "Tripeptide (Lys-Pro-Val); anti-inflammatory, may support gut health and wound healing", "rawName": "KPV"}],
'l-carnitine': [{"code": "LC400", "qty": "10 x 400mg vials", "price": 130, "desc": "Amino acid derivative; supports fat metabolism, energy production, and exercise performance", "rawName": "L-carnitine"}, {"code": "LC600", "qty": "10 x 600mg vials", "price": 150, "desc": "Amino acid derivative; supports fat metabolism, energy production, and exercise performance", "rawName": "L-carnitine"}],
'lc526': [{"code": "lc526", "qty": "10 x 10mg vials", "price": 200, "desc": "Lipo-C 526 blend; lipotropic compound for metabolic support and fat metabolism", "rawName": "lc526"}],
'lemon bottle': [{"code": "", "qty": "10 x 10mg vials", "price": 110, "desc": "Lipolytic injection blend; fat-dissolving formula for localized fat reduction", "rawName": "lemon bottle"}],
'lipo c': [{"code": "lc120", "qty": "10 x 10mg vials", "price": 110, "desc": "Lipotropic vitamin C injection; antioxidant support, skin brightening, immune health", "rawName": "lipo c"}],
'lipo c with b12': [{"code": "lc216", "qty": "10 x 10mg vials", "price": 110, "desc": "Lipotropic vitamin C with B12; supports energy, metabolism, and immune function", "rawName": "Lipo c with b12"}],
'll37': [{"code": "", "qty": "10 x 5mg vials", "price": 150, "desc": "Cathelicidin antimicrobial peptide; broad-spectrum antimicrobial, immune modulation, wound healing", "rawName": "LL37"}],
'mazdutide': [{"code": "MDT5", "qty": "10 x 5mg vials", "price": 200, "desc": "Dual GLP-1/GCGR agonist; investigational for obesity and type 2 diabetes management", "rawName": "Mazdutide"}, {"code": "MDT10", "qty": "10 x 100mg vials", "price": 360, "desc": "Dual GLP-1/GCGR agonist; investigational for obesity and type 2 diabetes management", "rawName": "Mazdutide"}],
'melanotan 1': [{"code": "MT1", "qty": "10 x 10mg vials", "price": 80, "desc": "Melanotan I; melanocortin receptor agonist for UV-independent skin pigmentation", "rawName": "MT-1"}],
'melanotan ii': [{"code": "ML10", "qty": "10 x 10mg vials", "price": 80, "desc": "Synthetic melanocortin analog; induces tanning, may reduce appetite and increase libido", "rawName": "Melanotan2\uff08121062-08-06\uff09"}],
'mgf (mechano growth factor)': [{"code": "FM2", "qty": "10 x 2mg vials", "price": 80, "desc": "Mechano growth factor; IGF-1 splice variant, supports muscle repair and hypertrophy", "rawName": "MGF"}],
'mots-c': [{"code": "MS10", "qty": "10 x 10mg vials", "price": 110, "desc": "Mitochondrial-derived peptide; improves insulin sensitivity, metabolic homeostasis, and exercise performance", "rawName": "MOTS-C"}, {"code": "MS20", "qty": "10 x 20mg vials", "price": 220, "desc": "Mitochondrial-derived peptide; improves insulin sensitivity, metabolic homeostasis, and exercise performance", "rawName": "MOTS-C"}, {"code": "MS30", "qty": "10 x 30mg vials", "price": 300, "desc": "Mitochondrial-derived peptide; improves insulin sensitivity, metabolic homeostasis, and exercise performance", "rawName": "MOTS-C"}, {"code": "MS40", "qty": "10 x 40mg vials", "price": 380, "desc": "Mitochondrial-derived peptide; improves insulin sensitivity, metabolic homeostasis, and exercise performance", "rawName": "MOTS-C"}],
'nad': [{"code": "NJ100", "qty": "10 x 100mg vials", "price": 80, "desc": "Nicotinamide adenine dinucleotide; essential coenzyme for cellular energy, DNA repair, and longevity", "rawName": "NAD"}, {"code": "NJ500", "qty": "10 x 500mg vials", "price": 140, "desc": "Nicotinamide adenine dinucleotide; essential coenzyme for cellular energy, DNA repair, and longevity", "rawName": "NAD"}, {"code": "NJ1000", "qty": "10 x 1000mg vials", "price": 240, "desc": "Nicotinamide adenine dinucleotide; essential coenzyme for cellular energy, DNA repair, and longevity", "rawName": "NAD"}],
'oxytocin': [{"code": "OT2", "qty": "10 x 2mg vials", "price": 60, "desc": "Neuropeptide hormone; promotes social bonding, trust, lactation, and uterine contractions", "rawName": "Oxytocin Acetate"}, {"code": "OT5", "qty": "10 x 5mg vials", "price": 90, "desc": "Neuropeptide hormone; promotes social bonding, trust, lactation, and uterine contractions", "rawName": "Oxytocin Acetate"}, {"code": "OT10", "qty": "10 x 10mg vials", "price": 150, "desc": "Neuropeptide hormone; promotes social bonding, trust, lactation, and uterine contractions", "rawName": "Oxytocin Acetate"}],
'p21': [{"code": "P21", "qty": "10 x 5mg vials", "price": 300, "desc": "Synthetic peptide; investigational cognitive enhancer and neuroprotective compound", "rawName": "P21"}],
'pe-22-28': [{"code": "", "qty": "10 x 10mg vials", "price": 160, "desc": "Synthetic peptide; investigational nootropic and neuroprotective agent", "rawName": "PE-22-28"}],
'peg mgf': [{"code": "FMP2", "qty": "10 x 2mg vials", "price": 140, "desc": "Pegylated mechano growth factor; promotes muscle growth and recovery after exercise", "rawName": "PEG MGF"}],
'pinealon': [{"code": "PI5", "qty": "10 x 5mg vials", "price": 80, "desc": "Synthetic tripeptide; may support cognitive function, pineal gland regulation, and circadian rhythms", "rawName": "Pinealon"}, {"code": "PI10", "qty": "10 x 10ml vials", "price": 120, "desc": "Synthetic tripeptide; may support cognitive function, pineal gland regulation, and circadian rhythms", "rawName": "Pinealon"}],
'pnc-27': [{"code": "", "qty": "10 x 5mg vials", "price": 200, "desc": "Anticancer peptide; investigational for selective destruction of cancer cells", "rawName": "PNC-27"}],
'pt-141': [{"code": "P41", "qty": "10 x 10mg vials", "price": 110, "desc": "Bremelanotide; melanocortin receptor agonist for treating sexual dysfunction (FDA-approved for HSDD)", "rawName": "PT-141"}],
'retatrutide': [{"code": "RT5", "qty": "10 x 5mg vials", "price": 100, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT10", "qty": "10 x 10mg vials", "price": 140, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT15", "qty": "10 x 15mg vials", "price": 190, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT20", "qty": "10 x 20mg vials", "price": 240, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT30", "qty": "10 x 30mg vials", "price": 320, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT36", "qty": "10 x 36mg vials", "price": 330, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT40", "qty": "10 x 40mg vials", "price": 400, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT50", "qty": "10 x 50mg vials", "price": 460, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}, {"code": "RT60", "qty": "10 x 60mg vials", "price": 520, "desc": "Triple GIP/GLP-1/Glucagon receptor agonist; investigational for obesity and metabolic disease", "rawName": "Retatrutide"}],
'selank': [{"code": "SK5", "qty": "10 x 5mg vials", "price": 90, "desc": "Synthetic heptapeptide; anxiolytic and nootropic, may reduce anxiety and improve cognitive performance", "rawName": "Selank"}, {"code": "SK10", "qty": "10 x 10mg vials", "price": 120, "desc": "Synthetic heptapeptide; anxiolytic and nootropic, may reduce anxiety and improve cognitive performance", "rawName": "Selank"}],
'semaglutide': [{"code": "SM5", "qty": "10 x 5mg vials", "price": 70, "desc": "GLP-1 receptor agonist; FDA-approved for diabetes and obesity (Ozempic/Wegovy)", "rawName": "Semaglutide\uff08SM\uff09"}, {"code": "SM10", "qty": "10 x 10mg vials", "price": 100, "desc": "GLP-1 receptor agonist; FDA-approved for diabetes and obesity (Ozempic/Wegovy)", "rawName": "Semaglutide\uff08SM\uff09"}, {"code": "SM15", "qty": "10 x 15mg vials", "price": 140, "desc": "GLP-1 receptor agonist; FDA-approved for diabetes and obesity (Ozempic/Wegovy)", "rawName": "Semaglutide\uff08SM\uff09"}, {"code": "SM20", "qty": "10 x 20mg vials", "price": 180, "desc": "GLP-1 receptor agonist; FDA-approved for diabetes and obesity (Ozempic/Wegovy)", "rawName": "Semaglutide\uff08SM\uff09"}],
'semax': [{"code": "XA5", "qty": "10 x 5mg vials", "price": 90, "desc": "Synthetic heptapeptide; nootropic and neuroprotective, may improve cognitive function and BDNF levels", "rawName": "Semax"}, {"code": "XA10", "qty": "10 x 10mg vials", "price": 120, "desc": "Synthetic heptapeptide; nootropic and neuroprotective, may improve cognitive function and BDNF levels", "rawName": "Semax"}, {"code": "XA5", "qty": "10 x 5mg vials", "price": 100, "desc": "Synthetic heptapeptide; nootropic and neuroprotective, may improve cognitive function and BDNF levels", "rawName": "Semax"}, {"code": "XA10", "qty": "10 x 10mg vials", "price": 120, "desc": "Synthetic heptapeptide; nootropic and neuroprotective, may improve cognitive function and BDNF levels", "rawName": "Semax"}],
'sermorelin': [{"code": "SMO5", "qty": "10 x 5mg vials", "price": 120, "desc": "GHRH analog; stimulates natural GH production, supports anti-aging and body composition", "rawName": "Sermorelin Acetate"}, {"code": "SMO10", "qty": "10 x 10mg vials", "price": 200, "desc": "GHRH analog; stimulates natural GH production, supports anti-aging and body composition", "rawName": "Sermorelin Acetate"}],
'slu-pp-332': [{"code": "", "qty": "10 x 5mg vials", "price": 280, "desc": "Research peptide; specific function under investigation", "rawName": "slupp332"}],
'snap-8': [{"code": "NP810", "qty": "10 x 10mg vials", "price": 90, "desc": "Acetyl octapeptide-3; topical muscle-relaxing peptide, reduces expression wrinkles", "rawName": "snap-8"}],
'ss-31': [{"code": "2S10", "qty": "10 x 10mg vials", "price": 170, "desc": "Elamipretide; mitochondria-targeting antioxidant, protects mitochondrial function and reduces oxidative stress", "rawName": "SS31"}, {"code": "2S50", "qty": "10 x 50mg vials", "price": 560, "desc": "Elamipretide; mitochondria-targeting antioxidant, protects mitochondrial function and reduces oxidative stress", "rawName": "SS31"}],
'survodutide': [{"code": "SUR10", "qty": "10 x 10mg vials", "price": 520, "desc": "Dual GLP-1/GCGR agonist; investigational for obesity and metabolic disease", "rawName": "survodutide"}],
'tb-500': [{"code": "BT5", "qty": "10 x 5mg vials", "price": 140, "desc": "Thymosin Beta-4 fragment; promotes wound healing, tissue repair, and anti-inflammatory effects", "rawName": "TB500"}, {"code": "BT10", "qty": "10 x 10mg vials", "price": 240, "desc": "Thymosin Beta-4 fragment; promotes wound healing, tissue repair, and anti-inflammatory effects", "rawName": "TB500"}],
'tesamorelin': [{"code": "TSM5", "qty": "10 x 5mg vials", "price": 170, "desc": "GHRH analog; FDA-approved for reducing visceral adiposity in HIV-associated lipodystrophy (Egrifta)", "rawName": "Tesamorelin"}, {"code": "TSM10", "qty": "10 x 10mg vials", "price": 320, "desc": "GHRH analog; FDA-approved for reducing visceral adiposity in HIV-associated lipodystrophy (Egrifta)", "rawName": "Tesamorelin"}, {"code": "TSM15", "qty": "10 x 15mg vials", "price": 440, "desc": "GHRH analog; FDA-approved for reducing visceral adiposity in HIV-associated lipodystrophy (Egrifta)", "rawName": "Tesamorelin"}, {"code": "TSM20", "qty": "10 x 20mg vials", "price": 530, "desc": "GHRH analog; FDA-approved for reducing visceral adiposity in HIV-associated lipodystrophy (Egrifta)", "rawName": "Tesamorelin"}],
'thyamlin / thymogen': [{"code": "TY10", "qty": "10 x 10mg vials", "price": 120, "desc": "Thymus-derived peptide; supports immune system regulation and T-cell maturation", "rawName": "thymalin"}],
'thymosin-alpha 1': [{"code": "TA5", "qty": "10 x 5mg vials", "price": 160, "desc": "Immune-modulating peptide; enhances T-cell function, used as vaccine adjuvant and in immune disorders", "rawName": "Thymosin Alpha-1"}, {"code": "TA10", "qty": "10 x 10mg vials", "price": 290, "desc": "Immune-modulating peptide; enhances T-cell function, used as vaccine adjuvant and in immune disorders", "rawName": "Thymosin Alpha-1"}],
'tirzepatide': [{"code": "TR5", "qty": "10 x 5mg vials", "price": 80, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR10", "qty": "10 x 10mg vials", "price": 110, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR15", "qty": "10 x 15mg vials", "price": 130, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR20", "qty": "10 x 20mg vials", "price": 150, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR30", "qty": "10 x 30mg vials", "price": 170, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR40", "qty": "10 x 40mg vials", "price": 200, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR50", "qty": "10 x 50mg vials", "price": 270, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR60", "qty": "10 x 60mg vials", "price": 320, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}, {"code": "TR100", "qty": "10 x 100mg vials", "price": 420, "desc": "Dual GIP/GLP-1 receptor agonist; FDA-approved for type 2 diabetes and weight management (Mounjaro/Zepbound)", "rawName": "Tirzepatide"}],
'vip': [{"code": "VP5", "qty": "10 x 5mg vials", "price": 150, "desc": "Neuropeptide; regulates immune response, vasodilation, and GI function", "rawName": "Vasoactive Intestinal Peptide (VIP)"}, {"code": "VP10", "qty": "10 x 10mg vials", "price": 240, "desc": "Neuropeptide; regulates immune response, vasodilation, and GI function", "rawName": "Vasoactive Intestinal Peptide (VIP)"}],
};
const SHOP_CATS = {
fat: ['tirzepatide','semaglutide','retatrutide','cagrilintide','aod','mots-c','mazdutide','survodutide','adipotide','5-amino-1mq','lipo','lc526'],
heal: ['bpc','tb500','tb-500','ghk','kpv','klow','glow','ara-290','dermorphin'],
cog: ['semax','selank','dihexa','adamax','cerebrolysin','pe-22-28','p21','pnc-27','pinealon'],
horm: ['sermorelin','cjc','ghrp','hgh','hcg','hmg','ipamorelin','tesamorelin','hexarelin','kisspeptin'],
long: ['epithalon','nad','ss31','foxo4','thymalin','thyamlin'],
musc: ['igf','mgf','peg mgf','aicar','l-carnitine'],
imm: ['thymosin','thymalin','ll37','vip','vasoactive','kpv','crystagen','epo'],
sex: ['melanotan','pt-141','oxytocin','kisspeptin','botulinum'],
};
function normKey(n) { return n.toLowerCase().replace(/[(())[\]]/g,'').replace(/\s+/g,' ').trim(); }
function slug(s) { return s.replace(/[^a-z0-9]/g,''); }
const PRICE_ALIAS = {
'epitalon':'epithalon','nad+':'nad',
'ghk-cu':'ghk-cu','ss-31':'ss-31','igf-1 lr3':'igf-1 lr3',
'semax / na semax amidate':'semax','selank / na selank amidate':'selank',
'tb-500':'tb-500','vip':'vip','ll-37':'ll37','ll37':'ll37',
'hgh 191aa':'hgh 191aa','peg mgf':'peg mgf','slu-pp-332':'slu-pp-332','ara-290':'ara-290',
'cjc-1295 no dac':'cjc-1295 no dac','cjc-1295 dac':'cjc-1295 dac',
'thyamlin / thymogen':'thyamlin / thymogen','thymosin-alpha 1':'thymosin-alpha 1',
'bpc-157 / tb-500 blend':'bpc-157 / tb-500 blend',
'glow blend ghk-cu bpc-157 tb-500':'glow blend (ghk-cu, bpc-157, tb-500)',
'klow blend ghk-cu bpc-157 tb-500 kpv':'klow blend (ghk-cu, bpc-157, tb-500, kpv)',
'cagrisema cagrilintide + semaglutide':'cagrisema (cagrilintide + semaglutide)',
'mgf mechano growth factor':'mgf (mechano growth factor)',
};
function findVariants(name) {
const key = normKey(name);
if (PRICE_ALIAS[key] && PRICES[PRICE_ALIAS[key]]) return PRICES[PRICE_ALIAS[key]];
if (PRICES[key]) return PRICES[key];
const ks = slug(key);
for (const [k,v] of Object.entries(PRICES)) { if (slug(k) === ks) return v; }
for (const [k,v] of Object.entries(PRICES)) { const s=slug(k); if (s.length >= 4 && (ks.startsWith(s) || s.startsWith(ks))) return v; }
const fw = key.split(' ')[0].replace(/[^a-z0-9]/g,'');
if (fw.length >= 4) { for (const [k,v] of Object.entries(PRICES)) { const s=slug(k); if (s===fw||s.startsWith(fw)) return v; } }
return null;
}
function buildPricePanel(r) {
const variants = findVariants(r.name);
if (!variants || !variants.length) return '
💰 Pricing Not in current price list
';
const dn = (variants[0].rawName || r.name).replace(/\\/g,'\\\\').replace(/`/g,'\\`').replace(/\$/g,'\\$');
const vh = variants.map(v => {
const ic = cart.some(c => c.code === v.code);
const sq = v.qty.replace(/`/g,'\\`');
return `
$${v.price}
${ic?'✓ Added':'+ Cart'}
`;
}).join('');
return `
💰 Pricing — per pack of 10 vials (AUD) ${vh}
`;
}
// ─── CART ─────────────────────────────────────────────────────────────────────
function addToCart(code, name, qty, price) {
const idx = cart.findIndex(i => i.code === code);
if (idx >= 0) { cart[idx].count = (cart[idx].count||1)+1; } else { cart.push({code,name,qty,price,count:1}); }
updateCartUI();
refreshPlannerPicker();
document.querySelectorAll('[data-cart-code="' + code + '"]').forEach(b => { b.textContent='✓ Added'; b.classList.add('added'); setTimeout(()=>{b.textContent='+ Cart';b.classList.remove('added');},1200); });
document.querySelectorAll('[data-cart-variant="' + code + '"]').forEach(el => el.classList.add('in-cart'));
}
function removeFromCart(code) {
cart = cart.filter(i => i.code !== code); updateCartUI();
refreshPlannerPicker();
document.querySelectorAll('[data-cart-variant="' + code + '"]').forEach(el => el.classList.remove('in-cart'));
}
function clearCart() {
cart = []; updateCartUI();
document.querySelectorAll('.in-cart').forEach(el => el.classList.remove('in-cart'));
closeOverlay('cartOverlay');
}
function cartTotal() { return cart.reduce((s,i) => s+i.price*(i.count||1), 0); }
function cartCount() { return cart.reduce((s,i) => s+(i.count||1), 0); }
function updateCartUI() {
const total=cartTotal()+SHIPPING_FLAT, subtotal=cartTotal(), count=cartCount();
const bar=document.getElementById('cartBar');
if (bar) bar.className = count > 0 ? 'show' : '';
const tb=document.getElementById('cartTotalBar'); if(tb) tb.textContent='$'+total;
const ci=document.getElementById('cartItemCount'); if(ci) ci.textContent=count+' item'+(count!==1?'s':'');
updateFloatBadge();
renderCartModal();
}
function renderCartModal() {
const list = document.getElementById('cartList');
const summary = document.getElementById('cartSummary');
if (!list) return;
if (!cart.length) {
list.innerHTML = '
Your order is empty. Browse the 🛒 Shop tab.
';
if (summary) summary.innerHTML = ''; return;
}
list.innerHTML = cart.map(item => `
${item.name}
${item.qty}
${item.code}${item.count>1?' × '+item.count:''}
$${item.price*(item.count||1)}
✕
`).join('');
const subtotal = cartTotal(), total = subtotal + SHIPPING_FLAT, count = cartCount();
if (summary) summary.innerHTML = `
${count} item${count!==1?'s':''} $${total}
Total (AUD) $${total}
Per pack of 10 vials. Reference order — confirm with supplier.
`;
}
// ─── SHOP ─────────────────────────────────────────────────────────────────────
function renderShop() {
const q = (document.getElementById('shopSearch')?.value||'').toLowerCase();
const cat = document.getElementById('shopCat')?.value||'';
const sort= document.getElementById('shopSort')?.value||'name';
const grid= document.getElementById('priceGrid');
if (!grid) return;
let entries = Object.entries(PRICES);
if (q) entries = entries.filter(([name,variants]) => name.includes(q) || variants.some(v => v.code.toLowerCase().includes(q) || v.qty.toLowerCase().includes(q)));
if (cat && SHOP_CATS[cat]) { const kws=SHOP_CATS[cat]; entries=entries.filter(([name])=>kws.some(kw=>name.toLowerCase().includes(kw))); }
if (sort==='name') entries.sort((a,b)=>a[0].localeCompare(b[0]));
else entries.sort((a,b)=>{ const am=Math.min(...a[1].map(v=>v.price)),bm=Math.min(...b[1].map(v=>v.price)); return sort==='price-asc'?am-bm:bm-am; });
if (!entries.length) { grid.innerHTML='
🛒 No products match
'; return; }
grid.innerHTML = entries.map(([name,variants]) => {
const dn = (variants[0]?.rawName||name).replace(/`/g,'\\`').replace(/\$/g,'\\$');
const desc = variants[0]?.desc||'';
const vh = variants.map(v => {
const ic = cart.some(c => c.code === v.code);
const sq = v.qty.replace(/`/g,'\\`');
return `
$${v.price}
${ic?'✓ Added':'+ Cart'}
`;
}).join('');
return `
`;
}).join('');
}
// ─── STANDALONE CALC ─────────────────────────────────────────────────────────
function runCalc() {
const p=parseFloat(document.getElementById('cP').value),pu=document.getElementById('cPU').value;
const w=parseFloat(document.getElementById('cW').value);
const d=parseFloat(document.getElementById('cD').value),du=document.getElementById('cDU').value;
if(isNaN(p)||isNaN(w)||isNaN(d)||w<=0||d<=0){alert('Fill in all fields.');return;}
const res=calcDose(p,pu,w,d,du);
const fu=res.volMl*100;
document.getElementById('rConc').textContent=fmtConc(res.concVal,res.concUnit);
document.getElementById('rVol').textContent=isFinite(res.volMl)?res.volMl.toFixed(3)+' ml':'—';
document.getElementById('rU').textContent=isFinite(fu)?fu.toFixed(1)+' units':'—';
document.getElementById('rD').textContent=res.dosesInVial>0?res.dosesInVial:'—';
document.getElementById('calcResult').classList.add('show');
}
function resetCalc(){['cP','cW','cD'].forEach(id=>document.getElementById(id).value='');document.getElementById('calcResult').classList.remove('show');}
// ─── PLANNER ─────────────────────────────────────────────────────────────────
function setFreqMode(mode) {
plannerFreqMode = mode;
document.getElementById('fmode-days').classList.toggle('active', mode==='days');
document.getElementById('fmode-every').classList.toggle('active', mode==='every');
document.getElementById('freq-days-row').style.display = mode==='days' ? 'flex' : 'none';
document.getElementById('freq-every-row').style.display = mode==='every' ? 'flex' : 'none';
plannerCalc();
}
function setPlanMode(mode) {
plannerPlanMode = mode;
document.getElementById('plan-mode-supply').classList.toggle('active', mode==='supply');
document.getElementById('plan-mode-duration').classList.toggle('active', mode==='duration');
document.getElementById('supplyModeInputs').style.display = mode==='supply' ? 'block' : 'none';
document.getElementById('durationModeInputs').style.display = mode==='duration' ? 'block' : 'none';
plannerCalc();
}
function setPlannerSyr(el, cap) {
document.querySelectorAll('.syr-choice-btn').forEach(b => b.classList.remove('active'));
el.classList.add('active'); plannerSyrCap = cap; plannerCalc();
}
function plannerToggleIU() {
const vu=document.getElementById('my-vial-unit')?.value;
const du=document.getElementById('my-dose-unit')?.value;
const row=document.getElementById('iuToggleRow');
if (row) row.style.display = (vu==='iu'||du==='iu') ? 'flex' : 'none';
}
function toggleIUConv() {
const row=document.getElementById('iuConvRow');
const btn=document.getElementById('iuConvBtn');
const show=row.classList.contains('show');
row.classList.toggle('show',!show); btn.classList.toggle('active',!show);
btn.textContent = show ? '+ Conv. Rate' : '− Conv. Rate';
}
function getInjectionsPerWeek() {
if (plannerFreqMode==='days') {
const d=parseFloat(document.getElementById('my-freq-days')?.value);
return isNaN(d) ? null : Math.min(7,Math.max(1,d));
} else {
const e=parseFloat(document.getElementById('my-freq-every')?.value);
return isNaN(e)||e<=0 ? null : 7/e;
}
}
// ─── SAVE PROTOCOL FROM PLANNER ──────────────────────────────────────────────
function saveCurrentProtocol() {
const sel = document.getElementById('plannerCompound');
if (!sel || sel.value === '') {
alert('Please select a compound first.');
return;
}
const r = D[parseInt(sel.value)];
saveProtocol(r.name);
// Update status
const status = document.getElementById('saveProtocolStatus');
if (status) status.textContent = '✓ ' + r.name + ' saved';
}
function saveProtocol(compoundName) {
if (!compoundName) return;
protocolStore[compoundName] = {
vialAmt: parseFloat(document.getElementById('my-vial')?.value) || null,
vialUnit: document.getElementById('my-vial-unit')?.value || 'mg',
bacMl: parseFloat(document.getElementById('my-bac')?.value) || null,
doseAmt: parseFloat(document.getElementById('my-dose')?.value) || null,
doseUnit: document.getElementById('my-dose-unit')?.value || 'mcg',
timing: document.getElementById('my-timing')?.value || '',
freqMode: plannerFreqMode,
freqDays: parseFloat(document.getElementById('my-freq-days')?.value) || null,
freqEvery: parseFloat(document.getElementById('my-freq-every')?.value) || null,
duration: '', // filled from compound data
savedAt: Date.now(),
};
// Visual feedback
refreshPlannerPicker();
const btn = document.getElementById('saveProtocolBtn');
if (btn) { btn.textContent = '✓ Saved'; btn.style.background = 'var(--accent)'; btn.style.color = '#000';
setTimeout(() => { btn.textContent = 'Save Protocol'; btn.style.background = ''; btn.style.color = ''; }, 1500); }
}
function isProtocolComplete(name) {
const p = protocolStore[name];
if (!p) return false;
return p.vialAmt > 0 && p.bacMl > 0 && p.doseAmt > 0;
}
function getProtocolSummary(name) {
const p = protocolStore[name];
if (!p) return null;
// Format frequency string
let freqStr = '';
if (p.freqMode === 'days' && p.freqDays) freqStr = p.freqDays + ' days/week';
else if (p.freqMode === 'every' && p.freqEvery) freqStr = 'every ' + p.freqEvery + ' days';
// Calculate syringe fill
let syringeInfo = '—';
if (p.vialAmt && p.bacMl && p.doseAmt) {
const vb = p.vialUnit === 'mg' ? p.vialAmt * 1000 : p.vialAmt;
const db = p.doseUnit === 'mg' ? p.doseAmt * 1000 : p.doseAmt;
const conc = vb / p.bacMl;
const vol = db / conc;
const units = vol * 100;
if (isFinite(vol) && vol > 0) syringeInfo = vol.toFixed(3) + ' ml = ' + units.toFixed(1) + ' units (U-100)';
}
return { ...p, freqStr, syringeInfo };
}
function initPlannerPicker() {
refreshPlannerPicker();
}
function refreshPlannerPicker() {
const sel = document.getElementById('plannerCompound');
if (!sel) return;
// Save current selection
const currentVal = sel.value;
// Clear existing options except the first
while (sel.options.length > 1) sel.remove(1);
if (!cart.length) {
const o = document.createElement('option');
o.value = ''; o.textContent = '— Add compounds to cart first —'; o.disabled = true;
sel.appendChild(o);
return;
}
// Only show compounds that are in the cart
const cartNames = cart.map(i => i.name.toLowerCase());
const cartCompounds = D.filter(r => cartNames.includes(r.name.toLowerCase()));
cartCompounds.sort((a,b) => a.name.localeCompare(b.name));
cartCompounds.forEach(r => {
const o = document.createElement('option');
o.value = D.indexOf(r);
// Show save status
const saved = isProtocolComplete(r.name);
o.textContent = (saved ? '✓ ' : '◦ ') + r.name;
sel.appendChild(o);
});
// Restore selection if still valid
if (currentVal && [...sel.options].some(o => o.value === currentVal)) {
sel.value = currentVal;
}
}
function plannerLoadCompound() {
const idx=document.getElementById('plannerCompound').value;
if (idx==='') {
['rec-vial','rec-bac','rec-dose','rec-timing','rec-freq','rec-dur'].forEach(id=>{
const el=document.getElementById(id); if(el) el.textContent='—';
});
plannerCalc(); return;
}
const r=D[parseInt(idx)];
const set=(id,val)=>{ const el=document.getElementById(id); if(el) el.textContent=val; };
set('rec-vial',r.vial); set('rec-bac',r.bac); set('rec-dose',r.dose);
set('rec-timing',r.timing); set('rec-freq',r.frequency); set('rec-dur',r.duration);
const di=parseDoseStr(r.dose), bml=parseBacStr(r.bac), vi=parseDoseStr(r.vial);
const inp=(id,val)=>{ const el=document.getElementById(id); if(el) el.value=val; };
const sel=(id,val)=>{ const el=document.getElementById(id); if(el) el.value=val; };
if (vi) { inp('my-vial',vi.val); sel('my-vial-unit',vi.unit); }
if (bml) inp('my-bac',bml);
if (di) { inp('my-dose',di.val); sel('my-dose-unit',di.unit); }
inp('my-timing',r.timing);
const freq=r.frequency.toLowerCase();
if (freq.includes('every day')||freq.includes('daily')) { setFreqMode('days'); inp('my-freq-days',7); }
else if (freq.match(/5\s*days/)) { setFreqMode('days'); inp('my-freq-days',5); }
else if (freq.match(/3[x\s]*(?:per\s*)?week/)) { setFreqMode('days'); inp('my-freq-days',3); }
else if (freq.match(/2[x\s]*(?:per\s*)?week/)) { setFreqMode('days'); inp('my-freq-days',2); }
else if (freq.includes('once')||freq.match(/1[x\s]*(?:per\s*)?week/)) { setFreqMode('days'); inp('my-freq-days',1); }
else if (freq.includes('every other')) { setFreqMode('every'); inp('my-freq-every',2); }
else { setFreqMode('days'); inp('my-freq-days',5); }
plannerToggleIU(); plannerCalc();
}
function plannerCalc() {
const vAmt=parseFloat(document.getElementById('my-vial')?.value);
const vUnit=document.getElementById('my-vial-unit')?.value||'mg';
const bac=parseFloat(document.getElementById('my-bac')?.value);
const dAmt=parseFloat(document.getElementById('my-dose')?.value);
const dUnit=document.getElementById('my-dose-unit')?.value||'mcg';
const conv=parseFloat(document.getElementById('iuConvRate')?.value)||0;
const inj=getInjectionsPerWeek();
const svgEl=document.getElementById('plannerSyrSVG');
const maxMl=maxMlForCap(plannerSyrCap);
const setText=(id,v)=>{ const el=document.getElementById(id); if(el) el.textContent=v; };
const setPull=(pull,sub,ml)=>{
const pe=document.getElementById('fillPull'),se=document.getElementById('fillSub'),me=document.getElementById('fillMlLabel');
if(pe){pe.textContent=pull;pe.style.color='var(--accent2)';}
if(se) se.textContent=sub;
if(me) me.textContent=ml||'';
};
if (!isNaN(vAmt)&&!isNaN(bac)&&!isNaN(dAmt)&&bac>0&&dAmt>0&&vAmt>0) {
let vBase,dBase;
if (vUnit==='iu'&&dUnit==='iu') { vBase=vAmt; dBase=dAmt; }
else if (vUnit==='iu'&&conv>0) { vBase=vAmt*(1000/conv); dBase=toBase(dAmt,dUnit); }
else if (dUnit==='iu'&&conv>0) { vBase=toBase(vAmt,vUnit); dBase=dAmt*(1000/conv); }
else { vBase=toBase(vAmt,vUnit); dBase=toBase(dAmt,dUnit); }
const conc=vBase/bac, vol=dBase/conc, fu=vol*plannerSyrCap;
const dosesPerVial=vBase/dBase;
if (svgEl) drawSyringe(svgEl,isFinite(vol)?vol:0,maxMl,plannerSyrCap);
if (isFinite(fu)&&fu>0) {
if (vol>maxMl) { setPull('⚠ OVER','Exceeds syringe — split or use larger',''); if(document.getElementById('fillPull')) document.getElementById('fillPull').style.color='#ff6b6b'; }
else { setPull('Pull to '+fu.toFixed(1)+' units','on your '+(plannerSyrCap===100?'U-100':plannerSyrCap===50?'U-50':'U-30')+' syringe',vol.toFixed(3)+' ml per injection'); }
} else { setPull('—','Enter vial + dose above',''); }
setText('planDosesPerVial',isFinite(dosesPerVial)?Math.floor(dosesPerVial):'—');
if (inj&&isFinite(dosesPerVial)) {
setText('planInjectionsPerWeek',inj%1===0?inj.toString():inj.toFixed(1));
if (plannerPlanMode==='supply') {
const vials=parseFloat(document.getElementById('plan-vials')?.value)||10;
const totalD=dosesPerVial*vials, totalDays=totalD/(inj/7);
const wks=totalDays/7, mths=totalDays/30.44;
let durStr,durLabel,durSub;
if(wks<4){durStr=wks.toFixed(1);durLabel='weeks';durSub='('+Math.round(totalDays)+' days)';}
else if(mths<12){durStr=mths.toFixed(1);durLabel='months';durSub='('+Math.round(wks)+' weeks)';}
else{durStr=(mths/12).toFixed(1);durLabel='years';durSub='('+Math.round(mths)+' months)';}
setText('planHighlightVal',durStr);
setText('planHighlightLabel',vials+' vial'+(vials!==1?'s':'')+' will last '+durLabel);
setText('planHighlightSub',durSub);
setText('planTotalInjections',Math.floor(totalD).toString());
const tp=dBase*Math.floor(totalD);
const tpStr=vUnit==='iu'||dUnit==='iu'?tp.toFixed(0)+' IU':tp>=1000?(tp/1000).toFixed(2)+' mg':tp.toFixed(0)+' mcg';
setText('planTotalPeptide',tpStr);
const daysPerVial=dosesPerVial/(inj/7), wksPerVial=daysPerVial/7;
const bd=document.getElementById('planBreakdown');
if(bd) bd.innerHTML='
'+Math.floor(dosesPerVial)+' doses per vial
'+
'
'+wksPerVial.toFixed(1)+' weeks per vial ('+Math.round(daysPerVial)+' days)
'+
'
'+Math.floor(totalD)+' total injections from '+vials+' vials
'+
'At
'+inj.toFixed(1)+' injections/week ';
} else {
const durVal=parseFloat(document.getElementById('plan-weeks')?.value)||0;
const durUnit=document.getElementById('plan-weeks-unit')?.value||'weeks';
let dd=durUnit==='weeks'?durVal*7:durUnit==='months'?durVal*30.44:durVal;
if(dd>0){
const ti=(inj/7)*dd, vn=Math.ceil(ti/dosesPerVial);
const tp=dBase*Math.ceil(ti);
const tpStr=vUnit==='iu'||dUnit==='iu'?tp.toFixed(0)+' IU':tp>=1000?(tp/1000).toFixed(2)+' mg':tp.toFixed(0)+' mcg';
setText('planHighlightVal',vn.toString());
setText('planHighlightLabel','vials needed for your cycle');
setText('planHighlightSub',durVal+' '+durUnit+' · '+Math.ceil(ti)+' injections');
setText('planTotalInjections',Math.ceil(ti).toString());
setText('planTotalPeptide',tpStr);
const bd=document.getElementById('planBreakdown');
if(bd) bd.innerHTML='Cycle:
'+durVal+' '+durUnit+' ('+Math.round(dd)+' days)
'+
'Total injections:
'+Math.ceil(ti)+' '+
'Vials required:
'+vn+' '+
'Total peptide:
'+tpStr+' ';
}
}
}
} else {
if(svgEl) drawSyringe(svgEl,0,maxMl,plannerSyrCap);
setPull('—','Select a compound or enter values above','');
['planDosesPerVial','planInjectionsPerWeek','planTotalInjections','planTotalPeptide'].forEach(id=>setText(id,'—'));
setText('planHighlightVal','—'); setText('planHighlightLabel','Enter dose and frequency'); setText('planHighlightSub','');
const bd=document.getElementById('planBreakdown'); if(bd) bd.textContent='Enter dose and frequency to see breakdown.';
}
}
// ─── INIT ─────────────────────────────────────────────────────────────────────
function init() {
// Populate purpose dropdown
const purposes = [...new Set(D.map(r => r.purpose))].sort();
const sel = document.getElementById('fPurpose');
if (sel) purposes.forEach(p => { const o=document.createElement('option'); o.value=p; o.textContent=p; sel.appendChild(o); });
// Stats
const st=document.getElementById('statTotal'); if(st) st.textContent=D.length;
const sn=document.getElementById('statNew'); if(sn) sn.textContent=D.filter(r=>r.src==='peptidedosages').length;
const sns=document.getElementById('statNasal'); if(sns) sns.textContent=D.filter(r=>r.nasal).length;
// Events — main table
const searchEl=document.getElementById('search'); if(searchEl) searchEl.addEventListener('input', renderTable);
const fpEl=document.getElementById('fPurpose'); if(fpEl) fpEl.addEventListener('change', renderTable);
const ftEl=document.getElementById('fTiming'); if(ftEl) ftEl.addEventListener('change', renderTable);
// Events — shop
const ss=document.getElementById('shopSearch'); if(ss) ss.addEventListener('input',renderShop);
const sc=document.getElementById('shopCat'); if(sc) sc.addEventListener('change',renderShop);
const so=document.getElementById('shopSort'); if(so) so.addEventListener('change',renderShop);
// Events — planner
['plan-vials','plan-weeks','my-vial','my-bac','my-dose','my-timing','my-freq-days','my-freq-every','iuConvRate'].forEach(id => {
const el=document.getElementById(id); if(el) el.addEventListener('input',plannerCalc);
});
['my-vial-unit','my-dose-unit','plan-weeks-unit'].forEach(id => {
const el=document.getElementById(id); if(el) el.addEventListener('change',()=>{plannerToggleIU();plannerCalc();});
});
initPlannerPicker();
initMainSyringe();
renderTable();
}
// ── FLOATING PILLS + PDF ──
// ─── FLOATING PILLS ──────────────────────────────────────────────────────────
function setTabByName(name) {
const el = document.querySelector('.tab[data-tab="' + name + '"]');
if (el) setTab(el);
// Scroll tab into view
if (el) el.scrollIntoView({behavior:'smooth', block:'nearest', inline:'center'});
}
// Update cart badge on floating pill
function updateFloatBadge() {
const count = cartCount();
const badge = document.getElementById('floatCartCount');
if (!badge) return;
if (count > 0) {
badge.textContent = count;
badge.style.display = 'inline-block';
} else {
badge.style.display = 'none';
}
}
const SHIPPING_FLAT = 50;
// ─── PDF REPORT ───────────────────────────────────────────────────────────────
function openPDFReport() {
if (!cart.length) { alert('Add compounds to your cart first.'); return; }
// Check which cart items have saved protocols
const missing = cart.filter(item => !isProtocolComplete(item.name)).map(item => item.name);
if (missing.length > 0) {
const msg = 'Please complete and save your protocol for:\n\n• ' + missing.join('\n• ') + '\n\nGo to the 📋 Planner tab, select each compound, adjust values and tap Save Protocol.';
alert(msg);
// Switch to planner
setTabByName('planner');
return;
}
renderPDFPreview();
openOverlay('pdfOverlay');
}
function renderPDFPreview() {
const preview = document.getElementById('pdfPreview');
if (!preview) return;
const subtotal = cartTotal();
const total = subtotal + SHIPPING_FLAT;
let rows = cart.map(item => {
const p = protocolStore[item.name];
const complete = isProtocolComplete(item.name);
const doseStr = p ? p.doseAmt + ' ' + p.doseUnit : '—';
const freqStr = p ? p.freqStr : '—';
const statusIcon = complete ? '✓' : '⚠';
const statusColor = complete ? 'var(--accent)' : '#ff9900';
return `
${statusIcon} ${item.name}
${complete ? doseStr + ' · ' + freqStr : 'Protocol not saved — go to Planner tab '}
$${item.price * (item.count || 1)}
`;
}).join('');
rows += `
🚚 Flat rate shipping $${SHIPPING_FLAT}
`;
rows += `
Total (AUD) $${total}
`;
preview.innerHTML = rows;
}
function generatePDF() {
const { jsPDF } = window.jspdf;
if (!jsPDF) { alert('PDF library not loaded. Check your internet connection.'); return; }
const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
const pageW = doc.internal.pageSize.getWidth();
const pageH = doc.internal.pageSize.getHeight();
const margin = 18;
const gold = [245, 200, 0];
const dark = [10, 10, 20];
const mid = [30, 30, 50];
const light= [240, 240, 248];
const purple = [124, 106, 255];
// ── HEADER ──
doc.setFillColor(...dark);
doc.rect(0, 0, pageW, 38, 'F');
// Gold accent bar
doc.setFillColor(...gold);
doc.rect(0, 0, 4, 38, 'F');
doc.setTextColor(...gold);
doc.setFont('helvetica', 'bold');
doc.setFontSize(22);
doc.text("HUTTO'S PEPTIDE RESOURCE", margin + 2, 16);
doc.setFont('helvetica', 'normal');
doc.setFontSize(9);
doc.setTextColor(180, 170, 120);
doc.text('Protocol Report · For research & educational use only', margin + 2, 24);
const dateStr = new Date().toLocaleDateString('en-AU', { day:'numeric', month:'long', year:'numeric' });
doc.text('Generated: ' + dateStr, margin + 2, 31);
// ── DISCLAIMER ──
doc.setFillColor(25, 20, 5);
doc.rect(0, 38, pageW, 12, 'F');
doc.setTextColor(180, 160, 80);
doc.setFontSize(7.5);
doc.setFont('helvetica', 'italic');
doc.text('⚠ This report is for educational reference only. Not medical advice. Consult a qualified practitioner before starting any peptide protocol.', margin, 45, { maxWidth: pageW - margin * 2 });
let y = 58;
// ── COMPOUND TABLE ──
doc.setFont('helvetica', 'bold');
doc.setFontSize(12);
doc.setTextColor(...dark);
doc.text('Selected Compounds', margin, y);
y += 6;
// Build table data
const tableHead = [['Compound', 'Vial', 'BAC Water', 'Dose', 'Timing', 'Frequency', 'Duration', 'Price']];
const tableBody = cart.map(item => {
const c = D.find(d => d.name.toLowerCase() === item.name.toLowerCase()) ||
D.find(d => findVariants && findVariants(d.name) && findVariants(d.name).some(v => v.code === item.code));
const p = protocolStore[item.name]; // user's saved protocol
// Use saved protocol values where available, fall back to compound defaults
const vialDisplay = p ? p.vialAmt + ' ' + p.vialUnit : (c ? c.vial : item.qty);
const bacDisplay = p ? p.bacMl + ' ml' : (c ? c.bac : '—');
const doseDisplay = p ? p.doseAmt + ' ' + p.doseUnit : (c ? c.dose : '—');
const timingDisplay = p ? (p.timing || (c ? c.timing : '—')) : (c ? c.timing : '—');
const freqDisplay = p ? (p.freqStr || (c ? c.frequency : '—')) : (c ? c.frequency : '—');
const durDisplay = c ? c.duration : '—';
return [
item.name,
vialDisplay,
bacDisplay,
doseDisplay,
timingDisplay,
freqDisplay,
durDisplay,
'$' + (item.price * (item.count || 1))
];
});
doc.autoTable({
startY: y,
head: tableHead,
body: tableBody,
margin: { left: margin, right: margin },
headStyles: {
fillColor: dark,
textColor: gold,
fontStyle: 'bold',
fontSize: 8,
cellPadding: 4,
},
bodyStyles: {
fontSize: 7.5,
cellPadding: 3.5,
textColor: [30, 30, 50],
},
alternateRowStyles: { fillColor: [248, 247, 255] },
columnStyles: {
0: { fontStyle: 'bold', cellWidth: 32 },
1: { cellWidth: 18 },
2: { cellWidth: 18 },
3: { cellWidth: 20 },
4: { cellWidth: 18 },
5: { cellWidth: 32 },
6: { cellWidth: 28 },
7: { cellWidth: 16, halign: 'right', fontStyle: 'bold' },
},
didDrawPage: (data) => {
// Footer on each page
doc.setFontSize(7);
doc.setTextColor(160, 155, 130);
doc.setFont('helvetica', 'normal');
doc.text("Hutto's Peptide Resource · Research use only · Not medical advice", margin, pageH - 8);
doc.text('Page ' + data.pageNumber, pageW - margin, pageH - 8, { align: 'right' });
}
});
y = doc.lastAutoTable.finalY + 10;
// ── PROTOCOL NOTES TABLE ──
if (y < pageH - 60) {
doc.setFont('helvetica', 'bold');
doc.setFontSize(12);
doc.setTextColor(...dark);
doc.text('Protocol Notes', margin, y);
y += 6;
const notesHead = [['Compound', 'Syringe Fill (U-100)', 'Nasal Route', 'Notes']];
const notesBody = cart.map(item => {
const c = D.find(d => d.name.toLowerCase() === item.name.toLowerCase()) ||
D.find(d => findVariants && findVariants(d.name) && findVariants(d.name).some(v => v.code === item.code));
const p = protocolStore[item.name];
// Use user's saved protocol for syringe calc if available
let syringeInfo = p ? p.syringeInfo : '—';
if (!syringeInfo || syringeInfo === '—') {
if (c) {
const di = parseDoseStr(c.dose), bml = parseBacStr(c.bac), vi = parseDoseStr(c.vial);
if (di && bml && vi) {
const pb = di.unit === 'mg' ? di.val * 1000 : di.val;
const vb = vi.unit === 'mg' ? vi.val * 1000 : vi.val;
const conc = vb / bml;
const vol = pb / conc;
const units= vol * 100;
if (isFinite(units)) syringeInfo = vol.toFixed(3) + ' ml = ' + units.toFixed(1) + ' units';
}
}
}
return [
item.name,
syringeInfo,
c && c.nasal ? (c.nasalDose || '✓ available') : 'Sub-Q only',
c && c.note ? c.note.substring(0, 80) + (c.note.length > 80 ? '…' : '') : '—',
];
});
doc.autoTable({
startY: y,
head: notesHead,
body: notesBody,
margin: { left: margin, right: margin },
headStyles: {
fillColor: [12, 10, 30],
textColor: [180, 160, 255],
fontStyle: 'bold',
fontSize: 8,
cellPadding: 4,
},
bodyStyles: { fontSize: 7.5, cellPadding: 3.5, textColor: [30, 30, 50] },
alternateRowStyles: { fillColor: [248, 248, 255] },
columnStyles: {
0: { fontStyle: 'bold', cellWidth: 32 },
1: { cellWidth: 36 },
2: { cellWidth: 24 },
3: { cellWidth: 'auto' },
},
});
y = doc.lastAutoTable.finalY + 10;
}
// ── ORDER SUMMARY ──
if (y > pageH - 55) { doc.addPage(); y = 20; }
const subtotal = cartTotal();
const total = subtotal + SHIPPING_FLAT;
const boxW = 90;
const boxX = pageW - margin - boxW;
doc.setFillColor(...dark);
doc.roundedRect(boxX, y, boxW, 44, 3, 3, 'F');
doc.setFillColor(...gold);
doc.roundedRect(boxX, y, 3, 44, 1.5, 1.5, 'F');
doc.setFont('helvetica', 'bold');
doc.setFontSize(10);
doc.setTextColor(...gold);
doc.text('ORDER SUMMARY', boxX + 8, y + 10);
doc.setFont('helvetica', 'normal');
doc.setFontSize(9);
doc.setTextColor(200, 195, 160);
doc.text('Subtotal (' + cartCount() + ' items)', boxX + 8, y + 20);
doc.text('$' + subtotal, boxX + boxW - 6, y + 20, { align: 'right' });
doc.text('Flat rate shipping', boxX + 8, y + 28);
doc.text('$' + SHIPPING_FLAT, boxX + boxW - 6, y + 28, { align: 'right' });
doc.setDrawColor(...gold);
doc.setLineWidth(0.4);
doc.line(boxX + 6, y + 32, boxX + boxW - 6, y + 32);
doc.setFont('helvetica', 'bold');
doc.setFontSize(11);
doc.setTextColor(...gold);
doc.text('TOTAL (AUD)', boxX + 8, y + 40);
doc.text('$' + total, boxX + boxW - 6, y + 40, { align: 'right' });
// ── DISCLAIMER FOOTER ──
y += 54;
if (y > pageH - 30) { doc.addPage(); y = 20; }
doc.setFillColor(20, 15, 5);
doc.rect(margin, y, pageW - margin * 2, 20, 'F');
doc.setFont('helvetica', 'italic');
doc.setFontSize(7);
doc.setTextColor(160, 148, 100);
doc.text(
'DISCLAIMER: All information in this report is for educational and research purposes only. It does not constitute medical advice, diagnosis, or treatment. ' +
'Dosing protocols are reference starting points only. Individual responses vary. Always consult a qualified healthcare practitioner before starting any protocol. ' +
"Hutto's Peptide Resource accepts no liability for outcomes resulting from use of this information.",
margin + 4, y + 7, { maxWidth: pageW - margin * 2 - 8 }
);
doc.save("huttos-peptide-protocol-" + new Date().toISOString().slice(0,10) + ".pdf");
closeOverlay('pdfOverlay');
}
window.onload = function() {
try {
init();
} catch(e) {
document.body.insertAdjacentHTML('afterbegin',
'
' +
'JS ERROR: ' + e.message + ' ' + e.stack + '
'
);
console.error('init() error:', e);
}
};
ting points only. Individual responses vary. Always consult a qualified healthcare practitioner before starting any protocol. ' +
"Hutto's Peptide Resource accepts no liability for outcomes resulting from use of this information.",
margin + 4, y + 7, { maxWidth: pageW - margin * 2 - 8 }
);
doc.save("huttos-peptide-protocol-" + new Date().toISOString().slice(0,10) + ".pdf");
closeOverlay('pdfOverlay');
}
window.onload = function() {
init();
};