// 方案 ② —— 日历月 + 点一下放大过场（rAF 驱动，环境无关）
function MonthCalendar({ onExit }) {
  const wrapRef = useRef(null);
  const [drill, setDrill] = useState(null); // {type:'day'|'week', value, rect}
  const [p, setP] = useState(0);            // 放大进度 0..1
  const pRef = useRef(0);
  const rafRef = useRef(null);
  const fullRef = useRef({ w: 0, h: 0 });
  const lerp = (a, b, t) => a + (b - a) * t;

  const cc = (id) => (window.CATS[id] || {}).color || '#9DB4BF';

  const setProg = (v) => { pRef.current = v; setP(v); };
  const tweenP = (target, done) => {
    cancelAnimationFrame(rafRef.current);
    const start = pRef.current, t0 = performance.now(), dur = 400;
    const ease = (t) => 1 - Math.pow(1 - t, 3);
    const step = (now) => {
      const t = Math.min(1, (now - t0) / dur);
      setProg(start + (target - start) * ease(t));
      if (t < 1) rafRef.current = requestAnimationFrame(step);
      else if (done) done();
    };
    rafRef.current = requestAnimationFrame(step);
  };

  const openFrom = (e, type, value) => {
    const wrap = wrapRef.current.getBoundingClientRect();
    const r = e.currentTarget.getBoundingClientRect();
    fullRef.current = { w: wrap.width, h: wrap.height };
    setDrill({ type, value, rect: { top: r.top - wrap.top, left: r.left - wrap.left, width: r.width, height: r.height } });
    setProg(0);
    requestAnimationFrame(() => tweenP(1));
  };
  const back = () => { tweenP(0, () => setDrill(null)); };

  return (
    <div ref={wrapRef} style={mcStyles.root}>
      <div style={mcStyles.head}>
        <div style={mcStyles.title}>六月</div>
        <div style={mcStyles.subRow}>
          {Object.values(window.THREADS).map(t => (
            <span key={t.id} style={mcStyles.threadTag}>
              <span style={{ ...mcStyles.threadLine, background: t.color }} />{t.name}
            </span>
          ))}
        </div>
      </div>

      <div style={mcStyles.weekHdr}>
        {window.WEEKDAYS.map(w => <div key={w} style={mcStyles.wd}>{w}</div>)}
      </div>

      <div style={mcStyles.gridWrap}>
        {window.WEEKS.map((week, wi) => (
          <div key={wi} style={mcStyles.weekRow}>
            <button style={mcStyles.weekGrip} onClick={(e) => openFrom(e, 'week', wi)} title="看这一周">
              <span style={mcStyles.gripBar} /><span style={mcStyles.gripTxt}>W{wi + 1}</span>
            </button>
            <div style={mcStyles.daysRow}>
              {week.map((day, di) => {
                if (!day) return <div key={di} style={mcStyles.empty} />;
                const ch = window.CHANNELS[day.channel];
                const isToday = day.d === window.TODAY;
                return (
                  <button key={di} onClick={(e) => openFrom(e, 'day', day.d)}
                    style={{
                      ...mcStyles.cell,
                      background: day.rest ? 'rgba(255,255,255,0.30)' : `${ch.tint}aa`,
                      ...(isToday ? mcStyles.cellToday : {}),
                    }}>
                    <span style={{ ...mcStyles.cellNum, ...(isToday ? mcStyles.cellNumToday : {}) }}>{day.d}</span>
                    {day.rest ? (
                      <span style={mcStyles.restDot}>留白</span>
                    ) : (
                      <span style={mcStyles.dots}>
                        {day.key.slice(0, 3).map((it, i) => (
                          <span key={i} style={{ ...mcStyles.dot, background: cc(it.cat) }} />
                        ))}
                      </span>
                    )}
                  </button>
                );
              })}
            </div>
          </div>
        ))}
      </div>

      <div style={mcStyles.foot}>
        <span style={mcStyles.footHint}>点某天 → 放大成「日」 · 点左侧 W → 看「周」</span>
      </div>

      {/* 放大过场（rAF 驱动，inline 计算，环境无关）*/}
      {drill && (
        <div style={{
          ...mcStyles.overlay,
          top: lerp(drill.rect.top, 0, p),
          left: lerp(drill.rect.left, 0, p),
          width: lerp(drill.rect.width, fullRef.current.w, p),
          height: lerp(drill.rect.height, fullRef.current.h, p),
          borderRadius: 14 * (1 - p),
        }}>
          <div style={{ ...mcStyles.overlayInner, opacity: Math.max(0, Math.min(1, (p - 0.2) / 0.5)) }}>
            <button style={mcStyles.backBtn} onClick={back}>‹ 六月</button>
            {drill.type === 'day'
              ? <TodayView dayNum={drill.value} />
              : <WeekView weekIndex={drill.value}
                  onPickDay={(d) => { setDrill({ type: 'day', value: d, rect: drill.rect }); }}
                  onPickToday={() => { setDrill({ type: 'day', value: window.TODAY, rect: drill.rect }); }} />}
          </div>
        </div>
      )}
    </div>
  );
}

