// Calendar — day-to-day task scheduling for designers
// Aggregates from: tasks (calendar-only), deals (design appts, quote presentations,
// forecast deposits), contacts (reminders)
function Calendar({ tasks, deals, contacts, reps, currentUser, showroomScope, allowedShowrooms, onCreateTask, onUpdateTask, onDeleteTask, onOpenDeal, onOpenContact }) {
  // Use the REAL current date (local), formatted as YYYY-MM-DD without any UTC shift
  const _now = new Date();
  const CAL_TODAY = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, '0')}-${String(_now.getDate()).padStart(2, '0')}`;
  const [view, setView] = React.useState('week'); // week | month | day
  const [anchor, setAnchor] = React.useState(new Date(CAL_TODAY + 'T00:00:00'));
  const [filterRep, setFilterRep] = React.useState(currentUser.role === 'sales_designer' ? currentUser.repId : 'all');
  const [modalOpen, setModalOpen] = React.useState(false);
  const [editingTask, setEditingTask] = React.useState(null);
  const [pickerOpen, setPickerOpen] = React.useState(false);
  const [density, setDensity] = React.useState(() => {
    try { return localStorage.getItem('kub_calendar_density') || 'comfortable'; } catch (e) { return 'comfortable'; }
  });
  React.useEffect(() => {
    try { localStorage.setItem('kub_calendar_density', density); } catch (e) {}
  }, [density]);
  const compact = density === 'compact';

  // === Access enforcement ===
  // Sales designers see ONLY their own events (no override possible)
  // Managers see ONLY events for reps working at their managed showrooms
  // Admin + Leadership see everyone
  const isSalesDesigner = currentUser.role === 'sales_designer';
  const isManager = currentUser.role === 'manager';
  const accessibleRepIds = React.useMemo(() => {
    if (isSalesDesigner) return [currentUser.repId];
    if (isManager) {
      const managed = currentUser.manages || [];
      return reps.filter(r => (r.works || []).some(w => managed.includes(w))).map(r => r.id);
    }
    return reps.map(r => r.id); // admin + leadership
  }, [reps, currentUser, isSalesDesigner, isManager]);

  // Build a unified event list
  const events = React.useMemo(() => {
    const list = [];
    // 1. User-created tasks
    for (const t of tasks) {
      list.push({
        ...t,
        kind: 'task',
        date: t.date,
        time: t.time || '09:00',
        title: t.title,
        type: t.type || 'task',
        rep: t.repId,
        repName: reps.find(r => r.id === t.repId)?.name || '',
        link: t.link || null,
      });
    }
    // 2. Deal-derived events
    for (const d of deals) {
      // showroom filter
      if (showroomScope !== 'all' && d.showroom !== showroomScope) continue;
      if (!allowedShowrooms.includes(d.showroom)) continue;
      if (d.designApptDate) {
        list.push({
          id: 'da_' + d.id,
          kind: 'derived',
          date: d.designApptDate,
          time: '10:00',
          title: `Design appt · ${d.customer}`,
          type: 'design_appt',
          rep: d.rep,
          repName: d.repName,
          link: { kind: 'deal', id: d.id },
          source: 'From deal ' + d.id,
        });
      }
      if (d.quotePresentationDate) {
        list.push({
          id: 'qp_' + d.id,
          kind: 'derived',
          date: d.quotePresentationDate,
          time: '14:00',
          title: `Quote presentation · ${d.customer}`,
          type: 'quote_presentation',
          rep: d.rep,
          repName: d.repName,
          link: { kind: 'deal', id: d.id },
          source: 'From deal ' + d.id,
        });
      }
      if (d.forecastDepositMonth) {
        list.push({
          id: 'fd_' + d.id,
          kind: 'derived',
          date: d.forecastDepositMonth,
          time: '09:00',
          title: `Forecast deposit · ${d.customer}`,
          type: 'forecast_deposit',
          rep: d.rep,
          repName: d.repName,
          link: { kind: 'deal', id: d.id },
          source: 'From deal ' + d.id,
        });
      }
      // Deal-level follow-up reminder
      if (d.followUpReminder && d.followUpReminder.date) {
        list.push({
          id: 'fur_' + d.id,
          kind: 'reminder',
          date: d.followUpReminder.date,
          time: d.followUpReminder.time || '09:00',
          title: (window.apptTypeLabel ? window.apptTypeLabel(d.followUpReminder.type) : 'Follow up') + ' · ' + d.customer,
          type: d.followUpReminder.type || 'reminder',
          rep: d.rep,
          repName: d.repName,
          link: { kind: 'deal', id: d.id },
          source: d.followUpReminder.note || 'Reminder from deal',
        });
      }
    }
    // 3. Contact reminders
    for (const c of contacts) {
      if (showroomScope !== 'all' && c.homeShowroom !== showroomScope) continue;
      if (!allowedShowrooms.includes(c.homeShowroom)) continue;
      if (c.reminder && c.reminder.date) {
        const repObj = reps.find(r => r.name === c.owner);
        list.push({
          id: 'rem_' + c.id,
          kind: 'reminder',
          date: c.reminder.date,
          time: c.reminder.time || '09:00',
          title: (window.apptTypeLabel ? window.apptTypeLabel(c.reminder.type) : 'Follow up') + ' · ' + c.name,
          type: c.reminder.type || 'reminder',
          rep: repObj?.id || null,
          repName: c.owner || '',
          link: { kind: 'contact', id: c.id },
          source: c.reminder.text || 'Reminder from contact card',
        });
      }
    }
    return list;
  }, [tasks, deals, contacts, reps, showroomScope, allowedShowrooms]);

  // Filter by rep — apply access lock first, then user-selected filter
  const accessibleEvents = events.filter(e => !e.rep || accessibleRepIds.includes(e.rep));
  const filteredEvents = filterRep === 'all' ? accessibleEvents : accessibleEvents.filter(e => e.rep === filterRep);

  // Calendar range
  const start = new Date(anchor);
  start.setHours(0, 0, 0, 0);
  if (view === 'week') {
    start.setDate(start.getDate() - start.getDay()); // Sunday-start week
  } else if (view === 'month') {
    start.setDate(1);
    start.setDate(start.getDate() - start.getDay());
  }
  const days = view === 'day' ? 1 : view === 'week' ? 7 : 35;

  // Bucket events by day
  const eventsByDay = {};
  for (const e of filteredEvents) {
    if (!eventsByDay[e.date]) eventsByDay[e.date] = [];
    eventsByDay[e.date].push(e);
  }
  for (const date in eventsByDay) {
    eventsByDay[date].sort((a, b) => (a.time || '00:00').localeCompare(b.time || '00:00'));
  }

  function dateKey(d) {
    // Local date (NOT toISOString — that shifts by the UTC offset and mis-highlights "today")
    const y = d.getFullYear();
    const m = String(d.getMonth() + 1).padStart(2, '0');
    const dd = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${dd}`;
  }

  function navigate(dir) {
    const next = new Date(anchor);
    if (view === 'day') next.setDate(next.getDate() + dir);
    else if (view === 'week') next.setDate(next.getDate() + dir * 7);
    else next.setMonth(next.getMonth() + dir);
    setAnchor(next);
  }

  const today = CAL_TODAY;

  // Upcoming panel — next 7 days of appointments & reminders
  const weekAhead = (() => { const d = new Date(today + 'T00:00:00'); d.setDate(d.getDate() + 7); return dateKey(d); })();
  const upcomingReminders = filteredEvents
    .filter(e => e.date > today && e.date <= weekAhead)
    .sort((a, b) => (a.date + (a.time || '')).localeCompare(b.date + (b.time || '')))
    .slice(0, 12);

  const eligibleReps = isSalesDesigner
    ? reps.filter(r => r.id === currentUser.repId)
    : reps.filter(r => accessibleRepIds.includes(r.id));

  const eventTypeColors = {
    design_appt: 'oklch(0.5 0.12 145)',
    quote_presentation: 'oklch(0.5 0.13 30)',
    forecast_deposit: 'oklch(0.6 0.14 70)',
    reminder: 'oklch(0.55 0.13 60)',
    site_visit: 'oklch(0.5 0.1 240)',
    call: 'oklch(0.5 0.1 200)',
    call_customer: 'oklch(0.5 0.1 200)',
    followup_call: 'oklch(0.55 0.13 60)',
    showroom_visit: 'var(--accent)',
    contract_signing: 'oklch(0.45 0.13 300)',
    payment_followup: 'oklch(0.5 0.13 30)',
    install_check: 'oklch(0.5 0.12 145)',
    meeting: 'var(--accent)',
    task: 'oklch(0.4 0.05 240)',
  };
  const colorFor = (t) => eventTypeColors[t] || 'oklch(0.5 0.08 250)';

  // Density-driven sizing — cells have a fixed height; events scroll within so ALL are reachable
  const cellHeight = view === 'day' ? (compact ? 460 : 620)
    : view === 'week' ? (compact ? 184 : 264)
    : (compact ? 104 : 150);
  const evGap = compact ? 2 : 3;

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
        <div className="seg">
          <button className={view === 'day' ? 'on' : ''} onClick={() => setView('day')}>Day</button>
          <button className={view === 'week' ? 'on' : ''} onClick={() => setView('week')}>Week</button>
          <button className={view === 'month' ? 'on' : ''} onClick={() => setView('month')}>Month</button>
        </div>
        <button className="btn sm" onClick={() => navigate(-1)} title="Previous"><Icon name="chevron-left" size={12}/></button>
        <button className="btn sm" onClick={() => setAnchor(new Date(CAL_TODAY + 'T00:00:00'))}>Today</button>
        <button className="btn sm" onClick={() => navigate(1)} title="Next"><Icon name="chevron-right" size={12}/></button>
        <div style={{ position: 'relative', marginLeft: 8 }}>
          <button
            onClick={() => setPickerOpen(o => !o)}
            title="Jump to month"
            style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 14, fontWeight: 600, padding: '4px 8px', borderRadius: 6, color: 'var(--ink)', background: pickerOpen ? 'var(--surface-2)' : 'transparent' }}
          >
            {anchor.toLocaleDateString('en-AU', { month: 'long', year: 'numeric' })}
            <Icon name="chevron-down" size={12} style={{ color: 'var(--ink-3)' }}/>
          </button>
          {pickerOpen && (
            <MonthYearPicker
              anchor={anchor}
              onClose={() => setPickerOpen(false)}
              onPick={(d) => { setAnchor(d); setPickerOpen(false); }}
            />
          )}
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8 }}>
          <div className="seg" role="group" aria-label="Calendar density">
            <button className={!compact ? 'on' : ''} onClick={() => setDensity('comfortable')} title="Comfortable — roomy cells">
              <Icon name="dashboard" size={12} style={{ marginRight: 5, verticalAlign: '-1px' }}/>Comfortable
            </button>
            <button className={compact ? 'on' : ''} onClick={() => setDensity('compact')} title="Compact — denser cells">
              <Icon name="table" size={12} style={{ marginRight: 5, verticalAlign: '-1px' }}/>Compact
            </button>
          </div>
          {!isSalesDesigner && (
            <select className="sel" value={filterRep} onChange={(e) => setFilterRep(e.target.value)}>
              <option value="all">{isManager ? 'All my designers' : 'All designers'}</option>
              {reps.filter(r => accessibleRepIds.includes(r.id)).map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
            </select>
          )}
          <button className="btn primary" onClick={() => { setEditingTask(null); setModalOpen(true); }}>
            <Icon name="plus" size={12}/> {isSalesDesigner ? 'New task' : 'Allocate appointment'}
          </button>
        </div>
      </div>

      <div className="cal-layout">
        <div className="card" style={{ overflow: 'hidden' }}>
          <div className="card-hd">
            <div>
              <div className="card-title">
                {view === 'day' && anchor.toLocaleDateString('en-AU', { weekday: 'long', day: 'numeric', month: 'long' })}
                {view === 'week' && 'Week view'}
                {view === 'month' && 'Month view'}
              </div>
              <div className="card-sub">{filteredEvents.length} events in scope</div>
            </div>
          </div>
          <div style={{
            display: 'grid',
            gridTemplateColumns: view === 'day' ? '1fr' : 'repeat(7, minmax(0, 1fr))',
            borderTop: '1px solid var(--border)',
          }}>
            {Array.from({ length: days }).map((_, i) => {
              const d = new Date(start);
              d.setDate(d.getDate() + i);
              const key = dateKey(d);
              const isToday = key === today;
              const isCurrentMonth = d.getMonth() === anchor.getMonth();
              const dayEvents = eventsByDay[key] || [];
              return (
                <div
                  key={key}
                  style={{
                    height: cellHeight,
                    border: '1px solid var(--border)',
                    margin: '-0.5px',
                    padding: 6,
                    background: isToday ? 'var(--accent-soft)' : isCurrentMonth ? 'var(--surface)' : 'var(--surface-2)',
                    cursor: 'pointer',
                    display: 'flex',
                    flexDirection: 'column',
                    minHeight: 0,
                  }}
                  onClick={(e) => {
                    if (e.target.closest('.cal-event')) return;
                    setEditingTask(null);
                    setModalOpen({ date: key });
                  }}
                >
                  <div style={{
                    fontSize: 11,
                    fontWeight: isToday ? 700 : 500,
                    color: isCurrentMonth ? 'var(--ink-2)' : 'var(--ink-4)',
                    marginBottom: 4,
                    display: 'flex',
                    justifyContent: 'space-between',
                    flexShrink: 0,
                  }}>
                    <span>{d.toLocaleDateString('en-AU', { weekday: view === 'month' ? 'narrow' : 'short' })} {d.getDate()}</span>
                    {dayEvents.length > 0 && <span style={{ background: isToday ? 'var(--accent)' : 'var(--ink)', color: 'white', borderRadius: 8, padding: '0 5px', fontSize: 9 }}>{dayEvents.length}</span>}
                  </div>
                  <div className="cal-daycell-events" style={{ flex: 1, overflowY: 'auto', minHeight: 0, marginRight: -4, paddingRight: 2 }}>
                    {dayEvents.map(ev => (
                      <div
                        key={ev.id}
                        className="cal-event"
                        onClick={(e) => {
                          e.stopPropagation();
                          if (ev.kind === 'task') {
                            setEditingTask(ev);
                            setModalOpen(true);
                          } else if (ev.link?.kind === 'deal') {
                            const deal = deals.find(d => d.id === ev.link.id);
                            if (deal) onOpenDeal(deal);
                          } else if (ev.link?.kind === 'contact') {
                            const c = contacts.find(c => c.id === ev.link.id);
                            if (c) onOpenContact(c);
                          }
                        }}
                        style={{
                          background: `color-mix(in oklch, ${colorFor(ev.type)} 12%, var(--surface))`,
                          borderLeft: `3px solid ${colorFor(ev.type)}`,
                          padding: compact ? '2px 6px' : '4px 7px',
                          marginBottom: evGap,
                          borderRadius: 3,
                          cursor: 'pointer',
                        }}
                        title={`${ev.time} · ${ev.title} · ${ev.repName}`}
                      >
                        {compact ? (
                          <div style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', fontSize: 9.5, pointerEvents: 'none' }}>
                            <span className="mono" style={{ fontSize: 9, color: 'var(--ink-3)' }}>{ev.time}</span>{' '}
                            <span style={{ fontWeight: 500 }}>{ev.title}</span>
                          </div>
                        ) : (
                          <div style={{ pointerEvents: 'none' }}>
                            <div style={{ display: 'flex', gap: 5, alignItems: 'baseline' }}>
                              <span className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', flexShrink: 0 }}>{ev.time}</span>
                              <span style={{ fontWeight: 500, fontSize: 11, lineHeight: 1.25 }}>{ev.title}</span>
                            </div>
                            <div style={{ fontSize: 9.5, color: 'var(--ink-3)', marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                              {ev.repName}{ev.source ? ' · ' + ev.source : ''}
                            </div>
                          </div>
                        )}
                      </div>
                    ))}
                    {dayEvents.length === 0 && view === 'day' && (
                      <div className="empty" style={{ padding: '14px 8px' }}>No events scheduled. Click anywhere to add one.</div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }} className="cal-side">
          <div className="card">
            <div className="card-hd">
              <div>
                <div className="card-title">Upcoming</div>
                <div className="card-sub">Next 7 days · appointments &amp; reminders</div>
              </div>
            </div>
            {upcomingReminders.length === 0 ? (
              <div className="empty">Nothing scheduled in the next 7 days.</div>
            ) : (
              <div style={{ padding: '6px 0' }}>
                {upcomingReminders.map(r => (
                  <div
                    key={r.id}
                    style={{
                      padding: '9px 14px',
                      borderBottom: '1px solid var(--border)',
                      cursor: 'pointer',
                      display: 'flex',
                      alignItems: 'center',
                      gap: 10,
                    }}
                    onClick={() => {
                      if (r.kind === 'task') { setEditingTask(r); setModalOpen(true); }
                      else if (r.link?.kind === 'deal') { const dd = deals.find(x => x.id === r.link.id); if (dd) onOpenDeal(dd); }
                      else if (r.link?.kind === 'contact') { const c = contacts.find(x => x.id === r.link.id); if (c) onOpenContact(c); }
                    }}
                  >
                    <div style={{
                      width: 34, height: 34, borderRadius: 17,
                      background: `color-mix(in oklch, ${colorFor(r.type)} 16%, var(--surface))`,
                      color: colorFor(r.type),
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      flexShrink: 0,
                      border: `1px solid color-mix(in oklch, ${colorFor(r.type)} 30%, transparent)`,
                    }}>
                      <Icon name="calendar" size={14}/>
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.title}</div>
                      <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>
                        {fmt.shortDate(r.date)} · {r.time}{r.repName ? ' · ' + r.repName : ''}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          <div className="card">
            <div className="card-hd">
              <div>
                <div className="card-title">Today's schedule</div>
                <div className="card-sub">{(eventsByDay[today] || []).length} events</div>
              </div>
            </div>
            <div style={{ padding: 4 }}>
              {(eventsByDay[today] || []).length === 0 ? (
                <div className="empty">No events scheduled today.</div>
              ) : (
                (eventsByDay[today] || []).map(ev => (
                  <div key={ev.id} style={{ display: 'flex', gap: 10, padding: '8px 12px', borderRadius: 4 }}>
                    <span className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', flexShrink: 0, width: 40 }}>{ev.time}</span>
                    <span style={{
                      width: 4, background: eventTypeColors[ev.type] || 'var(--ink-3)', borderRadius: 2,
                    }}/>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5, fontWeight: 500 }}>{ev.title}</div>
                      <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{ev.repName}</div>
                    </div>
                  </div>
                ))
              )}
            </div>
          </div>
        </div>
      </div>

      {modalOpen && (
        <TaskModal
          task={editingTask}
          defaultDate={typeof modalOpen === 'object' ? modalOpen.date : today}
          reps={eligibleReps}
          showrooms={[]}
          contacts={contacts}
          deals={deals}
          tasks={tasks}
          onOpenContact={onOpenContact}
          currentUser={currentUser}
          onClose={() => { setModalOpen(false); setEditingTask(null); }}
          onSave={(task) => {
            if (editingTask) onUpdateTask(editingTask.id, task);
            else onCreateTask(task);
            setModalOpen(false);
            setEditingTask(null);
          }}
          onDelete={editingTask ? () => { onDeleteTask(editingTask.id); setModalOpen(false); setEditingTask(null); } : null}
        />
      )}
    </div>
  );
}

function TaskModal({ task, defaultDate, reps, contacts, deals, tasks, onOpenContact, currentUser, onClose, onSave, onDelete }) {
  const [draft, setDraft] = React.useState(task || {
    title: '',
    type: 'followup_call',
    date: defaultDate,
    time: '09:00',
    repId: currentUser.repId || reps[0]?.id || '',
    contactId: null,
    notes: '',
    leadMinutes: 15,
  });
  const [custQuery, setCustQuery] = React.useState('');
  const [custOpen, setCustOpen] = React.useState(false);

  const valid = draft.title.trim().length > 1 && draft.date && draft.time && draft.repId;
  const _today = new Date();
  const today = `${_today.getFullYear()}-${String(_today.getMonth() + 1).padStart(2, '0')}-${String(_today.getDate()).padStart(2, '0')}`;
  const isPast = task && task.date < today;

  const types = (window.apptTypes ? window.apptTypes() : [
    { id: 'design_appt', label: 'Design appointment' },
    { id: 'site_visit', label: 'Site visit' },
    { id: 'quote_presentation', label: 'Quote presentation' },
    { id: 'followup_call', label: 'Follow-up call' },
    { id: 'meeting', label: 'Showroom meeting' },
    { id: 'task', label: 'Other task' },
  ]);

  const selectedContact = draft.contactId ? (contacts || []).find(c => c.id === draft.contactId) : null;
  const matches = custQuery.trim().length >= 2
    ? (contacts || []).filter(c => {
        const q = custQuery.toLowerCase();
        return (c.name || '').toLowerCase().includes(q) || (c.phone || '').replace(/\s/g, '').includes(custQuery.replace(/\s/g, ''));
      }).slice(0, 6)
    : [];

  // Draggable modal — header is the grab handle. Lets the user move it aside to see a profile.
  const [pos, setPos] = React.useState(null); // {x, y} top-left once dragged; null = centered
  const dragRef = React.useRef(null);
  const onDragStart = (e) => {
    if (e.target.closest('button') || e.target.closest('input') || e.target.closest('select')) return;
    const modal = e.currentTarget.closest('.invite-modal');
    const rect = modal.getBoundingClientRect();
    const offX = e.clientX - rect.left;
    const offY = e.clientY - rect.top;
    const move = (ev) => setPos({ x: ev.clientX - offX, y: ev.clientY - offY });
    const up = () => { window.removeEventListener('mousemove', move); window.removeEventListener('mouseup', up); };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
  };
  // Auto-dock the modal to the left when opening the linked profile (which slides in from the right)
  const dockLeftAndOpen = (c) => {
    setPos({ x: 24, y: Math.max(24, window.innerHeight / 2 - 280) });
    if (onOpenContact) onOpenContact(c);
  };
  const modalPosStyle = pos
    ? { zIndex: 53, width: 560, left: pos.x, top: pos.y, transform: 'none', animation: 'none' }
    : { zIndex: 53, width: 560 };

  const pickContact = (c) => {
    const owner = (reps || []).find(r => r.name === c.owner);
    setDraft(d => ({
      ...d,
      contactId: c.id,
      repId: owner ? owner.id : d.repId,
      title: d.title || (window.apptTypeLabel ? window.apptTypeLabel(d.type) : 'Appointment') + ' · ' + c.name,
    }));
    setCustOpen(false);
    setCustQuery('');
  };

  // Position summary for selected contact
  const posInfo = selectedContact ? contactPosition(selectedContact, deals) : null;

  return (
    <div>
      <div className="invite-modal" style={modalPosStyle}>
        <div onMouseDown={onDragStart} style={{ padding: '18px 22px 14px', borderBottom: '1px solid var(--border)', cursor: pos ? 'grab' : 'default' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div>
              <div style={{ fontSize: 18, fontWeight: 600, letterSpacing: '-0.02em', display: 'flex', alignItems: 'center', gap: 8 }}>
                <Icon name="more" size={14} style={{ color: 'var(--ink-4)', cursor: 'grab' }}/>
                {task ? (isPast ? 'View past appointment (locked)' : 'Edit appointment') : 'New appointment'}
              </div>
              {isPast && (
                <div style={{ fontSize: 11.5, color: 'var(--lost)', marginTop: 4, display: 'flex', alignItems: 'center', gap: 4 }}>
                  <Icon name="alert" size={11}/> Past-dated items are locked. Create a new one to reschedule.
                </div>
              )}
            </div>
            <button className="detail-close" style={{ marginLeft: 'auto' }} onClick={onClose}>
              <Icon name="close" size={16}/>
            </button>
          </div>
        </div>
        <div style={{ padding: '18px 22px' }}>
          <div className="detail-section">
            {/* Customer selector */}
            {!isPast && (
              <div className="detail-field" style={{ marginBottom: 14, position: 'relative' }}>
                <span className="lbl">Link a customer <span style={{ fontSize: 10, color: 'var(--ink-3)' }}>· optional — leave blank for a private reminder</span></span>
                {selectedContact ? (
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', border: '1px solid var(--accent)', borderRadius: 6, background: 'var(--accent-soft)' }}>
                    <Avatar name={selectedContact.name} sz="sm"/>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 500, fontSize: 13 }}>{selectedContact.name}</div>
                      <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{selectedContact.phone || 'no phone'} · {selectedContact.owner || 'unassigned'}</div>
                    </div>
                    <button className="btn sm" onClick={() => dockLeftAndOpen(selectedContact)}>Open profile</button>
                    <button className="btn sm" onClick={() => setDraft(d => ({ ...d, contactId: null }))}><Icon name="close" size={11}/></button>
                  </div>
                ) : (
                  <div style={{ position: 'relative' }}>
                    <input
                      value={custQuery}
                      onChange={(e) => { setCustQuery(e.target.value); setCustOpen(true); }}
                      onFocus={() => setCustOpen(true)}
                      placeholder="Search customer by name or phone…"
                    />
                    {custOpen && matches.length > 0 && (
                      <div style={{ position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 10, background: 'var(--surface)', border: '1px solid var(--border-strong)', borderRadius: 6, marginTop: 2, boxShadow: 'var(--shadow-md)', maxHeight: 220, overflowY: 'auto' }}>
                        {matches.map(c => (
                          <div key={c.id} onClick={() => pickContact(c)} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', cursor: 'pointer', borderBottom: '1px solid var(--border)' }} onMouseDown={(e) => e.preventDefault()}>
                            <Avatar name={c.name} sz="sm"/>
                            <div style={{ flex: 1, minWidth: 0 }}>
                              <div style={{ fontSize: 12.5, fontWeight: 500 }}>{c.name}</div>
                              <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{c.phone || 'no phone'} · {c.owner || 'unassigned'}</div>
                            </div>
                            {window.LifecyclePill && <LifecyclePill stage={c.lifecycle}/>}
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                )}
              </div>
            )}

            {/* Current position popup for the selected customer */}
            {selectedContact && posInfo && (
              <div style={{ marginBottom: 14, padding: '10px 12px', borderRadius: 8, background: `color-mix(in oklch, ${posInfo.color} 8%, var(--surface))`, border: `1px solid color-mix(in oklch, ${posInfo.color} 25%, transparent)` }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontSize: 10.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', color: posInfo.color }}>Currently sits at</span>
                  {window.LifecyclePill && <LifecyclePill stage={selectedContact.lifecycle}/>}
                </div>
                <div style={{ fontSize: 12, color: 'var(--ink-2)', marginTop: 4 }}>{posInfo.detail}</div>
              </div>
            )}

            <div className="detail-grid">
              <div className="detail-field" style={{ gridColumn: '1 / -1' }}>
                <span className="lbl">Title *</span>
                <input value={draft.title} onChange={(e) => setDraft({ ...draft, title: e.target.value })} placeholder="e.g. Site visit at customer's home" disabled={isPast}/>
              </div>
              <div className="detail-field">
                <span className="lbl">Type</span>
                <select value={draft.type} onChange={(e) => setDraft({ ...draft, type: e.target.value })} disabled={isPast}>
                  {types.map(t => <option key={t.id} value={t.id}>{t.label}</option>)}
                </select>
              </div>
              <div className="detail-field">
                <span className="lbl">{window.T ? window.T('rep') : 'Designer'}</span>
                <select value={draft.repId} onChange={(e) => setDraft({ ...draft, repId: e.target.value })} disabled={isPast}>
                  {reps.map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
                </select>
              </div>
              <div className="detail-field" style={{ gridColumn: '1 / -1' }}>
                <span className="lbl">Quick pick</span>
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  {(window.quickReminderPresets ? window.quickReminderPresets() : []).map(p => {
                    const pd = window.quickReminderDate(p.days);
                    return (
                      <button key={p.id} className={`filter-chip ${draft.date === pd ? 'active' : ''}`} onClick={() => setDraft({ ...draft, date: pd })} disabled={isPast}>{p.label}</button>
                    );
                  })}
                </div>
              </div>
              <div className="detail-field">
                <span className="lbl">Date *</span>
                <input type="date" value={draft.date} min={task ? draft.date : today} onChange={(e) => setDraft({ ...draft, date: e.target.value })} disabled={isPast}/>
              </div>
              <div className="detail-field">
                <span className="lbl">Time *</span>
                <input type="time" value={draft.time} onChange={(e) => setDraft({ ...draft, time: e.target.value })} disabled={isPast} required/>
              </div>
              <div className="detail-field">
                <span className="lbl">Remind me before</span>
                <select value={draft.leadMinutes != null ? draft.leadMinutes : 15} onChange={(e) => setDraft({ ...draft, leadMinutes: Number(e.target.value) })} disabled={isPast}>
                  {(window.REMINDER_LEADS || [{ v: 15, label: '15 minutes before' }]).map(o => <option key={o.v} value={o.v}>{o.label}</option>)}
                </select>
              </div>
              <div className="detail-field" style={{ gridColumn: '1 / -1' }}>
                <span className="lbl">Notes</span>
                <textarea
                  value={draft.notes || ''}
                  onChange={(e) => setDraft({ ...draft, notes: e.target.value })}
                  placeholder="Location, prep notes, attendees…"
                  rows="2"
                  disabled={isPast}
                  style={{ width: '100%', padding: '8px 10px', border: '1px solid var(--border)', borderRadius: 4, fontFamily: 'inherit', fontSize: 12.5, resize: 'vertical', outline: 'none' }}
                />
              </div>
            </div>
            {draft.contactId && (
              <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 8, display: 'flex', alignItems: 'center', gap: 5 }}>
                <Icon name="check" size={11}/> This appointment will be logged to the customer's profile audit trail.
              </div>
            )}
          </div>
        </div>
        <div style={{ padding: '14px 22px', borderTop: '1px solid var(--border)', background: 'var(--surface-2)', display: 'flex', gap: 8 }}>
          <button className="btn" onClick={onClose}>Close</button>
          {onDelete && !isPast && <button className="btn" onClick={onDelete} style={{ color: 'var(--lost)', borderColor: 'var(--lost-soft)' }}>Delete</button>}
          {!isPast && (
            <button
              className="btn primary"
              disabled={!valid}
              style={{ marginLeft: 'auto', opacity: !valid ? 0.5 : 1 }}
              onClick={() => onSave(draft)}
            ><Icon name="check" size={12}/> Save appointment</button>
          )}
        </div>
      </div>
    </div>
  );
}

// Lightweight position summary for the calendar popup
function contactPosition(c, deals) {
  const lc = c.lifecycle || 'new_contact';
  const myDeals = (deals || []).filter(d => (c.dealIds || []).includes(d.id));
  const active = myDeals.find(d => d.stage !== 'sold' && d.stage !== 'lost');
  const colors = {
    customer_active: 'var(--won)', past_customer: 'var(--won)', in_pipeline: 'var(--accent)',
    qualified: 'oklch(0.55 0.12 145)', new_lead: 'oklch(0.5 0.1 240)', new_contact: 'oklch(0.55 0.02 90)',
    lost_quote: 'var(--lost)', no_sale: 'var(--lost)',
  };
  const base = lc.replace('dormant_', '');
  let detail;
  if (active) detail = `${active.statusRaw || active.stage} · ${active.product || 'job'} · ${window.fmt ? fmt.money(active.value, true) : '$' + active.value}`;
  else if (base === 'past_customer') detail = `${myDeals.filter(d => d.stage === 'sold').length} past sale(s) · re-engagement opportunity`;
  else if (base === 'new_lead') detail = 'Lead — not yet quoted. Needs nurturing.';
  else if (base === 'qualified') detail = 'Qualified — appointment stage.';
  else if (base === 'lost_quote') detail = 'Previously quoted but did not proceed.';
  else detail = 'Early-stage contact.';
  if (lc.startsWith('dormant_')) detail = 'Dormant · ' + detail;
  return { color: colors[base] || 'var(--ink-3)', detail };
}

// Quick month/year jump — opens from the month label
function MonthYearPicker({ anchor, onPick, onClose }) {
  const [year, setYear] = React.useState(anchor.getFullYear());
  const [mode, setMode] = React.useState('month'); // 'month' | 'year'
  const [yearBase, setYearBase] = React.useState(anchor.getFullYear() - 7); // top-left of the year grid
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  const thisYear = new Date().getFullYear();
  const thisMonth = new Date().getMonth();
  const years = Array.from({ length: 16 }).map((_, i) => yearBase + i); // 16-year page (incl. past & future)

  return (
    <React.Fragment>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 40 }}></div>
      <div style={{
        position: 'absolute', top: '100%', left: 0, marginTop: 6, zIndex: 41,
        background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)',
        boxShadow: 'var(--shadow-lg)', padding: 12, width: 268,
      }}>
        {mode === 'month' ? (
          <React.Fragment>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
              <button className="btn sm icon" onClick={() => setYear(y => y - 1)} title="Previous year"><Icon name="chevron-left" size={13}/></button>
              <button
                onClick={() => { setYearBase(year - 7); setMode('year'); }}
                title="Pick a year"
                style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontWeight: 600, fontSize: 14, fontVariantNumeric: 'tabular-nums', padding: '3px 10px', borderRadius: 6 }}
                onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface-2)'}
                onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
              >
                {year} <Icon name="chevron-down" size={11} style={{ color: 'var(--ink-3)' }}/>
              </button>
              <button className="btn sm icon" onClick={() => setYear(y => y + 1)} title="Next year"><Icon name="chevron-right" size={13}/></button>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6 }}>
              {months.map((m, i) => {
                const isCurrent = anchor.getFullYear() === year && anchor.getMonth() === i;
                const isToday = year === thisYear && i === thisMonth;
                return (
                  <button key={m} onClick={() => onPick(new Date(year, i, 1))} className={`my-month ${isCurrent ? 'on' : ''}`}>
                    {m}
                    {isToday && !isCurrent && <span className="my-today-dot"></span>}
                  </button>
                );
              })}
            </div>
          </React.Fragment>
        ) : (
          <React.Fragment>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
              <button className="btn sm icon" onClick={() => setYearBase(b => b - 16)} title="Earlier years"><Icon name="chevron-left" size={13}/></button>
              <span style={{ fontWeight: 600, fontSize: 13, color: 'var(--ink-2)', fontVariantNumeric: 'tabular-nums' }}>{years[0]} – {years[years.length - 1]}</span>
              <button className="btn sm icon" onClick={() => setYearBase(b => b + 16)} title="Later years"><Icon name="chevron-right" size={13}/></button>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
              {years.map(y => {
                const isCurrent = y === year;
                const isToday = y === thisYear;
                return (
                  <button key={y} onClick={() => { setYear(y); setMode('month'); }} className={`my-month ${isCurrent ? 'on' : ''}`} style={{ fontVariantNumeric: 'tabular-nums', fontSize: 12 }}>
                    {y}
                    {isToday && !isCurrent && <span className="my-today-dot"></span>}
                  </button>
                );
              })}
            </div>
          </React.Fragment>
        )}
      </div>
    </React.Fragment>
  );
}

window.Calendar = Calendar;
