You have been signed out. The dashboard is safe to use again. Open the Account tab to sign back in.
You have been signed out. Use the Account tab to sign in again.
EPK Method

Human OS

EPK - Hydr-EAT intelligence platform

Private beta • Member access • v4.33 dashboard clean

Measure what matters. Complete a five-day assessment to establish your current status across Energy, Hydration, Movement, Sleep, Breathing and Mindset. Generate your report, identify priorities, and follow a personalised improvement pathway.

01AssessmentFive-day baseline
02AnalysisStatus report
03PrioritisationKey targets
04ImplementationApply changes
05ReviewTrack progress

Member Dashboard

One place for your latest status, next action and recommended lesson.

Not calculated yet

Sign in, upload five complete days, then follow the report-led learning path.

EPK Intake
Coverage of energy used
Hydration guidance
Movement track

Start assessment

Sign in, enter or upload your five days, then generate your report.

Last report

No saved report yet. Sign in, generate a report, then save it to your secure hosting account.

Reports

Saved reports now load from the your secure member account when you are signed in. If the API is unavailable, the app will fall back to this browser only for testing.

Create an account or sign in to use the app, save reports and view your report history.
No saved reports yetCalculate a report, then choose Save report to account.

Human OS Library

The member sees clear chapters — Welcome, Energy, Movement, Hydration, Sleep, Breathing, Mindspace and Research — rather than a long strip of module numbers. Each chapter contains its foundation lessons, practical application lessons, supporting articles and conversations.

Education is included with the platform, but lessons unlock after account sign-in. You can preview the library structure below.

◉ Welcome

Set up, five-day tracking and first report.

12 lessonsFirst report

⚡ Energy

EPK, energy availability and first nutrition changes.

FoundationApplication

🏃 Movement

Movement readiness, training level and weekly plans.

FoundationApplication

💧 Hydration

Fluid, food water, metabolic water and electrolytes.

FoundationApplication

🌙 Sleep

Recovery capacity and practical sleep support.

FoundationApplication

🫁 Breathing

CO₂, stress, recovery and practical regulation tools.

FoundationApplication

🧠 Mindspace

State, capacity, consistency and action.

FoundationApplication

📚 Research

The evidence library that supports the whole platform.

Evidence

Welcome

Get signed in, set up, assessed and confident reading the first report.

1 chapter blocks12 lessons/resources 1 foundation

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Welcome Video

Welcome — How The System Works

Start here before completing your first five-day assessment.

Course 1

System Onboarding

The app-first start: setup, five-day tracking, first report and next action.

1
Welcome — How The System Works
2
What Success Looks Like
3
Set Up Your Tools
4
Collecting Your First Five Days
5
Generating Your First Report
6
Understanding My Report
7
The Five Numbers That Matter
8
Traffic Lights & Readiness
9
Beyond Calories — Hydration & Movement
10
Your Personal Learning Path
11
Calibrate, Don't Overreact
12
From Estimates To Precision

Energy

Build and maintain energy availability so the rest of the system can work.

2 chapter blocks19 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 1

Energy — Foundation

Understand EPK, energy availability, the zones and how to adjust without panic.

1
Why Energy Comes First (Always)
2
What Energy Availability Actually Means
3
Red, Amber, Green & Gold
4
Why Eating Less Is Rarely Useful
5
The 10% Increase Strategy
6
Macro Mix — When Fat Drives The Surplus
7
Why Eating More Doesn't Automatically Mean Fat Gain
8
Carbohydrates, DNL & Context
9
How To Adjust Over Time
Course 1

Energy — Application

Turn report findings into practical food, tracking and adjustment decisions.

1
How To Set Your Baseline
2
How To Track Without Becoming Obsessive
3
How To Calculate EPK
4
How To Identify Your Reality Gap
5
How To Increase Intake
6
How To Lower Fat Intake
7
How To Build Simple, Repeatable Meals
8
When To Hold vs Increase
9
What To Expect When You Eat More
10
Troubleshooting Weight, Hunger & Energy

📖 Supporting articles

What Is EPK? Needs Adjusted EPK Reality Gap Constrained Energy Expenditure Herman Pontzer RED-S DNL Randle Cycle Appetite Regulation Carbohydrates & Fat Storage

