function CalendarView() {
  const { state, update } = useStore();
  const data = window.PLAN_DATA;
  const TODAY = useToday();
  const today = fmtDate(TODAY);
  const [hover, setHover] = React.useState(null);
  const [focusDate, setFocusDate] = React.useState(null);
  const byDate = {};
  data.calendar.forEach(day => { byDate[day.date] = day; });

  const firstEntry = parseDate(data.calendar[0].date);
  const startMon = new Date(firstEntry);
  while (startMon.getDay() !== 1) startMon.setDate(startMon.getDate() - 1);
  const lastEntry = parseDate(data.calendar[data.calendar.length - 1].date);
  const totalDays = daysBetween(startMon, lastEntry) + 1;
  const weeks = Math.ceil(totalDays / 7);
  const grid = [];
  for (let w = 0; w < weeks; w += 1) {
    const row = [];
    for (let dow = 0; dow < 7; dow += 1) {
      const d = new Date(startMon);
      d.setDate(d.getDate() + w * 7 + dow);
      row.push(d);
    }
    grid.push(row);
  }

  const focusEntry = focusDate ? byDate[focusDate] : null;
  const focusState = focusDate ? (state.days[focusDate] || {}) : {};

  function cellFor(d) {
    const key = fmtDate(d);
    const entry = byDate[key];
    if (!entry) return { kind: 'empty', date: key };
    return {
      kind: 'real',
      date: key,
      entry,
      done: !!state.days?.[key]?.done,
      active: dayIsActive(state.days?.[key]),
      isToday: key === today,
    };
  }

  function setFocusDay(patch) {
    if (!focusDate) return;
    update(prev => ({
      ...prev,
      days: {
        ...(prev.days || {}),
        [focusDate]: {
          ...(prev.days?.[focusDate] || {}),
          ...patch,
        },
      },
    }));
  }

  function missionTitle(entry) {
    if (!entry) return '';
    if (entry.type === 'BUFFER') return 'Buffer day.';
    if (entry.type === 'WEEKEND') return 'Deep work day.';
    if (entry.newTopicIds?.some(id => id.includes('azure'))) return 'Cloud day.';
    if (entry.newTopicIds?.some(id => id.includes('api') || id.includes('fastapi') || id.includes('sql'))) return 'API day.';
    if (entry.newTopicIds?.some(id => id.includes('genai') || id.includes('prompt'))) return 'GenAI day.';
    return 'Python day.';
  }

  return (
    <div className="calendar-page">
      <section className="calendar-head">
        <div>
          <div className="kicker">13-Week Prep OS</div>
          <h1 className="h-title">Every <em>day</em> mapped.</h1>
        </div>
        <div className="legend">
          {['STUDY', 'WEEKEND', 'BUFFER', 'PYTHON', 'API', 'AZURE', 'GENAI'].map(type => (
            <div key={type} className="legend-item">
              <span className={`legend-dot type-${type.toLowerCase()}`}></span>
              <span>{type}</span>
            </div>
          ))}
        </div>
      </section>

      <section className="calendar-heatmap">
        <div className="calendar-grid-head">
          <div></div>
          {['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].map(day => <div key={day}>{day.toUpperCase()}</div>)}
        </div>
        {grid.map((week, wi) => (
          <div className="calendar-week" key={wi}>
            <div className="calendar-week-label">{week[0].toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}</div>
            {week.map((d, di) => {
              const cell = cellFor(d);
              if (cell.kind === 'empty') return <div key={di} className="calendar-cell empty-cell"></div>;
              const firstTopic = data.topics.find(topic => topic.id === cell.entry.newTopicIds?.[0]);
              const classType = firstTopic?.category || cell.entry.type;
              return (
                <button
                  key={di}
                  className={`calendar-cell type-${String(classType).toLowerCase()} ${cell.done ? 'done' : ''} ${cell.active ? 'active-day' : ''} ${cell.isToday ? 'today-cell' : ''}`}
                  onClick={() => setFocusDate(cell.date)}
                  onMouseEnter={event => setHover({ x: event.clientX, y: event.clientY, entry: cell.entry })}
                  onMouseMove={event => setHover({ x: event.clientX, y: event.clientY, entry: cell.entry })}
                  onMouseLeave={() => setHover(null)}
                >
                  <span>{d.getDate()}</span>
                  <small>{cell.entry.type === 'WEEKEND' ? 'DEEP' : cell.entry.type}</small>
                  <em>{cell.entry.focus}</em>
                </button>
              );
            })}
          </div>
        ))}
      </section>

      {hover && (
        <div className="tip" style={{ left: Math.min(hover.x + 16, window.innerWidth - 380), top: hover.y + 14 }}>
          <div className="kicker">{hover.entry.day} - {hover.entry.display}</div>
          <strong>{hover.entry.focus}</strong>
        </div>
      )}

      {focusEntry && (
        <div className="modal-bg" onClick={() => setFocusDate(null)}>
          <div className="modal" onClick={event => event.stopPropagation()}>
            <div className="modal-head">
              <div>
                <div className="kicker">{focusEntry.day} - {focusEntry.display}</div>
                <h1 className="modal-title">{missionTitle(focusEntry)}</h1>
                <div className="row">
                  <PhasePill phase={focusEntry.phase} />
                  <TypePill type={focusEntry.type} />
                  <Pill>{focusEntry.hours}h</Pill>
                </div>
              </div>
              <button className="btn ghost" onClick={() => setFocusDate(null)}>x close</button>
            </div>

            <div className="modal-mission">
              <div className="kicker accent-text">Mission</div>
              <h2>{focusEntry.focus}</h2>
              <div className="mission-detail-grid">
                <div>
                  <div className="kicker">Concept</div>
                  <p className="copy">{focusEntry.concept}</p>
                </div>
                <div>
                  <div className="kicker">Practice</div>
                  <p className="copy">{focusEntry.practice}</p>
                </div>
                <div>
                  <div className="kicker">Done When</div>
                  <p className="copy">{focusEntry.deliverable}</p>
                </div>
              </div>
              <div className="daily-block-list">
                {(focusEntry.blocks || []).map(block => (
                  <div className="daily-block-row" key={block.label}>
                    <span className="mono accent-text">{block.minutes}m</span>
                    <strong>{block.label}</strong>
                    <p>{block.task}</p>
                  </div>
                ))}
              </div>
              {!!focusEntry.dueRebuildIds?.length && (
                <div className="due-topic-list">
                  <div className="kicker">Due Rebuild Topics</div>
                  {focusEntry.dueRebuildIds.slice(0, 8).map(id => {
                    const topic = state.rebuild?.topics?.[id] || data.topics.find(item => item.id === id);
                    if (!topic) return null;
                    return (
                      <div className="due-topic-row" key={id}>
                        <Pill tone={categoryTone(topic.category)}>{categoryLabel(topic.category)}</Pill>
                        <div>
                          <strong>{topic.title}</strong>
                          <p>{topic.artifactPrompt}</p>
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
            </div>

            <div className="modal-log">
              <div className="row">
                <Check on={!!focusState.done} onClick={() => setFocusDay({ done: !focusState.done })} size={28} />
                <strong>{focusState.done ? 'Day complete' : 'Mark day complete'}</strong>
              </div>
              <div className="daily-log-grid">
                <label>
                  <span className="kicker">Actual Hours</span>
                  <input className="input mono" type="number" step="0.25" min="0" placeholder="0.0" value={focusState.actualHours || ''} onChange={event => setFocusDay({ actualHours: event.target.value })} />
                </label>
                <label>
                  <span className="kicker">Sleep Hours</span>
                  <input className="input mono" type="number" step="0.25" min="0" placeholder="0.0" value={focusState.sleepHours || ''} onChange={event => setFocusDay({ sleepHours: event.target.value })} />
                </label>
                <label>
                  <span className="kicker">Energy (1-5)</span>
                  <Rating value={focusState.energy || 0} onChange={value => setFocusDay({ energy: value })} />
                </label>
                <label>
                  <span className="kicker">Sleep Quality (1-5)</span>
                  <Rating value={focusState.sleep || 0} onChange={value => setFocusDay({ sleep: value })} color="var(--blue)" />
                </label>
              </div>
              <textarea className="textarea" placeholder="Notes - wins, blockers, weak concepts..." value={focusState.note || ''} onChange={event => setFocusDay({ note: event.target.value })} />
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

window.CalendarView = CalendarView;
