<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Peptide Reconstitution Calculator</title>
<style>
:root{
--text:#111827;
--muted:#6b7280;
--line:#e5e7eb;
--accent:#2563eb;
--calcbg:#f9fafb;
--card-dose-bg:#f8fafc; /* cool blue-gray */
--card-recon-bg:#f0f7ff; /* light modern blue */
}
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;color:var(--text);background:transparent}
.wrap{max-width:720px;margin:0 auto;padding:16px}
.card{
border:1px solid var(--line);
border-radius:12px;
padding:16px;
background:#fff;
}
.card-dose{background:var(--card-dose-bg); margin-bottom:24px;} /* visual separation */
.card-recon{background:var(--card-recon-bg);}
/* Tighter title/description spacing */
h3{margin:0 0 2px;font-size:20px}
.sub{margin:0 0 4px;color:var(--muted);font-size:14px}
/* Ensure no inline style can widen spacing */
.card h3 + .sub{margin-bottom:4px !important;}
.section{margin:8px 0 6px;font-size:13px;font-weight:800;color:#374151}
.grid{display:grid;gap:12px;grid-template-columns:1fr}
@media(min-width:680px){.grid{grid-template-columns:repeat(3,1fr)}}
label{display:block;font-size:12px;font-weight:700;margin-bottom:6px;color:#374151}
.row{display:flex;gap:8px;align-items:center}
/* Inputs set to 75% width of the row */
input,select{
flex:1;
padding:10px 12px;
border:1px solid var(--line);
border-radius:10px;
outline:none;
background:#fff;
max-width:75%;
}
input:focus,select:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(37,99,235,.15)}
.results{display:grid;gap:12px;margin-top:8px;grid-template-columns:1fr}
@media(min-width:680px){.results{grid-template-columns:repeat(4,1fr)}}
.results.recon{grid-template-columns:1fr}
@media(min-width:680px){.results.recon{grid-template-columns:repeat(3,1fr)}}
.stat{border:1px solid var(--line);border-radius:10px;padding:12px;background:var(--calcbg)}
.stat h4{margin:0 0 4px;color:var(--muted);font-size:12px}
.stat p{margin:0;font-size:18px;font-variant-numeric:tabular-nums}
.foot{margin-top:8px;color:var(--muted);font-size:12px}
/* Remove number input spinners */
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{ -webkit-appearance: none; margin: 0; }
input[type=number]{ -moz-appearance: textfield; appearance: textfield; }
/* ---- tighten title + description spacing (force override) ---- */
.card > h3{
margin: 0 !important;
line-height: 1.25;
}
.card > .sub{
margin: 2px 0 4px !important; /* small top + bottom gap */
line-height: 1.35;
}
/* nudge the inputs closer to the subtitle */
.card .grid{
margin-top: 4px !important;
}
/* control subtitle spacing globally */
.card > .sub { margin: 2px 0 24px !important; line-height: 1.35; }
/* ensure the grid doesn't cap the gap — let the subtitle margin define it */
.card .grid { margin-top: 0 !important; }
</style>
</head>
<body>
<div class="wrap">
<!-- 1) Peptide Dose Calculator -->
<div class="card card-dose" id="simple-calc">
<h3>Peptide Dose Calculator</h3>
<p class="sub">Determine how many syringe units to draw for your desired peptide dose and reconstitution volume.<br></br></p>
<div class="grid">
<div>
<label>Peptide Vial Contents (mg)</label>
<div class="row">
<select id="vialPreset">
<option value="" selected disabled>Select mg</option>
<option value="10">10</option>
<option value="30">30</option>
<option value="other">Other</option>
</select>mg
<input type="number" id="vialMgOther" placeholder="Other mg" min="0" step="0.01" style="display:none" />
</div>
</div>
<div>
<label>Bacteriostatic Water (mL)</label>
<div class="row">
<select id="waterPreset">
<option value="" selected disabled>Select mL</option>
<option value="3">3</option>
<option value="10">10</option>
<option value="other">Other</option>
</select>mL
<input type="number" id="waterMlOther" placeholder="Other mL" min="0" step="0.1" style="display:none" />
</div>
</div>
<div>
<label>Desired Dose</label>
<div class="row">
<input type="number" id="doseValue" placeholder="e.g., 250" min="0" step="0.001" />
<select id="doseUnit">
<option value="" selected disabled>Select unit</option>
<option value="mcg">mcg</option>
<option value="mg">mg</option>
</select>
</div>
<div id="doseHelp" class="suffix" aria-live="polite"></div>
</div>
</div>
<div class="section">Results:</div>
<div class="results">
<div class="stat"><h4>Draw syringe to</h4><p id="units">—</p></div>
<div class="stat"><h4>Peptide dose</h4><p id="doseEcho">—</p></div>
<div class="stat"><h4>Concentration</h4><p id="conc">—</p></div>
<div class="stat"><h4>Doses per vial</h4><p id="doses">—</p></div>
</div>
<div class="foot">
Formulas: <strong>units</strong> = (dose mg ÷ concentration mg/mL) × 100;
<strong>dose</strong> shows your input converted to mg;
<strong>concentration</strong> = vial mg ÷ mL;
<strong>doses per vial</strong> = vial mg ÷ dose mg.
</div>
</div>
<!-- 2) Peptide Reconstitution Calculator -->
<div class="card card-recon" id="recon-calc">
<h3>Peptide Reconstitution Calculator</h3>
<!-- Removed inline margins; CSS handles tight spacing -->
<p class="sub">Determine the ideal amount of bacteriostatic water to add for your desired syringe draw units and dose strength.<br></br></p>
<div class="grid">
<div>
<label>Peptide Vial Contents (mg)</label>
<div class="row">
<select id="vialPreset2">
<option value="" selected disabled>Select mg</option>
<option value="10">10</option>
<option value="30">30</option>
<option value="other">Other</option>
</select>mg
<input type="number" id="vialMgOther2" placeholder="Other mg" min="0" step="0.01" style="display:none" />
</div>
</div>
<div>
<label>Desired Dose</label>
<div class="row">
<input type="number" id="doseValue2" placeholder="e.g., 250" min="0" step="0.001" />
<select id="doseUnit2">
<option value="" selected disabled>Select unit</option>
<option value="mcg">mcg</option>
<option value="mg">mg</option>
</select>
</div>
<div id="doseHelp2" class="suffix" aria-live="polite"></div>
</div>
<div>
<label>Desired Draw (units)</label>
<div class="row">
<input type="number" id="targetUnits2" placeholder="e.g., 10" min="0" step="0.1" />
</div>
</div>
</div>
<div class="section">Results:</div>
<div class="results recon">
<div class="stat"><h4>Bacteriostatic water to add</h4><p id="reconWater">—</p></div>
<div class="stat"><h4>Resulting concentration</h4><p id="reconConc">—</p></div>
<div class="stat"><h4>Doses per vial</h4><p id="reconDoses">—</p></div>
</div>
<div class="foot">
Formulas: <strong>water (mL)</strong> = (units × vial mg) ÷ (dose mg × 100);
<strong>concentration</strong> = vial mg ÷ water mL;
<strong>doses per vial</strong> = vial mg ÷ dose mg.
</div>
</div>
</div>
<script>
// ===== Dose Calculator =====
(function(){
const vialPreset=document.getElementById('vialPreset');
const vialMgOther=document.getElementById('vialMgOther');
const waterPreset=document.getElementById('waterPreset');
const waterMlOther=document.getElementById('waterMlOther');
const doseValue=document.getElementById('doseValue');
const doseUnit=document.getElementById('doseUnit');
const unitsEl=document.getElementById('units');
const concEl=document.getElementById('conc');
const dosesEl=document.getElementById('doses');
const doseEcho=document.getElementById('doseEcho');
const doseHelp=document.getElementById('doseHelp');
const fmt=(n,dec=2)=>!isFinite(n)?'—':(+n.toFixed(dec)).toString();
function reset(){ unitsEl.textContent=concEl.textContent=dosesEl.textContent=doseEcho.textContent='—'; doseHelp.textContent=''; }
function getVialMg(){
if(vialPreset.value==='other'){ return parseFloat(vialMgOther.value); }
return parseFloat(vialPreset.value);
}
function getWaterMl(){
if(waterPreset.value==='other'){ return parseFloat(waterMlOther.value); }
return parseFloat(waterPreset.value);
}
function compute(){
const vial=getVialMg();
const water=getWaterMl();
const rawDose=parseFloat(doseValue.value);
const unit=doseUnit.value;
if(!isFinite(vial) || !isFinite(water) || !isFinite(rawDose) || !unit){ reset(); return; }
const doseMg=(unit==='mcg')? rawDose/1000 : rawDose;
doseHelp.textContent = (unit==='mg')
? `${fmt(rawDose)} mg = ${fmt(rawDose*1000,0)} mcg`
: `${fmt(rawDose,0)} mcg = ${fmt(rawDose/1000)} mg`;
if(water<=0||vial<=0||doseMg<=0){ reset(); return; }
const conc=vial/water;
const mlPerDose=doseMg/conc;
const units=mlPerDose*100;
const doses=vial/doseMg;
unitsEl.textContent=`${fmt(units,1)} units`;
concEl.textContent=`${fmt(conc,3)} mg/mL`;
dosesEl.textContent=`${fmt(doses,1)}`;
doseEcho.textContent=`${fmt(doseMg,3)} mg`;
}
function syncVial(){
const showOther = vialPreset.value==='other';
vialMgOther.style.display = showOther ? 'block' : 'none';
compute();
}
function syncWater(){
const showOther = waterPreset.value==='other';
waterMlOther.style.display = showOther ? 'block' : 'none';
compute();
}
['input','change'].forEach(ev=>{
[vialPreset,vialMgOther,waterPreset,waterMlOther,doseValue,doseUnit].forEach(el=>el.addEventListener(ev,compute));
vialPreset.addEventListener(ev,syncVial);
waterPreset.addEventListener(ev,syncWater);
});
reset();
})();
// ===== Reconstitution Calculator =====
(function(){
const vialPreset2=document.getElementById('vialPreset2');
const vialMgOther2=document.getElementById('vialMgOther2');
const doseValue2=document.getElementById('doseValue2');
const doseUnit2=document.getElementById('doseUnit2');
const targetUnits2=document.getElementById('targetUnits2');
const reconWater=document.getElementById('reconWater');
const reconConc=document.getElementById('reconConc');
const reconDoses=document.getElementById('reconDoses');
const doseHelp2=document.getElementById('doseHelp2');
const fmt2=(n,dec=2)=>!isFinite(n)?'—':(+n.toFixed(dec)).toString();
function reset2(){ reconWater.textContent=reconConc.textContent=reconDoses.textContent='—'; doseHelp2.textContent=''; }
function getVialMg2(){
if(vialPreset2.value==='other'){ return parseFloat(vialMgOther2.value); }
return parseFloat(vialPreset2.value);
}
function compute2(){
const vial=getVialMg2();
const rawDose=parseFloat(doseValue2.value);
const unit=doseUnit2.value;
const targetUnits=parseFloat(targetUnits2.value);
if(!isFinite(vial) || !isFinite(rawDose) || !unit || !isFinite(targetUnits)){ reset2(); return; }
const doseMg=(unit==='mcg')? rawDose/1000 : rawDose;
doseHelp2.textContent = (unit==='mg')
? `${fmt2(rawDose)} mg = ${fmt2(rawDose*1000,0)} mcg`
: `${fmt2(rawDose,0)} mcg = ${fmt2(rawDose/1000)} mg`;
if(doseMg<=0 || vial<=0 || targetUnits<=0){ reset2(); return; }
const water = (targetUnits * vial) / (doseMg * 100);
const conc = vial / water;
const doses = vial / doseMg;
reconWater.textContent = `${fmt2(water,3)} mL`;
reconConc.textContent = `${fmt2(conc,3)} mg/mL`;
reconDoses.textContent = `${fmt2(doses,1)}`;
}
function syncVial2(){
const showOther = vialPreset2.value==='other';
vialMgOther2.style.display = showOther ? 'block' : 'none';
compute2();
}
['input','change'].forEach(ev=>{
[vialPreset2,vialMgOther2,doseValue2,doseUnit2,targetUnits2].forEach(el=>el.addEventListener(ev,compute2));
vialPreset2.addEventListener(ev,syncVial2);
});
reset2();
})();
</script>
</body>
</html>