🎧 Discussions / audio

Billy's 6000 kcal Experiment Why Diets Stop Working Why Hunger Isn't Weakness Why Athletes Under-Eat
🏃

Movement

Match movement to readiness, build capacity and avoid doing more than the body can support.

2 chapter blocks24 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 1

Movement — Foundation

Movement as capacity building, not calorie punishment.

1
Welcome — What Movement Is Actually For
2
Movement Isn't Exercise
3
Why More Exercise Doesn't Mean More Fat Loss
4
The Cardio Trap
5
Strength Comes Before Size
6
Muscle Is A Metabolic Organ
7
Power Is The First Thing We Lose With Age
8
Braking and Control
9
Minimum Effective Dose
10
Training Must Be Fuelled
11
Choosing Training Based On Your Energy State
12
Movement Hub
13
Movement Is An Investment In Your Future
14
Final Summary
Course 1

Movement — Application

Help members choose a level, build a week and adjust without burnout.

1
Choose Your Level
2
Build A Weekly Plan
3
Use MED
4
Avoid The Cardio Trap
5
Low Energy Days
6
Stay Consistent
7
Progress Without Burnout
8
Adjust Training
9
Track Progress
10
Build Strength That Lasts

📖 Supporting articles

Constrained Energy & Exercise Explosive Sports & Fuel Use Sarcopenia Muscle As An Endocrine Organ MED Training

🎧 Discussions / audio

Why More Exercise Isn't Better Bike Trials & Metabolism The Biggest Exercise Myths
💧

Hydration

Make hydration contextual: energy, food water, metabolic water, electrolytes and sweat.

2 chapter blocks21 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 1

Hydration — Foundation

Visual, practical and linked to the report.

1
Welcome
2
Hydration Begins With Energy
3
Drink More Water Myth
4
Too Much Water
5
Sodium
6
Sodium-Potassium Pump
7
Chloride & Acid Balance
8
Sweat & Exercise
9
Signs Hydration Is Off
10
Hydration Calculator
11
Final Summary
Course 1

Hydration — Application

Turn fluid and electrolyte insight into simple daily habits.

1
Calculate Fluid Needs
2
Structure Hydration
3
Use Sodium Correctly
4
Balance Electrolytes
5
Hydrate Around Exercise
6
Spot Under-Hydration
7
Fix Over-Hydration
8
Biofeedback Instead Of Rules
9
Adjust Hydration
10
Make Hydration Automatic

📖 Supporting articles

Food Water Metabolic Water Electrolytes Acid/Base Balance Sweat Science Nix Explained Potassium

🎧 Discussions / audio

Biggest Hydration Myths Why Two Litres Isn't A Rule Athlete Hydration Mistakes
🌙

Sleep

Teach sleep as recovery capacity, not another score to chase.

2 chapter blocks24 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 2

Sleep & Recovery — Foundation

Mostly audio-first with calm graphics; users may consume this while tired.

1
Welcome
2
You Don't Recover During Training
3
Why You Feel Tired But Can't Sleep
4
Sleep Is A Nervous System State
5
The Cortisol Misunderstanding
6
Why Under-Eating Disrupts Sleep
7
Blood Sugar Stability & Sleep
8
Temperature, Metabolism & Sleep
9
Why You Wake At 3am
10
Should You Eat Before Bed?
11
Why You Feel Worse After A Good Night's Sleep
12
Alcohol, Caffeine & Sleep
13
How To Improve Sleep Without Obsessing
14
Final Summary
Course 2

Sleep — Application

Practical, mostly audio and simple graphics.

1
Set Up Your Environment
2
Use Light Properly
3
Build A Night Routine
4
Improve Sleep Through Energy Intake
5
Use Food Timing
6
What To Do When You Can't Sleep
7
What To Do When You Wake At 3am
8
Tired But Can't Switch Off
9
Track Sleep Without Obsession
10
Build A Repeatable Sleep System

📖 Supporting articles

Cortisol Sleep Architecture Blood Sugar Alcohol Caffeine Temperature & Sleep

🎧 Discussions / audio

Recovery Is Underrated Biggest Sleep Myths
🫁

Breathing

Use breathing as a regulation tool, not another thing to overthink.

2 chapter blocks24 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 2

