// App.jsx — root component + navigation (pregnancy / cycle / ttc modes)
(function () {
  const { useState, useCallback, useEffect, useRef } = React;
  const { t, calculateCurrentWeek, calculateCycle, GOALS, COLOR_SCHEMES, applyColorScheme } = window.AliaData;
  const localISO = window.AliaData.localISO || (d => d.toISOString().split('T')[0]);
  const todayISO = window.AliaData.todayISO || (() => localISO(new Date()));
  const formatDayMonth = window.AliaData.formatDayMonth || (iso => iso || '');
  const { isLoggedIn, logout: apiLogout, getProfile, updateProfile, saveCycle, getCycles, deleteCycle, getLogs, saveLog, getMe,
          getNotifications, markNotificationsRead } = window.AliaAPI;
  const { NotificationsSheet } = window;
  const { currentCycleInfo } = window.AliaData;

  /* ── SVG Icons ───────────────────────────────────────────────── */
  function IconHome({ size = 24 }) {
    return <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>;
  }
  function IconCompass({ size = 24 }) {
    return <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm2.5-10.5L9 11l-1.5 4.5L13 14l1.5-4.5z"/></svg>;
  }
  function IconTools({ size = 24 }) {
    return <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M4 7h16v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7zm5-3h6a2 2 0 0 1 2 2v1H7V6a2 2 0 0 1 2-2zm-1 9h8v-2H8v2z"/></svg>;
  }

  /* ── Baby Info Sheet ─────────────────────────────────────────── */
  function BabyInfoSheet({ lang, currentName, currentGender, onSave, onClose }) {
    const [name, setName]     = useState(currentName || '');
    const [gender, setGender] = useState(currentGender || 'unknown');
    const GENDERS = [
      { id:'unknown', ru:'Не знаем', en:'Unknown', emoji:'👶' },
      { id:'boy',     ru:'Мальчик',  en:'Boy',     emoji:'💙' },
      { id:'girl',    ru:'Девочка',  en:'Girl',    emoji:'💗' },
    ];
    const s = sheetStyles();
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{lang === 'ru' ? 'Имя и пол малыша' : "Baby's name & gender"}</div>
          <div>
            <label style={s.label}>{lang === 'ru' ? 'Имя малыша' : "Baby's name"}</label>
            <input style={s.input} type="text" value={name}
              placeholder={lang === 'ru' ? 'Ванечки (в родит. падеже)' : "Baby's name"}
              onChange={e => setName(e.target.value)} />
          </div>
          <div>
            <label style={s.label}>{lang === 'ru' ? 'Пол малыша' : 'Gender'}</label>
            <div style={s.genderRow}>
              {GENDERS.map(g => (
                <button key={g.id} style={s.genderBtn(gender===g.id)} onClick={() => setGender(g.id)}>
                  <span style={{fontSize:22}}>{g.emoji}</span>
                  <span>{lang === 'ru' ? g.ru : g.en}</span>
                </button>
              ))}
            </div>
          </div>
          <button style={s.saveBtn} onClick={() => onSave(name.trim(), gender)}>
            {lang === 'ru' ? 'Сохранить' : 'Save'}
          </button>
        </div>
      </div>
    );
  }

  /* ── Goal Sheet (переключение режима) ─────────────────────────── */
  function GoalSheet({ lang, currentGoal, onSave, onClose }) {
    const [goal, setGoal] = useState(currentGoal || 'pregnancy');
    const s = sheetStyles();
    const ru = lang === 'ru';
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{t('goalTitle', lang)}</div>
          {GOALS.map(g => (
            <button key={g.id} style={s.goalBtn(goal===g.id)} onClick={() => setGoal(g.id)}>
              <span style={{fontSize:24}}>{g.emoji}</span>
              <span>{ru ? g.ru : g.en}</span>
            </button>
          ))}
          <button style={s.saveBtn} onClick={() => onSave(goal)}>{t('saveBtn', lang)}</button>
        </div>
      </div>
    );
  }

  /* ── Cycle Settings Sheet ─────────────────────────────────────── */
  function CycleSettingsSheet({ lang, cycle, onSave, onClose }) {
    const [cycleLen, setCycleLen]   = useState(cycle.cycle_length || 28);
    const [periodLen, setPeriodLen] = useState(cycle.period_length || 5);
    const [luteal, setLuteal]       = useState(cycle.luteal_phase || '');
    const [last, setLast]           = useState(cycle.last_period || '');
    const s = sheetStyles();
    const today = todayISO();
    const clamp = (v, lo, hi, def) => {
      const n = Math.round(Number(v));
      if (!isFinite(n) || isNaN(n)) return def;
      return Math.max(lo, Math.min(hi, n));
    };
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{t('cycleSettings', lang)}</div>
          <div>
            <label style={s.label}>{t('labelLMP', lang)}</label>
            <input type="date" style={s.input} value={last} max={today} onChange={e => setLast(e.target.value)} />
          </div>
          <div style={{ display:'flex', gap:10 }}>
            <div style={{flex:1}}>
              <label style={s.label}>{t('cycleLength', lang)}</label>
              <input type="number" style={s.input} value={cycleLen} min={20} max={45} inputMode="numeric"
                onChange={e => setCycleLen(e.target.value)}
                onBlur={() => setCycleLen(clamp(cycleLen, 20, 45, 28))} />
            </div>
            <div style={{flex:1}}>
              <label style={s.label}>{t('periodLength', lang)}</label>
              <input type="number" style={s.input} value={periodLen} min={1} max={10} inputMode="numeric"
                onChange={e => setPeriodLen(e.target.value)}
                onBlur={() => setPeriodLen(clamp(periodLen, 1, 10, 5))} />
            </div>
          </div>
          <div>
            <label style={s.label}>{t('lutealPhase', lang)} ({lang==='ru'?'необяз.':'optional'})</label>
            <input type="number" style={s.input} value={luteal} min={9} max={16} placeholder="14" inputMode="numeric"
              onChange={e => setLuteal(e.target.value)}
              onBlur={() => setLuteal(luteal === '' ? '' : clamp(luteal, 9, 16, 14))} />
          </div>
          <div style={{ fontSize:12, color:'var(--text-2)', lineHeight:1.4 }}>
            {lang === 'ru' ? 'Цикл 20–45 дн., менструация 1–10 дн., лютеиновая фаза 9–16 дн.'
                           : 'Cycle 20–45 d, period 1–10 d, luteal phase 9–16 d.'}
          </div>
          <button style={s.saveBtn} onClick={() => {
            const pl = clamp(periodLen, 1, 10, 5);
            const cl = clamp(cycleLen, 20, 45, 28);
            onSave({
              cycle_length: cl,
              period_length: Math.min(pl, cl - 1),
              luteal_phase: luteal === '' ? null : clamp(luteal, 9, 16, 14),
              last_period: last || null,
            });
          }}>{t('saveBtn', lang)}</button>
        </div>
      </div>
    );
  }

  /* ── Settings Sheet ──────────────────────────────────────────── */
  function SettingsSheet({ lang, colorScheme, appMode, onColorScheme, onProfile, onLangToggle, onEditDate, onBabyInfo, onGoal, onCycle, onLegal, onLogout, onClose }) {
    const s = sheetStyles();
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{lang === 'ru' ? 'Настройки' : 'Settings'}</div>

          <div style={s.row} onClick={onProfile}>
            <span style={s.rowLabel}>{lang === 'ru' ? '👤 Профиль' : '👤 Profile'}</span><span style={s.rowValue}>›</span>
          </div>

          <div style={s.schemeSection}>
            <div style={s.schemeLbl}>{lang === 'ru' ? 'Цветовая тема' : 'Color theme'}</div>
            <div style={s.swatches}>
              {COLOR_SCHEMES.map(sc => (
                <div key={sc.id} style={s.swatch(colorScheme === sc.id, sc.light['--primary'])}
                  title={lang === 'ru' ? sc.nameRu : sc.nameEn} onClick={() => onColorScheme(sc.id)}></div>
              ))}
            </div>
          </div>

          <div style={s.row} onClick={onGoal}>
            <span style={s.rowLabel}>{t('goalTitle', lang)}</span><span style={s.rowValue}>›</span>
          </div>
          {appMode === 'pregnancy' ? (
            <div style={s.row} onClick={onBabyInfo}>
              <span style={s.rowLabel}>{lang === 'ru' ? 'Имя и пол малыша' : "Baby's name & gender"}</span><span style={s.rowValue}>›</span>
            </div>
          ) : (
            <div style={s.row} onClick={onCycle}>
              <span style={s.rowLabel}>{t('cycleSettings', lang)}</span><span style={s.rowValue}>›</span>
            </div>
          )}
          <div style={s.row} onClick={onLangToggle}>
            <span style={s.rowLabel}>{lang === 'ru' ? 'Язык' : 'Language'}</span>
            <span style={s.rowValue}>{lang === 'ru' ? 'Русский → EN' : 'English → RU'}</span>
          </div>
          {appMode === 'pregnancy' && (
            <div style={s.row} onClick={onEditDate}>
              <span style={s.rowLabel}>{t('editDate', lang)}</span><span style={s.rowValue}>›</span>
            </div>
          )}
          <div style={s.row} onClick={onLegal}>
            <span style={s.rowLabel}>{lang === 'ru' ? '⚖️ Правовая информация' : '⚖️ Legal'}</span><span style={s.rowValue}>›</span>
          </div>
          <div style={{ ...s.rowLast, marginTop:4 }} onClick={onLogout}>
            <span style={{ ...s.rowLabel, color:'#E05070' }}>{lang === 'ru' ? 'Выйти из аккаунта' : 'Sign out'}</span>
            <span style={{ fontSize:16 }}>↩</span>
          </div>
        </div>
      </div>
    );
  }

  /* ── Legal Sheets ────────────────────────────────────────────── */
  function LegalSheet({ lang, onOpenDoc, onClose }) {
    const s = sheetStyles();
    const docs = (window.AliaLegal && window.AliaLegal.docs) || [];
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{lang === 'ru' ? 'Правовая информация' : 'Legal'}</div>
          {docs.map(d => (
            <div key={d.id} style={s.row} onClick={() => onOpenDoc(d.id)}>
              <span style={s.rowLabel}>{d.icon + ' ' + d.title[lang]}</span><span style={s.rowValue}>›</span>
            </div>
          ))}
          <div style={{ fontSize:12, color:'var(--text-2)', lineHeight:1.5, marginTop:4 }}>
            {lang === 'ru'
              ? 'Приложение носит информационно-справочный характер и не заменяет консультацию врача.'
              : 'The app is for informational purposes only and does not replace medical advice.'}
          </div>
        </div>
      </div>
    );
  }

  function LegalDocSheet({ lang, docId, onBack, onClose }) {
    const s = sheetStyles();
    const docs = (window.AliaLegal && window.AliaLegal.docs) || [];
    const doc = docs.find(d => d.id === docId);
    if (!doc) return null;
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={{ ...s.sheet, maxHeight:'86vh' }} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <span onClick={onBack} style={{ fontSize:20, cursor:'pointer', color:'var(--text-2)' }}>‹</span>
            <div style={s.title}>{doc.icon + ' ' + doc.title[lang]}</div>
          </div>
          <div style={{ overflowY:'auto', whiteSpace:'pre-wrap', fontSize:14, lineHeight:1.65,
                        color:'var(--text)', WebkitOverflowScrolling:'touch' }}>
            {doc.body[lang]}
          </div>
        </div>
      </div>
    );
  }

  /* ── Profile Sheet ───────────────────────────────────────────── */
  function ProfileSheet({ lang, isGuest, goal, appMode, dueDate, currentWeek, cycle, onLogout, onClose }) {
    const ru = lang === 'ru';
    const s = sheetStyles();
    const [me, setMe] = useState(() => ({
      name:  localStorage.getItem('alia_name')  || '',
      email: localStorage.getItem('alia_email') || '',
      created_at: null,
    }));
    const [err, setErr] = useState(false);

    // Подтягиваем актуальные данные аккаунта из БД (заодно проверяем токен)
    useEffect(() => {
      if (isGuest || !isLoggedIn() || !getMe) return;
      getMe().then(d => {
        setMe(m => ({ ...m, ...d }));
        if (d.name != null)  localStorage.setItem('alia_name', d.name);
        if (d.email != null) localStorage.setItem('alia_email', d.email);
      }).catch(() => setErr(true));
    }, []); // eslint-disable-line

    const modeLabel = appMode === 'pregnancy'
      ? (ru ? 'Беременность' : 'Pregnancy')
      : appMode === 'ttc'
        ? (ru ? 'Планирование беременности' : 'Trying to conceive')
        : (ru ? 'Слежение за циклом' : 'Cycle tracking');
    const created = me.created_at ? new Date(me.created_at).toLocaleDateString(ru ? 'ru-RU' : 'en-US',
      { year:'numeric', month:'long', day:'numeric' }) : null;
    const displayName = (me.name || '').trim() || (isGuest ? (ru ? 'Гость' : 'Guest') : (ru ? 'Без имени' : 'No name'));
    const initial = (me.name || me.email || (isGuest ? 'G' : '?')).trim().charAt(0).toUpperCase();

    const ps = {
      head: { display:'flex', alignItems:'center', gap:14, margin:'4px 0 18px' },
      avatar: { width:60, height:60, borderRadius:'50%', background:'var(--primary)', color:'#fff',
                display:'flex', alignItems:'center', justifyContent:'center', fontSize:26, fontWeight:900, flexShrink:0 },
      name: { fontSize:20, fontWeight:900, color:'var(--text)' },
      sub:  { fontSize:14, color:'var(--text-2)', marginTop:2, wordBreak:'break-all' },
      badge: (ok) => ({ display:'inline-block', marginTop:6, fontSize:11.5, fontWeight:800, letterSpacing:'0.3px',
                borderRadius:20, padding:'3px 10px', color: ok ? '#2E7D5B' : '#B26A00',
                background: ok ? 'rgba(46,125,91,0.12)' : 'rgba(178,106,0,0.12)' }),
      note: { background:'var(--primary-light)', borderRadius:14, padding:'12px 14px', fontSize:13.5,
              color:'var(--text)', lineHeight:1.5, margin:'4px 0 14px' },
    };

    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{ru ? 'Профиль' : 'Profile'}</div>

          <div style={ps.head}>
            <div style={ps.avatar}>{initial}</div>
            <div style={{ minWidth:0 }}>
              <div style={ps.name}>{displayName}</div>
              {!isGuest && me.email && <div style={ps.sub}>{me.email}</div>}
              <span style={ps.badge(!isGuest)}>
                {isGuest ? (ru ? 'Гостевой режим' : 'Guest mode') : (ru ? '✓ Синхронизируется' : '✓ Synced')}
              </span>
            </div>
          </div>

          {isGuest ? (
            <div style={ps.note}>
              {ru ? 'Вы вошли как гость. Данные хранятся только на этом устройстве и не синхронизируются между устройствами. Создайте аккаунт, чтобы сохранять их в облаке.'
                  : 'You are in guest mode. Data is stored only on this device and is not synced across devices. Create an account to keep it in the cloud.'}
            </div>
          ) : (
            <>
              <div style={s.row}>
                <span style={s.rowLabel}>{ru ? 'Аккаунт' : 'Account'}</span>
                <span style={s.rowValue}>{err ? (ru ? 'нет связи' : 'offline') : (ru ? 'активен' : 'active')}</span>
              </div>
              {created && (
                <div style={s.row}>
                  <span style={s.rowLabel}>{ru ? 'Регистрация' : 'Member since'}</span>
                  <span style={s.rowValue}>{created}</span>
                </div>
              )}
            </>
          )}

          <div style={s.row}>
            <span style={s.rowLabel}>{ru ? 'Режим' : 'Mode'}</span>
            <span style={s.rowValue}>{modeLabel}</span>
          </div>
          {appMode === 'pregnancy' && dueDate && (
            <div style={s.row}>
              <span style={s.rowLabel}>{ru ? 'ПДР' : 'Due date'}</span>
              <span style={s.rowValue}>{new Date(dueDate).toLocaleDateString(ru ? 'ru-RU' : 'en-US')}{currentWeek ? ` · ${ru ? 'нед.' : 'wk'} ${currentWeek}` : ''}</span>
            </div>
          )}
          {appMode !== 'pregnancy' && cycle && cycle.last_period && (
            <div style={s.row}>
              <span style={s.rowLabel}>{ru ? 'Последние месячные' : 'Last period'}</span>
              <span style={s.rowValue}>{new Date(cycle.last_period).toLocaleDateString(ru ? 'ru-RU' : 'en-US')}</span>
            </div>
          )}

          <div style={{ ...s.rowLast, marginTop:4 }} onClick={onLogout}>
            <span style={{ ...s.rowLabel, color:'#E05070' }}>
              {isGuest ? (ru ? 'Создать аккаунт / войти' : 'Create account / sign in') : (ru ? 'Выйти из аккаунта' : 'Sign out')}
            </span>
            <span style={{ fontSize:16 }}>↩</span>
          </div>
        </div>
      </div>
    );
  }

  /* ── Edit Date Sheet ─────────────────────────────────────────── */
  function EditDateSheet({ lang, currentDueDate, onSave, onClose }) {
    const { calculateDueFromLMP } = window.AliaData;
    const [mode, setMode] = useState('pdr');
    const [val, setVal]   = useState(currentDueDate || '');
    const today  = todayISO();
    const maxPDR = localISO(new Date(Date.now() + 300 * 86400000));
    const s = sheetStyles();
    return (
      <div style={s.overlay} onClick={onClose}>
        <div style={s.sheet} onClick={e => e.stopPropagation()}>
          <span style={s.handle}></span>
          <div style={s.title}>{t('setDueDateTitle', lang)}</div>
          <div style={{ display:'flex', gap:8 }}>
            <button style={s.modeBtn(mode==='pdr')} onClick={() => { setMode('pdr'); setVal(''); }}>{t('inputModePDR', lang)}</button>
            <button style={s.modeBtn(mode==='lmp')} onClick={() => { setMode('lmp'); setVal(''); }}>{t('inputModeLMP', lang)}</button>
          </div>
          <input type="date" style={s.input} value={val}
            min={mode === 'pdr' ? today : localISO(new Date(Date.now() - 300 * 86400000))}
            max={mode === 'pdr' ? maxPDR : today}
            onChange={e => setVal(e.target.value)} />
          <button style={s.saveBtn} onClick={() => { if (!val) return; onSave(mode === 'lmp' ? calculateDueFromLMP(val) : val); }}>
            {t('btnContinue', lang)}
          </button>
        </div>
      </div>
    );
  }

  /* ── Cycle Home (режимы cycle / ttc) ──────────────────────────── */
  function CycleHomeScreen({ lang, goal, cycle, periods, onLogPeriod, onOpenSettings, onOpenCalendar, onOpenPhaseInfo }) {
    const ru = lang === 'ru';
    const info = currentCycleInfo(periods, cycle) || calculateCycle(cycle);
    const phaseLabel = {
      period:     ru ? 'Менструация' : 'Period',
      follicular: ru ? 'Фолликулярная фаза' : 'Follicular phase',
      fertile:    ru ? 'Фертильное окно' : 'Fertile window',
      luteal:     ru ? 'Лютеиновая фаза' : 'Luteal phase',
      delay:      ru ? 'Задержка' : 'Delay',
    };
    const phaseColor = { period:'#E8637A', fertile:'#3BAF82', follicular:'#7FA8E0', luteal:'#C98BD4', delay:'#E8923D' };
    const pluralDayRu = window.AliaData.pluralDayRu || (() => 'дн.');
    const st = {
      scroll:{ height:'100%', overflowY:'auto', WebkitOverflowScrolling:'touch', paddingBottom:'24px' },
      inner:{ padding:'20px 16px', display:'flex', flexDirection:'column', gap:14, maxWidth:480, margin:'0 auto' },
      ring:{ width:230, height:230, margin:'8px auto', borderRadius:'50%', display:'flex', flexDirection:'column',
             alignItems:'center', justifyContent:'center', color:'#fff',
             background: info ? `conic-gradient(${phaseColor[info.phase]||'var(--primary)'} ${(info.cycleDay/info.cycleLength)*360}deg, var(--primary-light) 0deg)` : 'var(--primary-light)' },
      ringInner:{ width:190, height:190, borderRadius:'50%', background:'var(--bg-card)', display:'flex',
                  flexDirection:'column', alignItems:'center', justifyContent:'center', gap:4 },
      bigNum:{ fontSize:44, fontWeight:900, color:'var(--text)' },
      phase:{ fontSize:15, fontWeight:800, color: info ? (phaseColor[info.phase]||'var(--primary)') : 'var(--text-2)' },
      sub:{ fontSize:13, color:'var(--text-2)' },
      card:{ background:'var(--bg-card)', borderRadius:18, padding:'16px 18px', boxShadow:'0 2px 12px var(--shadow)' },
      row:{ display:'flex', justifyContent:'space-between', padding:'9px 0', borderBottom:'1px solid var(--border)' },
      btn:{ padding:'15px 0', borderRadius:15, border:'none', background:'var(--primary)', color:'#fff',
            fontSize:16, fontWeight:800, cursor:'pointer', fontFamily:'Nunito,sans-serif', width:'100%' },
      btn2:{ padding:'13px 0', borderRadius:14, border:'2px solid var(--border)', background:'var(--bg-card)',
             color:'var(--text)', fontSize:14, fontWeight:700, cursor:'pointer', fontFamily:'Nunito,sans-serif', width:'100%' },
    };
    if (!info) {
      return (
        <div style={st.scroll}><div style={st.inner}>
          <div style={st.card}>
            <div style={{fontSize:16, fontWeight:800, marginBottom:8}}>{ru ? 'Настройте цикл' : 'Set up your cycle'}</div>
            <div style={st.sub}>{ru ? 'Укажите дату последней менструации и длину цикла, чтобы видеть прогнозы овуляции и месячных.' : 'Add your last period and cycle length to see ovulation and period predictions.'}</div>
          </div>
          <button style={st.btn} onClick={onOpenSettings}>{t('cycleSettings', lang)}</button>
        </div></div>
      );
    }
    return (
      <div style={st.scroll}><div style={st.inner}>
        <div style={{ ...st.ring, cursor:'pointer' }} onClick={onOpenCalendar}
          title={ru ? 'Открыть календарь' : 'Open calendar'}>
          <div style={st.ringInner}>
            <div style={{ fontSize:13, fontWeight:800, color:'var(--primary)' }}>{formatDayMonth(todayISO(), lang)}</div>
            <div style={st.sub}>{ru ? 'День цикла' : 'Cycle day'}</div>
            <div style={st.bigNum}>{info.cycleDay}</div>
            <button onClick={(e) => { e.stopPropagation(); onOpenPhaseInfo && onOpenPhaseInfo(info.phase); }}
              style={{ ...st.phase, display:'inline-flex', alignItems:'center', gap:5, border:'none',
                background:'none', cursor:'pointer', fontFamily:'Nunito,sans-serif', padding:'2px 6px' }}>
              {phaseLabel[info.phase]} <span style={{ opacity:0.65, fontSize:12 }}>ⓘ</span>
            </button>
          </div>
        </div>
        {info.delayDays > 0 && (
          <div style={{ ...st.card, display:'flex', alignItems:'center', gap:12, background:'#E8923D22', border:'1px solid #E8923D55' }}>
            <span style={{ fontSize:26 }}>⏳</span>
            <div style={{ flex:1 }}>
              <div style={{ fontSize:16, fontWeight:900, color:'#C9772A' }}>
                {ru ? `Задержка ${info.delayDays} ${pluralDayRu(info.delayDays)}` : `Period late by ${info.delayDays} ${info.delayDays === 1 ? 'day' : 'days'}`}
              </div>
              <div style={{ fontSize:13, color:'var(--text-2)', marginTop:2 }}>
                {ru ? 'Месячные не начались в ожидаемый день. Отметьте их начало или сделайте тест.'
                    : "Your period hasn't started as expected. Log its start or take a test."}
              </div>
            </div>
          </div>
        )}
        {goal === 'ttc' && (
          <div style={{ ...st.card, textAlign:'center', background: info.phase==='fertile' ? 'var(--primary-light)' : 'var(--bg-card)' }}>
            <div style={{fontSize:15, fontWeight:800, color: info.phase==='fertile' ? 'var(--primary)' : 'var(--text)'}}>
              {info.isOvulationToday ? (ru ? '🌸 Сегодня овуляция!' : '🌸 Ovulation today!')
                : info.daysToOvulation >= 0 ? (ru ? `До овуляции ${info.daysToOvulation} дн.` : `Ovulation in ${info.daysToOvulation} d`)
                : (ru ? 'Овуляция прошла' : 'Ovulation passed')}
            </div>
          </div>
        )}
        <div style={st.card}>
          <div style={st.row}><span style={st.sub}>{ru ? 'Следующие месячные' : 'Next period'}</span><b>{info.delayDays > 0 ? (ru ? `задержка ${info.delayDays} ${pluralDayRu(info.delayDays)}` : `late ${info.delayDays} d`) : `${info.daysToNextPeriod} ${t('days', lang)} · ${formatDayMonth(info.nextPeriod, lang)}`}</b></div>
          <div style={st.row}><span style={st.sub}>{ru ? 'Овуляция' : 'Ovulation'}</span><b>{formatDayMonth(info.ovulation, lang)}</b></div>
          <div style={{ ...st.row, borderBottom:'none' }}><span style={st.sub}>{ru ? 'Фертильное окно' : 'Fertile window'}</span><b>{formatDayMonth(info.fertileStart, lang)} – {formatDayMonth(info.fertileEnd, lang)}</b></div>
        </div>
        <button style={st.btn} onClick={onLogPeriod}>{ru ? '🩸 Отметить начало месячных' : '🩸 Log period start'}</button>
        <button style={st.btn2} onClick={onOpenCalendar}>{'📅 ' + t('calOpen', lang)}</button>
        <button style={st.btn2} onClick={onOpenSettings}>{t('cycleSettings', lang)}</button>
      </div></div>
    );
  }

  /* ── Main App ────────────────────────────────────────────────── */
  function App() {
    useEffect(() => { if (window.__aliaSplashHide) window.__aliaSplashHide(); }, []);

    // Гостевой режим отключён: доступ к приложению только после регистрации/входа.
    // Старый флаг гостя очищаем, чтобы прежние гости попадали на экран входа.
    try { localStorage.removeItem('alia_guest'); } catch (e) {}
    const [isAuth, setIsAuth]   = useState(() => isLoggedIn());
    const [isGuest, setIsGuest] = useState(false);
    const [lang, setLang]       = useState(() => localStorage.getItem('alia_lang') || 'ru');
    const [dueDate, setDueDateSt] = useState(() => localStorage.getItem('alia_due_date') || '');
    const [setupDone, setSetupDone] = useState(() => !!localStorage.getItem('alia_setup_done') || !!localStorage.getItem('alia_due_date'));
    const [tab, setTab] = useState('home');
    const [toolsView, setToolsView] = useState(null); // быстрый переход к инструменту с главной
    const [toolsKey, setToolsKey] = useState(0);       // сброс на сетку при тапе по вкладке
    const [profileLoading, setProfileLoading] = useState(false);
    const [refreshTick, setRefreshTick] = useState(0); // обновление данных (кнопка / pull-to-refresh)
    const [refreshing, setRefreshing] = useState(false);
    const [pullY, setPullY] = useState(0);             // pull-to-refresh: смещение оттягивания
    const pullRef = useRef({ startY: 0, active: false });

    // Навигация с главного экрана: kicks/contractions → вкладка «Инструменты» + нужный экран
    const navigate = useCallback(target => {
      if (target === 'kicks' || target === 'contractions') { setToolsView(target); setTab('tools'); }
      else setTab(target);
    }, []);

    // Уведомления
    const [notifications, setNotifications] = useState(() => {
      try { return JSON.parse(localStorage.getItem('alia_notifications') || '[]'); } catch (e) { return []; }
    });
    const [showNotifications, setShowNotifications] = useState(false);
    const unreadCount = notifications.filter(n => !n.is_read).length;

    const [showSettings, setShowSettings] = useState(false);
    const [showProfile, setShowProfile]   = useState(false);
    const [showEditDate, setShowEditDate] = useState(false);
    const [showBabyInfo, setShowBabyInfo] = useState(false);
    const [showGoal, setShowGoal]         = useState(false);
    const [showCycle, setShowCycle]       = useState(false);
    const [showCalendar, setShowCalendar] = useState(false);
    const [showPeriodEdit, setShowPeriodEdit] = useState(false);
    const [showLegal, setShowLegal] = useState(false);
    const [legalDoc, setLegalDoc] = useState(null);
    const [phaseInfo, setPhaseInfo] = useState(null);
    const [logs, setLogs] = useState(() => {
      try { return JSON.parse(localStorage.getItem('alia_logs') || '{}'); } catch (e) { return {}; }
    });
    const [periods, setPeriods] = useState(() => {
      try { return JSON.parse(localStorage.getItem('alia_periods') || '[]'); } catch (e) { return []; }
    });

    const [colorScheme, setColorSchemeSt] = useState(() => localStorage.getItem('alia_color_scheme') || 'rose');
    const [babyName, setBabyNameSt]   = useState(() => localStorage.getItem('alia_baby_name') || '');
    const [babyGender, setBabyGenderSt] = useState(() => localStorage.getItem('alia_baby_gender') || 'unknown');

    // Режимы и цикл
    const [appMode, setAppModeSt] = useState(() => localStorage.getItem('alia_app_mode') || 'pregnancy');
    const [goal, setGoalSt]       = useState(() => localStorage.getItem('alia_goal') || 'pregnancy');
    const [cycle, setCycleSt]     = useState(() => ({
      last_period:   localStorage.getItem('alia_last_period') || '',
      cycle_length:  +(localStorage.getItem('alia_cycle_length') || 28),
      period_length: +(localStorage.getItem('alia_period_length') || 5),
      luteal_phase:  localStorage.getItem('alia_luteal_phase') ? +localStorage.getItem('alia_luteal_phase') : null,
    }));

    // Load profile from API
    useEffect(() => {
      if (!isAuth || isGuest || !isLoggedIn()) return;
      if (refreshTick === 0) setProfileLoading(true); // полноэкранный сплэш только при первой загрузке
      getProfile()
        .then(p => {
          if (p.lang)         { setLang(p.lang);         localStorage.setItem('alia_lang', p.lang); }
          if (p.due_date)     { setDueDateSt(p.due_date); localStorage.setItem('alia_due_date', p.due_date); }
          if (p.baby_name)    { setBabyNameSt(p.baby_name); localStorage.setItem('alia_baby_name', p.baby_name); }
          if (p.baby_gender)  { setBabyGenderSt(p.baby_gender); localStorage.setItem('alia_baby_gender', p.baby_gender); }
          if (p.color_scheme) { setColorSchemeSt(p.color_scheme); localStorage.setItem('alia_color_scheme', p.color_scheme); }
          if (p.app_mode)     { setAppModeSt(p.app_mode); localStorage.setItem('alia_app_mode', p.app_mode); }
          if (p.goal)         { setGoalSt(p.goal); localStorage.setItem('alia_goal', p.goal); }
          // План родов: зеркалим в localStorage, чтобы экран плана родов подхватил его на новом устройстве
          if (p.birth_plan && typeof p.birth_plan === 'object') localStorage.setItem('alia_birth_plan', JSON.stringify(p.birth_plan));
          const cyc = {
            last_period:   p.last_period || '',
            cycle_length:  p.cycle_length || 28,
            period_length: p.period_length || 5,
            luteal_phase:  p.luteal_phase || null,
          };
          setCycleSt(cyc);
          localStorage.setItem('alia_cycle_length', cyc.cycle_length);
          localStorage.setItem('alia_period_length', cyc.period_length);
          if (cyc.last_period) localStorage.setItem('alia_last_period', cyc.last_period);
          if (cyc.luteal_phase) localStorage.setItem('alia_luteal_phase', cyc.luteal_phase);
          // setup считается завершённым, если есть ПДР (беременность) или дата месячных (цикл)
          if (p.due_date || p.last_period || localStorage.getItem('alia_setup_done')) setSetupDone(true);
        })
        .catch(() => {})
        .finally(() => setProfileLoading(false));
    }, [isAuth, refreshTick]); // eslint-disable-line

    useEffect(() => {
      applyColorScheme(colorScheme);
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      const handler = () => applyColorScheme(colorScheme);
      if (mq.addEventListener) mq.addEventListener('change', handler);
      return () => { if (mq.removeEventListener) mq.removeEventListener('change', handler); };
    }, [colorScheme]);

    function syncProfile(fields) {
      if (isLoggedIn() && !isGuest) updateProfile(fields).catch(() => {});
    }

    const setDueDate = useCallback(d => { setDueDateSt(d); localStorage.setItem('alia_due_date', d); syncProfile({ due_date: d }); }, []); // eslint-disable-line
    const setColorScheme = useCallback(id => { setColorSchemeSt(id); localStorage.setItem('alia_color_scheme', id); syncProfile({ color_scheme: id }); }, []); // eslint-disable-line
    const setBabyName = useCallback(n => { setBabyNameSt(n); localStorage.setItem('alia_baby_name', n); syncProfile({ baby_name: n }); }, []); // eslint-disable-line
    const setBabyGender = useCallback(g => { setBabyGenderSt(g); localStorage.setItem('alia_baby_gender', g); syncProfile({ baby_gender: g }); }, []); // eslint-disable-line

    const setGoalAndMode = useCallback(g => {
      const def = GOALS.find(x => x.id === g) || GOALS[0];
      setGoalSt(g); setAppModeSt(def.mode);
      localStorage.setItem('alia_goal', g); localStorage.setItem('alia_app_mode', def.mode);
      syncProfile({ goal: g, app_mode: def.mode });
    }, []); // eslint-disable-line

    const saveCycleSettings = useCallback(c => {
      // Запоминаем прежний «первый день месячных» ДО перезаписи — чтобы заменить
      // его в истории, а не плодить дубли.
      const prevLast = localStorage.getItem('alia_last_period') || null;
      const newLast = c.last_period || null;

      setCycleSt(c);
      localStorage.setItem('alia_cycle_length', c.cycle_length);
      localStorage.setItem('alia_period_length', c.period_length);
      if (newLast) localStorage.setItem('alia_last_period', newLast); else localStorage.removeItem('alia_last_period');
      if (c.luteal_phase) localStorage.setItem('alia_luteal_phase', c.luteal_phase); else localStorage.removeItem('alia_luteal_phase');
      syncProfile({ cycle_length: c.cycle_length, period_length: c.period_length,
        luteal_phase: c.luteal_phase, last_period: newLast });

      // Только если ДАТА последних месячных реально изменилась — это исправление
      // якоря: заменяем прежний старт новым (прочая история циклов не трогается).
      // Если поменяли только длины/лютеин — историю не трогаем вообще.
      if (newLast !== prevLast) {
        const loggedIn = isLoggedIn() && !localStorage.getItem('alia_guest');
        setPeriods(prev => {
          let list = (prev || []).filter(p => p && p.start_date);
          if (prevLast) list = list.filter(p => p.start_date !== prevLast);
          if (newLast)  list = list.filter(p => p.start_date !== newLast);
          if (newLast)  list.push({ start_date: newLast, end_date: null });
          list.sort((a, b) => a.start_date.localeCompare(b.start_date));
          localStorage.setItem('alia_periods', JSON.stringify(list));
          return list;
        });
        if (loggedIn) {
          if (newLast && saveCycle) saveCycle({ start_date: newLast }).catch(() => {});
          // удаляем прежний якорь из БД (id берём из свежего списка)
          if (prevLast && deleteCycle && getCycles) {
            getCycles().then(res => {
              const rows = (res && res.periods) || [];
              rows.filter(r => r.start_date === prevLast && r.id).forEach(r => deleteCycle(r.id).catch(() => {}));
            }).catch(() => {});
          }
        }
      }
    }, []); // eslint-disable-line

    const handleAuth = useCallback(userData => {
      if (userData.isGuest) { localStorage.setItem('alia_guest', '1'); setIsGuest(true); }
      else {
        localStorage.removeItem('alia_guest'); setIsGuest(false);
        // Сохраняем имя/почту для экрана «Профиль» (офлайн-отображение)
        if (userData.name != null)  localStorage.setItem('alia_name', userData.name);
        if (userData.email != null) localStorage.setItem('alia_email', userData.email);
      }
      if (userData.lang) { setLang(userData.lang); localStorage.setItem('alia_lang', userData.lang); }
      setIsAuth(true);
    }, []);

    const handleSetupComplete = useCallback(payload => {
      const { lang: l, goal: g, mode, due_date, baby_name, baby_gender, last_period, cycle_length, period_length } = payload;
      setLang(l); localStorage.setItem('alia_lang', l);
      setGoalSt(g); setAppModeSt(mode);
      localStorage.setItem('alia_goal', g); localStorage.setItem('alia_app_mode', mode);
      if (due_date) setDueDate(due_date);
      if (baby_name) setBabyName(baby_name);
      if (baby_gender) setBabyGender(baby_gender);
      const cyc = { last_period: last_period || '', cycle_length: cycle_length || 28, period_length: period_length || 5, luteal_phase: null };
      setCycleSt(cyc);
      localStorage.setItem('alia_cycle_length', cyc.cycle_length);
      localStorage.setItem('alia_period_length', cyc.period_length);
      if (cyc.last_period) localStorage.setItem('alia_last_period', cyc.last_period);
      localStorage.setItem('alia_setup_done', '1');
      setSetupDone(true);
      if (isLoggedIn() && !localStorage.getItem('alia_guest')) {
        updateProfile({ lang: l, goal: g, app_mode: mode, due_date: due_date || null,
          baby_name: baby_name || '', baby_gender: baby_gender || 'unknown',
          last_period: last_period || null, cycle_length, period_length }).catch(() => {});
      }
    }, [setDueDate, setBabyName, setBabyGender]); // eslint-disable-line

    const logPeriod = useCallback(() => {
      const today = todayISO();
      // Обновляем якорь «последние месячные», НЕ трогая прошлую историю циклов.
      setCycleSt(c => ({ ...c, last_period: today }));
      localStorage.setItem('alia_last_period', today);
      syncProfile({ last_period: today });
      // Добавляем сегодня как НОВЫЙ старт месячных (прошлые циклы сохраняются)
      setPeriods(prev => {
        if (prev.some(p => p.start_date === today)) return prev;
        const next = [...prev, { start_date: today, end_date: null }].sort((a, b) => a.start_date.localeCompare(b.start_date));
        localStorage.setItem('alia_periods', JSON.stringify(next));
        return next;
      });
      if (isLoggedIn() && !isGuest && saveCycle) saveCycle({ start_date: today }).catch(() => {});
    }, [isGuest]); // eslint-disable-line

    // Load daily logs (memorable days) + period history from API for signed-in users
    useEffect(() => {
      if (!isAuth || isGuest || !isLoggedIn()) return;
      if (getLogs) {
        getLogs()
          .then(res => {
            const rows = (res && res.logs) || [];
            const map = {};
            rows.forEach(r => { if (r && r.log_date) map[r.log_date] = r.payload || {}; });
            setLogs(map);
            localStorage.setItem('alia_logs', JSON.stringify(map));
          })
          .catch(() => {});
      }
      if (getCycles) {
        getCycles()
          .then(res => {
            const rows = (res && res.periods) || [];
            const list = rows.map(r => ({ start_date: r.start_date, end_date: r.end_date || null }))
              .filter(x => x.start_date);
            setPeriods(list);
            localStorage.setItem('alia_periods', JSON.stringify(list));
          })
          .catch(() => {});
      }
    }, [isAuth, refreshTick]); // eslint-disable-line

    // Загрузка уведомлений с сервера
    useEffect(() => {
      if (!isAuth || !isLoggedIn()) return;
      getNotifications && getNotifications()
        .then(res => {
          const list = (res && res.notifications) || [];
          setNotifications(list);
          localStorage.setItem('alia_notifications', JSON.stringify(list));
        })
        .catch(() => {});
    }, [isAuth, refreshTick]); // eslint-disable-line

    // Слушаем сообщения от service worker (push пришёл пока приложение открыто)
    useEffect(() => {
      if (!('serviceWorker' in navigator)) return;
      const handler = (event) => {
        if (event.data && event.data.type === 'PUSH_NOTIFICATION') {
          // Добавляем новое уведомление в начало списка
          const p = event.data.payload;
          const newNotif = {
            id: Date.now(),
            type: p.type || 'period_reminder',
            title_ru: p.title_ru || '',
            title_en: p.title_en || '',
            body_ru: p.body_ru || '',
            body_en: p.body_en || '',
            is_read: false,
            scheduled_for: p.scheduled_for || '',
            created_at: new Date().toISOString(),
          };
          setNotifications(prev => {
            const next = [newNotif, ...prev];
            localStorage.setItem('alia_notifications', JSON.stringify(next));
            return next;
          });
        }
        if (event.data && event.data.type === 'OPEN_NOTIFICATIONS') {
          setShowNotifications(true);
        }
      };
      navigator.serviceWorker.addEventListener('message', handler);
      return () => navigator.serviceWorker.removeEventListener('message', handler);
    }, []); // eslint-disable-line

    const handleMarkNotificationsRead = useCallback(() => {
      setNotifications(prev => {
        const next = prev.map(n => ({ ...n, is_read: true }));
        localStorage.setItem('alia_notifications', JSON.stringify(next));
        return next;
      });
      if (isLoggedIn()) markNotificationsRead && markNotificationsRead().catch(() => {});
    }, []); // eslint-disable-line

    const saveLogEntry = useCallback((dateISO, payload) => {
      setLogs(prev => {
        const next = { ...prev, [dateISO]: payload };
        localStorage.setItem('alia_logs', JSON.stringify(next));
        return next;
      });
      if (isLoggedIn() && !isGuest && saveLog) {
        saveLog({ log_date: dateISO, payload }).catch(() => {});
      }
    }, [isGuest]); // eslint-disable-line

    // Save full period history (from the editor): diff against current, sync to backend
    const savePeriods = useCallback((episodes) => {
      const list = (episodes || []).filter(e => e && e.start_date)
        .map(e => ({ start_date: e.start_date, end_date: e.end_date || null }))
        .sort((a, b) => a.start_date.localeCompare(b.start_date));
      const prevStarts = periods.map(p => p.start_date);
      const nextStarts = list.map(p => p.start_date);
      setPeriods(list);
      localStorage.setItem('alia_periods', JSON.stringify(list));
      // keep last_period (latest start) in profile/cycle for the home ring fallback
      const latest = list.length ? list[list.length - 1].start_date : '';
      setCycleSt(c => {
        const nc = { ...c, last_period: latest };
        if (latest) localStorage.setItem('alia_last_period', latest); else localStorage.removeItem('alia_last_period');
        return nc;
      });
      if (isLoggedIn() && !isGuest) {
        if (latest) syncProfile({ last_period: latest });
        if (saveCycle) list.forEach(p => saveCycle({ start_date: p.start_date, end_date: p.end_date }).catch(() => {}));
        // delete removed starts
        if (deleteCycle) {
          const removed = prevStarts.filter(s => nextStarts.indexOf(s) === -1);
          // backend deletes by id; we don't track ids here, so re-fetch and reconcile
          if (removed.length && getCycles) {
            getCycles().then(res => {
              const rows = (res && res.periods) || [];
              rows.filter(r => removed.indexOf(r.start_date) !== -1 && r.id)
                .forEach(r => deleteCycle(r.id).catch(() => {}));
            }).catch(() => {});
          }
        }
      }
    }, [periods, isGuest]); // eslint-disable-line

    const toggleLang = useCallback(() => {
      const nl = lang === 'ru' ? 'en' : 'ru';
      setLang(nl); localStorage.setItem('alia_lang', nl); syncProfile({ lang: nl });
    }, [lang]); // eslint-disable-line

    // Обновление данных: перезапрашивает профиль/логи/циклы (через refreshTick в deps эффектов)
    // и перемонтирует активный экран инструментов, чтобы он заново подтянул данные из БД.
    const doRefresh = useCallback(() => {
      if (refreshing) return;
      setRefreshing(true);
      setRefreshTick(t => t + 1);
      setTimeout(() => setRefreshing(false), 900);
    }, [refreshing]);

    // Выход: чистим токен и ВСЕ локальные данные (alia_*), чтобы следующий
    // аккаунт/гость не видел чужой кэш, затем перезагружаем на экран входа.
    const doLogout = useCallback(() => {
      apiLogout();
      try {
        const keys = [];
        for (let i = 0; i < localStorage.length; i++) {
          const k = localStorage.key(i);
          if (k && k.indexOf('alia_') === 0) keys.push(k);
        }
        keys.forEach(k => localStorage.removeItem(k));
      } catch (e) {}
      window.location.reload();
    }, []); // eslint-disable-line

    // ── Routing ────────────────────────────────────────────────
    if (!isAuth) return <AuthScreen onComplete={handleAuth} />;
    if (profileLoading) return (
      <div style={{ display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', height:'100dvh', background:'var(--bg)', gap:12 }}>
        <div style={{ fontSize:52 }}>🌸</div>
        <div style={{ fontSize:22, fontWeight:900, color:'var(--primary)' }}>Alia</div>
      </div>
    );
    if (!setupDone) return <Onboarding onComplete={handleSetupComplete} initialLang={lang} />;

    const currentWeek = calculateCurrentWeek(dueDate);
    const isPreg = appMode === 'pregnancy';

    const tabs = [
      { id:'home',   Icon: IconHome,    label: t('navHome', lang) },
      { id:'useful', Icon: IconCompass, label: t('navUseful', lang) },
      { id:'tools',  Icon: IconTools,   label: t('navTools', lang) },
    ];

    const st = {
      root: { display:'flex', flexDirection:'column', height:'100dvh', background:'var(--bg)', overflow:'hidden', fontFamily:'Nunito, sans-serif' },
      header: { display:'flex', alignItems:'center', justifyContent:'space-between', padding:'12px 20px',
                paddingTop:'calc(12px + env(safe-area-inset-top))', background:'var(--bg-card)',
                borderBottom:'1px solid var(--border)', flexShrink:0, boxShadow:'0 1px 8px var(--shadow)' },
      logo: { fontSize:22, fontWeight:900, color:'var(--primary)', letterSpacing:'-0.5px' },
      headerRight: { display:'flex', alignItems:'center', gap:10 },
      langBtn: { background:'var(--primary-light)', border:'none', borderRadius:8, padding:'6px 12px', fontSize:12,
                 fontWeight:800, color:'var(--primary)', cursor:'pointer', fontFamily:'Nunito,sans-serif', letterSpacing:'0.3px' },
      settingsBtn: { background:'var(--bg)', border:'none', borderRadius:10, padding:'7px 10px', fontSize:18, cursor:'pointer' },
      bellWrap: { position:'relative', display:'inline-flex' },
      bellBtn: { background:'var(--bg)', border:'none', borderRadius:10, padding:'7px 10px', fontSize:18, cursor:'pointer', lineHeight:1 },
      bellBadge: { position:'absolute', top:2, right:2, width:16, height:16, borderRadius:'50%',
                   background:'var(--primary)', color:'#fff', fontSize:10, fontWeight:900,
                   display:'flex', alignItems:'center', justifyContent:'center', pointerEvents:'none' },
      refreshBtn: { background:'var(--bg)', border:'none', borderRadius:10, padding:'7px 10px', fontSize:18, cursor:'pointer',
                    lineHeight:1, display:'inline-flex', alignItems:'center', justifyContent:'center' },
      screenWrap: { flex:1, overflow:'hidden', position:'relative' },
      tabBar: { display:'flex', background:'var(--bg-card)', borderTop:'1px solid var(--border)', paddingBottom:'env(safe-area-inset-bottom)', flexShrink:0 },
      tabItem: (active) => ({ flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center',
        gap:3, padding:'10px 4px', border:'none', background:'none', cursor:'pointer',
        color: active ? 'var(--primary)' : 'var(--text-2)', fontFamily:'Nunito,sans-serif', transition:'color .2s' }),
      tabDot: { width:4, height:4, borderRadius:2, background:'var(--primary)' },
      tabLabel: { fontSize:10, fontWeight:700, letterSpacing:'0.2px' },
    };

    // ── Pull-to-refresh: ищем ближайший скролл-контейнер и тянем, только если он вверху ──
    function scrollableAtTop(target) {
      let el = target;
      while (el && el !== document.body && el.nodeType === 1) {
        const oy = window.getComputedStyle(el).overflowY;
        if ((oy === 'auto' || oy === 'scroll') && el.scrollHeight > el.clientHeight) return el.scrollTop <= 0;
        el = el.parentElement;
      }
      return true;
    }
    const PULL_THRESHOLD = 60;
    function onTouchStart(e) {
      if (refreshing || !e.touches || !e.touches[0]) return;
      pullRef.current = { startY: e.touches[0].clientY, active: scrollableAtTop(e.target) };
    }
    function onTouchMove(e) {
      if (!pullRef.current.active || refreshing) return;
      const dy = e.touches[0].clientY - pullRef.current.startY;
      if (dy > 0) setPullY(Math.min(dy * 0.5, 80)); else setPullY(0);
    }
    function onTouchEnd() {
      if (pullY >= PULL_THRESHOLD && !refreshing) doRefresh();
      setPullY(0);
      pullRef.current.active = false;
    }
    const pullActive = pullY > 0 || refreshing;

    return (
      <div style={st.root}>
        <style>{`@keyframes aliaSpin { to { transform: rotate(360deg); } } .alia-spin { animation: aliaSpin .8s linear infinite; }`}</style>
        <header style={st.header}>
          <span style={st.logo}>🌸 Alia</span>
          <div style={st.headerRight}>
            <button style={st.refreshBtn} onClick={doRefresh} title={lang === 'ru' ? 'Обновить' : 'Refresh'} aria-label="refresh">
              <span className={refreshing ? 'alia-spin' : ''} style={{ display:'inline-flex', color:'var(--primary)' }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M17.65 6.35A7.96 7.96 0 0 0 12 4a8 8 0 1 0 7.74 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.15.69 4.22 1.78L13 11h7V4z"/></svg>
              </span>
            </button>
            <div style={st.bellWrap}>
              <button style={st.bellBtn} onClick={() => setShowNotifications(true)} aria-label="notifications">
                🔔
              </button>
              {unreadCount > 0 && (
                <div style={st.bellBadge}>{unreadCount > 9 ? '9+' : unreadCount}</div>
              )}
            </div>
            <button style={st.langBtn} onClick={toggleLang}>{lang === 'ru' ? 'EN' : 'RU'}</button>
            <button style={st.settingsBtn} onClick={() => setShowSettings(true)}>⚙️</button>
          </div>
        </header>

        <div style={st.screenWrap} onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd}>
          {pullActive && (
            <div style={{ position:'absolute', top:0, left:0, right:0, zIndex:20, display:'flex', alignItems:'center',
              justifyContent:'center', height: refreshing ? 40 : Math.max(0, pullY), pointerEvents:'none',
              color:'var(--primary)', fontSize:22, transition: refreshing ? 'height .2s' : 'none' }}>
              <span className={refreshing ? 'alia-spin' : ''} style={{ display:'inline-flex',
                transform: refreshing ? 'none' : `rotate(${Math.min(pullY * 4, 360)}deg)` }}>
                <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M17.65 6.35A7.96 7.96 0 0 0 12 4a8 8 0 1 0 7.74 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.15.69 4.22 1.78L13 11h7V4z"/></svg>
              </span>
            </div>
          )}
          <div style={{ height:'100%', transform: pullActive ? `translateY(${refreshing ? 40 : pullY}px)` : 'none',
            transition: (refreshing || pullY === 0) ? 'transform .2s' : 'none' }}>
          {tab === 'home' && (isPreg
            ? <HomeScreen dueDate={dueDate} currentWeek={currentWeek} lang={lang} onNavigate={navigate} babyName={babyName} babyGender={babyGender} />
            : <CycleHomeScreen lang={lang} goal={goal} cycle={cycle} periods={periods} onLogPeriod={logPeriod} onOpenSettings={() => setShowCycle(true)} onOpenCalendar={() => setShowCalendar(true)} onOpenPhaseInfo={ph => setPhaseInfo(ph)} />
          )}
          {tab === 'useful' && <UsefulScreen lang={lang} currentWeek={currentWeek} appMode={appMode} />}
          {tab === 'tools'  && <ToolsScreen key={toolsKey} lang={lang} currentWeek={currentWeek} dueDate={dueDate} appMode={appMode} babyGender={babyGender} isGuest={isGuest}
            initialView={toolsView} onViewConsumed={() => setToolsView(null)} refreshTick={refreshTick} />}
          </div>
        </div>

        <nav style={st.tabBar}>
          {tabs.map(({ id, Icon, label }) => (
            <button key={id} style={st.tabItem(tab === id)}
              onClick={() => { if (id === 'tools') { setToolsView(null); setToolsKey(k => k + 1); } setTab(id); }}>
              <Icon size={22} />
              {tab === id && <div style={st.tabDot}></div>}
              <span style={st.tabLabel}>{label}</span>
            </button>
          ))}
        </nav>

        {showSettings && (
          <SettingsSheet lang={lang} colorScheme={colorScheme} appMode={appMode}
            onColorScheme={id => setColorScheme(id)}
            onProfile={() => { setShowSettings(false); setShowProfile(true); }}
            onLangToggle={() => { toggleLang(); setShowSettings(false); }}
            onEditDate={() => { setShowSettings(false); setShowEditDate(true); }}
            onBabyInfo={() => { setShowSettings(false); setShowBabyInfo(true); }}
            onGoal={() => { setShowSettings(false); setShowGoal(true); }}
            onCycle={() => { setShowSettings(false); setShowCycle(true); }}
            onLegal={() => { setShowSettings(false); setShowLegal(true); }}
            onLogout={doLogout}
            onClose={() => setShowSettings(false)} />
        )}
        {showLegal && (
          <LegalSheet lang={lang}
            onOpenDoc={id => setLegalDoc(id)}
            onClose={() => setShowLegal(false)} />
        )}
        {legalDoc && (
          <LegalDocSheet lang={lang} docId={legalDoc}
            onBack={() => setLegalDoc(null)}
            onClose={() => { setLegalDoc(null); setShowLegal(false); }} />
        )}
        {showProfile && (
          <ProfileSheet lang={lang} isGuest={isGuest} goal={goal} appMode={appMode}
            dueDate={dueDate} currentWeek={currentWeek} cycle={cycle}
            onLogout={doLogout} onClose={() => setShowProfile(false)} />
        )}
        {showEditDate && (
          <EditDateSheet lang={lang} currentDueDate={dueDate}
            onSave={d => { setDueDate(d); setShowEditDate(false); }} onClose={() => setShowEditDate(false)} />
        )}
        {showBabyInfo && (
          <BabyInfoSheet lang={lang} currentName={babyName} currentGender={babyGender}
            onSave={(name, gender) => { setBabyName(name); setBabyGender(gender); setShowBabyInfo(false); }}
            onClose={() => setShowBabyInfo(false)} />
        )}
        {showGoal && (
          <GoalSheet lang={lang} currentGoal={goal}
            onSave={g => { setGoalAndMode(g); setShowGoal(false); setTab('home'); }} onClose={() => setShowGoal(false)} />
        )}
        {showCycle && (
          <CycleSettingsSheet lang={lang} cycle={cycle}
            onSave={c => { saveCycleSettings(c); setShowCycle(false); }} onClose={() => setShowCycle(false)} />
        )}
        {showCalendar && (
          <CalendarScreen lang={lang} cycle={cycle} periods={periods} logs={logs}
            onSaveLog={saveLogEntry}
            onEditPeriod={() => setShowPeriodEdit(true)}
            onClose={() => setShowCalendar(false)} />
        )}
        {showPeriodEdit && (
          <PeriodEditScreen lang={lang} periods={periods} cycle={cycle}
            onSave={eps => { savePeriods(eps); setShowPeriodEdit(false); }}
            onClose={() => setShowPeriodEdit(false)} />
        )}
        {phaseInfo && (
          <PhaseInfoSheet lang={lang} phase={phaseInfo} onClose={() => setPhaseInfo(null)} />
        )}
        {showNotifications && NotificationsSheet && (
          <NotificationsSheet
            lang={lang}
            notifications={notifications}
            onClose={() => setShowNotifications(false)}
            onMarkRead={() => { handleMarkNotificationsRead(); }}
            onNewNotification={() => {
              // Перезагружаем список с сервера после теста
              window.AliaAPI.getNotifications && window.AliaAPI.getNotifications()
                .then(res => {
                  const list = (res && res.notifications) || [];
                  setNotifications(list);
                  localStorage.setItem('alia_notifications', JSON.stringify(list));
                }).catch(() => {});
            }}
          />
        )}
      </div>
    );
  }

  /* ── Shared sheet styles ─────────────────────────────────────── */
  function sheetStyles() {
    return {
      overlay: { position:'fixed', inset:0, background:'rgba(0,0,0,0.4)', zIndex:200, display:'flex', alignItems:'flex-end', backdropFilter:'blur(4px)' },
      sheet: { width:'100%', background:'var(--bg-card)', borderRadius:'24px 24px 0 0', padding:'20px 24px',
               paddingBottom:'calc(28px + env(safe-area-inset-bottom))', display:'flex', flexDirection:'column', gap:16,
               boxShadow:'0 -4px 24px rgba(0,0,0,0.15)', maxWidth:520, margin:'0 auto' },
      handle: { width:40, height:4, borderRadius:2, background:'var(--border)', margin:'0 auto' },
      title: { fontSize:18, fontWeight:800, color:'var(--text)' },
      label: { fontSize:11, fontWeight:700, color:'var(--text-2)', letterSpacing:'0.5px', textTransform:'uppercase', marginBottom:8, display:'block' },
      input: { width:'100%', padding:'14px 15px', borderRadius:13, border:'2px solid var(--border)', background:'var(--bg)',
               color:'var(--text)', fontSize:16, fontFamily:'Nunito,sans-serif', outline:'none', boxSizing:'border-box' },
      genderRow: { display:'flex', gap:10 },
      genderBtn: (a) => ({ flex:1, padding:'13px 6px', borderRadius:15, border:'2px solid',
        borderColor: a ? 'var(--primary)' : 'var(--border)', background: a ? 'var(--primary-light)' : 'var(--bg)',
        color: a ? 'var(--primary)' : 'var(--text-2)', fontSize:11, fontWeight:700, cursor:'pointer',
        fontFamily:'Nunito,sans-serif', display:'flex', flexDirection:'column', alignItems:'center', gap:6 }),
      goalBtn: (a) => ({ display:'flex', alignItems:'center', gap:12, width:'100%', padding:'14px 16px', borderRadius:15, border:'2px solid',
        borderColor: a ? 'var(--primary)' : 'var(--border)', background: a ? 'var(--primary-light)' : 'var(--bg)',
        color: a ? 'var(--primary)' : 'var(--text)', fontSize:15, fontWeight:700, cursor:'pointer', fontFamily:'Nunito,sans-serif', textAlign:'left' }),
      modeBtn: (a) => ({ flex:1, padding:'10px 8px', borderRadius:13, border:'2px solid',
        borderColor: a ? 'var(--primary)' : 'var(--border)', background: a ? 'var(--primary-light)' : 'var(--bg)',
        color: a ? 'var(--primary)' : 'var(--text-2)', fontSize:13, fontWeight:700, cursor:'pointer', fontFamily:'Nunito,sans-serif' }),
      saveBtn: { padding:'15px 0', borderRadius:15, border:'none', background:'var(--primary)', color:'#fff', fontSize:16, fontWeight:800, cursor:'pointer', fontFamily:'Nunito,sans-serif' },
      row: { display:'flex', alignItems:'center', justifyContent:'space-between', padding:'13px 0', borderBottom:'1px solid var(--border)', cursor:'pointer' },
      rowLast: { display:'flex', alignItems:'center', justifyContent:'space-between', padding:'13px 0', cursor:'pointer' },
      rowLabel: { fontSize:16, fontWeight:600, color:'var(--text)' },
      rowValue: { fontSize:14, color:'var(--text-2)', fontWeight:500 },
      schemeSection: { padding:'4px 0 12px', borderBottom:'1px solid var(--border)' },
      schemeLbl: { fontSize:16, fontWeight:600, color:'var(--text)', marginBottom:12 },
      swatches: { display:'flex', flexWrap:'wrap', gap:12, alignItems:'center' },
      swatch: (active, color) => ({ width: active ? 34 : 28, height: active ? 34 : 28, borderRadius:'50%', background: color,
        cursor:'pointer', border: active ? '3px solid var(--text)' : '2px solid transparent',
        boxShadow: active ? '0 0 0 2px var(--bg-card), 0 2px 8px rgba(0,0,0,0.2)' : '0 2px 6px rgba(0,0,0,0.15)', transition:'all .2s', flexShrink:0 }),
    };
  }

  ReactDOM.createRoot(document.getElementById('root')).render(<App />);
})();
