// ---------- Kursplan ----------
// Monthly calendar plotting course events. Uses the same filter set as the
// Alle-Kurse page (category chips, leader select, free-text search). The
// occurrence data is placeholder — designed so a backend / Google Calendar
// feed can drop in via window.WB_KURSPLAN_EVENTS later (see fallback below).

const { useState: useStateK, useMemo: useMemoK, useEffect: useEffectK } = React;

const kpCats = window.WB_CATEGORIES;
const kpCourses = window.WB_COURSES;
const kpLeaders = window.WB_LEADERS;
const kpCatById = Object.fromEntries(kpCats.map(c => [c.id, c]));
const kpCourseById = Object.fromEntries(kpCourses.map(c => [c.id, c]));

// ---------- Date helpers ----------
const KP_MONTHS = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
const KP_DOW = ['Mo','Di','Mi','Do','Fr','Sa','So'];
const kpPad = n => String(n).padStart(2, '0');
const kpKey = d => `${d.getFullYear()}-${kpPad(d.getMonth()+1)}-${kpPad(d.getDate())}`;
const kpSameDay = (a, b) => a.getFullYear()===b.getFullYear() && a.getMonth()===b.getMonth() && a.getDate()===b.getDate();
const kpAddDays = (d, n) => { const r = new Date(d); r.setDate(r.getDate()+n); return r; };
const kpStartOfMonthGrid = (year, month) => {
  // Monday-first 6-week grid
  const first = new Date(year, month, 1);
  const dow = (first.getDay() + 6) % 7; // Mon=0..Sun=6
  return kpAddDays(first, -dow);
};

// ---------- Placeholder occurrence generator ----------
// Maps course schedule strings → recurring weekday patterns. This is the
// stand-in for a real Google Calendar feed: same shape (date+course) so
// swapping it out is mechanical.
const KP_DOW_MAP = { 'Mo':1, 'Di':2, 'Mi':3, 'Do':4, 'Fr':5, 'Sa':6, 'So':0 };
const kpParseSchedule = (raw) => {
  // Returns { dows: [1..7], time: '10:00–11:30' } or null when ad-hoc
  if (!raw) return null;
  const dowMatches = [...raw.matchAll(/\b(Mo|Di|Mi|Do|Fr|Sa|So)\b/g)].map(m => KP_DOW_MAP[m[1]]);
  const timeMatch = raw.match(/(\d{1,2}:\d{2})\s*[–-]\s*(\d{1,2}:\d{2})/);
  if (!dowMatches.length) return null;
  return {
    dows: [...new Set(dowMatches)],
    time: timeMatch ? `${timeMatch[1]}–${timeMatch[2]}` : '',
  };
};

const kpBuildEvents = () => {
  // If a backend feed is present, use it as-is.
  if (Array.isArray(window.WB_KURSPLAN_EVENTS) && window.WB_KURSPLAN_EVENTS.length) {
    return window.WB_KURSPLAN_EVENTS;
  }
  // Otherwise generate ~6 months of recurring occurrences from course schedules.
  const events = [];
  const today = new Date();
  const start = new Date(today.getFullYear(), today.getMonth() - 1, 1);
  const end = new Date(today.getFullYear(), today.getMonth() + 5, 0);
  kpCourses.forEach(course => {
    const parsed = kpParseSchedule(course.schedule);
    if (!parsed) return;
    let cursor = new Date(start);
    while (cursor <= end) {
      if (parsed.dows.includes(cursor.getDay())) {
        events.push({
          id: `${course.id}-${kpKey(cursor)}`,
          courseId: course.id,
          date: new Date(cursor),
          time: parsed.time,
        });
      }
      cursor = kpAddDays(cursor, 1);
    }
  });
  return events;
};

