Free Tool
Calcium-to-Phosphorus
Ratio Builder
Build your beardie’s salad and see the real Ca:P ratio in real time. Add ingredients, adjust portions, and get an instant verdict.
🔍
Ca:P ≥ 2:1 (ideal)
Ca:P 1–2:1 (ok)
Ca:P < 1:1 (supplement)
Today’s Salad
0 ingredients
🥗
Click any food to add it
Overall Ratio
—
Ca : P
Add ingredients to see your salad’s score
Calcium0 mg
Phosphorus0 mg
0g
Total
0
Ingredients
0
Ideal foods
💡 Pro tip
Start with a calcium-rich staple green like collard greens or dandelion greens as your base — these anchor a healthy ratio before you add anything else.
More free tools: Cost Calculator · Tank Size Calculator · UVB Calculator
const FOODS = {
'Staple Greens': [
{ name: 'Collard Greens', ca: 232, p: 25, notes: 'Top staple — exceptional Ca:P' },
{ name: 'Dandelion Greens', ca: 187, p: 66, notes: 'High calcium, widely available' },
{ name: 'Mustard Greens', ca: 115, p: 58, notes: 'Good staple, slightly peppery' },
{ name: 'Turnip Greens', ca: 190, p: 42, notes: 'Excellent ratio, underused' },
{ name: 'Endive / Escarole', ca: 52, p: 28, notes: 'Mild flavour, good rotation' },
{ name: 'Watercress', ca: 120, p: 60, notes: 'High Ca, adds variety' },
{ name: 'Cactus Pad (Nopal)', ca: 164, p: 24, notes: 'Outstanding Ca:P, hydrating' },
{ name: 'Alfalfa Sprouts', ca: 32, p: 70, notes: 'Moderate — use sparingly' },
],
'Occasional Greens': [
{ name: 'Kale', ca: 150, p: 92, notes: 'Goitrogens — 1-2x/week max' },
{ name: 'Arugula (Rocket)', ca: 160, p: 52, notes: 'Good Ca:P, peppery mix-in' },
{ name: 'Romaine Lettuce', ca: 33, p: 30, notes: 'Low nutrients — filler only' },
{ name: 'Butterhead Lettuce', ca: 35, p: 33, notes: 'Very low nutrition' },
{ name: 'Bok Choy', ca: 105, p: 37, notes: 'Good Ca:P, goitrogenic' },
{ name: 'Swiss Chard', ca: 51, p: 46, notes: 'High oxalates — occasional' },
{ name: 'Spinach', ca: 99, p: 49, notes: 'High oxalates — rare treats' },
{ name: 'Beet Greens', ca: 117, p: 41, notes: 'High oxalates — limit use' },
],
'Vegetables': [
{ name: 'Butternut Squash', ca: 48, p: 33, notes: 'Good staple veg, hydrating' },
{ name: 'Acorn Squash', ca: 44, p: 47, notes: 'Borderline — use in rotation' },
{ name: 'Bell Pepper (Red)', ca: 7, p: 26, notes: 'Low Ca — add with greens' },
{ name: 'Bell Pepper (Green)', ca: 10, p: 20, notes: 'Low Ca but good hydration' },
{ name: 'Sweet Potato', ca: 30, p: 47, notes: 'Low Ca:P — occasional only' },
{ name: 'Carrots', ca: 33, p: 35, notes: 'Vitamin A — 2x/week max' },
{ name: 'Green Beans', ca: 37, p: 38, notes: 'Near 1:1 — use sparingly' },
{ name: 'Peas (fresh)', ca: 25, p: 108, notes: 'Very high P — avoid' },
{ name: 'Cucumber', ca: 16, p: 24, notes: 'Mostly water, occasional' },
{ name: 'Zucchini', ca: 16, p: 38, notes: 'Low Ca — filler only' },
{ name: 'Broccoli', ca: 47, p: 66, notes: 'Goitrogenic + low Ca:P' },
{ name: 'Tomato', ca: 10, p: 24, notes: 'Acidic — rare treat only' },
],
'Fruits (treats)': [
{ name: 'Papaya', ca: 20, p: 10, notes: 'Best fruit Ca:P, digestive enzymes' },
{ name: 'Mango', ca: 11, p: 14, notes: 'Good tropical treat' },
{ name: 'Strawberries', ca: 16, p: 24, notes: '1-2x/week, high sugar' },
{ name: 'Blueberries', ca: 6, p: 12, notes: 'Antioxidants, high sugar' },
{ name: 'Raspberries', ca: 25, p: 29, notes: 'Higher fibre, occasional' },
{ name: 'Apples (no seeds)', ca: 6, p: 11, notes: 'Low nutrition treat' },
{ name: 'Watermelon', ca: 7, p: 11, notes: 'Good hydration treat' },
{ name: 'Grapes', ca: 10, p: 20, notes: 'High sugar — once/week max' },
{ name: 'Banana', ca: 5, p: 22, notes: 'High P + sugar — rare' },
{ name: 'Pear', ca: 9, p: 12, notes: 'Low nutrition, occasional' },
],
'Insects (live feeders)': [
{ name: 'Dubia Roaches', ca: 71, p: 75, notes: 'Best feeder overall' },
{ name: 'Crickets', ca: 28, p: 90, notes: 'Dust every feeding — high P' },
{ name: 'Black Soldier Fly Larvae', ca: 934, p: 565, notes: 'Exceptional Ca — great supplement feeder' },
{ name: 'Hornworms', ca: 46, p: 68, notes: 'High moisture, soft' },
{ name: 'Silkworms', ca: 177, p: 174, notes: 'Near 1:1 but high overall Ca' },
{ name: 'Mealworms', ca: 13, p: 195, notes: 'Very high P — juvenile max 1x/wk' },
{ name: 'Waxworms', ca: 28, p: 280, notes: 'Treat only — very high P + fat' },
{ name: 'Superworms', ca: 18, p: 272, notes: 'High P + fat — adults only, rare' },
]
};
const CAT_ICONS = {
'Staple Greens': '🥬',
'Occasional Greens': '🌿',
'Vegetables': '🥕',
'Fruits (treats)': '🍓',
'Insects (live feeders)': '🦗',
};
let salad = {};
function ratio(food) { return food.p === 0 ? 99 : food.ca / food.p; }
function ratioClass(r) { return r >= 2 ? 'ratio-great' : r >= 1 ? 'ratio-ok' : 'ratio-bad'; }
function ratioLabel(r) { return r >= 99 ? '∞' : r.toFixed(1) + ':1'; }
function renderBrowser(filter) {
filter = filter || '';
const container = document.getElementById('foodBrowser');
container.innerHTML = '';
const q = filter.toLowerCase();
for (const [cat, foods] of Object.entries(FOODS)) {
const filtered = foods.filter(f => !q || f.name.toLowerCase().includes(q));
if (!filtered.length) continue;
const block = document.createElement('div');
block.className = 'category-block';
const hdr = document.createElement('div');
hdr.className = 'cat-header open';
hdr.innerHTML = '<span class="cat-icon">' + (CAT_ICONS[cat]||'🌿') + '</span><span class="cat-title">' + cat + '</span><span class="cat-count">' + filtered.length + ' foods</span><span class="cat-chevron">▼</span>';
hdr.onclick = function() {
const wrap = block.querySelector('.food-grid-wrap');
const isOpen = hdr.classList.toggle('open');
wrap.classList.toggle('collapsed', !isOpen);
};
const wrap = document.createElement('div');
wrap.className = 'food-grid-wrap';
const grid = document.createElement('div');
grid.className = 'food-grid';
filtered.forEach(function(food) {
const r = ratio(food);
const isAdded = !!salad[food.name];
const item = document.createElement('div');
item.className = 'food-item' + (isAdded ? ' added' : '');
item.title = food.notes;
item.innerHTML = '<div class="food-item-left"><span class="food-name">' + food.name + '</span><span class="food-ratio ' + ratioClass(r) + '">' + ratioLabel(r) + '</span></div><button class="food-add-btn" title="' + (isAdded ? 'Added' : 'Add') + '">' + (isAdded ? '✓' : '+') + '</button>';
item.onclick = function() { toggleFood(food); };
grid.appendChild(item);
});
wrap.appendChild(grid);
block.appendChild(hdr);
block.appendChild(wrap);
container.appendChild(block);
}
}
function toggleFood(food) {
if (salad[food.name]) { delete salad[food.name]; }
else { salad[food.name] = { food: food, grams: 50 }; }
renderSalad(); renderBrowser(document.getElementById('searchInput').value); updateScore();
}
function renderSalad() {
const container = document.getElementById('saladItems');
const count = Object.keys(salad).length;
document.getElementById('saladCount').textContent = count + ' ingredient' + (count !== 1 ? 's' : '');
if (!count) { container.innerHTML = '<div class="salad-empty"><span class="salad-empty-icon">🥗</span>Click any food to add it</div>'; return; }
container.innerHTML = '';
for (const name in salad) {
const entry = salad[name];
const row = document.createElement('div');
row.className = 'salad-row';
row.innerHTML = '<span class="salad-row-name">' + name + '</span><div class="salad-row-grams"><button class="gram-btn" data-n="' + name + '" onclick="changeGrams(this.dataset.n, -10)">−</button><span class="gram-val">' + entry.grams + 'g</span><button class="gram-btn" data-n="' + name + '" onclick="changeGrams(this.dataset.n, 10)">+</button></div><button class="salad-row-remove" data-n="' + name + '" onclick="removeFood(this.dataset.n)" title="Remove">✕</button>';
container.appendChild(row);
}
}
function changeGrams(name, delta) {
if (!salad[name]) return;
salad[name].grams = Math.max(10, Math.min(500, salad[name].grams + delta));
renderSalad(); updateScore();
}
function removeFood(name) {
delete salad[name];
renderSalad(); renderBrowser(document.getElementById('searchInput').value); updateScore();
}
function clearSalad() {
salad = {};
renderSalad(); renderBrowser(document.getElementById('searchInput').value); updateScore();
}
function filterFoods(q) { renderBrowser(q); }
function updateScore() {
var totalCa=0, totalP=0, totalGrams=0, idealCount=0;
var entries = Object.values(salad);
entries.forEach(function(e) {
var f = e.food, g = e.grams, factor = g/100;
totalCa += f.ca * factor; totalP += f.p * factor; totalGrams += g;
if (ratio(f) >= 2) idealCount++;
});
var scoreEl = document.getElementById('scoreNum');
var verdictEl = document.getElementById('scoreVerdict');
document.getElementById('caVal').textContent = Math.round(totalCa) + ' mg';
document.getElementById('pVal').textContent = Math.round(totalP) + ' mg';
document.getElementById('totalGrams').textContent = totalGrams + 'g';
document.getElementById('ingredientCount').textContent = entries.length;
document.getElementById('highRatioCount').textContent = idealCount;
if (!entries.length) {
scoreEl.textContent = '—'; scoreEl.style.color = 'var(--bark-light)';
verdictEl.className = 'score-verdict verdict-empty';
verdictEl.textContent = 'Add ingredients to see your salad score';
document.getElementById('caBar').style.width = '0%';
document.getElementById('pBar').style.width = '0%';
document.getElementById('tipText').textContent = 'Start with a calcium-rich staple green like collard greens or dandelion greens as your base.';
return;
}
var r = totalP === 0 ? 99 : totalCa / totalP;
scoreEl.textContent = r >= 99 ? '∞' : r.toFixed(2) + ':1';
var maxBar = Math.max(totalCa, totalP, 1);
document.getElementById('caBar').style.width = Math.min(100, (totalCa/maxBar)*100) + '%';
document.getElementById('caBar').style.background = 'var(--green)';
document.getElementById('pBar').style.width = Math.min(100, (totalP/maxBar)*100) + '%';
document.getElementById('pBar').style.background = totalP > totalCa ? 'var(--red)' : 'var(--amber)';
var tips = {
great: ['Great ratio! Keep staple greens at 60-70% of total salad volume to maintain it.','Top salad. Rotate collard, dandelion, mustard, and turnip greens for variety without sacrificing Ca:P.','Pair this salad with calcium-dusted Dubia roaches and you are ticking all the boxes.'],
close: ['You are nearly there. Swap one item for dandelion greens to tip the balance.','Try adding cactus pad (nopal) — it has a 6.8:1 Ca:P ratio and adds hydration too.','Collard greens at 100g adds 232mg Ca for only 25mg P — the single highest-impact swap.'],
low: ['Calcium dust on every feeder insect helps offset a low-ratio salad, but greens are the foundation.','Replace high-P veg like peas or broccoli with turnip greens or mustard greens.','Aim for 60% staple greens by weight — that base usually lifts the ratio above 2:1.'],
bad: ['Check for high-P foods: peas, bananas, waxworms, and superworms drag the ratio down fast.','Metabolic bone disease develops silently over months. Fix the ratio now before symptoms appear.','Removing phosphorus sources helps as much as adding calcium — both matter.']
};
var level, verdict;
if (r >= 2) {
scoreEl.style.color='var(--green)'; verdictEl.className='score-verdict verdict-great';
verdictEl.textContent='Excellent! This salad hits the 2:1 Ca:P target.'; level='great';
} else if (r >= 1.5) {
scoreEl.style.color='var(--amber)'; verdictEl.className='score-verdict verdict-ok';
verdictEl.textContent='Close — ratio is '+r.toFixed(2)+':1. Add more collard or dandelion greens to push above 2:1.'; level='close';
} else if (r >= 1) {
scoreEl.style.color='var(--amber)'; verdictEl.className='score-verdict verdict-ok';
verdictEl.textContent='Below target ('+r.toFixed(2)+':1). Add calcium-rich greens or dust feeders with calcium supplement.'; level='low';
} else {
scoreEl.style.color='var(--red)'; verdictEl.className='score-verdict verdict-bad';
verdictEl.textContent='Calcium-deficient ('+r.toFixed(2)+':1). Over time this risks metabolic bone disease. Swap high-P foods for collard greens or cactus pad.'; level='bad';
}
var t = tips[level]; document.getElementById('tipText').textContent = t[Math.floor(Math.random()*t.length)];
}
renderBrowser(); updateScore();
document.documentElement.style.setProperty('--scrollbar-offset', window.innerWidth - document.documentElement.clientWidth + 'px' );
document.addEventListener('DOMContentLoaded', function() {
var related = document.querySelector('.entry-related');
if (!related) return;
related.querySelectorAll('h3.entry-title').forEach(function(h3) {
var p = document.createElement('p');
p.className = h3.className;
p.innerHTML = h3.innerHTML;
h3.parentNode.replaceChild(p, h3);
});
});
var kadenceConfig = {"screenReader":{"expand":"Child menu","expandOf":"Child menu of","collapse":"Child menu","collapseOf":"Child menu of"},"breakPoints":{"desktop":"1024","tablet":768},"scrollOffset":"0"};
//# sourceURL=kadence-navigation-js-extra
https://thebeardie.com/wp-content/themes/kadence/assets/js/navigation.min.js