const mcStyles = {
  root: { flex: 1, minHeight: 0, position: 'relative', display: 'flex', flexDirection: 'column', padding: '16px 14px 6px' },
  head: { padding: '2px 6px 10px' },
  title: { fontSize: 28, fontWeight: 700, letterSpacing: '-0.5px' },
  subRow: { display: 'flex', gap: 12, marginTop: 6, flexWrap: 'wrap' },
  threadTag: { fontSize: 11.5, fontWeight: 600, color: 'var(--ink-soft)', display: 'flex', alignItems: 'center', gap: 5 },
  threadLine: { width: 16, height: 3, borderRadius: 2, display: 'inline-block' },

  weekHdr: { display: 'flex', paddingLeft: 30, marginBottom: 4 },
  wd: { flex: 1, textAlign: 'center', fontSize: 11, fontWeight: 700, color: 'var(--ink-faint)' },

  gridWrap: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', gap: 7 },
  weekRow: { flex: 1, display: 'flex', gap: 6, alignItems: 'stretch' },
  weekGrip: { width: 24, flexShrink: 0, border: 'none', background: 'rgba(255,255,255,0.35)', borderRadius: 10, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 4, cursor: 'pointer', padding: 0 },
  gripBar: { width: 3, height: 18, borderRadius: 2, background: 'linear-gradient(#6FCBB2,#6FB4FF)' },
  gripTxt: { fontSize: 9, fontWeight: 700, color: 'var(--ink-faint)' },

  daysRow: { flex: 1, display: 'flex', gap: 6 },
  empty: { flex: 1 },
  cell: { flex: 1, border: '1px solid rgba(255,255,255,0.55)', borderRadius: 14, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'space-between', padding: '7px 2px 8px', cursor: 'pointer', boxShadow: '0 5px 14px -12px rgba(54,84,99,.5)', transition: 'transform .15s ease' },
  cellToday: { border: '1.5px solid #6FCBB2', boxShadow: '0 8px 18px -8px rgba(111,180,178,.55)' },
  cellNum: { fontSize: 15, fontWeight: 700, color: 'var(--ink)', lineHeight: 1 },
  cellNumToday: { color: '#fff', background: 'linear-gradient(135deg,#6FCBB2,#6FB4FF)', width: 24, height: 24, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center' },
  dots: { display: 'flex', gap: 3, height: 8, alignItems: 'center' },
  dot: { width: 6, height: 6, borderRadius: 999 },
  restDot: { fontSize: 9.5, color: 'var(--ink-faint)', fontWeight: 600, opacity: .8 },

  foot: { textAlign: 'center', padding: '8px 0 4px' },
  footHint: { fontSize: 11.5, color: 'var(--ink-faint)', fontWeight: 500 },

  overlay: { position: 'absolute', overflow: 'hidden', background: 'linear-gradient(165deg,#EAF6F1 0%,#DEEDFF 52%,#F3E8F5 100%)', boxShadow: '0 30px 80px -30px rgba(54,84,99,.5)', willChange: 'top,left,width,height', zIndex: 50 },
  overlayInner: { position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column' },
  backBtn: { alignSelf: 'flex-start', margin: '14px 0 0 16px', border: 'none', background: 'rgba(255,255,255,0.7)', color: 'var(--ink)', fontSize: 14, fontWeight: 600, padding: '7px 14px', borderRadius: 999, cursor: 'pointer', fontFamily: 'var(--font)', boxShadow: '0 6px 16px -8px rgba(54,84,99,.4)', flexShrink: 0 },
};

window.MonthCalendar = MonthCalendar;