// ---------- Filter bar (mirrors all-courses, compacted for inline use) ----------
const KpFilterBar = ({ activeCat, setActiveCat, leader, setLeader, query, setQuery, count }) => {
  // Collapse on small viewports. Mobile users open the panel only when they
  // want to filter — saves a ton of vertical space above the calendar.
  const [isMobile, setIsMobile] = useStateK(() =>
    typeof window !== 'undefined' && window.matchMedia
      ? window.matchMedia('(max-width: 720px)').matches
      : false
  );
  const [open, setOpen] = useStateK(false);

  useEffectK(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return undefined;
    const mq = window.matchMedia('(max-width: 720px)');
    const onChange = (e) => {
      setIsMobile(e.matches);
      // When growing back to desktop, force the panel open so it always
      // shows; on shrink, collapse it again.
      if (!e.matches) setOpen(false);
    };
    onChange(mq);
    mq.addEventListener ? mq.addEventListener('change', onChange) : mq.addListener(onChange);
    return () => {
      mq.removeEventListener ? mq.removeEventListener('change', onChange) : mq.removeListener(onChange);
    };
  }, []);

  // Count active (non-default) filters for the summary chip
  const activeCount =
    (activeCat !== 'all' ? 1 : 0) +
    (leader !== 'all' ? 1 : 0) +
    (query.trim() ? 1 : 0);

  const activeCatLabel = activeCat === 'all'
    ? null
    : (kpCats.find(c => c.id === activeCat) || {}).title;

  const resetAll = (e) => {
    e.stopPropagation();
    setActiveCat('all');
    setLeader('all');
    setQuery('');
  };

  const expanded = !isMobile || open;

  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: expanded ? 14 : 0,
      padding: isMobile ? '14px 16px' : '20px 22px',
      background: 'rgba(250, 246, 241, 0.6)',
      border: '1px solid rgba(196, 169, 143, 0.4)',
      borderRadius: 14,
      marginBottom: 24,
      backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)',
      transition: 'gap 200ms var(--ease)',
    }}>
      {/* Mobile-only summary header — tap to expand/collapse */}
      {isMobile && (
        <button type="button"
          onClick={() => setOpen(o => !o)}
          aria-expanded={open}
          aria-controls="kp-filter-body"
          style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            gap: 10, padding: '4px 0',
            background: 'transparent', border: 'none',
            fontFamily: 'inherit', cursor: 'pointer',
            color: 'var(--ink)', textAlign: 'left',
          }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
            <span aria-hidden="true" style={{
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              width: 22, height: 22,
              fontSize: 13, color: 'var(--ink-70)',
            }}>
              {/* Filter icon */}
              <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                <path d="M2 4h12M4 8h8M6 12h4" />
              </svg>
            </span>
            <span style={{ fontSize: 13.5, fontWeight: 600, letterSpacing: '0.01em' }}>
              Filter
            </span>
            {activeCount > 0 ? (
              <span style={{
                display: 'inline-flex', alignItems: 'center',
                fontSize: 11.5, fontWeight: 600,
                padding: '2px 8px', borderRadius: 999,
                background: 'var(--heather-plum)', color: 'var(--offwhite)',
                lineHeight: 1.4,
              }}>
                {activeCount} aktiv
              </span>
            ) : (
              <span style={{
                fontSize: 12, color: 'var(--ink-50)',
                whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0,
              }}>
                {activeCatLabel ? `Kategorie: ${activeCatLabel}` : `${count} ${count === 1 ? 'Termin' : 'Termine'}`}
              </span>
            )}
          </span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
            {activeCount > 0 && (
              <span
                role="button"
                onClick={resetAll}
                style={{
                  fontSize: 11.5, fontWeight: 500,
                  color: 'var(--ink-70)', textDecoration: 'underline',
                  textUnderlineOffset: 2, cursor: 'pointer',
                }}
              >zurücksetzen</span>
            )}
            <span aria-hidden="true" style={{
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              width: 22, height: 22,
              fontSize: 11, color: 'var(--ink-50)',
              transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
              transition: 'transform 200ms var(--ease)',
            }}>▼</span>
          </span>
        </button>
      )}

      {/* Collapsible body */}
      <div
        id="kp-filter-body"
        style={{
          display: 'flex', flexDirection: 'column', gap: 14,
          overflow: 'hidden',
          maxHeight: expanded ? 800 : 0,
          opacity: expanded ? 1 : 0,
          marginTop: expanded && isMobile ? 6 : 0,
          transition: 'max-height 280ms var(--ease), opacity 180ms var(--ease), margin-top 200ms var(--ease)',
          pointerEvents: expanded ? 'auto' : 'none',
        }}
        aria-hidden={!expanded}
      >
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
          <KpCatChip active={activeCat === 'all'} onClick={() => setActiveCat('all')}
            label="Alle" tone={null} count={kpCourses.length} />
          {kpCats.map(c => {
            const n = kpCourses.filter(x => x.cat === c.id).length;
            return (
              <KpCatChip key={c.id} active={activeCat === c.id}
                onClick={() => setActiveCat(c.id)}
                label={c.title} tone={c} count={n} />
            );
          })}
        </div>

        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center' }}>
          <div style={{ position: 'relative', flex: '1 1 240px', maxWidth: 320 }}>
            <input type="text" value={query} onChange={(e) => setQuery(e.target.value)}
              placeholder="Kurs suchen…"
              style={{
                width: '100%', padding: '10px 14px 10px 36px',
                background: 'var(--offwhite)',
                border: '1px solid var(--sandstone)', borderRadius: 10,
                fontSize: 13.5, fontFamily: 'inherit', color: 'var(--ink)',
                outline: 'none',
              }} />
            <span style={{
              position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)',
              fontSize: 13, opacity: 0.5,
            }}>⌕</span>
          </div>

          <div style={{ position: 'relative', minWidth: 220 }}>
            <select value={leader} onChange={(e) => setLeader(e.target.value)}
              style={{
                width: '100%',
                appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none',
                padding: '10px 36px 10px 14px',
                borderRadius: 10,
                background: 'var(--offwhite)',
                border: '1px solid var(--sandstone)',
                fontSize: 13.5, fontFamily: 'inherit', color: 'var(--ink)',
                fontWeight: 500, lineHeight: 1.4,
                cursor: 'pointer', outline: 'none',
              }}>
              <option value="all">Alle Kursleitungen</option>
              {kpLeaders.map(n => <option key={n} value={n}>{n}</option>)}
            </select>
            <span style={{
              position: 'absolute', right: 14, top: '50%',
              transform: 'translateY(-50%)',
              fontSize: 10, color: 'var(--ink-50)',
              pointerEvents: 'none', lineHeight: 1,
            }}>▼</span>
          </div>

          <span style={{ marginLeft: 'auto', fontSize: 12.5, color: 'var(--ink-70)' }}>
            {count} {count === 1 ? 'Termin' : 'Termine'} im Monat
          </span>
        </div>
      </div>
    </div>
  );
};

