// ---- Month Calendar Page ----
// Month grid of Firestore calendar events, notes, and (endurance) activities.
// Holistic users also get the AI month planner.

const SESSION_META = {
  meditation: { icon: '🧘', accent: '#a78bfa', color: 'rgba(139,92,246,0.22)',  border: '#7c3aed' },
  yoga:       { icon: '🪷', accent: '#4ade80', color: 'rgba(34,197,94,0.22)',   border: '#16a34a' },
  movement:   { icon: '🚶', accent: '#22d3ee', color: 'rgba(34,211,238,0.20)',  border: '#0891b2' },
  strength:   { icon: '🏋️', accent: '#fbbf24', color: 'rgba(251,191,36,0.20)',  border: '#d97706' },
  breathwork: { icon: '🌬️', accent: '#93c5fd', color: 'rgba(96,165,250,0.20)',  border: '#2563eb' },
};

const SPORT_ICONS = { Swim: '🏊', Ride: '🚴', VirtualRide: '🚴', Run: '🏃', WeightTraining: '🏋️', Walk: '🚶' };

const SYMPTOM_ICONS = {
  cramps: '😣', headache: '🤕', bloating: '😮‍💨', low_energy: '🔋',
  high_energy: '⚡', mood_low: '😔', mood_high: '😊',
  sore_breasts: '💜', insomnia: '🌙', cravings: '🍫',
};
window.SYMPTOM_ICONS = SYMPTOM_ICONS;

// Cycle phase visuals — subtle background tint per phase + ovulation highlight.
// focusKey points at the Dr. Stacy Sims per-phase training focus copy
// (kept in sync with CYCLE_PHASE_GUIDANCE in server/coaching-engine.js).
const CYCLE_META = {
  menstrual:        { tint: 'rgba(239,68,68,0.16)',  dot: '#ef4444', key: 'cycleMenstrual', focusKey: 'cycleFocusMenstrual' },
  follicular:       { tint: 'rgba(34,197,94,0.12)',  dot: '#22c55e', key: 'cycleFollicular', focusKey: 'cycleFocusFollicular' },
  ovulation:        { tint: 'rgba(236,72,153,0.22)', dot: '#ec4899', key: 'cycleOvulation', focusKey: 'cycleFocusOvulation' },
  early_mid_luteal: { tint: 'rgba(251,191,36,0.12)', dot: '#fbbf24', key: 'cycleLuteal', focusKey: 'cycleFocusLuteal' },
  late_luteal:      { tint: 'rgba(148,163,184,0.14)', dot: '#94a3b8', key: 'cycleLateLuteal', focusKey: 'cycleFocusLateLuteal' },
};
// Babel-standalone runs each script in its own scope — 17-cycle.jsx reads this via window.
window.CYCLE_META = CYCLE_META;

const iconBtn = {
  background: 'none', border: 'none', cursor: 'pointer', fontSize: 13,
  padding: '2px 4px', borderRadius: 6, lineHeight: 1, opacity: 0.7,
};
const inputStyle = {
  width: '100%', boxSizing: 'border-box', fontSize: 13, padding: '8px 10px',
  background: 'var(--bg-card)', border: '1px solid var(--border)',
  borderRadius: 8, color: 'var(--text-primary)',
};

function fmtDateKey(d) {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}

function ConsistencyCard({ t, refreshKey }) {
  const [stats, setStats] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    api.get('/api/wellness/consistency?days=60')
      .then(d => { if (!cancelled) setStats(d); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, [refreshKey]);

  if (!stats) return null;

  const stat = (value, label, accent) => (
    <div style={{ textAlign: 'center', flex: 1 }}>
      <div style={{ fontSize: 26, fontWeight: 700, fontFamily: 'JetBrains Mono, monospace', color: accent }}>{value}</div>
      <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{label}</div>
    </div>
  );

  return (
    <div className="card" style={{ marginBottom: 16, borderColor: 'rgba(139,92,246,0.3)' }}>
      <div className="card-header">
        <div className="card-title" style={{ color: 'var(--accent-purple)' }}>{'🔥'} {t('consistencyTitle')}</div>
      </div>
      <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>
        {stat(stats.currentStreak, t('currentStreak'), 'var(--accent-purple)')}
        {stat(stats.longestStreak, t('longestStreak'), 'var(--text-primary)')}
        {stat(stats.thisMonthCount, t('thisMonthSessions'), 'var(--accent-green)')}
      </div>
      {/* 30-day dot strip */}
      <div style={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
        {stats.recent.map((d, i) => (
          <span key={i} title={d.date} style={{
            width: 14, height: 14, borderRadius: 4,
            background: d.active ? 'var(--accent-purple)' : 'var(--surface-2)',
            border: '1px solid var(--border)',
          }} />
        ))}
      </div>
      <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 8 }}>{t('last30Days')}</div>
    </div>
  );
}

