Kaya transition v1

This commit is contained in:
Dayowe 2025-11-12 16:44:43 +01:00
parent 90657f9aa4
commit 7fd139b321
4 changed files with 278 additions and 224 deletions

View File

@ -200,6 +200,12 @@
color: var(--text-label);
}
/* Kaya end-weight readonly field: compact, non-editable */
#kayaEndWeight {
width: 120px;
display: inline-block;
}
.dog-calculator-results {
background: linear-gradient(135deg, rgba(241, 154, 95, 0.08) 0%, rgba(241, 154, 95, 0.04) 100%);
border: 1px solid rgba(241, 154, 95, 0.2);
@ -1964,50 +1970,18 @@
<div class="dog-calculator-container" id="dogCalculator">
<div class="dog-calculator-section">
<div class="dog-calculator-section-header">
<h2>Dog's Characteristics</h2>
<div class="dog-calculator-unit-switch">
<span class="dog-calculator-unit-label active" id="metricLabel">Metric</span>
<label class="dog-calculator-switch">
<input type="checkbox" id="unitToggle">
<span class="dog-calculator-slider"></span>
</label>
<span class="dog-calculator-unit-label" id="imperialLabel">Imperial</span>
</div>
</div>
<div class="dog-calculator-form-group">
<label for="dogType">Dog Type / Activity Level:</label>
<select id="dogType" aria-describedby="dogTypeHelp">
<option value="">Select dog type...</option>
<option value="3.0">Puppy (0-4 months)</option>
<option value="2.0">Puppy (4 months - adult)</option>
<option value="1.2">Adult - inactive/obese</option>
<option value="1.6">Adult (neutered/spayed) - average activity</option>
<option value="1.8">Adult (intact) - average activity</option>
<option value="1.0">Adult - weight loss</option>
<option value="1.7">Adult - weight gain</option>
<option value="2.0">Working dog - light work</option>
<option value="3.0">Working dog - moderate work</option>
<option value="5.0">Working dog - heavy work</option>
<option value="1.1">Senior dog</option>
</select>
<h2>Kayas Transition</h2>
</div>
<div class="dog-calculator-form-group">
<label for="weight" id="weightLabel">Dog's Weight (kg):</label>
<input type="number" id="weight" min="0.1" step="0.1" placeholder="Enter weight in kg" aria-describedby="weightHelp">
<div id="weightError" class="dog-calculator-error dog-calculator-hidden">Please enter a valid weight (minimum 0.1 kg)</div>
<label for="ageMonths">Kayas age (months):</label>
<input type="number" id="ageMonths" min="2" max="12" step="0.1" placeholder="Enter age in months" aria-describedby="ageHelp">
<div id="ageClampNote" class="dog-calculator-error dog-calculator-hidden">Age adjusted to the supported 212 month range.</div>
</div>
<div class="dog-calculator-results" id="calorieResults" style="display: none;">
<div class="dog-calculator-result-item">
<span class="dog-calculator-result-label">Resting Energy Requirement (RER):</span>
<span class="dog-calculator-result-value" id="rerValue">- cal/day</span>
</div>
<div class="dog-calculator-result-item">
<span class="dog-calculator-result-label">Maintenance Energy Requirement (MER):</span>
<span class="dog-calculator-result-value" id="merValue">- cal/day</span>
</div>
<div class="dog-calculator-form-group">
<label for="kayaEndWeight">Kayas endweight:</label>
<input type="text" id="kayaEndWeight" value="30 kg" readonly>
</div>
</div>
@ -2102,46 +2076,12 @@
</div>
</div>
<div class="dog-calculator-action-buttons">
<button class="dog-calculator-btn dog-calculator-btn-share" id="shareBtn">
Share
</button>
</div>
<div class="dog-calculator-footer">
<a href="https://caninenutritionandwellness.com" target="_blank" rel="noopener noreferrer">
by caninenutritionandwellness.com
</a>
</div>
<!-- Share Modal -->
<div id="shareModal" class="dog-calculator-modal" style="display: none;">
<div class="dog-calculator-modal-content">
<span class="dog-calculator-modal-close" id="shareModalClose">&times;</span>
<h3>Share Calculator</h3>
<div class="dog-calculator-share-buttons">
<button class="dog-calculator-share-btn dog-calculator-share-facebook plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-facebook" id="shareFacebook">
Facebook
</button>
<button class="dog-calculator-share-btn dog-calculator-share-twitter plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-twitter" id="shareTwitter">
Twitter
</button>
<button class="dog-calculator-share-btn dog-calculator-share-linkedin plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-linkedin" id="shareLinkedIn">
LinkedIn
</button>
<button class="dog-calculator-share-btn dog-calculator-share-email plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-email" id="shareEmail">
Email
</button>
<button class="dog-calculator-share-btn dog-calculator-share-copy plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-copy-link" id="shareCopy">
Copy Link
</button>
</div>
<div class="dog-calculator-share-url">
<input type="text" id="shareUrl" readonly>
</div>
</div>
</div>
</div>
<script>
/**
@ -2173,6 +2113,9 @@ const CALCULATOR_CONFIG = {
this.maxFoodSources = CALCULATOR_CONFIG.maxFoodSources;
this.mealsPerDay = 2;
this.showPerMeal = false;
// Kayafied reference source tracking
this.kibbleRefId = null;
this.gcRefId = null;
this.init();
}
@ -2227,8 +2170,45 @@ const CALCULATOR_CONFIG = {
// Food Source Management Methods
initializeFoodSources() {
this.addFoodSource();
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
name: 'Fred & Felia, gently cooked',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
isLocked: false
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
this.gcRefId = gc.id;
const kibble = {
id: this.generateFoodSourceId(),
name: 'Eukanuba, kibble',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
isLocked: false
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
this.kibbleRefId = kibble.id;
const treats = {
id: this.generateFoodSourceId(),
name: 'Treats',
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
isLocked: false
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
this.updateAddButton();
this.updateRemoveButtons();
this.refreshAllPercentageUI();
}
addFoodSource() {
@ -2263,6 +2243,9 @@ const CALCULATOR_CONFIG = {
if (index === -1) return;
this.foodSources.splice(index, 1);
// If reference IDs were removed, clear them
if (this.kibbleRefId === id) this.kibbleRefId = null;
if (this.gcRefId === id) this.gcRefId = null;
// Remove the DOM element
const element = document.getElementById(`foodSource-${id}`);
@ -2276,6 +2259,7 @@ const CALCULATOR_CONFIG = {
this.updateAddButton();
this.updateRemoveButtons();
this.refreshAllPercentageUI();
this.updateCalorieCalculations();
}
generateFoodSourceId() {
@ -2747,6 +2731,10 @@ const CALCULATOR_CONFIG = {
if (energyInput) {
energyInput.addEventListener('input', () => {
this.updateFoodSourceData(id, 'energy', energyInput.value);
// If kibble reference changed, recompute daily target
if (id === this.kibbleRefId) {
this.updateCalorieCalculations();
}
// Auto-select cups when entering energy for kcal/cup
const foodSource = this.foodSources.find(fs => fs.id === id);
@ -2784,6 +2772,9 @@ const CALCULATOR_CONFIG = {
if (energyUnitSelect) {
energyUnitSelect.addEventListener('change', () => {
this.updateFoodSourceData(id, 'energyUnit', energyUnitSelect.value);
if (id === this.kibbleRefId) {
this.updateCalorieCalculations();
}
// Auto-select the most appropriate unit based on energy unit
const unitSelect = document.getElementById('unit');
@ -2961,6 +2952,7 @@ const CALCULATOR_CONFIG = {
bindEvents() {
const weightInput = document.getElementById('weight');
const dogTypeSelect = document.getElementById('dogType');
const ageInput = document.getElementById('ageMonths');
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
const unitToggle = document.getElementById('unitToggle');
@ -2972,6 +2964,12 @@ const CALCULATOR_CONFIG = {
}
if (dogTypeSelect) dogTypeSelect.addEventListener('change', () => this.updateCalorieCalculations());
// Kayafied: age input drives energy target
if (ageInput) {
ageInput.addEventListener('input', () => this.updateCalorieCalculations());
ageInput.addEventListener('blur', () => this.updateCalorieCalculations());
}
if (daysInput) {
daysInput.addEventListener('input', () => {
@ -3316,57 +3314,86 @@ const CALCULATOR_CONFIG = {
}
updateCalorieCalculations() {
const dogTypeSelect = document.getElementById('dogType');
const calorieResults = document.getElementById('calorieResults');
const rerValue = document.getElementById('rerValue');
const merValue = document.getElementById('merValue');
// Kaya-specific: compute daily kcal target from age + kibble energy
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
if (!dogTypeSelect || !calorieResults || !rerValue || !merValue) {
// Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
if (!ageInput || !ageInput.value) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const weightKg = this.getWeightInKg();
const dogTypeFactor = dogTypeSelect.value;
this.showError('weightError', false);
if (!weightKg || weightKg < 0.1) {
const weightInput = document.getElementById('weight');
if (weightInput && weightInput.value) this.showError('weightError', true);
calorieResults.style.display = 'none';
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
if (!dogTypeFactor) {
calorieResults.style.display = 'none';
// Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
// Calculate interpolated kibble grams/day for 30 kg at this age
const kibbleGrams = this.getKayaKibbleGramsForAge(age);
// Get kibble reference energy density in kcal/100g
let kibbleEnergyPer100g = null;
if (this.kibbleRefId) {
const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
}
if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
// Cannot compute without kibble energy density
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const factor = parseFloat(dogTypeFactor);
const rer = this.calculateRER(weightKg);
const mer = this.calculateMER(rer, factor);
// Calculate range for MER
const range = this.getLifeStageRange(factor);
this.currentMERMin = this.calculateMER(rer, range.min);
this.currentMERMax = this.calculateMER(rer, range.max);
this.currentMER = mer; // Keep middle/selected value for compatibility
rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day';
// Show MER as range if applicable
if (range.min !== range.max) {
merValue.textContent = this.formatNumber(this.currentMERMin, 0) + '-' +
this.formatNumber(this.currentMERMax, 0) + ' cal/day';
} else {
merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
}
calorieResults.style.display = 'block';
const kcalPerGram = kibbleEnergyPer100g / 100.0;
const dailyKcal = kibbleGrams * kcalPerGram;
this.currentMER = dailyKcal;
this.currentMERMin = dailyKcal;
this.currentMERMax = dailyKcal;
this.updateFoodCalculations();
}
// Kaya: monthly table with interpolation between months
getKayaKibbleGramsForAge(ageMonths) {
// Precomputed monthly values for 30 kg (g/day)
const table = {
2: 250,
3: 330,
4: 365,
5: 382,
6: 400,
7: 405,
8: 410,
9: 410,
10: 410,
11: 408,
12: 405
};
// Exact integer month
const lower = Math.floor(ageMonths);
const upper = Math.ceil(ageMonths);
if (lower === upper) return table[lower] || 0;
// Linear interpolation between bounds
const lowerVal = table[lower] || 0;
const upperVal = table[upper] || 0;
const t = (ageMonths - lower) / (upper - lower);
return lowerVal + (upperVal - lowerVal) * t;
}
updateCupsButtonState() {
const cupsButton = document.getElementById('cupsButton');
if (!cupsButton) return;

View File

@ -190,6 +190,12 @@
color: var(--text-label);
}
/* Kaya end-weight readonly field: compact, non-editable */
#kayaEndWeight {
width: 120px;
display: inline-block;
}
.dog-calculator-results {
background: linear-gradient(135deg, rgba(241, 154, 95, 0.08) 0%, rgba(241, 154, 95, 0.04) 100%);
border: 1px solid rgba(241, 154, 95, 0.2);

View File

@ -1,50 +1,18 @@
<div class="dog-calculator-container" id="dogCalculator">
<div class="dog-calculator-section">
<div class="dog-calculator-section-header">
<h2>Dog's Characteristics</h2>
<div class="dog-calculator-unit-switch">
<span class="dog-calculator-unit-label active" id="metricLabel">Metric</span>
<label class="dog-calculator-switch">
<input type="checkbox" id="unitToggle">
<span class="dog-calculator-slider"></span>
</label>
<span class="dog-calculator-unit-label" id="imperialLabel">Imperial</span>
</div>
</div>
<div class="dog-calculator-form-group">
<label for="dogType">Dog Type / Activity Level:</label>
<select id="dogType" aria-describedby="dogTypeHelp">
<option value="">Select dog type...</option>
<option value="3.0">Puppy (0-4 months)</option>
<option value="2.0">Puppy (4 months - adult)</option>
<option value="1.2">Adult - inactive/obese</option>
<option value="1.6">Adult (neutered/spayed) - average activity</option>
<option value="1.8">Adult (intact) - average activity</option>
<option value="1.0">Adult - weight loss</option>
<option value="1.7">Adult - weight gain</option>
<option value="2.0">Working dog - light work</option>
<option value="3.0">Working dog - moderate work</option>
<option value="5.0">Working dog - heavy work</option>
<option value="1.1">Senior dog</option>
</select>
<h2>Kayas Transition</h2>
</div>
<div class="dog-calculator-form-group">
<label for="weight" id="weightLabel">Dog's Weight (kg):</label>
<input type="number" id="weight" min="0.1" step="0.1" placeholder="Enter weight in kg" aria-describedby="weightHelp">
<div id="weightError" class="dog-calculator-error dog-calculator-hidden">Please enter a valid weight (minimum 0.1 kg)</div>
<label for="ageMonths">Kayas age (months):</label>
<input type="number" id="ageMonths" min="2" max="12" step="0.1" placeholder="Enter age in months" aria-describedby="ageHelp">
<div id="ageClampNote" class="dog-calculator-error dog-calculator-hidden">Age adjusted to the supported 212 month range.</div>
</div>
<div class="dog-calculator-results" id="calorieResults" style="display: none;">
<div class="dog-calculator-result-item">
<span class="dog-calculator-result-label">Resting Energy Requirement (RER):</span>
<span class="dog-calculator-result-value" id="rerValue">- cal/day</span>
</div>
<div class="dog-calculator-result-item">
<span class="dog-calculator-result-label">Maintenance Energy Requirement (MER):</span>
<span class="dog-calculator-result-value" id="merValue">- cal/day</span>
</div>
<div class="dog-calculator-form-group">
<label for="kayaEndWeight">Kayas endweight:</label>
<input type="text" id="kayaEndWeight" value="30 kg" readonly>
</div>
</div>
@ -139,44 +107,10 @@
</div>
</div>
<div class="dog-calculator-action-buttons">
<button class="dog-calculator-btn dog-calculator-btn-share" id="shareBtn">
Share
</button>
</div>
<div class="dog-calculator-footer">
<a href="https://caninenutritionandwellness.com" target="_blank" rel="noopener noreferrer">
by caninenutritionandwellness.com
</a>
</div>
<!-- Share Modal -->
<div id="shareModal" class="dog-calculator-modal" style="display: none;">
<div class="dog-calculator-modal-content">
<span class="dog-calculator-modal-close" id="shareModalClose">&times;</span>
<h3>Share Calculator</h3>
<div class="dog-calculator-share-buttons">
<button class="dog-calculator-share-btn dog-calculator-share-facebook plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-facebook" id="shareFacebook">
Facebook
</button>
<button class="dog-calculator-share-btn dog-calculator-share-twitter plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-twitter" id="shareTwitter">
Twitter
</button>
<button class="dog-calculator-share-btn dog-calculator-share-linkedin plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-linkedin" id="shareLinkedIn">
LinkedIn
</button>
<button class="dog-calculator-share-btn dog-calculator-share-email plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-email" id="shareEmail">
Email
</button>
<button class="dog-calculator-share-btn dog-calculator-share-copy plausible-event-name=Calculator+Usage plausible-event-action=calculator-share-copy-link" id="shareCopy">
Copy Link
</button>
</div>
<div class="dog-calculator-share-url">
<input type="text" id="shareUrl" readonly>
</div>
</div>
</div>
</div>

View File

@ -15,6 +15,9 @@
this.maxFoodSources = CALCULATOR_CONFIG.maxFoodSources;
this.mealsPerDay = 2;
this.showPerMeal = false;
// Kayafied reference source tracking
this.kibbleRefId = null;
this.gcRefId = null;
this.init();
}
@ -69,8 +72,45 @@
// Food Source Management Methods
initializeFoodSources() {
this.addFoodSource();
// Seed three sources for Kaya's transition
const gc = {
id: this.generateFoodSourceId(),
name: 'Fred & Felia, gently cooked',
energy: '115',
energyUnit: 'kcal100g',
percentage: 5,
isLocked: false
};
this.foodSources.push(gc);
this.renderFoodSource(gc);
this.gcRefId = gc.id;
const kibble = {
id: this.generateFoodSourceId(),
name: 'Eukanuba, kibble',
energy: '372',
energyUnit: 'kcal100g',
percentage: 95,
isLocked: false
};
this.foodSources.push(kibble);
this.renderFoodSource(kibble);
this.kibbleRefId = kibble.id;
const treats = {
id: this.generateFoodSourceId(),
name: 'Treats',
energy: '',
energyUnit: 'kcal100g',
percentage: 0,
isLocked: false
};
this.foodSources.push(treats);
this.renderFoodSource(treats);
this.updateAddButton();
this.updateRemoveButtons();
this.refreshAllPercentageUI();
}
addFoodSource() {
@ -105,6 +145,9 @@
if (index === -1) return;
this.foodSources.splice(index, 1);
// If reference IDs were removed, clear them
if (this.kibbleRefId === id) this.kibbleRefId = null;
if (this.gcRefId === id) this.gcRefId = null;
// Remove the DOM element
const element = document.getElementById(`foodSource-${id}`);
@ -118,6 +161,7 @@
this.updateAddButton();
this.updateRemoveButtons();
this.refreshAllPercentageUI();
this.updateCalorieCalculations();
}
generateFoodSourceId() {
@ -589,6 +633,10 @@
if (energyInput) {
energyInput.addEventListener('input', () => {
this.updateFoodSourceData(id, 'energy', energyInput.value);
// If kibble reference changed, recompute daily target
if (id === this.kibbleRefId) {
this.updateCalorieCalculations();
}
// Auto-select cups when entering energy for kcal/cup
const foodSource = this.foodSources.find(fs => fs.id === id);
@ -626,6 +674,9 @@
if (energyUnitSelect) {
energyUnitSelect.addEventListener('change', () => {
this.updateFoodSourceData(id, 'energyUnit', energyUnitSelect.value);
if (id === this.kibbleRefId) {
this.updateCalorieCalculations();
}
// Auto-select the most appropriate unit based on energy unit
const unitSelect = document.getElementById('unit');
@ -803,6 +854,7 @@
bindEvents() {
const weightInput = document.getElementById('weight');
const dogTypeSelect = document.getElementById('dogType');
const ageInput = document.getElementById('ageMonths');
const daysInput = document.getElementById('days');
const unitSelect = document.getElementById('unit');
const unitToggle = document.getElementById('unitToggle');
@ -814,6 +866,12 @@
}
if (dogTypeSelect) dogTypeSelect.addEventListener('change', () => this.updateCalorieCalculations());
// Kayafied: age input drives energy target
if (ageInput) {
ageInput.addEventListener('input', () => this.updateCalorieCalculations());
ageInput.addEventListener('blur', () => this.updateCalorieCalculations());
}
if (daysInput) {
daysInput.addEventListener('input', () => {
@ -1158,57 +1216,86 @@
}
updateCalorieCalculations() {
const dogTypeSelect = document.getElementById('dogType');
const calorieResults = document.getElementById('calorieResults');
const rerValue = document.getElementById('rerValue');
const merValue = document.getElementById('merValue');
// Kaya-specific: compute daily kcal target from age + kibble energy
const ageInput = document.getElementById('ageMonths');
const ageClampNote = document.getElementById('ageClampNote');
if (!dogTypeSelect || !calorieResults || !rerValue || !merValue) {
// Default: hide clamp note
if (ageClampNote) ageClampNote.classList.add('dog-calculator-hidden');
if (!ageInput || !ageInput.value) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const weightKg = this.getWeightInKg();
const dogTypeFactor = dogTypeSelect.value;
this.showError('weightError', false);
if (!weightKg || weightKg < 0.1) {
const weightInput = document.getElementById('weight');
if (weightInput && weightInput.value) this.showError('weightError', true);
calorieResults.style.display = 'none';
let age = parseFloat(ageInput.value);
if (isNaN(age)) {
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
if (!dogTypeFactor) {
calorieResults.style.display = 'none';
// Clamp age to [2, 12]
if (age < 2) { age = 2; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
if (age > 12) { age = 12; if (ageClampNote) ageClampNote.classList.remove('dog-calculator-hidden'); }
// Calculate interpolated kibble grams/day for 30 kg at this age
const kibbleGrams = this.getKayaKibbleGramsForAge(age);
// Get kibble reference energy density in kcal/100g
let kibbleEnergyPer100g = null;
if (this.kibbleRefId) {
const kibbleRef = this.foodSources.find(fs => fs.id === this.kibbleRefId);
kibbleEnergyPer100g = kibbleRef ? this.getFoodSourceEnergyPer100g(kibbleRef) : null;
}
if (!kibbleEnergyPer100g || kibbleEnergyPer100g <= 0) {
// Cannot compute without kibble energy density
this.currentMER = 0;
this.currentMERMin = 0;
this.currentMERMax = 0;
return;
}
const factor = parseFloat(dogTypeFactor);
const rer = this.calculateRER(weightKg);
const mer = this.calculateMER(rer, factor);
// Calculate range for MER
const range = this.getLifeStageRange(factor);
this.currentMERMin = this.calculateMER(rer, range.min);
this.currentMERMax = this.calculateMER(rer, range.max);
this.currentMER = mer; // Keep middle/selected value for compatibility
rerValue.textContent = this.formatNumber(rer, 0) + ' cal/day';
// Show MER as range if applicable
if (range.min !== range.max) {
merValue.textContent = this.formatNumber(this.currentMERMin, 0) + '-' +
this.formatNumber(this.currentMERMax, 0) + ' cal/day';
} else {
merValue.textContent = this.formatNumber(mer, 0) + ' cal/day';
}
calorieResults.style.display = 'block';
const kcalPerGram = kibbleEnergyPer100g / 100.0;
const dailyKcal = kibbleGrams * kcalPerGram;
this.currentMER = dailyKcal;
this.currentMERMin = dailyKcal;
this.currentMERMax = dailyKcal;
this.updateFoodCalculations();
}
// Kaya: monthly table with interpolation between months
getKayaKibbleGramsForAge(ageMonths) {
// Precomputed monthly values for 30 kg (g/day)
const table = {
2: 250,
3: 330,
4: 365,
5: 382,
6: 400,
7: 405,
8: 410,
9: 410,
10: 410,
11: 408,
12: 405
};
// Exact integer month
const lower = Math.floor(ageMonths);
const upper = Math.ceil(ageMonths);
if (lower === upper) return table[lower] || 0;
// Linear interpolation between bounds
const lowerVal = table[lower] || 0;
const upperVal = table[upper] || 0;
const t = (ageMonths - lower) / (upper - lower);
return lowerVal + (upperVal - lowerVal) * t;
}
updateCupsButtonState() {
const cupsButton = document.getElementById('cupsButton');
if (!cupsButton) return;