const KpCatChip = ({ active, onClick, label, tone, count }) => {
  const baseBg = tone ? tone.pill.bg : '#FAF6F1';
  const baseText = tone ? tone.pill.text : 'var(--ink-70)';
  const baseBorder = tone ? tone.pill.border : 'var(--sandstone)';
  return (
    <button type="button" onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 7,
      padding: '7px 12px', borderRadius: 999,
      background: active && tone ? tone.tone.bg : (active ? 'var(--ink)' : baseBg),
      color: active ? (tone ? tone.tone.text : '#FAF6F1') : baseText,
      border: '1px solid ' + (active ? 'transparent' : baseBorder),
      fontSize: 12.5, fontWeight: 500, fontFamily: 'inherit',
      cursor: 'pointer', transition: 'all 160ms var(--ease)',
      whiteSpace: 'nowrap',
    }}>
      {tone && <span style={{
        width: 7, height: 7, borderRadius: 999,
        background: active ? 'rgba(255,255,255,0.9)' : tone.tone.solid,
      }} />}
      {label}
      <span style={{
        fontSize: 10.5, fontWeight: 600,
        opacity: active ? 0.75 : 0.55,
        marginLeft: 1,
      }}>{count}</span>
    </button>
  );
};

// ---------- Calendar grid ----------
const KpMonthGrid = ({ year, month, eventsByDay, onPickDay, selectedKey }) => {
  const _onPick = (key, e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    onPickDay(key, rect);
  };
  const today = new Date();
  const grid = useMemoK(() => {
    const start = kpStartOfMonthGrid(year, month);
    const out = [];
    for (let i = 0; i < 42; i++) out.push(kpAddDays(start, i));
    return out;
  }, [year, month]);

  return (
    <div style={{
      background: 'var(--offwhite)',
      border: '1px solid rgba(196, 169, 143, 0.5)',
      borderRadius: 16,
      overflow: 'hidden',
      boxShadow: '0 4px 16px rgba(42,34,29,0.06)',
    }}>
      {/* DOW header */}
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)',
        background: 'rgba(232, 213, 192, 0.45)',
        borderBottom: '1px solid rgba(196, 169, 143, 0.4)',
      }}>
        {KP_DOW.map((d, i) => (
          <div key={d} style={{
            padding: '10px 12px',
            fontSize: 11, fontWeight: 600, letterSpacing: '0.12em',
            textTransform: 'uppercase',
            color: i >= 5 ? 'var(--ink-50)' : 'var(--ink-70)',
            textAlign: 'left',
          }}>{d}</div>
        ))}
      </div>

      {/* Day cells */}
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)',
        gridAutoRows: 'minmax(108px, auto)',
      }}>
        {grid.map((d, i) => {
          const inMonth = d.getMonth() === month;
          const isToday = kpSameDay(d, today);
          const key = kpKey(d);
          const evs = eventsByDay[key] || [];
          const isSelected = selectedKey === key;
          const isWeekend = d.getDay() === 0 || d.getDay() === 6;
          const row = Math.floor(i / 7);
          const col = i % 7;
          return (
            <button key={key} type="button"
              data-kp-cell="1"
              onClick={(e) => evs.length && _onPick(key, e)}
              style={{
                textAlign: 'left',
                background: isSelected ? 'var(--heather-subtle)'
                  : (isToday ? 'rgba(232, 213, 192, 0.35)' : 'transparent'),
                border: 'none',
                borderRight: col < 6 ? '1px solid rgba(196, 169, 143, 0.2)' : 'none',
                borderTop: row > 0 ? '1px solid rgba(196, 169, 143, 0.2)' : 'none',
                padding: '8px 8px 10px',
                fontFamily: 'inherit',
                cursor: evs.length ? 'pointer' : 'default',
                opacity: inMonth ? 1 : 0.38,
                position: 'relative',
                minHeight: 108,
                display: 'flex', flexDirection: 'column', gap: 4,
                transition: 'background 140ms var(--ease)',
              }}
              onMouseEnter={(e) => {
                if (evs.length && !isSelected) {
                  e.currentTarget.style.background = 'rgba(239, 227, 231, 0.5)';
                }
              }}
              onMouseLeave={(e) => {
                if (!isSelected) {
                  e.currentTarget.style.background = isToday ? 'rgba(232, 213, 192, 0.35)' : 'transparent';
                }
              }}
            >
              <div style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                marginBottom: 2,
              }}>
                <span style={{
                  fontSize: 13, fontWeight: isToday ? 700 : 500,
                  fontFamily: isToday ? 'Fraunces, serif' : 'inherit',
                  color: isWeekend && inMonth ? 'var(--ink-50)' : 'var(--ink)',
                  display: 'inline-flex', alignItems: 'center',
                  width: 22, height: 22, borderRadius: 999,
                  justifyContent: 'center',
                  background: isToday ? 'var(--heather-plum)' : 'transparent',
                  color: isToday ? 'var(--offwhite)' : (isWeekend && inMonth ? 'var(--ink-50)' : 'var(--ink)'),
                }}>{d.getDate()}</span>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 3, overflow: 'hidden' }}>
                {evs.slice(0, 3).map(ev => {
                  const c = kpCourseById[ev.courseId];
                  const cat = kpCatById[c.cat];
                  return (
                    <div key={ev.id} style={{
                      fontSize: 10.5, lineHeight: 1.25,
                      padding: '3px 7px',
                      borderRadius: 6,
                      background: cat.pill.bg,
                      color: cat.pill.text,
                      borderLeft: `3px solid ${cat.tone.solid}`,
                      whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                      fontWeight: 500,
                    }} title={`${c.title} · ${ev.time}`}>
                      {ev.time && <span style={{ fontVariantNumeric: 'tabular-nums', opacity: 0.7, marginRight: 4 }}>{ev.time.split('–')[0]}</span>}
                      {c.title}
                    </div>
                  );
                })}
                {evs.length > 3 && (
                  <div style={{
                    fontSize: 10, color: 'var(--ink-50)',
                    padding: '1px 7px', fontWeight: 500,
                  }}>+{evs.length - 3} weitere</div>
                )}
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
};