Breathing — Foundation

Mostly graphics and audio. Only film practical demonstrations.

1
Welcome
2
Why You Can't Relax
3
Why You Feel Short Of Breath
4
Why Cardio Doesn't Always Fix Fitness
5
The CO₂ Misunderstanding
6
Why Stress Changes Breathing
7
Why Low Energy Makes Breathing Worse
8
Mouth vs Nasal Breathing
9
Why You Feel Worse Breathing More
10
Breathing, Anxiety & The Wired Feeling
11
Why You Don't Need To Train Your Breathing
12
What Good Breathing Actually Looks Like
13
How To Improve Breathing Without Thinking About It
14
Final Summary
Course 2

Breathing — Application

Tools, simple graphics and low-screen coaching.

1
Assess Your Breathing
2
When To Use Breathing Methods
3
Reset Your Breathing
4
Down-Regulate Stress
5
Build CO₂ Tolerance
6
Use CO₂ & Rebreathing
7
Use Breathing Before Sleep
8
Breathe During Exercise
9
Track Improvement
10
Make Better Breathing Automatic

📖 Supporting articles

CO₂ Physiology Buteyko Rebreathing Hyperventilation Breathing During Exercise

🎧 Discussions / audio

Why Deep Breathing Can Make You Worse Anxiety & Breathing
🧠

Mindspace

Turn psychology into state, capacity and practical action rather than willpower pressure.

3 chapter blocks25 lessons/resources 1 foundation 1 application

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Course 2

Mindspace — Foundation

Primarily audio for walking, driving and reflection.

1
Welcome
2
Thoughts Are Not The Problem
3
State vs Mindset
4
Why You Feel Unmotivated
5
Why You Feel Anxious
6
Why You Overthink
7
Why Willpower Isn't Real
8
Why You're Not Consistent
9
Why You Keep Resetting
10
Why You Feel Overwhelmed
11
Caffeine, Alcohol & Coping
12
Why You Don't Feel Like Yourself
13
How Your Mind Improves Without Forcing It
14
Final Summary
Course 2

Mindspace — Application

Authentic founder discussions and audio coaching.

1
Know What State You're In
2
Decide Today's Actions
3
Build A Day That Doesn't Collapse
4
What To Do When Your Routine Breaks
5
Why You Keep Starting Over
6
Stop Overthinking & Act Clearly
7
Adjust Without Second Guessing
8
Stop Letting Other Advice Derail You
9
Why Fixing Yourself Is The Problem
10
Stay Stable When Life Isn't
Course 2

Final Integration

Close by returning the user to the system.

1
Final Integration Video

📖 Supporting articles

Motivation vs Capacity Decision Fatigue Stress Physiology Habit Formation Sensory Load Modern Environment

🎧 Discussions / audio

Why Discipline Fails Why Everyone Starts Again Monday Living In A High-Stress World
📚

Research Library

Evidence, references and deeper mechanisms live here so the main product stays light.

3 chapter blocks22 lessons/resources

How this chapter works

Members arrive here from their report recommendation. The goal is to show the relevant foundation, practical lessons, deeper articles and founder conversations without making it feel like a numbered course.

Library

Energy Research

For enthusiasts and credibility, not compulsory viewing.

1
What Is EPK?
2
Needs Adjusted EPK
3
Reality Gap
4
Constrained Energy Expenditure
5
Herman Pontzer
6
RED-S
7
DNL
8
Randle Cycle
9
Appetite Regulation
10
Carbohydrates & Fat Storage
Library

Movement Research

Training science and physiology.

1
Constrained Energy & Exercise
2
Explosive Sports & Fuel Use
3
Sarcopenia
4
Muscle As An Endocrine Organ
5
MED Training
Library

Hydration Research

Fluid, electrolytes and sweat science.

1
Food Water
2
Metabolic Water
3
Electrolytes
4
Acid/Base Balance
5
Sweat Science
6
Nix Explained
7
Potassium

Member Login

Admin groundwork

Phase 1: single-file app app using CSV upload and local report generation.
Phase 2: Supabase users, stored uploads, daily data table and saved weekly reports.
Phase 3: Terra webhook receiver to replace manual CSV upload.
Phase 4: React Native / Expo iOS and Android apps using the same backend.

