// Calendar.jsx — cycle calendar with phases, ovulation, predictions and memorable days
(function () {
  const { useState, useMemo, useRef, useEffect, useCallback } = React;
  const { t, cycleMarksForRange, cycleMarksFromPeriods, currentCycleInfo, calculateCycle, formatDayMonth, PHASE_INFO, localISO, pluralDayRu } = window.AliaData;

  const PHASE_COLOR = { period:'#E8637A', fertile:'#16A8A8', ovulation:'#16A8A8', follicular:'#7FA8E0', luteal:'#C98BD4', delay:'#E8923D' };
  function phaseLabel(lang) {
    const ru = lang === 'ru';
    return {
      period:     ru ? 'Менструация' : 'Period',
      follicular: ru ? 'Фолликулярная фаза' : 'Follicular phase',
      fertile:    ru ? 'Фертильное окно' : 'Fertile window',
      ovulation:  ru ? 'Овуляция' : 'Ovulation',
      luteal:     ru ? 'Лютеиновая фаза' : 'Luteal phase',
      delay:      ru ? 'Задержка' : 'Delay',
    };
  }

  const C = {
    period:    '#E8637A',
    periodTxt: '#FFFFFF',
    fertile:   '#16A8A8',
    ovulation: '#16A8A8',
    delay:     '#E8923D',
  };

  const iso = d => localISO(d);
  const startOfMonth = (y, m) => new Date(y, m, 1);
  const daysInMonth = (y, m) => new Date(y, m + 1, 0).getDate();
  // Monday-first index for a Date
  const mondayIndex = d => (d.getDay() + 6) % 7;

  function todayISO() {
    const d = new Date(); d.setHours(0, 0, 0, 0); return iso(d);
  }

  // ── Symptom / mood / flow / event option tables ────────────────
  const FLOWS  = [['light','💧'], ['medium','💧💧'], ['heavy','💧💧💧']];
  const MOODS  = [['happy','😊'], ['calm','😌'], ['sad','😢'], ['anxious','😰'], ['irritable','😣']];
  const SYMS   = [['cramps','🤕'], ['headache','🤯'], ['tender','🫶'], ['bloating','🎈'], ['fatigue','😴'], ['acne','🩹']];
  const EVENTS = [['intimacy','❤️'], ['test','🧪'], ['doctor','🩺'], ['pill','💊'], ['anniversary','⭐'], ['note','📝']];

  function capFirst(k) { return k.charAt(0).toUpperCase() + k.slice(1); }
  function flowLabel(lang, k)  { return t('flow' + capFirst(k), lang); }
  function moodLabel(lang, k)  { return t('mood' + capFirst(k), lang); }
  function symLabel(lang, k)   { return t('sym' + capFirst(k), lang); }
  function evtLabel(lang, k)   { return t('evt' + capFirst(k), lang); }

  // payload helper — does this day have any user mark?
  function hasMark(p) {
    if (!p) return false;
    return !!(p.flow || p.mood || (p.symptoms && p.symptoms.length) || (p.events && p.events.length));
  }

  /* ── Phase info bottom sheet ───────────────────────────────────── */
  function PhaseInfoSheet({ lang, phase, onClose }) {
    const info = (PHASE_INFO[lang] || PHASE_INFO.ru)[phase];
    if (!info) return null;
    const color = PHASE_COLOR[phase] || 'var(--primary)';
    const s = {
      overlay: { position:'fixed', inset:0, background:'rgba(0,0,0,0.4)', zIndex:400, display:'flex', alignItems:'flex-end', backdropFilter:'blur(4px)' },
      sheet: { width:'100%', background:'var(--bg-card)', borderRadius:'24px 24px 0 0', padding:'18px 24px',
               paddingBottom:'calc(26px + env(safe-area-inset-bottom))', display:'flex', flexDirection:'column', gap:14,
               boxShadow:'0 -4px 24px rgba(0,0,0,0.15)', maxWidth:520, margin:'0 auto', maxHeight:'82vh', overflowY:'auto' },
      handle: { width:40, height:4, borderRadius:2, background:'var(--border)', margin:'0 auto' },
      head: { display:'flex', alignItems:'center', gap:12 },
      badge: { width:48, height:48, borderRadius:14, display:'flex', alignItems:'center', justifyContent:'center',
               fontSize:24, background: color + '22', flexShrink:0 },
      title: { fontSize:19, fontWeight:800, color: color },
      text: { fontSize:15, lineHeight:1.55, color:'var(--text)', fontWeight:500 },
      close: { padding:'14px 0', borderRadius:14, border:'none', background:'var(--primary-light)', color:'var(--primary)',
               fontSize:15, fontWeight:800, cursor:'pointer', fontFamily:'Nunito,sans-serif', marginTop:2 },
    };
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <div style={s.handle}></div>
          <div style={s.head}>
            <div style={s.badge}>{info.emoji}</div>
            <div style={s.title}>{info.title}</div>
          </div>
          <div style={s.text}>{info.text}</div>
          <button style={s.close} onClick={onClose}>{lang === 'ru' ? 'Понятно' : 'Got it'}</button>
        </div>
      </div>
    );
  }

  /* ── Bottom sheet for a single day ─────────────────────────────── */
  function DaySheet({ lang, dateISO, mark, payload, onSave, onClose, onPhaseInfo }) {
    const ru = lang === 'ru';
    const [flow, setFlow]   = useState(payload.flow || '');
    const [mood, setMood]   = useState(payload.mood || '');
    const [syms, setSyms]   = useState(payload.symptoms || []);
    const [events, setEvents] = useState(payload.events || []);

    const toggle = (arr, set, v) => set(arr.includes(v) ? arr.filter(x => x !== v) : [...arr, v]);

    const d = new Date(dateISO + 'T00:00:00');
    const dateLabel = d.getDate() + ' ' + t('calMonths', lang)[d.getMonth()].toLowerCase();

    const s = {
      overlay: { position:'fixed', inset:0, background:'rgba(0,0,0,0.4)', zIndex:300, display:'flex', alignItems:'flex-end', backdropFilter:'blur(4px)' },
      sheet: { width:'100%', background:'var(--bg-card)', borderRadius:'24px 24px 0 0', padding:'18px 22px',
               paddingBottom:'calc(24px + env(safe-area-inset-bottom))', display:'flex', flexDirection:'column', gap:14,
               boxShadow:'0 -4px 24px rgba(0,0,0,0.15)', maxWidth:520, margin:'0 auto', maxHeight:'82vh', overflowY:'auto' },
      handle: { width:40, height:4, borderRadius:2, background:'var(--border)', margin:'0 auto' },
      title: { fontSize:18, fontWeight:800, color:'var(--text)', textTransform:'capitalize' },
      cdsub: { fontSize:13, color:'var(--text-2)', fontWeight:600 },
      lbl: { fontSize:11, fontWeight:700, color:'var(--text-2)', letterSpacing:'0.5px', textTransform:'uppercase', marginBottom:9, display:'block' },
      chips: { display:'flex', flexWrap:'wrap', gap:8 },
      chip: (a) => ({ display:'flex', alignItems:'center', gap:6, padding:'9px 13px', borderRadius:13, border:'2px solid',
        borderColor: a ? 'var(--primary)' : 'var(--border)', background: a ? 'var(--primary-light)' : 'var(--bg)',
        color: a ? 'var(--primary)' : 'var(--text)', fontSize:13, fontWeight:700, cursor:'pointer', fontFamily:'Nunito,sans-serif' }),
      save: { padding:'15px 0', borderRadius:15, border:'none', background:'var(--primary)', color:'#fff', fontSize:16, fontWeight:800, cursor:'pointer', fontFamily:'Nunito,sans-serif', marginTop:4 },
    };

    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <div style={s.handle}></div>
          <div>
            <div style={s.title}>{dateLabel}</div>
            {mark && mark.phase && (
              <button onClick={() => onPhaseInfo(mark.isOvulation ? 'ovulation' : mark.phase)}
                style={{ display:'inline-flex', alignItems:'center', gap:5, marginTop:4, padding:'4px 10px', borderRadius:11,
                  border:'none', cursor:'pointer', fontFamily:'Nunito,sans-serif', fontSize:13, fontWeight:700,
                  background:(PHASE_COLOR[mark.isOvulation ? 'ovulation' : mark.phase] || 'var(--primary)') + '22',
                  color: PHASE_COLOR[mark.isOvulation ? 'ovulation' : mark.phase] || 'var(--primary)' }}>
                {(mark.phase === 'period' && mark.periodDay)
                  ? phaseLabel(lang).period + ' · ' + (ru ? 'день ' : 'day ') + mark.periodDay
                  : phaseLabel(lang)[mark.isOvulation ? 'ovulation' : mark.phase]}
                <span style={{ opacity:0.7 }}>ⓘ</span>
              </button>
            )}
          </div>

          <div>
            <span style={s.lbl}>{t('dayFlow', lang)}</span>
            <div style={s.chips}>
              {FLOWS.map(([k, e]) => (
                <button key={k} style={s.chip(flow === k)} onClick={() => setFlow(flow === k ? '' : k)}>
                  <span>{e}</span>{flowLabel(lang, k)}
                </button>
              ))}
            </div>
          </div>

          <div>
            <span style={s.lbl}>{t('dayMood', lang)}</span>
            <div style={s.chips}>
              {MOODS.map(([k, e]) => (
                <button key={k} style={s.chip(mood === k)} onClick={() => setMood(mood === k ? '' : k)}>
                  <span>{e}</span>{moodLabel(lang, k)}
                </button>
              ))}
            </div>
          </div>

          <div>
            <span style={s.lbl}>{t('daySymptoms', lang)}</span>
            <div style={s.chips}>
              {SYMS.map(([k, e]) => (
                <button key={k} style={s.chip(syms.includes(k))} onClick={() => toggle(syms, setSyms, k)}>
                  <span>{e}</span>{symLabel(lang, k)}
                </button>
              ))}
            </div>
          </div>

          <div>
            <span style={s.lbl}>{t('dayEvents', lang)}</span>
            <div style={s.chips}>
              {EVENTS.map(([k, e]) => (
                <button key={k} style={s.chip(events.includes(k))} onClick={() => toggle(events, setEvents, k)}>
                  <span>{e}</span>{evtLabel(lang, k)}
                </button>
              ))}
            </div>
          </div>

          <button style={s.save} onClick={() => onSave(dateISO, {
            flow, mood, symptoms: syms, events,
          })}>{t('saveBtn', lang)}</button>
        </div>
      </div>
    );
  }

  /* ── A single month grid ───────────────────────────────────────── */
  function MonthGrid({ lang, year, month, marks, logs, today, onDayTap }) {
    const total = daysInMonth(year, month);
    const lead = mondayIndex(startOfMonth(year, month));
    const cells = [];
    for (let i = 0; i < lead; i++) cells.push(null);
    for (let day = 1; day <= total; day++) cells.push(day);

    const st = {
      wrap: { padding:'4px 0 18px' },
      title: { fontSize:17, fontWeight:800, color:'var(--text)', textAlign:'center', margin:'10px 0 12px' },
      grid: { display:'grid', gridTemplateColumns:'repeat(7, 1fr)', rowGap:10 },
      cellWrap: { minHeight:46, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'flex-start', position:'relative' },
      cd: { fontSize:9, fontWeight:700, color:'var(--text-2)', height:11, lineHeight:'11px', marginBottom:1 },
    };

    function renderDay(day) {
      const d = new Date(year, month, day);
      const key = iso(d);
      const m = marks[key];
      const p = logs[key];
      const isToday = key === today;
      const marked = hasMark(p);

      // base cell styles — большая цифра = ДАТА, маленькая сверху = день цикла
      let circle = {
        width:34, height:34, borderRadius:'50%', display:'flex', alignItems:'center', justifyContent:'center',
        fontSize:14, fontWeight:700, color:'var(--text)', cursor:'pointer', position:'relative',
        border:'2px solid transparent', boxSizing:'border-box', lineHeight:1,
      };

      if (m && m.phase === 'delay') {
        circle.background = C.delay; circle.color = '#fff'; circle.fontWeight = 800;
      } else if (m && m.phase === 'period') {
        if (m.predicted) { circle.border = '2px dashed ' + C.period; circle.color = C.period; }
        else { circle.background = C.period; circle.color = C.periodTxt; }
      } else if (m && m.isOvulation) {
        circle.border = '2px dashed ' + C.ovulation; circle.color = C.ovulation; circle.fontWeight = 800;
      } else if (m && m.phase === 'fertile') {
        circle.color = C.fertile; circle.fontWeight = 800;
      }
      if (isToday) {
        circle.boxShadow = '0 0 0 2px var(--bg), 0 0 0 4px var(--text)';
      }

      return (
        <div key={key} style={st.cellWrap} onClick={() => onDayTap(key, m, p || {})}>
          <div style={st.cd}>{m && m.cycleDay ? m.cycleDay : ''}</div>
          <div style={circle}>{day}</div>
          {marked && <div style={{ width:5, height:5, borderRadius:3, background:'var(--text-2)', marginTop:2 }}></div>}
        </div>
      );
    }

    return (
      <div style={st.wrap}>
        <div style={st.title}>{t('calMonths', lang)[month] + ', ' + year}</div>
        <div style={st.grid}>
          {cells.map((c, idx) => c === null
            ? <div key={'e' + idx} style={st.cellWrap}></div>
            : renderDay(c))}
        </div>
      </div>
    );
  }

  /* ── Year overview (12 mini months) ────────────────────────────── */
  function YearGrid({ lang, year, marks, today, onMonthTap }) {
    const st = {
      grid: { display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:14, padding:'8px 0 18px' },
      mini: { cursor:'pointer', background:'var(--bg-card)', borderRadius:14, padding:'10px 8px', boxShadow:'0 2px 10px var(--shadow)' },
      mt: { fontSize:12, fontWeight:800, color:'var(--text)', textAlign:'center', marginBottom:6 },
      mg: { display:'grid', gridTemplateColumns:'repeat(7, 1fr)', rowGap:2 },
      dot: (bg, brd) => ({ width:11, height:11, margin:'0 auto', borderRadius:'50%', fontSize:7, lineHeight:'11px',
        textAlign:'center', background:bg || 'transparent', border: brd || 'none', color:'#fff', boxSizing:'border-box' }),
    };
    function miniMonth(month) {
      const total = daysInMonth(year, month);
      const lead = mondayIndex(startOfMonth(year, month));
      const cells = [];
      for (let i = 0; i < lead; i++) cells.push(null);
      for (let day = 1; day <= total; day++) cells.push(day);
      return (
        <div key={month} style={st.mini} onClick={() => onMonthTap(month)}>
          <div style={st.mt}>{t('calMonths', lang)[month]}</div>
          <div style={st.mg}>
            {cells.map((c, idx) => {
              if (c === null) return <div key={'e' + idx}></div>;
              const key = iso(new Date(year, month, c));
              const m = marks[key];
              let bg = 'transparent', brd = 'none', color = 'var(--text-2)';
              if (m && m.phase === 'delay') { bg = C.delay; color = '#fff'; }
              else if (m && m.phase === 'period') { if (m.predicted) { brd = '1px dashed ' + C.period; color = C.period; } else { bg = C.period; color = '#fff'; } }
              else if (m && (m.isOvulation || m.phase === 'fertile')) { brd = '1px solid ' + C.fertile; color = C.fertile; }
              return <div key={key} style={{ ...st.dot(bg, brd), color }}>{c}</div>;
            })}
          </div>
        </div>
      );
    }
    return <div style={st.grid}>{[0,1,2,3,4,5,6,7,8,9,10,11].map(miniMonth)}</div>;
  }

  /* ── Calendar screen ───────────────────────────────────────────── */
  function CalendarScreen({ lang, cycle, periods, logs, onSaveLog, onEditPeriod, onClose }) {
    const ru = lang === 'ru';
    const today = todayISO();
    const td = new Date(today + 'T00:00:00');
    const [view, setView]  = useState('month'); // 'month' | 'year'
    const [year, setYear]  = useState(td.getFullYear());
    const [daySheet, setDaySheet] = useState(null); // { dateISO, mark, payload }
    const [phaseSheet, setPhaseSheet] = useState(null); // phase key
    const info = useMemo(() => currentCycleInfo(periods, cycle), [periods, cycle]);
    const labels = phaseLabel(lang);
    const scrollRef = useRef(null);
    const todayRef = useRef(null);

    // Range of months to render: 6 back .. 12 forward
    const months = useMemo(() => {
      const list = [];
      const base = new Date(td.getFullYear(), td.getMonth(), 1);
      for (let i = -6; i <= 12; i++) {
        const d = new Date(base.getFullYear(), base.getMonth() + i, 1);
        list.push({ y: d.getFullYear(), m: d.getMonth() });
      }
      return list;
    }, [today]); // eslint-disable-line

    const marks = useMemo(() => {
      const first = months[0];
      const last = months[months.length - 1];
      const fromISO = iso(new Date(first.y, first.m, 1));
      const toISO = iso(new Date(last.y, last.m, daysInMonth(last.y, last.m)));
      return cycleMarksFromPeriods(periods, cycle, fromISO, toISO);
    }, [months, cycle, periods]);

    // year-view marks (full selected year)
    const yearMarks = useMemo(() => {
      return cycleMarksFromPeriods(periods, cycle, year + '-01-01', year + '-12-31');
    }, [year, cycle, periods]);

    const scrollToToday = useCallback(() => {
      if (todayRef.current && scrollRef.current) {
        todayRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
      }
    }, []);

    useEffect(() => {
      // jump to current month on first open (no animation)
      if (view === 'month' && todayRef.current) {
        todayRef.current.scrollIntoView({ block: 'center' });
      }
    }, [view]); // eslint-disable-line

    const handleDayTap = useCallback((dateISO, m, payload) => {
      setDaySheet({ dateISO, mark: m, payload });
    }, []);

    const handleSave = useCallback((dateISO, payload) => {
      onSaveLog(dateISO, payload);
      setDaySheet(null);
    }, [onSaveLog]);

    const st = {
      root: { position:'fixed', inset:0, zIndex:250, background:'var(--bg)', display:'flex', flexDirection:'column', fontFamily:'Nunito,sans-serif' },
      header: { display:'flex', alignItems:'center', justifyContent:'space-between', gap:10, padding:'12px 16px',
                paddingTop:'calc(12px + env(safe-area-inset-top))', background:'var(--bg-card)', borderBottom:'1px solid var(--border)', flexShrink:0 },
      close: { background:'var(--bg)', border:'none', borderRadius:10, width:38, height:38, fontSize:20, cursor:'pointer', color:'var(--text)' },
      toggle: { display:'flex', background:'var(--bg)', borderRadius:11, padding:3, gap:2 },
      tBtn: (a) => ({ padding:'7px 16px', borderRadius:9, border:'none', cursor:'pointer', fontFamily:'Nunito,sans-serif',
        fontSize:13, fontWeight:800, background: a ? 'var(--bg-card)' : 'transparent', color: a ? 'var(--primary)' : 'var(--text-2)',
        boxShadow: a ? '0 1px 4px var(--shadow)' : 'none' }),
      legend: { display:'flex', flexWrap:'wrap', gap:'6px 14px', padding:'10px 16px', background:'var(--bg-card)', borderBottom:'1px solid var(--border)', flexShrink:0 },
      legItem: { display:'flex', alignItems:'center', gap:6, fontSize:11, fontWeight:600, color:'var(--text-2)' },
      sw: (bg, brd) => ({ width:14, height:14, borderRadius:'50%', background:bg, border:brd || 'none', flexShrink:0 }),
      scroll: { flex:1, overflowY:'auto', WebkitOverflowScrolling:'touch', padding:'0 16px 16px' },
      yearNav: { display:'flex', alignItems:'center', justifyContent:'center', gap:24, padding:'12px 0 4px' },
      yearBtn: { background:'none', border:'none', fontSize:22, cursor:'pointer', color:'var(--primary)', fontWeight:900 },
      yearLbl: { fontSize:18, fontWeight:800, color:'var(--text)', minWidth:70, textAlign:'center' },
      todayFab: { position:'absolute', left:'50%', transform:'translateX(-50%)', bottom:'calc(86px + env(safe-area-inset-bottom))',
                  background:'var(--bg-card)', border:'1px solid var(--border)', borderRadius:22, padding:'10px 18px', fontSize:13,
                  fontWeight:800, color:'var(--text)', cursor:'pointer', fontFamily:'Nunito,sans-serif', boxShadow:'0 4px 16px var(--shadow)', zIndex:5 },
      footer: { flexShrink:0, padding:'12px 16px calc(14px + env(safe-area-inset-bottom))', background:'var(--bg-card)', borderTop:'1px solid var(--border)' },
      editBtn: { width:'100%', padding:'15px 0', borderRadius:15, border:'none', background:'var(--primary)', color:'#fff',
                 fontSize:15, fontWeight:800, cursor:'pointer', fontFamily:'Nunito,sans-serif' },
      weekdays: { display:'grid', gridTemplateColumns:'repeat(7, 1fr)', padding:'6px 0', position:'sticky', top:0,
                  background:'var(--bg)', zIndex:2 },
      wd: { textAlign:'center', fontSize:11, fontWeight:700, color:'var(--text-2)' },
      summary: { background:'var(--bg-card)', borderRadius:18, padding:'16px 18px', margin:'14px 0 6px',
                 boxShadow:'0 2px 12px var(--shadow)', display:'flex', flexDirection:'column', gap:12 },
      sumTop: { display:'flex', alignItems:'center', justifyContent:'space-between', gap:12 },
      sumDay: { fontSize:13, color:'var(--text-2)', fontWeight:600 },
      sumDayBig: { fontSize:26, fontWeight:900, color:'var(--text)', lineHeight:1.1 },
      sumPhase: (c) => ({ display:'inline-flex', alignItems:'center', gap:6, padding:'7px 13px', borderRadius:13,
        border:'none', cursor:'pointer', fontFamily:'Nunito,sans-serif', fontSize:13, fontWeight:800,
        background: c + '22', color: c }),
      bar: { height:8, borderRadius:5, background:'var(--primary-light)', overflow:'hidden' },
      barFill: (pct, c) => ({ height:'100%', width: Math.max(4, Math.min(100, pct)) + '%', background:c, borderRadius:5, transition:'width .3s' }),
      sumRow: { display:'flex', justifyContent:'space-between', fontSize:13 },
      hint: { fontSize:11, color:'var(--text-2)', textAlign:'center', fontWeight:600 },
    };

    const phaseC = info ? (PHASE_COLOR[info.phase] || 'var(--primary)') : 'var(--primary)';
    function ovulationLine() {
      if (!info) return null;
      if (info.isOvulationToday) return '🌟 ' + t('calOvulationToday', lang);
      if (info.daysToOvulation > 0) return t('calOvulationIn', lang) + ': ' + info.daysToOvulation + ' ' + t('days', lang);
      return t('calOvulationDone', lang);
    }
    const summaryCard = info ? (
      <div style={st.summary}>
        <div style={st.sumTop}>
          <div>
            <div style={st.sumDay}>{t('dayCycleDay', lang)}</div>
            <div style={st.sumDayBig}>{info.cycleDay} <span style={{ fontSize:14, fontWeight:700, color:'var(--text-2)' }}>{t('calCycleDayOf', lang)} {info.cycleLength}</span></div>
          </div>
          <button style={st.sumPhase(phaseC)} onClick={() => setPhaseSheet(info.phase)}>
            {labels[info.phase]} <span style={{ opacity:0.7 }}>ⓘ</span>
          </button>
        </div>
        <div style={st.bar}><div style={st.barFill((info.cycleDay / info.cycleLength) * 100, phaseC)}></div></div>
        {info.delayDays > 0 ? (
          <div style={{ background: C.delay + '22', borderRadius:12, padding:'10px 12px', display:'flex', alignItems:'center', gap:8 }}>
            <span style={{ fontSize:18 }}>⏳</span>
            <span style={{ color: C.delay, fontWeight:800, fontSize:14 }}>
              {ru ? `Задержка ${info.delayDays} ${pluralDayRu(info.delayDays)}` : `Period late by ${info.delayDays} ${info.delayDays === 1 ? 'day' : 'days'}`}
            </span>
          </div>
        ) : (
          <div style={st.sumRow}>
            <span style={{ color:'var(--text-2)', fontWeight:600 }}>{t('calNextPeriodIn', lang)}</span>
            <b style={{ color:'var(--text)' }}>{info.daysToNextPeriod} {t('days', lang)} · {formatDayMonth(info.nextPeriod, lang)}</b>
          </div>
        )}
        <div style={st.sumRow}>
          <span style={{ color:'var(--text-2)', fontWeight:600 }}>{ovulationLine()}</span>
          <b style={{ color:'var(--text)' }}>{formatDayMonth(info.ovulation, lang)}</b>
        </div>
        <div style={st.hint}>{t('calTapPhase', lang)}</div>
      </div>
    ) : null;

    return (
      <div style={st.root} className="screen-anim">
        <header style={st.header}>
          <button style={st.close} onClick={onClose}>✕</button>
          <div style={st.toggle}>
            <button style={st.tBtn(view === 'month')} onClick={() => setView('month')}>{t('calMonth', lang)}</button>
            <button style={st.tBtn(view === 'year')} onClick={() => setView('year')}>{t('calYear', lang)}</button>
          </div>
          <div style={{ width:38 }}></div>
        </header>

        <div style={st.legend}>
          <span style={st.legItem}><span style={st.sw(C.period)}></span>{t('calLegPeriod', lang)}</span>
          <span style={st.legItem}><span style={st.sw('transparent', '2px solid ' + C.fertile)}></span>{t('calLegFertile', lang)}</span>
          <span style={st.legItem}><span style={st.sw('transparent', '2px dashed ' + C.ovulation)}></span>{t('calLegOvulation', lang)}</span>
          <span style={st.legItem}><span style={st.sw('transparent', '2px dashed ' + C.period)}></span>{t('calLegPredicted', lang)}</span>
          <span style={st.legItem}><span style={{ ...st.sw('var(--text-2)'), width:7, height:7 }}></span>{t('calLegMark', lang)}</span>
        </div>

        {view === 'month' ? (
          <div style={st.scroll} ref={scrollRef}>
            {summaryCard}
            <div style={st.weekdays}>
              {t('calWeekdays', lang).map((w, i) => <div key={i} style={st.wd}>{w}</div>)}
            </div>
            {months.map(({ y, m }) => {
              const isCurrent = y === td.getFullYear() && m === td.getMonth();
              return (
                <div key={y + '-' + m} ref={isCurrent ? todayRef : null}>
                  <MonthGrid lang={lang} year={y} month={m} marks={marks} logs={logs} today={today} onDayTap={handleDayTap} />
                </div>
              );
            })}
          </div>
        ) : (
          <div style={st.scroll}>
            <div style={st.yearNav}>
              <button style={st.yearBtn} onClick={() => setYear(year - 1)}>‹</button>
              <span style={st.yearLbl}>{year}</span>
              <button style={st.yearBtn} onClick={() => setYear(year + 1)}>›</button>
            </div>
            <YearGrid lang={lang} year={year} marks={yearMarks} today={today}
              onMonthTap={() => { setView('month'); }} />
          </div>
        )}

        {view === 'month' && (
          <button style={st.todayFab} onClick={scrollToToday}>↓ {t('calBackToToday', lang)}</button>
        )}

        <div style={st.footer}>
          <button style={st.editBtn} onClick={onEditPeriod}>{t('calEditPeriod', lang)}</button>
        </div>

        {daySheet && (
          <DaySheet lang={lang} dateISO={daySheet.dateISO} mark={daySheet.mark} payload={daySheet.payload}
            onSave={handleSave} onClose={() => setDaySheet(null)}
            onPhaseInfo={ph => setPhaseSheet(ph)} />
        )}
        {phaseSheet && (
          <PhaseInfoSheet lang={lang} phase={phaseSheet} onClose={() => setPhaseSheet(null)} />
        )}
      </div>
    );
  }

  /* ── Period editor (tap-to-toggle menstruation days) ───────────── */
  function expandPeriodsToSet(periods, profile) {
    const set = {};
    const periodLen = (profile && profile.period_length) || 5;
    // Не предзаполняем будущие дни: для периода без даты окончания разворачиваем
    // только до сегодня. Иначе текущий период «без конца» помечал бы 4 будущих дня,
    // и при снятии сегодняшнего дня они оставались бы как месячные на будущее.
    const today = new Date(todayISO() + 'T00:00:00');
    (periods || []).forEach(p => {
      const s = (typeof p === 'string') ? p : (p && (p.start_date || p.start));
      if (!s) return;
      const sd = new Date(s + 'T00:00:00');
      if (isNaN(sd.getTime())) return;
      let endd;
      if (p && p.end_date) { endd = new Date(p.end_date + 'T00:00:00'); }
      else { endd = new Date(sd.getTime() + (periodLen - 1) * 86400000); }
      if (endd.getTime() > today.getTime()) endd = today;
      for (let d = new Date(sd); d.getTime() <= endd.getTime(); d = new Date(d.getTime() + 86400000)) {
        set[iso(d)] = true;
      }
    });
    return set;
  }

  function setToEpisodes(set) {
    const dates = Object.keys(set).filter(k => set[k]).sort();
    const episodes = [];
    let cur = null;
    dates.forEach(k => {
      const d = new Date(k + 'T00:00:00');
      if (cur && (d.getTime() - new Date(cur.end + 'T00:00:00').getTime()) === 86400000) {
        cur.end = k;
      } else {
        cur = { start: k, end: k };
        episodes.push(cur);
      }
    });
    return episodes.map(e => ({ start_date: e.start, end_date: e.end }));
  }

  function PeriodEditScreen({ lang, periods, cycle, onSave, onClose }) {
    const today = todayISO();
    const td = new Date(today + 'T00:00:00');
    const [sel, setSel] = useState(() => expandPeriodsToSet(periods, cycle));
    const todayRef = useRef(null);

    const months = useMemo(() => {
      const list = [];
      const base = new Date(td.getFullYear(), td.getMonth(), 1);
      for (let i = -12; i <= 2; i++) {
        const d = new Date(base.getFullYear(), base.getMonth() + i, 1);
        list.push({ y: d.getFullYear(), m: d.getMonth() });
      }
      return list;
    }, [today]); // eslint-disable-line

    useEffect(() => { if (todayRef.current) todayRef.current.scrollIntoView({ block: 'center' }); }, []);

    const toggle = key => setSel(s => { const n = { ...s }; if (n[key]) delete n[key]; else n[key] = true; return n; });

    const st = {
      root: { position:'fixed', inset:0, zIndex:260, background:'var(--bg)', display:'flex', flexDirection:'column', fontFamily:'Nunito,sans-serif' },
      header: { display:'flex', alignItems:'center', justifyContent:'space-between', padding:'12px 18px',
                paddingTop:'calc(12px + env(safe-area-inset-top))', background:'var(--bg-card)', borderBottom:'1px solid var(--border)', flexShrink:0 },
      cancel: { background:'none', border:'none', fontSize:15, fontWeight:700, color:'var(--text-2)', cursor:'pointer', fontFamily:'Nunito,sans-serif' },
      title: { fontSize:16, fontWeight:800, color:'var(--text)' },
      save: { background:'none', border:'none', fontSize:15, fontWeight:800, color:'var(--primary)', cursor:'pointer', fontFamily:'Nunito,sans-serif' },
      hint: { fontSize:12, color:'var(--text-2)', fontWeight:600, textAlign:'center', padding:'10px 16px', background:'var(--bg-card)', borderBottom:'1px solid var(--border)' },
      scroll: { flex:1, overflowY:'auto', WebkitOverflowScrolling:'touch', padding:'0 16px 24px' },
      weekdays: { display:'grid', gridTemplateColumns:'repeat(7, 1fr)', padding:'6px 0', position:'sticky', top:0, background:'var(--bg)', zIndex:2 },
      wd: { textAlign:'center', fontSize:11, fontWeight:700, color:'var(--text-2)' },
      mTitle: { fontSize:16, fontWeight:800, color:'var(--text)', textAlign:'center', margin:'12px 0 10px' },
      grid: { display:'grid', gridTemplateColumns:'repeat(7, 1fr)', rowGap:6 },
      cell: { aspectRatio:'1 / 1', display:'flex', alignItems:'center', justifyContent:'center', position:'relative' },
    };

    function dayCircle(on, isToday) {
      return {
        width:36, height:36, borderRadius:'50%', display:'flex', alignItems:'center', justifyContent:'center',
        fontSize:14, fontWeight:700, cursor:'pointer', boxSizing:'border-box', lineHeight:1,
        background: on ? C.period : 'transparent', color: on ? '#fff' : 'var(--text)',
        border: on ? 'none' : '2px solid var(--border)',
        boxShadow: isToday ? '0 0 0 2px var(--bg), 0 0 0 4px var(--text)' : 'none',
      };
    }

    function monthGrid(y, m) {
      const total = daysInMonth(y, m);
      const lead = mondayIndex(startOfMonth(y, m));
      const cells = [];
      for (let i = 0; i < lead; i++) cells.push(null);
      for (let day = 1; day <= total; day++) cells.push(day);
      const isCurrent = y === td.getFullYear() && m === td.getMonth();
      return (
        <div key={y + '-' + m} ref={isCurrent ? todayRef : null}>
          <div style={st.mTitle}>{t('calMonths', lang)[m] + ', ' + y}</div>
          <div style={st.grid}>
            {cells.map((c, idx) => {
              if (c === null) return <div key={'e' + idx} style={st.cell}></div>;
              const key = iso(new Date(y, m, c));
              const future = new Date(y, m, c).getTime() > td.getTime();
              return (
                <div key={key} style={st.cell}>
                  <div style={{ ...dayCircle(!!sel[key], key === today), opacity: future ? 0.4 : 1 }}
                    onClick={() => { if (!future) toggle(key); }}>{c}</div>
                </div>
              );
            })}
          </div>
        </div>
      );
    }

    return (
      <div style={st.root} className="screen-anim">
        <header style={st.header}>
          <button style={st.cancel} onClick={onClose}>{lang === 'ru' ? 'Отмена' : 'Cancel'}</button>
          <div style={st.title}>{t('calEditPeriod', lang)}</div>
          <button style={st.save} onClick={() => onSave(setToEpisodes(sel))}>{t('saveBtn', lang)}</button>
        </header>
        <div style={st.hint}>{lang === 'ru' ? 'Нажмите на дни, когда шли месячные' : 'Tap the days you had your period'}</div>
        <div style={st.scroll}>
          <div style={st.weekdays}>
            {t('calWeekdays', lang).map((w, i) => <div key={i} style={st.wd}>{w}</div>)}
          </div>
          {months.map(({ y, m }) => monthGrid(y, m))}
        </div>
      </div>
    );
  }

  Object.assign(window, { CalendarScreen, PhaseInfoSheet, PeriodEditScreen });
})();
