.hhc-ovu{--ink:#1D1D1F;--mut:#6E6E73;--grey:#F5F5F7;--line:#E5E5EA;--acc:#C2185B;--pur:#7E3FB8;--lav:#E9DDF7;width:100%;font-family:Inter,system-ui,sans-serif;color:var(--ink)}
.hhc-ovu *{box-sizing:border-box}
.hhc-ovu p{margin:0}
.hhc-ovu em{font-style:normal}
.hhc-ovu .card{background:var(--grey);border-radius:28px;padding:32px}
.hhc-ovu .inputs{display:grid;grid-template-columns:1.2fr 1fr 1fr;gap:20px}
.hhc-ovu label{display:block;margin:0 0 8px;font-size:13px;font-weight:600;color:var(--mut)}
.hhc-ovu input[type=date]{width:100%;height:52px;margin:0;border:0!important;border-radius:999px;background:#fff;padding:0 20px;font:600 16px Inter,sans-serif;color:var(--ink);box-shadow:none;outline:none}
.hhc-ovu .step{display:flex;align-items:center;justify-content:space-between;height:52px;padding:4px;background:#fff;border-radius:999px}
.hhc-ovu .step button{width:44px;height:44px;padding:0;border:0;border-radius:50%;background:var(--grey);color:var(--ink);font:600 22px/1 Inter,sans-serif;cursor:pointer}
.hhc-ovu .step button:hover,.hhc-ovu .step button:focus{background:var(--line);color:var(--ink)}
.hhc-ovu .step span{font-size:17px;font-weight:700}
.hhc-ovu .help{margin-top:8px;font-size:12px;color:var(--mut)}
.hhc-ovu .note{display:none;margin-top:16px;padding:14px 18px;border-radius:16px;background:#FFF4E0;color:#7A4B00;font-size:14px;line-height:1.5}
.hhc-ovu .note a{color:#7A4B00;font-weight:700}
.hhc-ovu .priv{margin-top:14px;font-size:12px;color:var(--mut)}
.hhc-ovu .hero{margin-top:12px;padding:48px 24px;background:#000;border-radius:28px;text-align:center}
.hhc-ovu .hero .k{font-size:15px;font-weight:600;color:#A1A1A6}
.hhc-ovu .hero .big{margin:10px 0 12px;font:800 88px/1 'Inter Tight',Inter,sans-serif;letter-spacing:-.03em;color:#fff}
.hhc-ovu .hero .ph{font-size:19px;font-weight:600}
.hhc-ovu .stats{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:12px}
.hhc-ovu .stat{padding:24px;background:var(--grey);border-radius:24px}
.hhc-ovu .stat .l{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--mut)}
.hhc-ovu .dot{flex:none;width:10px;height:10px;border-radius:50%}
.hhc-ovu .stat .v{margin:10px 0 6px;font:800 30px/1.1 'Inter Tight',Inter,sans-serif;letter-spacing:-.02em}
.hhc-ovu .stat .s{font-size:14px;font-weight:600}
.hhc-ovu .sec{margin-top:64px}
.hhc-ovu .sechd{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:12px 16px;margin-bottom:20px}
.hhc-ovu h3.t{margin:0;font:800 32px/1.1 'Inter Tight',Inter,sans-serif;letter-spacing:-.02em;color:var(--ink)}
.hhc-ovu .legend{display:flex;flex-wrap:wrap;gap:14px;font-size:13px;color:var(--mut)}
.hhc-ovu .legend span{display:inline-flex;align-items:center;gap:6px}
.hhc-ovu .sw{display:inline-block;width:12px;height:12px;border-radius:4px}
.hhc-ovu .days{display:grid;grid-template-columns:repeat(7,1fr);gap:8px}
.hhc-ovu .d{padding:10px 6px;background:var(--grey);border:2px solid transparent;border-radius:14px;text-align:center}
.hhc-ovu .d small{display:block;font-size:11px;font-weight:600;color:var(--mut)}
.hhc-ovu .d b{display:block;margin-top:2px;font-size:15px}
.hhc-ovu .d.per{background:var(--acc);color:#fff}
.hhc-ovu .d.fer{background:var(--lav);color:var(--pur)}
.hhc-ovu .d.ovu{background:var(--pur);color:#fff}
.hhc-ovu .d.per small,.hhc-ovu .d.ovu small{color:rgba(255,255,255,.85)}
.hhc-ovu .d.fer small{color:var(--pur)}
.hhc-ovu .d.tod{border-color:#000}
.hhc-ovu table{width:100%;margin:0;border:0;border-collapse:collapse;font-size:15px}
.hhc-ovu th{padding:12px;border:0;border-bottom:1px solid var(--line);background:none;text-align:left;font-size:13px;font-weight:600;color:var(--mut)}
.hhc-ovu td{padding:16px 12px;border:0;border-bottom:1px solid var(--line);background:none;font-weight:600}
.hhc-ovu tr:nth-child(odd) td{background:none}
.hhc-ovu td.pa{color:var(--acc)}
@media (max-width:767px){
.hhc-ovu .card{padding:24px 20px}
.hhc-ovu .inputs{grid-template-columns:1fr;gap:16px}
.hhc-ovu .hero{padding:40px 20px}
.hhc-ovu .hero .big{font-size:56px}
.hhc-ovu .stats{grid-template-columns:1fr}
.hhc-ovu .days{grid-template-columns:repeat(5,1fr);gap:6px}
.hhc-ovu .d b{font-size:14px}
.hhc-ovu .sec{margin-top:48px}
.hhc-ovu h3.t{font-size:26px}
.hhc-ovu thead{display:none}
.hhc-ovu table,.hhc-ovu tbody,.hhc-ovu tr,.hhc-ovu td{display:block;width:100%}
.hhc-ovu tr{margin-bottom:10px;padding:16px 18px;background:var(--grey);border-radius:20px}
.hhc-ovu td,.hhc-ovu tr:nth-child(odd) td{display:flex;justify-content:space-between;gap:12px;padding:4px 0;border:0;background:none}
.hhc-ovu td:before{content:attr(data-l);font-weight:500;color:var(--mut)}
.hhc-ovu td.c{font-size:17px;font-weight:800}
.hhc-ovu td.c:before{content:none}
}
This cycle, day by day.
PeriodFertileOvulationToday
The next three cycles.
| Cycle | Fertile window | Ovulation (est.) | Period starts |
|---|
(function(){
/* ================= SETTINGS (safe to edit) =================
Only change the text inside the quotes '...' or the numbers.
WhatsApp number: 92 + your number, without + and without the first 0. */
var WHATSAPP_NUMBER = '920000000000';
var DEFAULT_CYCLE = 28, CYCLE_MIN = 21, CYCLE_MAX = 45;
var DEFAULT_PERIOD = 5, PERIOD_MIN = 2, PERIOD_MAX = 10;
var DEFAULT_DAYS_AGO = 11; /* first visit: last period = today minus this many days */
var NORMAL_CYCLE_MIN = 21, NORMAL_CYCLE_MAX = 35; /* outside this range = soft warning */
var TEXT = {
dayOf: 'Day {d} of {c}',
period: 'Period', fertile: 'Fertile window', ovulation: 'Ovulation day',
before: 'Before fertile window', after: 'After ovulation',
inDays: 'In {n} days', inDay: 'In 1 day', isToday: 'Today', daysAgo: '{n} days ago', dayAgo: '1 day ago',
fertileSub: '6 days, ending on ovulation',
thisCycle: 'This cycle', nextCycle: 'Next cycle', in2: 'In 2 cycles',
colCycle: 'Cycle', colFertile: 'Fertile window', colOvu: 'Ovulation (est.)', colPeriod: 'Period starts',
privacy: 'Your entries stay on this phone. Nothing is sent to us.',
warning: 'Cycles shorter than 21 or longer than 35 days can be a sign of PCOS or a thyroid issue. The
PCOS Test can help you prepare for a doctor\u2019s visit.',
late: 'Based on a {c}-day cycle, your period looks
{n} days late. The dates below assume a new cycle started on time. The
Late Period Calculator explains common reasons.',
future: 'That date is in the future. Please choose the first day of your most recent period.'
};
var TIPS = {
period: 'Iron first: add daal, chana or a little red meat with a squeeze of lemon. Rest is productive too.',
before: 'Energy usually rises now. Good days for strength training and higher-protein meals.',
fertile: 'Build every meal on protein and fibre. If you are trying to conceive, these are your most fertile days.',
after: 'Cravings may rise. Plan a protein snack like roasted chana or dahi before 5 pm.'
};
var WA_MESSAGE = 'Assalam o Alaikum! I used the Ovulation Calculator on HerHormonesCare.\nLast period: {last}. Cycle: {cycle} days. Ovulation est.: {ovu}.\nPlease make my cycle-based meal plan.';
/* ================= END SETTINGS ================= */
var KEY = 'hhc_cycle';
var root = (document.currentScript && document.currentScript.parentNode) || document.querySelector('.hhc-ovu');
if (!root) return;
function $(s){ return root.querySelector(s); }
var DN = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], MN = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
function mid(d){ return new Date(d.getFullYear(), d.getMonth(), d.getDate()); }
function add(d,n){ return new Date(d.getFullYear(), d.getMonth(), d.getDate()+n); }
function diff(a,b){ return Math.round((mid(b)-mid(a))/86400000); }
function iso(d){ return d.getFullYear()+'-'+('0'+(d.getMonth()+1)).slice(-2)+'-'+('0'+d.getDate()).slice(-2); }
function parse(s){ var p=String(s||'').split('-'); if(p.length!==3) return null; var d=new Date(+p[0],+p[1]-1,+p[2]); return isNaN(d.getTime())?null:d; }
function f1(d){ return d.getDate()+' '+MN[d.getMonth()]; }
function f2(d){ return DN[d.getDay()]+' '+f1(d); }
function fill(s,o){ return String(s).replace(/\{(\w+)\}/g,function(m,k){ return o[k]!=null?o[k]:m; }); }
function rel(n){ return n===0?TEXT.isToday:n===1?TEXT.inDay:n>1?fill(TEXT.inDays,{n:n}):n===-1?TEXT.dayAgo:fill(TEXT.daysAgo,{n:-n}); }
function clamp(v,a,b){ return Math.max(a,Math.min(b,v)); }
var st = { last: iso(add(mid(new Date()),-DEFAULT_DAYS_AGO)), cycle: DEFAULT_CYCLE, period: DEFAULT_PERIOD };
try { var sv=JSON.parse(localStorage.getItem(KEY)||'null'); if(sv && parse(sv.last)){ st.last=sv.last; st.cycle=clamp(+sv.cycle||DEFAULT_CYCLE,CYCLE_MIN,CYCLE_MAX); st.period=clamp(+sv.period||DEFAULT_PERIOD,PERIOD_MIN,PERIOD_MAX); } } catch(e){}
function save(){ try { localStorage.setItem(KEY, JSON.stringify(st)); } catch(e){} }
var inp = $('#hhc-ovu-last');
inp.value = st.last; inp.max = iso(new Date());
$('.priv').textContent = TEXT.privacy;
var steps = root.querySelectorAll('.step');
for (var i=0;i<steps.length;i++){ steps[i].addEventListener('click', function(e){ var b=e.target.closest('button'); if(!b) return; var k=this.getAttribute('data-k'), d=+b.getAttribute('data-d'); if(k==='cycle') st.cycle=clamp(st.cycle+d,CYCLE_MIN,CYCLE_MAX); else st.period=clamp(st.period+d,PERIOD_MIN,PERIOD_MAX); calc(); }); }
function onDate(){ if(parse(inp.value)){ st.last=inp.value; calc(); } }
inp.addEventListener('change', onDate); inp.addEventListener('input', onDate);
function note(sel,html){ var n=$(sel); n.innerHTML=html||''; n.style.display=html?'block':'none'; }
function each(sel,fn){ var l=document.querySelectorAll(sel); for(var j=0;j=0?Math.floor(since/C):0, start=add(last,k*C);
var cday=since>=0?since-k*C+1:null;
var next=add(start,C), ovu=add(next,-14), fs=add(ovu,-5);
function ph(d){ var n=diff(start,d)+1; if(n>=1&&n<=P) return 'period'; var o=diff(ovu,d); if(o===0) return 'ovulation'; if(o=0) return 'fertile'; return o<0?'before':'after'; }
var p=cday?ph(today):null;
var COL={period:'#FF5C8D',fertile:'#FFB3CB',ovulation:'#C9A3F0',before:'#A1A1A6',after:'#A1A1A6'};
$('.big').textContent=cday?fill(TEXT.dayOf,{d:cday,c:C}):'\u2014';
var pe=$('.ph'); pe.textContent=p?TEXT[p]:''; pe.style.color=p?COL[p]:'';
$('.s1v').textContent=f2(next); $('.s1s').textContent=rel(diff(today,next));
$('.s2v').textContent=f2(ovu); $('.s2s').textContent=rel(diff(today,ovu));
$('.s3v').textContent=f1(fs)+' \u2013 '+f1(ovu); $('.s3s').textContent=TEXT.fertileSub;
note('.nf', since<0?TEXT.future:'');
note('.nw', (CNORMAL_CYCLE_MAX)?TEXT.warning:'');
note('.nl', since-C>=1?fill(TEXT.late,{c:C,n:since-C}):'');
var h='';
for(var i=0;i<C;i++){ var d=add(start,i), c=ph(d), cl=c==='period'?'per':c==='fertile'?'fer':c==='ovulation'?'ovu':''; if(diff(d,today)===0) cl+=' tod'; h+='
Day '+(i+1)+''+f1(d)+'
'; }
$('.days').innerHTML=h;
var names=[TEXT.thisCycle,TEXT.nextCycle,TEXT.in2], r='';
for(var j=0;j<3;j++){ var s=add(start,j*C), n2=add(s,C), o2=add(n2,-14), f=add(o2,-5); r+='
| '+names[j]+' | '+f1(f)+' \u2013 '+f1(o2)+' | '+f2(o2)+' | '+f2(n2)+' |
'; }
$('.rows').innerHTML=r;
var tipKey=p==='ovulation'?'fertile':(p||'fertile');
each('.hhc-ovu-phase',function(el){ el.textContent=p?TEXT[p]:TEXT.fertile; });
each('.hhc-ovu-tip',function(el){ el.textContent=TIPS[tipKey]; });
var msg=fill(WA_MESSAGE,{last:f1(last),cycle:C,ovu:f2(ovu)});
each('.hhc-ovu-wa',function(a){ a.href='https://wa.me/'+WHATSAPP_NUMBER+'?text='+encodeURIComponent(msg); });
}
calc();
if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',calc); else setTimeout(calc,0);
})();