Suggested database tables later

TablePurpose
profilesUser name, email, settings and current programme status
raw_importsOriginal CSV/API payloads so reports can be regenerated
daily_metricsCalories, macros, body, activity, hydration and WHOOP-derived totals
weekly_reportsEPK, hydration, movement, readiness, flags and PDF/report text
education_progressCompleted lessons and next recommended content
ResearchLesson 1 / 5Video hosted here

How to Read Nutrient Reference Values

Research lessons explain what each value means, what the limits of standardised references are, and how to use the result as a guide for further investigation.

📄 Research notes
📚 References
📝 Investigation worksheet

Upload / Assessment

Step 1: Your basic details (RMR)

Safety protection

Low-weight / eating-disorder risk check

This calculator is not a medical or eating-disorder screening tool. These checks switch the app into restore-first mode where it avoids restriction, weight-loss or compensatory training guidance.

Step 2: Activity level (PAL) including physical and mental strain

Mental strain counts because it increases recovery demand. If sleep is poor, stress is high, and you are under-fuelled, your day often behaves like a higher PAL even if steps are modest.

At over 25% fat, effective status becomes amber. At over 35% fat, effective status becomes red. This is a macro-rebalancing flag, not an instruction to eat less.

Step 3: Fixed 5-day Cronometer input

Enter each day’s total calories plus macro calories from Cronometer. Cronometer can show carbs, protein and fat as kcal, which makes the split easier for users to copy across. If you upload a CSV that contains grams, the app converts those grams into macro kcal automatically.

CSV upload option: this will fill the 5 most recent complete days and exclude today if it appears incomplete.

Step 4: Hydration context

This section uses the Cronometer energy and macro data above. It estimates fluid support from food water and metabolic water, then suggests the remaining drinking-fluid range. It is not a medical fluid prescription.

Optional: Nix Hydration Biosensor session data
Use this only when the user has worn the sensor for a specific training session. It refines session hydration guidance; it does not replace the daily EPK calculation.

Step 5: Biofeedback

These do not override the numbers, but they help place them in real physiology.

Summary

Traffic-light decision

Complete the calculator to select your track.

Your energy picture

Dot 1 = intake energy position. Dot 2 = required EPK position.

Visualise it

Biofeedback

Hydration readiness

Movement Hub / Whoop AI programme selection

Nutrition depth from Cronometer

When your Cronometer CSV includes these columns, the app now reads them automatically. If a column is missing, it simply shows as unavailable rather than breaking the report.

Macro pie chart

Fat-type pie chart

Micronutrient support

Meal distribution & food variety

EPK Coach decision engine

Readiness Score

Risk flags

Pattern recognition

Macro optimiser

Recommended lessons & tools

Day-by-day

Your next 30 days

Send this to your coach