// ---------- Day detail popover (floats next to clicked cell) ----------
const KpDayPopover = ({ dayKey, anchorRect, events, onOpenInquiry, onClear }) => {
  const popRef = React.useRef(null);
  const [pos, setPos] = useStateK(null);

  // Position the popover next to the anchor cell — flip to the left or above
  // when there's not enough room on the right / below. Recomputes on resize
  // and scroll so it stays glued to its cell.
  useEffectK(() => {
    if (!dayKey || !anchorRect) return undefined;
    const W = 340, GAP = 10, MARGIN = 12;
    const compute = () => {
      const vw = window.innerWidth;
      const vh = window.innerHeight;
      const rect = anchorRect;
      // Horizontal: prefer right of cell; flip left if no room
      let left = rect.right + GAP;
      if (left + W > vw - MARGIN) left = rect.left - GAP - W;
      if (left < MARGIN) left = Math.max(MARGIN, Math.min(vw - W - MARGIN, rect.left));
      // Vertical: align top to cell top, then clamp into viewport
      const maxH = Math.min(420, vh - MARGIN * 2);
      let top = rect.top;
      if (top + maxH > vh - MARGIN) top = Math.max(MARGIN, vh - maxH - MARGIN);
      if (top < MARGIN) top = MARGIN;
      setPos({ left, top, maxH, width: W });
    };
    compute();
    window.addEventListener('resize', compute);
    window.addEventListener('scroll', compute, true);
    return () => {
      window.removeEventListener('resize', compute);
      window.removeEventListener('scroll', compute, true);
    };
  }, [dayKey, anchorRect]);

  // Outside-click + Escape dismiss
  useEffectK(() => {
    if (!dayKey) return undefined;
    const onDown = (e) => {
      if (popRef.current && !popRef.current.contains(e.target)) {
        // Don't close if click landed on a calendar day cell — let the cell
        // handler swap the selection cleanly.
        const cell = e.target.closest && e.target.closest('[data-kp-cell]');
        if (cell) return;
        onClear();
      }
    };
    const onKey = (e) => { if (e.key === 'Escape') onClear(); };
    document.addEventListener('mousedown', onDown);
    window.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDown);
      window.removeEventListener('keydown', onKey);
    };
  }, [dayKey, onClear]);

  if (!dayKey || !pos) return null;
  const [y, m, d] = dayKey.split('-').map(Number);
  const date = new Date(y, m-1, d);
  const dowLong = ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'][date.getDay()];

  return (
    <div ref={popRef} style={{
      position: 'fixed',
      left: pos.left, top: pos.top,
      width: pos.width, maxHeight: pos.maxH,
      background: 'var(--offwhite)',
      border: '1px solid rgba(196, 169, 143, 0.5)',
      borderRadius: 14,
      padding: '18px 20px 20px',
      boxShadow: '0 18px 48px rgba(42,34,29,0.22)',
      zIndex: 80,
      display: 'flex', flexDirection: 'column',
      animation: 'kpPop 180ms var(--ease)',
    }}>
      <style>{`@keyframes kpPop{from{opacity:0;transform:translateY(4px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}`}</style>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14, flexShrink: 0 }}>
        <div>
          <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--heather-plum)' }}>
            {dowLong}
          </div>
          <div style={{
            fontFamily: 'Fraunces, serif', fontSize: 24, lineHeight: 1.05,
            fontVariationSettings: '"opsz" 96, "SOFT" 50, "WONK" 1',
            color: 'var(--ink)', marginTop: 4,
          }}>{d}. {KP_MONTHS[m-1]}</div>
        </div>
        <button type="button" onClick={onClear} aria-label="Schließen" style={{
          width: 28, height: 28, borderRadius: 999,
          background: 'transparent', color: 'var(--ink-50)',
          border: '1px solid var(--sandstone-border)', fontSize: 15, lineHeight: 1,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer',
        }}>×</button>
      </div>

      <div style={{
        display: 'flex', flexDirection: 'column', gap: 10,
        overflowY: 'auto', minHeight: 0,
        margin: '0 -4px', padding: '0 4px',
      }}>
        {events.length === 0 ? (
          <div style={{ color: 'var(--ink-70)', fontSize: 13.5 }}>Keine Termine an diesem Tag.</div>
        ) : events.map(ev => {
          const c = kpCourseById[ev.courseId];
          const cat = kpCatById[c.cat];
          return (
            <div key={ev.id} style={{
              border: '1px solid ' + cat.pill.border,
              borderLeft: `4px solid ${cat.tone.solid}`,
              borderRadius: 10,
              padding: '12px 14px',
              background: '#FAF6F1',
              display: 'flex', flexDirection: 'column', gap: 4,
            }}>
              <div style={{
                display: 'flex', alignItems: 'center', gap: 8,
                fontSize: 10.5, fontWeight: 600, letterSpacing: '0.12em', textTransform: 'uppercase',
                color: cat.pill.text,
              }}>
                <span style={{ width: 6, height: 6, borderRadius: 999, background: cat.tone.solid }} />
                {cat.title}
                {ev.time && (
                  <span style={{
                    marginLeft: 'auto',
                    fontSize: 11.5, color: 'var(--ink-70)',
                    fontVariantNumeric: 'tabular-nums', letterSpacing: 0,
                    textTransform: 'none', fontWeight: 500,
                  }}>{ev.time}</span>
                )}
              </div>
              <div style={{
                fontFamily: 'Fraunces, serif', fontSize: 17, lineHeight: 1.2,
                fontVariationSettings: '"opsz" 96, "SOFT" 50',
                color: 'var(--ink)',
              }}>{c.title}</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-70)' }}>
                Mit <span style={{ color: 'var(--ink)' }}>{c.leader}</span>
              </div>
              <button type="button"
                onClick={() => onOpenInquiry({ title: c.title, kind: 'course' })}
                style={{
                  marginTop: 6, alignSelf: 'flex-start',
                  fontSize: 12, fontWeight: 600,
                  color: cat.pill.text,
                  background: 'transparent',
                  border: 'none', padding: 0, cursor: 'pointer',
                }}>Anfrage stellen →</button>
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ---------- Top-level Kursplan section ----------
const Kursplan = ({ onOpenInquiry }) => {
  const headRef = useReveal();
  const today = new Date();
  const [year, setYear] = useStateK(today.getFullYear());
  const [month, setMonth] = useStateK(today.getMonth());

  const [activeCat, setActiveCat] = useStateK('all');
  const [leader, setLeader] = useStateK('all');
  const [query, setQuery] = useStateK('');
  const [selectedKey, setSelectedKey] = useStateK(null);
  const [anchorRect, setAnchorRect] = useStateK(null);

  const pickDay = (key, rect) => {
    setSelectedKey(key);
    setAnchorRect(rect);
  };
  const clearDay = () => {
    setSelectedKey(null);
    setAnchorRect(null);
  };

  const allEvents = useMemoK(() => kpBuildEvents(), []);

  // Apply filters
  const filteredEvents = useMemoK(() => {
    const q = query.trim().toLowerCase();
    return allEvents.filter(ev => {
      const c = kpCourseById[ev.courseId];
      if (!c) return false;
      if (activeCat !== 'all' && c.cat !== activeCat) return false;
      if (leader !== 'all' && c.leader !== leader) return false;
      if (q && !(c.title.toLowerCase().includes(q) || c.desc.toLowerCase().includes(q) || c.leader.toLowerCase().includes(q))) return false;
      return true;
    });
  }, [allEvents, activeCat, leader, query]);

  // Group by day for the active month
  const eventsByDay = useMemoK(() => {
    const out = {};
    filteredEvents.forEach(ev => {
      if (ev.date.getFullYear() === year && ev.date.getMonth() === month) {
        const k = kpKey(ev.date);
        (out[k] = out[k] || []).push(ev);
      }
    });
    Object.values(out).forEach(list => list.sort((a, b) => (a.time || '').localeCompare(b.time || '')));
    return out;
  }, [filteredEvents, year, month]);

  const monthCount = useMemoK(() => Object.values(eventsByDay).reduce((s, v) => s + v.length, 0), [eventsByDay]);
  const selectedEvents = selectedKey ? (eventsByDay[selectedKey] || []) : [];

  const goPrev = () => {
    clearDay();
    if (month === 0) { setYear(y => y - 1); setMonth(11); }
    else setMonth(m => m - 1);
  };
  const goNext = () => {
    clearDay();
    if (month === 11) { setYear(y => y + 1); setMonth(0); }
    else setMonth(m => m + 1);
  };
  const goToday = () => {
    const t = new Date();
    setYear(t.getFullYear()); setMonth(t.getMonth()); clearDay();
  };

  return (
    <section id="kursplan" style={{ padding: 'clamp(80px, 12vw, 128px) 0 clamp(40px, 6vw, 64px)' }}>
      <div className="container">
        <div ref={headRef} className="reveal" style={{
          marginBottom: 32, display: 'flex', alignItems: 'flex-end',
          justifyContent: 'space-between', gap: 24, flexWrap: 'wrap',
        }}>
          <div style={{ maxWidth: 720 }}>
            <div className="eyebrow" style={{ marginBottom: 16 }}>Kursplan</div>
            <h2 style={{
              fontSize: 'clamp(36px, 5vw, 56px)', lineHeight: 1.1, letterSpacing: '-0.015em',
              marginBottom: 20,
              fontVariationSettings: '"opsz" 96, "SOFT" 50, "WONK" 1',
            }}>
              Alle Termine auf{' '}
              <em className="bacalisties" style={{ color: 'var(--heather-plum)' }}>einen Blick</em>.
            </h2>
            <p className="lead" style={{ maxWidth: 600 }}>
              Wann läuft welcher Kurs? Filter nach Kategorie, Kursleitung oder Stichwort —
              und finde deinen passenden Termin.
            </p>
          </div>
        </div>

        <KpFilterBar
          activeCat={activeCat} setActiveCat={setActiveCat}
          leader={leader} setLeader={setLeader}
          query={query} setQuery={setQuery}
          count={monthCount}
        />

        {/* Month nav */}
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          marginBottom: 16, gap: 12, flexWrap: 'wrap',
        }}>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
            <h3 style={{
              fontFamily: 'Fraunces, serif',
              fontSize: 'clamp(22px, 2.5vw, 28px)',
              fontVariationSettings: '"opsz" 96, "SOFT" 50, "WONK" 1',
              color: 'var(--ink)', lineHeight: 1.1,
            }}>{KP_MONTHS[month]} <span style={{ color: 'var(--ink-50)', fontWeight: 300 }}>{year}</span></h3>
          </div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
            <button type="button" onClick={goToday} style={{
              fontSize: 12.5, fontWeight: 500,
              padding: '8px 14px', borderRadius: 999,
              background: 'transparent',
              border: '1px solid var(--sandstone-border)',
              color: 'var(--ink)',
              cursor: 'pointer', fontFamily: 'inherit',
              transition: 'all 160ms var(--ease)',
            }}
              onMouseEnter={(e)=>{ e.currentTarget.style.background='var(--heather-subtle)'; e.currentTarget.style.borderColor='var(--heather-plum)'; }}
              onMouseLeave={(e)=>{ e.currentTarget.style.background='transparent'; e.currentTarget.style.borderColor='var(--sandstone-border)'; }}
            >Heute</button>
            <KpNavBtn dir={-1} onClick={goPrev} />
            <KpNavBtn dir={1} onClick={goNext} />
          </div>
        </div>

        {/* Calendar — full width */}
        <KpMonthGrid
          year={year} month={month}
          eventsByDay={eventsByDay}
          onPickDay={pickDay}
          selectedKey={selectedKey}
        />

        {/* Floating day-detail popover — anchored to the clicked cell */}
        <KpDayPopover
          dayKey={selectedKey}
          anchorRect={anchorRect}
          events={selectedEvents}
          onOpenInquiry={onOpenInquiry}
          onClear={clearDay}
        />


      </div>
    </section>
  );
};

const KpNavBtn = ({ dir, onClick }) => (
  <button type="button" onClick={onClick} aria-label={dir < 0 ? 'Vorheriger Monat' : 'Nächster Monat'}
    style={{
      width: 36, height: 36, borderRadius: 999,
      background: 'var(--offwhite)',
      border: '1px solid var(--sandstone-border)',
      color: 'var(--ink)', fontSize: 14,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      cursor: 'pointer', fontFamily: 'inherit',
      transition: 'all 160ms var(--ease)',
    }}
    onMouseEnter={(e)=>{ e.currentTarget.style.background='var(--heather-plum)'; e.currentTarget.style.color='var(--offwhite)'; e.currentTarget.style.borderColor='var(--heather-plum)'; }}
    onMouseLeave={(e)=>{ e.currentTarget.style.background='var(--offwhite)'; e.currentTarget.style.color='var(--ink)'; e.currentTarget.style.borderColor='var(--sandstone-border)'; }}
  >{dir < 0 ? '←' : '→'}</button>
);

window.Kursplan = Kursplan;