// ---- Plan Preview Modal ----
function PlanPreviewModal({ preview, setPreview, onConfirm, onCancel, confirming, lang, t }) {
  const dragIdxRef = React.useRef(null);
  const [dragOver, setDragOver] = React.useState(null);

  // 4-week grid anchored to Monday of the earliest session's week
  const minDate = preview.length > 0
    ? preview.reduce((min, s) => s.date < min ? s.date : min, preview[0].date)
    : fmtDateKey(new Date());
  const anchor = new Date(minDate + 'T12:00:00');
  anchor.setDate(anchor.getDate() - ((anchor.getDay() + 6) % 7)); // rewind to Monday

  const weeks = [];
  const cur = new Date(anchor);
  for (let w = 0; w < 4; w++) {
    const row = [];
    for (let d = 0; d < 7; d++) { row.push(new Date(cur)); cur.setDate(cur.getDate() + 1); }
    weeks.push(row);
  }

  const byDate = {};
  preview.forEach((s, i) => {
    if (!byDate[s.date]) byDate[s.date] = [];
    byDate[s.date].push({ ...s, _idx: i });
  });

  const dayNames = lang === 'es-ES'
    ? ['L', 'M', 'X', 'J', 'V', 'S', 'D']
    : lang === 'de-DE'
    ? ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
    : ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
  const todayKey = fmtDateKey(new Date());

  function moveSession(fromIdx, toDate) {
    setPreview(prev => prev.map((s, i) => i === fromIdx ? { ...s, date: toDate } : s));
  }
  function removeSession(idx) {
    setPreview(prev => prev.filter((_, i) => i !== idx));
  }

  return (
    <div className="modal-overlay" onClick={onCancel} style={{ alignItems: 'flex-start', overflowY: 'auto', padding: '6vh 16px 32px' }}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ width: 620, maxWidth: '98vw', maxHeight: '88vh', overflowY: 'auto', padding: 24 }}>
        {/* Header */}
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 16 }}>
          <div>
            <div style={{ fontSize: 17, fontWeight: 700, color: 'var(--accent-purple)' }}>✨ {t('previewPlanTitle')}</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{t('previewPlanHint')}</div>
          </div>
          <button onClick={onCancel} style={{ background: 'none', border: 'none', fontSize: 22, cursor: 'pointer', color: 'var(--text-muted)', lineHeight: 1 }}>×</button>
        </div>

        {/* 4-week grid */}
        <div style={{ overflowX: 'auto' }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 3, minWidth: 380 }}>
            {dayNames.map((d, i) => (
              <div key={i} style={{ textAlign: 'center', fontSize: 10, fontWeight: 700, color: 'var(--text-muted)', padding: '4px 0', letterSpacing: 0.5 }}>{d}</div>
            ))}
            {weeks.flat().map((date, i) => {
              const key = fmtDateKey(date);
              const sessions = byDate[key] || [];
              const isToday = key === todayKey;
              const isDragTarget = dragOver === key;
              return (
                <div
                  key={i}
                  onDragOver={e => { e.preventDefault(); setDragOver(key); }}
                  onDragLeave={() => setDragOver(null)}
                  onDrop={e => {
                    e.preventDefault();
                    setDragOver(null);
                    if (dragIdxRef.current !== null) { moveSession(dragIdxRef.current, key); dragIdxRef.current = null; }
                  }}
                  style={{
                    minHeight: 64, padding: '4px 3px', borderRadius: 6,
                    border: isDragTarget ? '2px dashed var(--accent-purple)' : (isToday ? '1px solid var(--accent-purple)' : '1px solid var(--border)'),
                    background: isDragTarget ? 'var(--accent-purple-dim)' : (isToday ? 'rgba(139,92,246,0.06)' : 'var(--bg-card)'),
                    transition: 'border-color 0.1s, background 0.1s',
                  }}
                >
                  <div style={{ fontSize: 10, color: isToday ? 'var(--accent-purple)' : 'var(--text-muted)', marginBottom: 3, textAlign: 'center', fontFamily: 'JetBrains Mono, monospace', fontWeight: isToday ? 700 : 400 }}>
                    {date.getDate()}
                  </div>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                    {sessions.map(s => {
                      const meta = SESSION_META[s.type];
                      return (
                        <div
                          key={s._idx}
                          draggable
                          onDragStart={e => { e.stopPropagation(); dragIdxRef.current = s._idx; }}
                          onDragEnd={() => { dragIdxRef.current = null; }}
                          title={s.title + (s.description ? '\n' + s.description : '')}
                          style={{
                            display: 'flex', alignItems: 'center', gap: 2,
                            background: meta ? meta.color : 'var(--bg-card-hover)',
                            borderLeft: `2px solid ${meta ? meta.border : 'var(--border)'}`,
                            borderRadius: 4, padding: '2px 4px', cursor: 'grab', userSelect: 'none',
                          }}
                        >
                          <span style={{ fontSize: 11 }}>{meta ? meta.icon : '📌'}</span>
                          <span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontSize: 9, color: 'var(--text-secondary)' }}>{s.title}</span>
                          <button
                            onClick={e => { e.stopPropagation(); removeSession(s._idx); }}
                            style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted)', fontSize: 11, padding: '0 1px', lineHeight: 1, flexShrink: 0 }}
                          >×</button>
                        </div>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        {/* Legend */}
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 12 }}>
          {Object.entries(SESSION_META).map(([type, m]) => (
            <span key={type} style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--text-muted)' }}>
              <span>{m.icon}</span> {t('focus_' + type)}
            </span>
          ))}
        </div>

        {/* Footer */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 16, paddingTop: 14, borderTop: '1px solid var(--border)' }}>
          <span style={{ fontSize: 13, color: 'var(--text-muted)', fontFamily: 'JetBrains Mono, monospace' }}>
            {preview.length} {t('sessionsPlanned')}
          </span>
          <div style={{ display: 'flex', gap: 10 }}>
            <button className="btn" onClick={onCancel} disabled={confirming}>Cancel</button>
            <button className="btn btn-primary" onClick={onConfirm} disabled={confirming || preview.length === 0}>
              {confirming ? t('scheduling') : t('confirmSchedule')}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// Maps CYCLE_META phase keys → recipe API phase keys (some differ)
const PHASE_TO_RECIPE_API = {
  menstrual:        'menstrual',
  follicular:       'follicular',
  ovulation:        'ovulatory',
  early_mid_luteal: 'luteal',
  late_luteal:      'luteal',
};

const PHASE_RATIONALE = {
  menstrual: (r) => {
    const facts = [];
    if (r.iron_mg > 1)   facts.push(`${r.iron_mg.toFixed(1)} mg iron`);
    if (r.omega3_g > 0.1) facts.push(`${r.omega3_g.toFixed(1)} g ω-3`);
    return (facts.length ? facts.join(' · ') + ' — ' : '') +
      'helps replenish during menstruation and reduce inflammation';
  },
  follicular: (r) => {
    const facts = [];
    if (r.fiber_g > 3)   facts.push(`${r.fiber_g.toFixed(0)} g fiber`);
    if (r.protein_g > 8) facts.push(`${r.protein_g.toFixed(0)} g protein`);
    return (facts.length ? facts.join(' · ') + ' — ' : '') +
      'supports rising estrogen and steady energy';
  },
  ovulation: (r) => {
    const facts = [];
    if (r.protein_g > 10) facts.push(`${r.protein_g.toFixed(0)} g protein`);
    if (r.zinc_mg > 1)    facts.push(`${r.zinc_mg.toFixed(1)} mg zinc`);
    return (facts.length ? facts.join(' · ') + ' — ' : '') +
      'fuels peak performance and supports ovulation';
  },
  early_mid_luteal: (r) => {
    const facts = [];
    if (r.carbs_g > 20) facts.push(`${r.carbs_g.toFixed(0)} g complex carbs`);
    if (r.fiber_g > 3)  facts.push(`${r.fiber_g.toFixed(0)} g fiber`);
    return (facts.length ? facts.join(' · ') + ' — ' : '') +
      'stabilises mood and reduces cravings in the luteal phase';
  },
  late_luteal: (r) => {
    const facts = [];
    if (r.carbs_g > 20)  facts.push(`${r.carbs_g.toFixed(0)} g complex carbs`);
    if (r.calcium_mg > 50) facts.push(`${Math.round(r.calcium_mg)} mg calcium`);
    return (facts.length ? facts.join(' · ') + ' — ' : '') +
      'supports comfort and eases PMS symptoms before menstruation';
  },
};

function DayRecipes({ phase, t }) {
  const [recipes, setRecipes] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [tooltip, setTooltip] = React.useState(null);

  React.useEffect(() => {
    const apiPhase = PHASE_TO_RECIPE_API[phase] || 'follicular';
    api.get(`/api/recipes?phase=${apiPhase}&limit=8`)
      .then(d => {
        const all = d.recipes || [];
        const shuffled = all.slice().sort(() => Math.random() - 0.5);
        setRecipes(shuffled.slice(0, 2));
      })
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [phase]);

  const phaseName = phase.replace(/_/g, ' ');
  const label = t('recipesForPhase').replace('{phase}', phaseName);
  const getRationale = PHASE_RATIONALE[phase] || (() => 'Recommended for this phase');

  if (loading) return (
    <div style={{ padding: '10px 0', color: 'var(--text-muted)', fontSize: 12, textAlign: 'center' }}>🍽️ …</div>
  );
  if (!recipes.length) return null;

  return (
    <div style={{ marginTop: 18 }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 8 }}>
        🍽️ {label}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
        {recipes.map((r, i) => (
          <a key={i} href={r.url} target="_blank" rel="noopener noreferrer"
            style={{ textDecoration: 'none', color: 'inherit' }}>
            <div style={{
              display: 'flex', alignItems: 'center', gap: 10,
              padding: '8px 10px', borderRadius: 10,
              background: 'var(--bg-card-hover)', border: '1px solid var(--border)',
              transition: 'border-color 0.15s',
            }}
              onMouseEnter={e => e.currentTarget.style.borderColor = 'var(--accent-purple)'}
              onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--border)'}
            >
              {r.image_url
                ? <img src={r.image_url} alt={r.name} style={{ width: 44, height: 44, borderRadius: 8, objectFit: 'cover', flexShrink: 0 }} loading="lazy" />
                : <div style={{ width: 44, height: 44, borderRadius: 8, background: 'var(--surface-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 20, flexShrink: 0 }}>🍽️</div>
              }
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600, lineHeight: 1.3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--text-primary)' }}>
                  {r.name}
                </div>
                {r.calories != null && (
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                    {Math.round(r.calories)} kcal{r.protein_g != null ? ` · ${Math.round(r.protein_g)}g protein` : ''}
                  </div>
                )}
              </div>
              <div style={{ position: 'relative', flexShrink: 0 }}
                onMouseEnter={e => { e.stopPropagation(); setTooltip(i); }}
                onMouseLeave={() => setTooltip(null)}
                onClick={e => e.preventDefault()}
              >
                <span style={{ fontSize: 14, cursor: 'default', color: 'var(--text-muted)', opacity: 0.7, lineHeight: 1 }}>ℹ️</span>
                {tooltip === i && (
                  <div style={{
                    position: 'absolute', right: 0, bottom: 'calc(100% + 6px)',
                    width: 210, padding: '8px 10px', borderRadius: 8, zIndex: 100,
                    background: 'var(--bg-card)', border: '1px solid var(--border)',
                    boxShadow: '0 4px 16px rgba(0,0,0,0.3)',
                    fontSize: 11, lineHeight: 1.55, color: 'var(--text-secondary)',
                    pointerEvents: 'none',
                  }}>
                    {getRationale(r)}
                  </div>
                )}
              </div>
            </div>
          </a>
        ))}
      </div>
    </div>
  );
}

window.CalendarPage = function CalendarPage({ config, t }) {
  const today = new Date();
  const [viewYear, setViewYear] = React.useState(today.getFullYear());
  const [viewMonth, setViewMonth] = React.useState(today.getMonth()); // 0-based
  const [data, setData] = React.useState({ events: [], notes: [], activities: [] });
  const [loading, setLoading] = React.useState(true);
  const [selectedDay, setSelectedDay] = React.useState(fmtDateKey(today));
  const [modalOpen, setModalOpen] = React.useState(false);

  // Planner state (holistic only)
  const isHolistic = config?.endurance_enabled === false;
  const [sessionsPerWeek, setSessionsPerWeek] = React.useState(4);
  const [focus, setFocus] = React.useState(['meditation', 'yoga', 'movement']);
  const [constraints, setConstraints] = React.useState('');
  const [planning, setPlanning] = React.useState(false);
  const [planResult, setPlanResult] = React.useState(null);
  const [preview, setPreview] = React.useState(null);    // null | session[]
  const [confirming, setConfirming] = React.useState(false);

  // Export / subscribe
  const [subUrl, setSubUrl] = React.useState(null);
  const [copied, setCopied] = React.useState(false);
  const [exporting, setExporting] = React.useState(false);

  // Manual event editing
  const [editing, setEditing] = React.useState(null); // null | {id?, type, title, description}
  const [saving, setSaving] = React.useState(false);
  const [refreshKey, setRefreshKey] = React.useState(0); // bumped when sessions change
  // Post-session check-in state: null = hidden, else { eventId, feeling: null|1-5, note: '' }
  const [checkIn, setCheckIn] = React.useState(null);

  const lang = config?.language === 'es' ? 'es-ES' : config?.language === 'de' ? 'de-DE' : 'en-US';
  const monthLabel = new Date(viewYear, viewMonth, 1).toLocaleDateString(lang, { month: 'long', year: 'numeric' });

  async function loadMonth(y, m) {
    setLoading(true);
    try {
      const first = new Date(y, m, 1);
      const last = new Date(y, m + 1, 0);
      const res = await api.get(`/api/calendar/month?start=${fmtDateKey(first)}&end=${fmtDateKey(last)}`);
      setData(res);
      setRefreshKey(k => k + 1);
    } catch (e) {
      console.error('Calendar load error:', e);
    } finally {
      setLoading(false);
    }
  }

  React.useEffect(() => { loadMonth(viewYear, viewMonth); }, [viewYear, viewMonth]);

  function shiftMonth(delta) {
    const d = new Date(viewYear, viewMonth + delta, 1);
    setViewYear(d.getFullYear());
    setViewMonth(d.getMonth());
  }

  // Index data by date for the grid
  const byDate = React.useMemo(() => {
    const map = {};
    const add = (date) => {
      if (!date) return false;
      if (!map[date]) map[date] = { events: [], notes: [], activities: [], symptomLog: null };
      return true;
    };
    (data.events || []).forEach(e => { add(e.date) && map[e.date].events.push(e); });
    (data.notes || []).forEach(n => { add(n.date) && map[n.date].notes.push(n); });
    (data.activities || []).forEach(a => { add(a.date) && map[a.date].activities.push(a); });
    (data.symptomLogs || []).forEach(s => { add(s.date); map[s.date].symptomLog = s; });
    return map;
  }, [data]);

  // Build week rows (Monday-start)
  const weeks = React.useMemo(() => {
    const first = new Date(viewYear, viewMonth, 1);
    const start = new Date(first);
    start.setDate(first.getDate() - ((first.getDay() + 6) % 7));
    const rows = [];
    const cur = new Date(start);
    do {
      const row = [];
      for (let i = 0; i < 7; i++) {
        row.push(new Date(cur));
        cur.setDate(cur.getDate() + 1);
      }
      rows.push(row);
    } while (cur.getMonth() === viewMonth);
    return rows;
  }, [viewYear, viewMonth]);

  const dayNames = lang === 'es-ES'
    ? ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom']
    : lang === 'de-DE'
    ? ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
    : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

  async function requestPreview() {
    setPlanning(true);
    setPlanResult(null);
    try {
      const res = await api.post('/api/holistic-plan/month/preview', {
        sessionsPerWeek, focus, weeks: 4,
        startDate: fmtDateKey(new Date()),
        constraints: constraints.trim() || undefined,
      });
      setPreview(res.sessions);
    } catch (e) {
      setPlanResult({ error: e.message });
    } finally {
      setPlanning(false);
    }
  }

  async function confirmPlan() {
    if (!preview || preview.length === 0) return;
    setConfirming(true);
    try {
      const res = await api.post('/api/holistic-plan/month/commit', { sessions: preview });
      setPreview(null);
      setPlanResult(res);
      await loadMonth(viewYear, viewMonth);
      showToast(t('planCreated').replace('{n}', res.created.length), 'success');
    } catch (e) {
      setPlanResult({ error: e.message });
      setPreview(null);
    } finally {
      setConfirming(false);
    }
  }

  async function downloadIcs() {
    setExporting(true);
    try {
      const headers = await window.api._getHeaders();
      const res = await fetch('/api/calendar/export.ics', { headers });
      const blob = await res.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'flow-ai-calendar.ics';
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch (e) {
      console.error('ICS download error:', e);
    } finally {
      setExporting(false);
    }
  }

  async function loadSubscription() {
    try {
      const res = await api.get('/api/calendar/subscription');
      setSubUrl(res);
    } catch (e) {
      console.error('Subscription URL error:', e);
    }
  }

  function copySubUrl() {
    if (!subUrl) return;
    navigator.clipboard.writeText(subUrl.webcal).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }).catch(() => {});
  }

  function startAdd() {
    setEditing({ type: 'meditation', title: '', description: '' });
  }
  function startEdit(e) {
    setEditing({ id: e.id, type: e.type, title: e.title || '', description: e.description || '' });
  }

  async function saveEvent() {
    if (!editing || !editing.title.trim()) return;
    setSaving(true);
    try {
      const body = {
        date: selectedDay,
        type: editing.type,
        title: editing.title.trim(),
        description: editing.description.trim(),
      };
      if (editing.id) await api.put(`/api/calendar/event/${editing.id}`, body);
      else await api.post('/api/calendar/event', body);
      setEditing(null);
      await loadMonth(viewYear, viewMonth);
    } catch (e) {
      console.error('Save event error:', e);
    } finally {
      setSaving(false);
    }
  }

  async function toggleComplete(e) {
    if (!e.completed) {
      // Marking as done → show check-in first
      setCheckIn({ eventId: e.id, feeling: null, note: '' });
      return;
    }
    // Unchecking — just toggle
    try {
      await api.put(`/api/calendar/event/${e.id}`, { completed: false });
      await loadMonth(viewYear, viewMonth);
    } catch (err) {
      console.error('Toggle complete error:', err);
    }
  }

  async function submitCheckIn(skip = false) {
    if (!checkIn) return;
    const payload = { completed: true };
    if (!skip && checkIn.feeling) {
      payload.feeling = checkIn.feeling;
      if (checkIn.note.trim()) payload.feeling_note = checkIn.note.trim();
    }
    try {
      await api.put(`/api/calendar/event/${checkIn.eventId}`, payload);
      await loadMonth(viewYear, viewMonth);
      setRefreshKey(k => k + 1);
    } catch (err) {
      console.error('Check-in submit error:', err);
    } finally {
      setCheckIn(null);
    }
  }

  async function deleteEvent(id) {
    if (!confirm(t('confirmDeleteSession'))) return;
    setSaving(true);
    try {
      await api.del(`/api/calendar/event/${id}`);
      await loadMonth(viewYear, viewMonth);
    } catch (e) {
      console.error('Delete event error:', e);
    } finally {
      setSaving(false);
    }
  }

  const todayKey = fmtDateKey(today);
  const sel = byDate[selectedDay];

  return (
    <div>
      <div className="page-header">
        <h2>{'📆'} {t('calendarPage')}</h2>
      </div>

      <ConsistencyCard t={t} refreshKey={refreshKey} />

      {/* Month navigation */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14 }}>
        <button className="btn btn-sm" onClick={() => shiftMonth(-1)}>‹</button>
        <div style={{ fontSize: 16, fontWeight: 600, minWidth: 170, textAlign: 'center', textTransform: 'capitalize' }}>
          {monthLabel}
        </div>
        <button className="btn btn-sm" onClick={() => shiftMonth(1)}>›</button>
        <button className="btn btn-sm" style={{ marginLeft: 'auto' }} onClick={() => {
          setViewYear(today.getFullYear()); setViewMonth(today.getMonth()); setSelectedDay(todayKey);
        }}>{t('todayBtn')}</button>
      </div>

      {/* Grid */}
      <div className="card" style={{ padding: 10, marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4 }}>
          {dayNames.map(d => (
            <div key={d} style={{ textAlign: 'center', fontSize: 11, color: 'var(--text-muted)', padding: '4px 0' }}>{d}</div>
          ))}
          {weeks.flat().map((d, i) => {
            const key = fmtDateKey(d);
            const inMonth = d.getMonth() === viewMonth;
            const isToday = key === todayKey;
            const isSelected = key === selectedDay;
            const day = byDate[key];
            const cycle = (data.cyclePhases || {})[key];
            const cycleMeta = cycle ? CYCLE_META[cycle.phase] : null;
            const isOvulation = cycle && cycle.phase === 'ovulation';
            const chips = [];
            if (day) {
              day.events.forEach(e => {
                const meta = SESSION_META[e.type];
                chips.push({ icon: meta ? meta.icon : '📌', bg: meta ? meta.color : 'rgba(255,255,255,0.06)', border: meta ? meta.border : 'transparent', title: e.title, completed: e.completed });
              });
              day.activities.forEach(a => chips.push({ icon: SPORT_ICONS[a.type] || '🏅', bg: 'rgba(255,255,255,0.06)', border: 'transparent', title: a.name, completed: true }));
            }
            return (
              <div key={i} onClick={() => { setSelectedDay(key); setModalOpen(true); }} style={{
                minHeight: 72, padding: 5, borderRadius: 8, cursor: 'pointer', position: 'relative',
                background: isSelected ? 'var(--surface-2)' : (cycleMeta ? cycleMeta.tint : 'transparent'),
                border: isOvulation ? '1px solid #ec4899' : (isToday ? '1px solid var(--accent-purple)' : '1px solid var(--border)'),
                opacity: inMonth ? 1 : 0.35,
              }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 3 }}>
                  <span style={{ fontSize: 11, fontFamily: 'JetBrains Mono, monospace', color: isToday ? 'var(--accent-purple)' : 'var(--text-muted)' }}>
                    {d.getDate()}
                  </span>
                  {cycleMeta && <span title={t(cycleMeta.key)} style={{ width: 7, height: 7, borderRadius: '50%', background: cycleMeta.dot }} />}
                </div>
                {isOvulation && (
                  <div style={{ fontSize: 8, fontWeight: 700, color: '#ec4899', textTransform: 'uppercase', letterSpacing: 0.3, marginBottom: 2 }}>
                    {t('cycleOvulation')}
                  </div>
                )}
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>
                  {chips.slice(0, 3).map((c, j) => (
                    <span key={j} title={c.title} style={{
                      fontSize: 12, background: c.bg, borderRadius: 4, padding: '0 2px',
                      opacity: c.completed === false ? 0.5 : 1,
                      border: `1px solid ${c.border || 'transparent'}`,
                      boxShadow: c.completed === true ? '0 0 0 1px var(--accent-green)' : 'none',
                    }}>{c.icon}</span>
                  ))}
                  {chips.length > 3 && <span style={{ fontSize: 10, color: 'var(--text-muted)' }}>+{chips.length - 3}</span>}
                  {day && day.notes.length > 0 && <span style={{ fontSize: 10 }} title={t('dailyNotes')}>📝</span>}
                  {day && day.symptomLog && (() => {
                    const e = day.symptomLog.energy;
                    const c = e >= 4 ? 'var(--accent-green)' : e <= 2 ? '#ef4444' : '#fbbf24';
                    return <span title={e != null ? `Energy ${e}/5` : 'Symptoms logged'} style={{ width: 7, height: 7, borderRadius: '50%', background: e != null ? c : 'var(--text-muted)', display: 'inline-block', flexShrink: 0 }} />;
                  })()}
                </div>
              </div>
            );
          })}
        </div>
        {loading && (
          <div style={{ display: 'flex', justifyContent: 'center', padding: 8 }}>
            <div className="spinner" style={{ width: 16, height: 16 }} />
          </div>
        )}
        {/* Cycle legend */}
        {data.cyclePhases && Object.keys(data.cyclePhases).length > 0 && (
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 10, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
            {Object.entries(CYCLE_META).map(([phase, m]) => (
              <span key={phase} style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-muted)' }}>
                <span style={{ width: 8, height: 8, borderRadius: '50%', background: m.dot }} />
                {t(m.key)}
              </span>
            ))}
          </div>
        )}
      </div>

      {/* Selected day detail — modal overlay */}
      {modalOpen && (
        <div className="modal-overlay" onClick={() => { setModalOpen(false); setEditing(null); }} style={{ alignItems: 'flex-start', overflowY: 'auto', padding: '8vh 16px 16px' }}>
          <div className="modal" onClick={e => e.stopPropagation()} style={{ width: 480, maxHeight: '80vh', overflowY: 'auto', padding: 0 }}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              padding: '18px 20px', borderBottom: '1px solid var(--border)',
              position: 'sticky', top: 0, background: 'var(--bg-card)', zIndex: 1, borderRadius: '14px 14px 0 0',
            }}>
              <div>
                <div style={{ fontSize: 16, fontWeight: 600, textTransform: 'capitalize' }}>
                  {new Date(selectedDay + 'T12:00:00').toLocaleDateString(lang, { weekday: 'long', day: 'numeric', month: 'long' })}
                </div>
                {(() => {
                  const cyc = (data.cyclePhases || {})[selectedDay];
                  if (!cyc) return null;
                  const m = CYCLE_META[cyc.phase];
                  return (
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 4, fontSize: 12, color: 'var(--text-muted)' }}>
                      <span style={{ width: 8, height: 8, borderRadius: '50%', background: m.dot }} />
                      {t(m.key)} · {t('cycleDay')} {cyc.dayOfCycle}
                    </div>
                  );
                })()}
              </div>
              <button onClick={() => { setModalOpen(false); setEditing(null); }} style={{
                background: 'none', border: 'none', color: 'var(--text-muted)', fontSize: 22,
                cursor: 'pointer', lineHeight: 1, padding: 0, width: 28, height: 28,
              }}>×</button>
            </div>

            <div style={{ padding: 20 }}>
              {/* Cycle training focus (Dr. Stacy Sims) */}
              {(() => {
                const cyc = (data.cyclePhases || {})[selectedDay];
                if (!cyc) return null;
                const m = CYCLE_META[cyc.phase];
                return (
                  <div style={{
                    marginBottom: 16, padding: '12px 14px', borderRadius: 10,
                    background: m.tint, border: `1px solid ${m.dot}`,
                  }}>
                    <div style={{ fontSize: 12, fontWeight: 700, color: m.dot, textTransform: 'uppercase', letterSpacing: 0.3, marginBottom: 5 }}>
                      {t(m.key)} · {t('cycleTrainingFocus')}
                    </div>
                    <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--text-secondary)' }}>{t(m.focusKey)}</div>
                  </div>
                );
              })()}
              {(!sel || (sel.events.length === 0 && sel.activities.length === 0 && sel.notes.length === 0 && !sel.symptomLog)) && !editing ? (
                <p style={{ color: 'var(--text-muted)', fontSize: 14, textAlign: 'center', padding: '20px 0' }}>{t('noEventsForDay')}</p>
              ) : (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                  {sel && sel.events.map((e, i) => {
                    const meta = SESSION_META[e.type];
                    return (
                      <div key={'e' + i} style={{
                        padding: '14px 16px', borderRadius: 10,
                        background: meta ? meta.color : 'var(--bg-card-hover)',
                        border: `1px solid ${e.completed ? 'var(--accent-green)' : (meta ? meta.border : 'var(--border)')}`,
                        borderLeft: `3px solid ${e.completed ? 'var(--accent-green)' : (meta ? meta.border : 'var(--border-light)')}`,
                        opacity: e.completed ? 0.85 : 1,
                      }}>
                        <div style={{ fontSize: 15, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 8 }}>
                          <span style={{ fontSize: 18 }}>{meta ? meta.icon : '📌'}</span>
                          <span style={{ textDecoration: e.completed ? 'line-through' : 'none', color: e.completed ? 'var(--text-secondary)' : (meta ? meta.border : 'var(--text-primary)') }}>{e.title}</span>
                          <span style={{ marginLeft: 'auto', display: 'flex', gap: 4 }}>
                            <button title={t('edit')} onClick={() => startEdit(e)} style={iconBtn}>✏️</button>
                            <button title={t('delete')} onClick={() => deleteEvent(e.id)} style={iconBtn}>🗑️</button>
                          </span>
                        </div>
                        {e.description && <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--text-secondary)', marginTop: 8 }}>{e.description}</div>}
                        <div style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                          <button onClick={() => toggleComplete(e)} style={{
                            padding: '5px 12px', borderRadius: 8, fontSize: 12, cursor: 'pointer',
                            fontWeight: 600,
                            background: e.completed ? 'var(--accent-green)' : 'transparent',
                            color: e.completed ? '#fff' : 'var(--accent-green)',
                            border: '1px solid var(--accent-green)',
                          }}>{e.completed ? `✓ ${t('completed')}` : t('markDone')}</button>
                          {e.completed && e.feeling && (
                            <span style={{ fontSize: 13 }} title={e.feeling_note || ''}>
                              {['😞','😕','😐','🙂','😄'][e.feeling - 1]} {e.feeling}/5
                            </span>
                          )}
                        </div>
                        {/* Post-session check-in inline panel */}
                        {checkIn && checkIn.eventId === e.id && (
                          <div style={{ marginTop: 12, padding: '12px', borderRadius: 10, background: 'var(--bg-primary)', border: '1px solid var(--border)' }}>
                            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 8 }}>How did it feel?</div>
                            <div style={{ display: 'flex', gap: 10, marginBottom: 10 }}>
                              {['😞','😕','😐','🙂','😄'].map((emoji, idx) => (
                                <button key={idx} onClick={() => setCheckIn(ci => ({ ...ci, feeling: idx + 1 }))} style={{
                                  fontSize: 22, background: 'none', border: checkIn.feeling === idx + 1 ? '2px solid var(--accent-purple)' : '2px solid transparent',
                                  borderRadius: 8, cursor: 'pointer', padding: '2px 4px',
                                }}>{emoji}</button>
                              ))}
                            </div>
                            <input
                              placeholder="Optional note (max 140 chars)"
                              value={checkIn.note}
                              onChange={ev => setCheckIn(ci => ({ ...ci, note: ev.target.value.slice(0, 140) }))}
                              style={{ width: '100%', boxSizing: 'border-box', fontSize: 12, padding: '6px 8px', background: 'var(--bg-card)', border: '1px solid var(--border)', borderRadius: 6, color: 'var(--text-primary)', marginBottom: 8 }}
                            />
                            <div style={{ display: 'flex', gap: 8 }}>
                              <button className="btn btn-primary btn-sm" onClick={() => submitCheckIn(false)}>Save</button>
                              <button className="btn btn-sm" onClick={() => submitCheckIn(true)} style={{ background: 'var(--bg-card-hover)', color: 'var(--text-primary)', border: '1px solid var(--border-light)' }}>Skip</button>
                            </div>
                          </div>
                        )}
                      </div>
                    );
                  })}
                  {sel && sel.activities.map((a, i) => (
                    <div key={'a' + i} style={{ padding: '14px 16px', borderRadius: 10, background: 'var(--bg-card-hover)', border: '1px solid var(--border-light)' }}>
                      <div style={{ fontSize: 15, display: 'flex', alignItems: 'center', gap: 8 }}>
                        <span style={{ fontSize: 18 }}>{SPORT_ICONS[a.type] || '🏅'}</span> {a.name}
                        {a.moving_time ? <span style={{ color: 'var(--text-muted)', marginLeft: 'auto', fontFamily: 'JetBrains Mono, monospace', fontSize: 13 }}>{Math.round(a.moving_time / 60)}min</span> : null}
                      </div>
                    </div>
                  ))}
                  {sel && sel.notes.map((n, i) => (
                    <div key={'n' + i} style={{ padding: '14px 16px', borderRadius: 10, border: '1px dashed var(--border)' }}>
                      <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--text-secondary)' }}>📝 {n.content}</div>
                    </div>
                  ))}
                  {sel && sel.symptomLog && (() => {
                    const log = sel.symptomLog;
                    const eColor = log.energy >= 4 ? 'var(--accent-green)' : log.energy <= 2 ? '#f87171' : '#fbbf24';
                    const eBg = log.energy >= 4 ? 'var(--accent-green-dim)' : log.energy <= 2 ? 'rgba(239,68,68,0.15)' : 'rgba(245,158,11,0.15)';
                    return (
                      <div style={{ padding: '12px 14px', borderRadius: 10, background: 'var(--bg-card-hover)', border: '1px solid var(--border-light)' }}>
                        <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 8 }}>🩺 How you felt</div>
                        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                          {log.energy != null && (
                            <span style={{ fontSize: 12, padding: '3px 10px', borderRadius: 12, background: eBg, color: eColor, border: '1px solid currentColor', fontWeight: 600 }}>
                              ⚡ {log.energy}/5
                            </span>
                          )}
                          {(log.symptoms || []).map(s => (
                            <span key={s} style={{ fontSize: 12, padding: '3px 10px', borderRadius: 12, background: 'var(--surface-2)', color: 'var(--text-primary)', border: '1px solid var(--border-light)' }}>
                              {SYMPTOM_ICONS[s] || '•'} {s.replace(/_/g, ' ')}
                            </span>
                          ))}
                          {log.notes && <span style={{ fontSize: 12, color: 'var(--text-muted)', alignSelf: 'center', fontStyle: 'italic' }}>{log.notes}</span>}
                        </div>
                      </div>
                    );
                  })()}
                </div>
              )}

              {/* Editor form */}
              {editing && (
                <div style={{ marginTop: 14, padding: 16, borderRadius: 10, background: 'var(--surface-2)', border: '1px solid var(--border)' }}>
                  <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>{editing.id ? t('editSession') : t('newSession')}</div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 10 }}>
                    {Object.keys(SESSION_META).map(type => (
                      <button key={type} onClick={() => setEditing({ ...editing, type })} style={{
                        padding: '4px 10px', borderRadius: 12, fontSize: 12, cursor: 'pointer', textTransform: 'capitalize',
                        background: editing.type === type ? 'var(--accent-purple-dim)' : 'var(--bg-card)',
                        color: editing.type === type ? 'var(--accent-purple)' : 'var(--text-secondary)',
                        border: editing.type === type ? '1px solid var(--accent-purple)' : '1px solid var(--border)',
                      }}>{SESSION_META[type].icon} {t('focus_' + type)}</button>
                    ))}
                  </div>
                  <input
                    value={editing.title}
                    onChange={e => setEditing({ ...editing, title: e.target.value })}
                    placeholder={t('sessionTitlePlaceholder')}
                    maxLength={80}
                    style={inputStyle}
                  />
                  <textarea
                    value={editing.description}
                    onChange={e => setEditing({ ...editing, description: e.target.value })}
                    placeholder={t('sessionNotesPlaceholder')}
                    rows={3}
                    maxLength={500}
                    style={{ ...inputStyle, marginTop: 8, resize: 'vertical', fontFamily: 'inherit' }}
                  />
                  <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
                    <button className="btn btn-primary btn-sm" onClick={saveEvent} disabled={saving || !editing.title.trim()}>
                      {saving ? '…' : t('save')}
                    </button>
                    <button className="btn btn-sm" onClick={() => setEditing(null)} disabled={saving}>{t('cancel')}</button>
                  </div>
                </div>
              )}

              {/* Add session */}
              {!editing && (
                <button className="btn btn-sm" onClick={startAdd} style={{ marginTop: 14, width: '100%' }}>
                  + {t('addSession')}
                </button>
              )}

              {/* Phase-specific recipe suggestions */}
              {!editing && (() => {
                const cyc = (data.cyclePhases || {})[selectedDay];
                if (!cyc) return null;
                return <DayRecipes phase={cyc.phase} t={t} />;
              })()}
            </div>
          </div>
        </div>
      )}

      {/* Export / subscribe to phone calendar */}
      <div className="card" style={{ marginBottom: 16 }}>
        <div className="card-header">
          <div className="card-title">{'📲'} {t('addToCalendar')}</div>
        </div>
        <p style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 14 }}>{t('addToCalendarDesc')}</p>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
          <button className="btn btn-sm" onClick={downloadIcs} disabled={exporting}>
            {exporting ? '…' : `⬇ ${t('downloadIcs')}`}
          </button>
          {!subUrl ? (
            <button className="btn btn-sm" onClick={loadSubscription}>🔗 {t('getSubscribeLink')}</button>
          ) : (
            <a className="btn btn-sm btn-primary" href={subUrl.webcal} style={{ textDecoration: 'none' }}>
              📅 {t('subscribeNow')}
            </a>
          )}
        </div>
        {subUrl && (
          <div style={{ marginTop: 12 }}>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 4 }}>{t('subscribeUrlLabel')}</div>
            <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
              <input readOnly value={subUrl.webcal} onFocus={e => e.target.select()} style={{
                flex: 1, fontSize: 12, fontFamily: 'JetBrains Mono, monospace', padding: '6px 8px',
                background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 6, color: 'var(--text-secondary)',
              }} />
              <button className="btn btn-sm" onClick={copySubUrl}>{copied ? t('copied') : t('copy')}</button>
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 6 }}>{t('subscribeHint')}</div>
          </div>
        )}
      </div>

      {/* Holistic month planner */}
      {isHolistic && (
        <div className="card" style={{ borderColor: 'rgba(139,92,246,0.3)' }}>
          <div className="card-header">
            <div className="card-title" style={{ color: 'var(--accent-purple)' }}>{'✨'} {t('monthPlannerTitle')}</div>
          </div>
          <p style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 14 }}>{t('monthPlannerDesc')}</p>

          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 6 }}>{t('sessionsPerWeek')}</div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 14 }}>
            {[2, 3, 4, 5, 6, 7].map(n => (
              <button key={n} onClick={() => setSessionsPerWeek(n)} style={{
                padding: '4px 12px', borderRadius: 14, fontSize: 13, cursor: 'pointer', fontFamily: 'JetBrains Mono, monospace',
                background: sessionsPerWeek === n ? 'var(--accent-purple-dim)' : 'var(--surface-2)',
                color: sessionsPerWeek === n ? 'var(--accent-purple)' : 'var(--text-secondary)',
                border: sessionsPerWeek === n ? '1px solid var(--accent-purple)' : '1px solid var(--border)',
              }}>{n}</button>
            ))}
          </div>

          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 6 }}>{t('planFocus')}</div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 16 }}>
            {Object.keys(SESSION_META).map(type => {
              const active = focus.includes(type);
              return (
                <button key={type} onClick={() => setFocus(f => active ? f.filter(x => x !== type) : [...f, type])} style={{
                  padding: '4px 12px', borderRadius: 14, fontSize: 13, cursor: 'pointer', textTransform: 'capitalize',
                  background: active ? 'var(--accent-purple-dim)' : 'var(--surface-2)',
                  color: active ? 'var(--accent-purple)' : 'var(--text-secondary)',
                  border: active ? '1px solid var(--accent-purple)' : '1px solid var(--border)',
                }}>{SESSION_META[type].icon} {t('focus_' + type)}</button>
              );
            })}
          </div>

          <div style={{ marginBottom: 16 }}>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 6 }}>{t('planConstraintsLabel')}</div>
            <textarea
              value={constraints}
              onChange={e => setConstraints(e.target.value)}
              placeholder={t('planConstraintsPlaceholder')}
              rows={2}
              style={{ ...inputStyle, resize: 'vertical', fontSize: 12, minHeight: 52 }}
            />
          </div>

          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <button className="btn btn-primary" onClick={requestPreview} disabled={planning || focus.length === 0}>
              {planning ? t('generatingPreview') : t('generatePreview')}
            </button>
            {planResult && !planResult.error && (
              <span style={{ fontSize: 13, color: 'var(--accent-green)' }}>
                ✓ {t('planCreated').replace('{n}', planResult.created.length)}
              </span>
            )}
            {planResult && planResult.error && (
              <span style={{ fontSize: 13, color: 'var(--accent-red)' }}>{planResult.error}</span>
            )}
          </div>
        </div>
      )}

      {/* Preview modal */}
      {preview && (
        <PlanPreviewModal
          preview={preview}
          setPreview={setPreview}
          onConfirm={confirmPlan}
          onCancel={() => setPreview(null)}
          confirming={confirming}
          lang={lang}
          t={t}
        />
      )}
    </div>
  );
};