This report can be copied, saved as PDF, or emailed to yourself with Billy copied in.


    
`; } function downloadPdf(){ if(!latest) calculate(); if(!latest) return; const w = window.open('', '_blank'); if(!w){ alert('Popup blocked. Please allow popups for this site, then try Download PDF Report again.'); return; } w.document.open(); w.document.write(reportHtml()); w.document.close(); } if($('calcBtn')) $('calcBtn').addEventListener('click', calculate); $('copyBtn').addEventListener('click',copyReport); $('pdfBtn').addEventListener('click',downloadPdf); $('copyBtnBottom').addEventListener('click',copyReport); $('pdfBtnBottom').addEventListener('click',downloadPdf); if($('saveReportBtn')) $('saveReportBtn').addEventListener('click',saveCurrentReport); if($('saveReportBtnBottom')) $('saveReportBtnBottom').addEventListener('click',saveCurrentReport); $('emailBtnBottom').addEventListener('click',emailReport); renderSavedReports(); $('csvFile').addEventListener('change', async e => { const file=e.target.files[0]; if(!file) return; const text=await file.text(); const rows=parseCSV(text); const days=getFiveCompleteDays(extractDays(rows)); importedDays = days; days.forEach((d,i)=>{ const x=i+1; $(`d${x}kcal`).value = r(d.kcal); $(`d${x}carb`).value = r(d.carb); $(`d${x}fat`).value = r(d.fat); $(`d${x}protein`).value = r(d.protein); }); }); function todayISO(){ return new Date().toISOString().slice(0,10); } function parseCSV(text){ const out=[]; let row=[], cell='', q=false; for(let i=0;iterms.some(t=>h.includes(t))); } function normDate(s){ s=String(s||'').trim(); const iso=s.match(/^(\d{4})-(\d{2})-(\d{2})/); if(iso) return `${iso[1]}-${iso[2]}-${iso[3]}`; const uk=s.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/); if(uk){ const y=uk[3].length==2?'20'+uk[3]:uk[3]; return `${y}-${uk[2].padStart(2,'0')}-${uk[1].padStart(2,'0')}`; } const d=new Date(s); return isNaN(d)?'':d.toISOString().slice(0,10); } function getFiveCompleteDays(allDays){ let days = allDays.filter(d=>d.date < todayISO()).sort((a,b)=>a.date.localeCompare(b.date)); if(days.length > 5){ const last = days[days.length-1]; const prev = days.slice(Math.max(0, days.length-6), days.length-1).map(d=>d.kcal).filter(Boolean).sort((a,b)=>a-b); if(prev.length >= 3){ const median = prev[Math.floor(prev.length/2)]; // If the final export day is obviously partial, do not use it in the 5-day average. if(last.kcal < median * 0.70) days = days.slice(0,-1); } } return days.slice(-5); } function findAny(headers, terms){ return headers.findIndex(h => terms.some(t => h.includes(t))); } function valBy(headers,row,terms){ const ix = findAny(headers,terms); return ix >= 0 ? clean(row[ix]) : 0; } function textBy(headers,row,terms){ const ix = findAny(headers,terms); return ix >= 0 ? String(row[ix] || '').trim() : ''; } function extractDays(rows){ if(!rows.length) return []; const h=rows[0].map(norm); const di=find(h,['date']); const gi=find(h,['group','meal']); const ki=find(h,['energy','calories','kcal']); const ci=find(h,['carbs (g)','carbohydrate (g)','carb']); const fi=find(h,['fat (g)','lipid (g)','fat']); const pi=find(h,['protein (g)','protein']); if(di<0||ki<0) return []; const dataRows = rows.slice(1); const totalRows = gi >= 0 ? dataRows.filter(rw => String(rw[gi] || '').trim().toLowerCase() === 'total') : []; const mealRows = gi >= 0 ? dataRows.filter(rw => { const g = String(rw[gi] || '').trim().toLowerCase(); return g && g !== 'total' && !['biometrics','exercise','activity'].includes(g); }) : dataRows; const extraMap = new Map(); function ensure(date){ if(!extraMap.has(date)) extraMap.set(date,{date,meals:{},mealMacros:{},foods:[]}); return extraMap.get(date); } // Build meal distribution and food-variety data from non-total rows when present. // Cronometer can show repeated meal groups such as Breakfast, Snack, Lunch, Snack, Dinner, Snack. // When the CSV preserves that order, split repeated snack blocks into Snack 1 / Snack 2 / Snack 3 // so the app shows morning, afternoon and evening snacks separately instead of merging them. const mealState = new Map(); function mealLabelFor(date, rawGroup){ const group = rawGroup || 'Uncategorised'; const key = date; if(!mealState.has(key)) mealState.set(key,{last:'', snackN:0}); const state = mealState.get(key); const g = String(group).trim(); const lower = g.toLowerCase(); const isSnack = lower === 'snack' || lower === 'snacks'; let label = g || 'Uncategorised'; if(isSnack){ if(state.last !== 'snack') state.snackN += 1; label = `Snack ${state.snackN || 1}`; state.last = 'snack'; } else { state.last = lower || 'other'; } return label; } mealRows.forEach(rw => { const date = normDate(rw[di]); if(!date) return; const d = ensure(date); const rawGroup = gi >= 0 ? (String(rw[gi] || '').trim() || 'Uncategorised') : 'Diary'; const group = mealLabelFor(date, rawGroup); const kcal = clean(rw[ki]); if(kcal) d.meals[group] = (d.meals[group] || 0) + kcal; if(kcal || ci >= 0 || fi >= 0 || pi >= 0){ if(!d.mealMacros[group]) d.mealMacros[group] = {kcal:0, carb:0, protein:0, fat:0}; d.mealMacros[group].kcal += kcal || 0; d.mealMacros[group].carb += ci >= 0 ? (clean(rw[ci]) * 4) : 0; d.mealMacros[group].protein += pi >= 0 ? (clean(rw[pi]) * 4) : 0; d.mealMacros[group].fat += fi >= 0 ? (clean(rw[fi]) * 9) : 0; } const food = textBy(h,rw,['food name','food','name','item']); if(food && !['total','breakfast','lunch','dinner','snacks','snack'].includes(food.toLowerCase())) d.foods.push(food); }); function vitaminDugFromRow(headers,row){ const iu = valBy(headers,row,['vitamin d (iu)','vit d (iu)']); if(iu) return iu / 40; const ug = valBy(headers,row,['vitamin d (µg)','vitamin d (mcg)','vit d (µg)','vit d (mcg)']); if(ug) return ug; const generic = valBy(headers,row,['vitamin d','vit d']); if(!generic) return 0; // If the export has no unit in the header, large values are probably IU; small values are probably µg/mcg. return generic > 200 ? generic / 40 : generic; } function addExtras(d,row){ const e = ensure(d.date); const extras = { fibre: valBy(h,row,['fiber (g)','fibre (g)','fiber','fibre']), sugar: valBy(h,row,['sugars (g)','sugar (g)','sugar']), starch: valBy(h,row,['starch (g)','starch']), water: valBy(h,row,['water (g)','water (ml)','water']), sodium: valBy(h,row,['sodium (mg)','sodium']), potassium: valBy(h,row,['potassium (mg)','potassium']), magnesium: valBy(h,row,['magnesium (mg)','magnesium']), calcium: valBy(h,row,['calcium (mg)','calcium']), zinc: valBy(h,row,['zinc (mg)','zinc']), iron: valBy(h,row,['iron (mg)','iron']), vitaminC: valBy(h,row,['vitamin c (mg)','vit c','vitamin c']), vitaminD: vitaminDugFromRow(h,row), caffeine: valBy(h,row,['caffeine (mg)','caffeine']), alcohol: valBy(h,row,['alcohol (g)','alcohol']), saturatedFat: valBy(h,row,['saturated fat (g)','saturated (g)','saturates (g)','saturated fat','saturates']), monoFat: valBy(h,row,['monounsaturated fat (g)','monounsaturated (g)','mono-unsaturated fat (g)','monounsaturated fat','monounsaturated','mono fat']), pufaFat: valBy(h,row,['polyunsaturated fat (g)','polyunsaturated (g)','poly-unsaturated fat (g)','polyunsaturated fat','polyunsaturated','pufa']), omega3: valBy(h,row,['omega-3 (g)','omega 3 (g)','omega-3','omega 3','n-3']), omega6: valBy(h,row,['omega-6 (g)','omega 6 (g)','omega-6','omega 6','n-6']) }; Object.assign(d,e,extras); d.meals = e.meals || {}; d.mealMacros = e.mealMacros || {}; d.foods = Array.from(new Set(e.foods || [])); return d; } function build(sourceRows, sumRows){ const map=new Map(); sourceRows.forEach(rw=>{ const date=normDate(rw[di]); if(!date) return; if(!map.has(date)) map.set(date,{date,kcal:0,carb:0,fat:0,protein:0}); const d=map.get(date); if(sumRows){ d.kcal+=clean(rw[ki]); if(ci>=0)d.carb+=clean(rw[ci])*4; if(fi>=0)d.fat+=clean(rw[fi])*9; if(pi>=0)d.protein+=clean(rw[pi])*4; } else { d.kcal=clean(rw[ki]); if(ci>=0)d.carb=clean(rw[ci])*4; if(fi>=0)d.fat=clean(rw[fi])*9; if(pi>=0)d.protein=clean(rw[pi])*4; } addExtras(d,rw); }); return Array.from(map.values()).filter(d=>d.kcal>0).sort((a,b)=>a.date.localeCompare(b.date)); } // Cronometer Daily Summary exports often contain both meal rows and a duplicated Total row. // Prefer the Total row when present, otherwise sum meal rows by date. if(totalRows.length) return build(totalRows, false); return build(dataRows, true); } })();