// Tasks — list + task detail + add-task sheet

// Jalali utilities from window.JalaliUtils (utils.js — R12 dedup)
const { _toJalali, _toGregorian, _jDays, _toIso, _fromIso, _jn, _pwIdx, J_MONTHS, J_WDAYS } = window.JalaliUtils;

// ── Recurrence helpers ───────────────────────────────────────────────
const _calcNextRecurrence = (task) => {
  const { recurrence, dueDate } = task;
  if (!recurrence || recurrence.type === 'none') return null;
  const { type, jalaliDay } = recurrence;
  const base = dueDate ? new Date(dueDate + 'T12:00:00') : new Date();
  const gdk = d => [d.getFullYear(), String(d.getMonth()+1).padStart(2,'0'), String(d.getDate()).padStart(2,'0')].join('-');
  if (type === 'daily')  return gdk(new Date(base.getTime() + 86400000));
  if (type === 'weekly') return gdk(new Date(base.getTime() + 7 * 86400000));
  if (type === 'monthly') {
    const [jy, jm] = _toJalali(base.getFullYear(), base.getMonth()+1, base.getDate());
    let nm = jm + 1, ny = jy;
    if (nm > 12) { nm = 1; ny++; }
    const day = Math.min(jalaliDay || 1, _jDays(ny, nm));
    const [gy, gm, gd] = _toGregorian(ny, nm, day);
    return _toIso(gy, gm, gd);
  }
  if (type === 'yearly') {
    const [jy, jm, jd] = _toJalali(base.getFullYear(), base.getMonth()+1, base.getDate());
    const ny = jy + 1;
    const day = Math.min(jalaliDay || jd, _jDays(ny, jm));
    const [gy, gm, gd] = _toGregorian(ny, jm, day);
    return _toIso(gy, gm, gd);
  }
  return null;
};

const getRecurrenceLabel = rec => {
  if (!rec || rec.type === 'none') return null;
  if (rec.type === 'daily')   return 'هر روز تکرار می‌شود';
  if (rec.type === 'weekly')  return 'هر هفته تکرار می‌شود';
  if (rec.type === 'yearly')  return 'هر سال تکرار می‌شود';
  if (rec.type === 'monthly') return rec.jalaliDay ? `هر ماه روز ${_jn(rec.jalaliDay)}ام تکرار می‌شود` : 'هر ماه تکرار می‌شود';
  return null;
};

// ── Project constants ────────────────────────────────────────────────
const PROJECT_PALETTES = ['#2A9D8F','#7C3AED','#FFAC1F','#059669','#DC2626','#0284C7','#DB2777','#64748B'];

// ── PersianDatePicker ────────────────────────────────────────────────
const dpCalS = {
  wrap:    { background: 'var(--surface)', borderRadius: 14, border: '1px solid var(--c-border-xs)', direction: 'rtl', userSelect: 'none', overflow: 'hidden' },
  head:    { display: 'flex', alignItems: 'center', padding: '10px 12px', borderBottom: '1px solid var(--c-border-xs)' },
  navBtn:  { width: 32, height: 32, borderRadius: 999, background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--ink-2)', display: 'grid', placeItems: 'center' },
  lbl:     { flex: 1, textAlign: 'center', font: "600 13px 'Estedad', sans-serif", color: 'var(--ink)' },
  grid:    { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 2, padding: '6px 8px 10px' },
  wdHead:  { textAlign: 'center', padding: '2px 0 5px', font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-3)' },
  day:     { height: 34, width: '100%', display: 'grid', placeItems: 'center', borderRadius: 8, background: 'transparent', border: 'none', cursor: 'pointer', font: "500 13px 'Estedad', sans-serif", color: 'var(--ink)', transition: 'background 80ms' },
  today:   { background: 'var(--firoozeh-soft)', color: 'var(--firoozeh-deep)' },
  sel:     { background: 'var(--firoozeh)', color: '#fff' },
};

function PersianDatePicker({ value, onChange }) {
  const { Icons } = window;
  const todayArr = (() => { const n = new Date(); return _toJalali(n.getFullYear(), n.getMonth()+1, n.getDate()); })();
  const selArr   = value ? _toJalali(..._fromIso(value)) : null;
  const [viewY, setViewY] = React.useState(() => (selArr || todayArr)[0]);
  const [viewM, setViewM] = React.useState(() => (selArr || todayArr)[1]);

  React.useEffect(() => {
    if (value) { const [jy, jm] = _toJalali(..._fromIso(value)); setViewY(jy); setViewM(jm); }
  }, [value]);

  const prevMonth = () => viewM === 1  ? (setViewY(y => y-1), setViewM(12)) : setViewM(m => m-1);
  const nextMonth = () => viewM === 12 ? (setViewY(y => y+1), setViewM(1))  : setViewM(m => m+1);

  const firstDate = (() => { const [gy, gm, gd] = _toGregorian(viewY, viewM, 1); return new Date(gy, gm-1, gd); })();
  const offset    = _pwIdx(firstDate.getDay());
  const total     = _jDays(viewY, viewM);
  const cells     = [...Array(offset).fill(null), ...Array.from({length: total}, (_, i) => i+1)];

  const isSel   = d => selArr   && selArr[0]===viewY && selArr[1]===viewM && selArr[2]===d;
  const isToday = d => todayArr[0]===viewY && todayArr[1]===viewM && todayArr[2]===d;

  return (
    <div style={dpCalS.wrap}>
      <div style={dpCalS.head}>
        <button style={dpCalS.navBtn} onClick={nextMonth} aria-label="ماه بعد"><Icons.ChevLeft size={15} /></button>
        <span style={dpCalS.lbl}>{J_MONTHS[viewM-1]} {_jn(viewY)}</span>
        <button style={dpCalS.navBtn} onClick={prevMonth} aria-label="ماه قبل"><Icons.Chev size={15} /></button>
      </div>
      <div style={dpCalS.grid}>
        {J_WDAYS.map(w => <div key={w} style={dpCalS.wdHead}>{w}</div>)}
        {cells.map((d, i) => d === null ? <div key={`_${i}`} /> : (
          <button key={d}
            style={{ ...dpCalS.day, ...(isSel(d) ? dpCalS.sel : isToday(d) ? dpCalS.today : {}) }}
            onClick={() => onChange(_toIso(..._toGregorian(viewY, viewM, d)))}
          >{_jn(d)}</button>
        ))}
      </div>
    </div>
  );
}

// ── PersianTimePicker ────────────────────────────────────────────────
const dpTimeS = {
  wrap:    { background: 'var(--surface)', borderRadius: 14, border: '1px solid var(--c-border-xs)', direction: 'rtl', userSelect: 'none', overflow: 'hidden', marginTop: 10 },
  head:    { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px 0' },
  lbl:     { font: "500 13px 'Estedad', sans-serif", color: 'var(--ink-2)' },
  body:    { display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '10px 16px 6px' },
  col:     { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 },
  btn:     { background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--ink-2)', padding: '4px 12px', display: 'grid', placeItems: 'center', borderRadius: 8 },
  val:     { font: "700 30px/1 'Estedad', sans-serif", color: 'var(--ink)', width: 60, textAlign: 'center' },
  sep:     { font: "700 28px/1 'Estedad', sans-serif", color: 'var(--ink-3)', padding: '0 4px', marginBottom: 4 },
  period:  { textAlign: 'center', padding: '2px 0 12px', font: "500 12px 'Estedad', sans-serif", color: 'var(--firoozeh-deep)' },
  empty:   { height: 14 },
};

function PersianTimePicker({ value, onChange }) {
  const { Icons } = window;
  const [on, setOn] = React.useState(!!value);
  const [h,  setH]  = React.useState(() => value ? parseInt(value.split(':')[0], 10) : 9);
  const [m,  setM]  = React.useState(() => value ? Math.round(parseInt(value.split(':')[1], 10) / 15) * 15 % 60 : 0);

  const emit = (enabled, hour, min) =>
    onChange(enabled ? `${String(hour).padStart(2,'0')}:${String(min).padStart(2,'0')}` : '');

  const toggle = () => { const next = !on; setOn(next); emit(next, h, m); };
  const adjH   = d => { const nh = (h + d + 24) % 24; setH(nh); emit(on, nh, m); };
  const adjM   = d => { const nm = (m + d + 60) % 60; setM(nm); emit(on, h, nm); };

  const period = h < 5 ? 'بامداد' : h < 12 ? 'صبح' : h === 12 ? 'ظهر' : h < 17 ? 'بعدازظهر' : 'شب';

  return (
    <div style={dpTimeS.wrap}>
      <div style={dpTimeS.head}>
        <span style={dpTimeS.lbl}>ساعت</span>
        <button onClick={toggle} aria-label="فعال" style={{
          width: 42, height: 24, borderRadius: 999, border: 'none', cursor: 'pointer',
          background: on ? 'var(--firoozeh)' : 'var(--ink-4)',
          position: 'relative', direction: 'ltr', transition: 'background 150ms', flexShrink: 0,
        }}>
          <span style={{ position: 'absolute', top: 3, left: on ? 21 : 3, width: 18, height: 18, borderRadius: '50%', background: '#fff', transition: 'left 150ms', display: 'block' }} />
        </button>
      </div>
      {on ? (
        <>
          <div style={dpTimeS.body}>
            <div style={dpTimeS.col}>
              <button style={dpTimeS.btn} onClick={() => adjH(1)}><Icons.ChevDown size={18} style={{ transform: 'rotate(180deg)' }} /></button>
              <span style={dpTimeS.val}>{_jn(String(h).padStart(2,'0'))}</span>
              <button style={dpTimeS.btn} onClick={() => adjH(-1)}><Icons.ChevDown size={18} /></button>
            </div>
            <span style={dpTimeS.sep}>:</span>
            <div style={dpTimeS.col}>
              <button style={dpTimeS.btn} onClick={() => adjM(15)}><Icons.ChevDown size={18} style={{ transform: 'rotate(180deg)' }} /></button>
              <span style={dpTimeS.val}>{_jn(String(m).padStart(2,'0'))}</span>
              <button style={dpTimeS.btn} onClick={() => adjM(-15)}><Icons.ChevDown size={18} /></button>
            </div>
          </div>
          <div style={dpTimeS.period}>{period}</div>
        </>
      ) : (
        <div style={dpTimeS.empty} />
      )}
    </div>
  );
}

const tasksStyles = {
  scroll: { height: '100%', overflow: 'auto', direction: 'rtl' },

  chipsRow: {
    display: 'flex', gap: 6, overflowX: 'auto',
    padding: '12px 0 6px', scrollbarWidth: 'none',
  },
  chip: {
    flex: 'none',
    font: "500 12px 'Estedad', sans-serif",
    padding: '7px 13px', borderRadius: 999,
    background: 'var(--paper-2)', color: 'var(--ink-2)',
    border: '1px solid var(--c-border-xs)',
    cursor: 'pointer',
  },
  chipActive: { background: 'var(--ink)', color: 'var(--paper)', borderColor: 'transparent' },

  section: { margin: '14px 0 10px' },
  sectionHead: {
    display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
    marginBottom: 8, padding: '0 2px',
  },
  sectionTitle: { font: "600 16px 'Estedad', sans-serif", color: 'var(--ink)' },
  sectionMeta:  { font: "500 12px 'Estedad', sans-serif", color: 'var(--ink-3)' },

  card: {
    background: 'var(--surface-glass)',
    border: '1px solid var(--c-border-xs)',
    borderRadius: 16,
    boxShadow: 'var(--shadow-lift), var(--shadow-press)',
    backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)',
    overflow: 'hidden',
  },
  row: {
    display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 12,
    padding: '13px 14px', alignItems: 'center',
    borderBottom: '1px solid var(--c-border-xs)',
    cursor: 'pointer',
  },
  rowLast: { borderBottom: 'none' },
  rowTitle: { font: "500 15px/1.4 'Estedad', sans-serif", color: 'var(--ink)' },
  rowTitleDone: { color: 'var(--ink-3)', textDecoration: 'line-through' },
  subRow: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 3, flexWrap: 'wrap' },
  subText: { font: "400 12.5px 'Estedad', sans-serif", color: 'var(--ink-2)' },
  metaDot: { width: 3, height: 3, borderRadius: '50%', background: 'var(--ink-4)' },
  catTag: { font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-2)', display: 'inline-flex', alignItems: 'center', gap: 4 },

  empty: {
    padding: '60px 16px', textAlign: 'center',
    color: 'var(--ink-3)', font: "400 15px 'Estedad', sans-serif",
    direction: 'rtl',
  },
  addBtn: {
    display: 'flex', alignItems: 'center', gap: 10,
    padding: '14px 4px', direction: 'rtl',
    color: 'var(--firoozeh-deep)',
    font: "500 14px 'Estedad', sans-serif",
    background: 'none', border: 'none',
    cursor: 'pointer', width: '100%',
    borderTop: '1px solid var(--c-border-xs)',
    marginTop: 8,
  },

  // ── detail ──────────────────────────────────────────────────────
  detail: {
    height: '100%', display: 'flex', flexDirection: 'column',
    overflow: 'hidden', direction: 'rtl',
  },
  detailHeader: {
    display: 'flex', alignItems: 'center', gap: 8,
    padding: '12px 14px',
    borderBottom: '1px solid var(--c-border-sm)',
    flexShrink: 0,
  },
  backBtn: {
    background: 'none', border: 'none', cursor: 'pointer',
    color: 'var(--firoozeh)', padding: '4px 2px 4px 8px',
    display: 'grid', placeItems: 'center',
  },
  detailScroll: { flex: 1, overflow: 'auto', padding: '20px 16px 120px' },

  titleRow: { display: 'flex', alignItems: 'flex-start', gap: 12, marginBottom: 24 },
  titleArea: {
    flex: 1, background: 'transparent', border: 'none', outline: 'none',
    font: "600 20px/1.5 'Estedad', sans-serif", color: 'var(--ink)',
    direction: 'rtl', textAlign: 'right', padding: 0, resize: 'none', width: '100%',
  },

  detailBlock: { marginBottom: 22 },
  detailLabel: {
    display: 'block',
    font: "500 12px 'Estedad', sans-serif", color: 'var(--ink-3)',
    marginBottom: 8,
  },
  chipGroup: { display: 'flex', gap: 8, flexWrap: 'wrap' },
  detailChip: {
    padding: '7px 16px', borderRadius: 999,
    font: "500 13px 'Estedad', sans-serif",
    border: '1px solid var(--c-border-sm)',
    background: 'var(--paper-2)', color: 'var(--ink-2)',
    cursor: 'pointer', transition: 'all 100ms',
  },
  detailChipActive: { background: 'var(--ink)', color: 'var(--paper)', borderColor: 'transparent' },

  notesArea: {
    width: '100%', minHeight: 90,
    background: 'var(--surface)',
    border: '1px solid var(--c-border-xs)',
    borderRadius: 12, padding: '12px 14px',
    font: "400 15px/1.75 'Estedad', sans-serif",
    color: 'var(--ink)', direction: 'rtl', textAlign: 'right',
    resize: 'none', outline: 'none', boxSizing: 'border-box',
  },

  metaText: { font: "400 12px 'Estedad', sans-serif", color: 'var(--ink-4)', marginBottom: 20 },

  deleteBtn: {
    width: '100%', padding: '13px',
    background: 'rgba(180,30,30,0.06)',
    border: '1px solid rgba(180,30,30,0.15)',
    borderRadius: 12, cursor: 'pointer',
    font: "500 14px 'Estedad', sans-serif",
    color: '#B41E1E',
    display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    direction: 'rtl',
  },

  // ── sheet ────────────────────────────────────────────────────────
  overlay: {
    position: 'absolute', inset: 0,
    background: 'rgba(0,0,0,0.35)',
    zIndex: 80, display: 'flex', alignItems: 'flex-end',
  },
  sheet: {
    background: 'var(--paper)',
    borderRadius: '20px 20px 0 0',
    width: '100%', padding: '20px 16px 100px',
    direction: 'rtl', maxHeight: '85%',
    overflow: 'auto',
    boxShadow: '0 -8px 32px rgba(0,0,0,0.15)',
  },
  sheetHeader: {
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    marginBottom: 20,
  },
  sheetTitle: { font: "600 17px 'Estedad', sans-serif", color: 'var(--ink)' },
  addInput: {
    width: '100%', background: 'var(--surface)',
    border: '1px solid var(--c-border-sm)',
    borderRadius: 12, padding: '13px 14px',
    font: "400 16px/1.4 'Estedad', sans-serif",
    color: 'var(--ink)', direction: 'rtl', textAlign: 'right',
    outline: 'none', boxSizing: 'border-box', marginBottom: 18,
  },
  primaryBtn: {
    width: '100%', padding: '14px',
    background: 'var(--firoozeh)', color: '#fff',
    borderRadius: 999, border: 'none',
    font: "600 15px 'Estedad', sans-serif",
    cursor: 'pointer', marginTop: 12, transition: 'opacity 120ms',
  },
  timeBadge: {
    display: 'inline-flex', alignItems: 'center', gap: 3,
    font: "500 11px 'Estedad', sans-serif",
    color: 'var(--firoozeh-deep)', background: 'var(--firoozeh-soft)',
    padding: '2px 7px', borderRadius: 999, flex: 'none',
  },
  timeInput: {
    width: '100%', background: 'var(--surface)',
    border: '1px solid var(--c-border-sm)',
    borderRadius: 12, padding: '11px 14px',
    font: "400 15px/1.4 system-ui, sans-serif",
    color: 'var(--ink)', direction: 'ltr', textAlign: 'left',
    outline: 'none', boxSizing: 'border-box', marginBottom: 18,
  },

  recurChip: {
    padding: '6px 14px', borderRadius: 999,
    font: "500 12px 'Estedad', sans-serif",
    border: '1px solid var(--c-border-sm)',
    background: 'var(--paper-2)', color: 'var(--ink-2)',
    cursor: 'pointer', transition: 'all 100ms', whiteSpace: 'nowrap',
  },
  recurBanner: {
    display: 'flex', alignItems: 'center', gap: 8,
    background: 'var(--firoozeh-soft)', borderRadius: 10,
    padding: '10px 12px', marginBottom: 16,
    font: "500 12px 'Estedad', sans-serif",
    color: 'var(--firoozeh-deep)', direction: 'rtl',
  },

  // ── Project styles ───────────────────────────────────────────────
  projGrid: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 4 },
  projCard: {
    background: 'var(--surface)', border: '1px solid var(--c-border-xs)',
    borderRadius: 16, overflow: 'hidden', cursor: 'pointer',
    boxShadow: 'var(--shadow-lift)', textAlign: 'right',
  },
  projAddCard: {
    background: 'var(--paper-2)', border: '2px dashed var(--c-border-sm)',
    borderRadius: 16, padding: '32px 8px', cursor: 'pointer',
    display: 'flex', flexDirection: 'column', alignItems: 'center',
    justifyContent: 'center', gap: 8, width: '100%',
  },
  projBody: { padding: '12px 12px 14px' },
  projName: { font: "600 14px 'Estedad', sans-serif", color: 'var(--ink)', marginBottom: 5, direction: 'rtl' },
  projMeta: { font: "400 11px 'Estedad', sans-serif", color: 'var(--ink-3)', marginBottom: 10, direction: 'rtl' },
  projBar:  { height: 4, background: 'var(--paper-2)', borderRadius: 999, overflow: 'hidden' },
  projDot:  { width: 10, height: 10, borderRadius: '50%', flex: 'none', display: 'inline-block' },

  // ── Calendar views ───────────────────────────────────────────────
  calNav:    { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0 12px', direction: 'rtl' },
  calNavBtn: { background: 'none', border: 'none', cursor: 'pointer', color: 'var(--firoozeh-deep)', padding: '4px 6px', font: "500 12px 'Estedad', sans-serif", display: 'inline-flex', alignItems: 'center', gap: 3 },
  calNavLbl: { font: "600 14px 'Estedad', sans-serif", color: 'var(--ink)' },
  calStrip:  { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 2, marginBottom: 16 },
  calDay:    { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3, padding: '6px 2px', borderRadius: 10, background: 'transparent', border: 'none', cursor: 'pointer', transition: 'background 80ms' },
  calDayOn:  { background: 'var(--firoozeh)' },
  calDayTdy: { background: 'var(--firoozeh-soft)' },
  calDayName:{ font: "400 10px 'Estedad', sans-serif", color: 'var(--ink-3)' },
  calDayNum: { font: "700 16px/1 'Estedad', sans-serif", color: 'var(--ink)' },
  calDot:    { width: 4, height: 4, borderRadius: '50%', marginTop: 1 },
  monthGrid: { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 3, marginBottom: 12 },
  monthWdHd: { textAlign: 'center', padding: '2px 0 6px', font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-3)' },
  monthCell: { display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '5px 2px', borderRadius: 8, cursor: 'pointer', minHeight: 42, background: 'transparent', border: 'none', transition: 'background 80ms' },
  monthTdy:  { background: 'var(--firoozeh)' },
  monthSel:  { background: 'var(--firoozeh-soft)' },
  monthNum:  { font: "500 13px 'Estedad', sans-serif", color: 'var(--ink)' },
  monthBadge:{ font: "500 9px 'Estedad', sans-serif", padding: '1px 5px', borderRadius: 999, marginTop: 2, background: 'var(--firoozeh-soft)', color: 'var(--firoozeh-deep)' },
  viewToggle:{ display: 'flex', gap: 1, background: 'var(--paper-2)', borderRadius: 10, padding: 2, flexShrink: 0 },
  viewBtn:   { padding: '5px 10px', borderRadius: 8, background: 'transparent', border: 'none', font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-3)', cursor: 'pointer', whiteSpace: 'nowrap' },
  viewBtnOn: { background: 'var(--surface)', color: 'var(--ink)', boxShadow: '0 1px 3px rgba(0,0,0,0.08)' },

  // ── Kanban ───────────────────────────────────────────────────────
  kanbanWrap: { display: 'flex', gap: 10, overflowX: 'auto', paddingBottom: 10, scrollbarWidth: 'none', direction: 'rtl' },
  kanbanCol:  { flex: '0 0 250px', background: 'var(--paper-2)', borderRadius: 14, padding: 10, alignSelf: 'flex-start' },
  kanbanColHead: { display: 'flex', alignItems: 'center', gap: 6, padding: '2px 4px 10px' },
  kanbanColDot:  { width: 8, height: 8, borderRadius: '50%', flex: 'none' },
  kanbanColTitle:{ font: "600 13px 'Estedad', sans-serif", color: 'var(--ink)' },
  kanbanColCount:{ font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-3)', marginInlineStart: 'auto' },
  kanbanCard: { background: 'var(--surface)', borderRadius: 12, padding: '10px 12px', marginBottom: 8, boxShadow: 'var(--shadow-lift)', border: '1px solid var(--c-border-xs)' },
  kanbanCardTitle: { font: "500 13.5px/1.45 'Estedad', sans-serif", color: 'var(--ink)', display: 'flex', alignItems: 'center', gap: 6, cursor: 'pointer' },
  kanbanCardMeta:  { font: "400 11px 'Estedad', sans-serif", color: 'var(--ink-3)', marginTop: 4 },
  kanbanMoveRow:   { display: 'flex', justifyContent: 'space-between', marginTop: 8, gap: 6 },
  kanbanMoveBtn:   { flex: 1, padding: '5px', borderRadius: 8, border: '1px solid var(--c-border-sm)', background: 'var(--paper-2)', color: 'var(--ink-2)', cursor: 'pointer', display: 'grid', placeItems: 'center' },
  kanbanMoveBtnOff:{ opacity: 0.3, cursor: 'default' },
};

const typeList = ['تسک', 'جلسه', 'یادآوری', 'ایده'];
const typeIconMap = { 'تسک': 'CheckCircle', 'جلسه': 'Calendar', 'یادآوری': 'Bell', 'ایده': 'Bolt' };
const typeColors = {
  'تسک':     { bg: 'var(--paper-2)',         color: 'var(--ink-2)' },
  'جلسه':    { bg: 'var(--firoozeh-soft)',   color: 'var(--firoozeh-deep)' },
  'یادآوری': { bg: 'var(--saffron-soft)',    color: 'var(--saffron)' },
  'ایده':    { bg: 'rgba(88,166,88,0.13)',   color: '#2E6B2E' },
};

// ── Status & priority model ───────────────────────────────────────
// status is canonical; `done` is kept in sync (done === status==='done')
// for the recurrence/Home consumers that still read it.
const STATUS_DEFS = {
  pending:       { label: 'در انتظار',    color: 'var(--ink-3)',      bg: 'var(--paper-2)' },
  'in-progress': { label: 'در حال انجام', color: 'var(--firoozeh-deep)', bg: 'var(--firoozeh-soft)' },
  done:          { label: 'انجام‌شده',    color: 'var(--moss)',       bg: 'rgba(88,166,88,0.13)' },
  cancelled:     { label: 'لغو‌شده',      color: 'var(--ink-4)',      bg: 'var(--paper-2)' },
};
const STATUS_ORDER = ['pending', 'in-progress', 'done', 'cancelled'];
const PRIORITY_DEFS = {
  urgent:    { label: 'فوری', color: '#DC2626', dot: '#DC2626' },
  important: { label: 'مهم',  color: 'var(--saffron)', dot: 'var(--saffron)' },
  normal:    { label: 'عادی', color: 'var(--ink-3)', dot: null },
};
const confirmDelete = (msg, fn) => (window.confirmAction || ((m, f) => f()))(msg, fn);
const taskStatus   = t => t.status || (t.done ? 'done' : 'pending');
const taskPriority = t => t.priority || (t.tag === 'فوری' ? 'urgent' : 'normal');
const isTaskDone   = t => taskStatus(t) === 'done';
const isTaskOpen   = t => { const s = taskStatus(t); return s === 'pending' || s === 'in-progress'; };

// ── Date helpers ──────────────────────────────────────────────────
const getDateKey = d => [
  d.getFullYear(),
  String(d.getMonth() + 1).padStart(2, '0'),
  String(d.getDate()).padStart(2, '0'),
].join('-');

const getDueLabel = key => {
  if (!key || key === 'later') return 'این هفته';
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const d = new Date(key + 'T12:00:00');
  const diff = Math.round((d - today) / 86400000);
  if (diff === 0) return 'امروز';
  if (diff === 1) return 'فردا';
  if (diff < 0)  return 'سررسید گذشته';
  return new Intl.DateTimeFormat('fa-IR', { weekday: 'long', month: 'long', day: 'numeric' }).format(d);
};

const getDueMeta = key => {
  if (!key || key === 'later') return '';
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const d = new Date(key + 'T12:00:00');
  const diff = Math.round((d - today) / 86400000);
  if (diff === 0 || diff === 1 || diff < 0)
    return new Intl.DateTimeFormat('fa-IR', { month: 'long', day: 'numeric' }).format(d);
  return '';
};

const getTaskDueKey = t => {
  if (t.dueDate) return t.dueDate;
  return t.section === 'today' ? getDateKey(new Date()) : 'later';
};

const toFaTime = t => t ? t.replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]) : '';

// ── Check circle ─────────────────────────────────────────────────
function TaskCheck({ done, urgent, size = 24, onToggle }) {
  return (
    <button
      onClick={e => { e.stopPropagation(); onToggle(); }}
      aria-label={done ? 'علامت انجام‌نشده' : 'علامت انجام‌شده'}
      style={{
        width: size, height: size, borderRadius: '50%',
        border: done ? 'none' : `2px solid ${urgent ? 'var(--saffron)' : 'var(--ink-3)'}`,
        background: done ? 'var(--moss)' : 'transparent',
        cursor: 'pointer', flex: 'none',
        display: 'grid', placeItems: 'center',
        padding: 0, transition: 'background 200ms, border-color 200ms',
      }}
    >
      {done && (
        <svg width="13" height="13" viewBox="0 0 13 13" fill="none">
          <path d="M2.5 6.5l3 3 5-5" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      )}
    </button>
  );
}

// ── Recurrence picker ─────────────────────────────────────────────
function RecurrencePicker({ value, onChange }) {
  const rec = value || { type: 'none' };
  const types = [
    { key: 'none',    label: 'هرگز' },
    { key: 'daily',   label: 'روزانه' },
    { key: 'weekly',  label: 'هفتگی' },
    { key: 'monthly', label: 'ماهانه' },
    { key: 'yearly',  label: 'سالانه' },
  ];
  const monthDays = [1, 5, 10, 11, 15, 20, 25, 29];
  const shortMonths = [7, 8, 9, 10, 11, 12]; // Jalali months 7-12 have 29-30 days
  const selectedDay = rec.jalaliDay || null;
  const mightClamp = selectedDay && selectedDay > 29;
  return (
    <div style={{ direction: 'rtl' }}>
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
        {types.map(t => (
          <button key={t.key}
            style={{ ...tasksStyles.recurChip, ...(rec.type === t.key ? tasksStyles.detailChipActive : {}) }}
            onClick={() => onChange({ type: t.key, jalaliDay: rec.jalaliDay })}
          >{t.label}</button>
        ))}
      </div>
      {rec.type === 'monthly' && (
        <div style={{ marginTop: 12 }}>
          <span style={{ ...tasksStyles.detailLabel, marginBottom: 8 }}>روز ماه شمسی</span>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {monthDays.map(d => (
              <button key={d}
                style={{ ...tasksStyles.recurChip, ...(rec.jalaliDay === d ? tasksStyles.detailChipActive : {}) }}
                onClick={() => onChange({ ...rec, jalaliDay: d })}
              >{_jn(d)}ام</button>
            ))}
          </div>
          {mightClamp && (
            <div style={{ font: "400 12px 'Estedad', sans-serif", color: '#D97706', marginTop: 8, direction: 'rtl' }}>
              این روز در ماه هدف وجود ندارد — به آخرین روز ماه تنظیم می‌شود
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ── Add task sheet ────────────────────────────────────────────────
function AddTaskSheet({ onClose, onAdd, projects = [], defaultProjectId = null }) {
  const { Icons } = window;
  const todayKey = getDateKey(new Date());
  const [title, setTitle]         = React.useState('');
  const [cat, setCat]             = React.useState('تسک');
  const [priority, setPriority]   = React.useState('normal');
  const [dueDate, setDueDate]     = React.useState(todayKey);
  const [dueTime, setDueTime]     = React.useState('');
  const [showDateInput, setShowDateInput] = React.useState(false);
  const [notes, setNotes]         = React.useState('');
  const [recurrence, setRecurrence] = React.useState({ type: 'none' });
  const [projectId, setProjectId] = React.useState(defaultProjectId);
  const inputRef = React.useRef(null);

  React.useEffect(() => { inputRef.current?.focus(); }, []);

  const handleAdd = () => {
    if (!title.trim()) return;
    const section = dueDate <= todayKey ? 'today' : 'upcoming';
    onAdd({
      title: title.trim(), cat, section,
      status: 'pending', done: false, priority,
      dueDate, dueTime: dueTime || undefined,
      notes: notes.trim(), sub: 'دستی',
      recurrence: recurrence.type !== 'none' ? recurrence : undefined,
      projectId: projectId || undefined,
    });
    onClose();
  };

  const quickDates = [
    { label: 'امروز',    key: getDateKey(new Date()) },
    { label: 'فردا',     key: getDateKey(new Date(Date.now() + 86400000)) },
    { label: 'پس‌فردا',  key: getDateKey(new Date(Date.now() + 172800000)) },
  ];
  const isQuick = quickDates.some(q => q.key === dueDate);

  return (
    <div style={tasksStyles.overlay} onClick={onClose}>
      <div style={tasksStyles.sheet} onClick={e => e.stopPropagation()}>
        <div style={tasksStyles.sheetHeader}>
          <span style={tasksStyles.sheetTitle}>آیتم جدید</span>
          <button style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-2)', padding: 4 }} onClick={onClose}>
            <Icons.X size={20} />
          </button>
        </div>

        <input
          ref={inputRef}
          value={title}
          onChange={e => setTitle(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && handleAdd()}
          placeholder="عنوان…"
          style={tasksStyles.addInput}
        />

        {/* Type */}
        <span style={tasksStyles.detailLabel}>نوع</span>
        <div style={{ ...tasksStyles.chipGroup, marginBottom: 18 }}>
          {typeList.map(c => {
            const TypeIcon = Icons[typeIconMap[c]];
            const active = cat === c;
            const tc = typeColors[c];
            return (
              <button key={c}
                style={{
                  ...tasksStyles.detailChip,
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                  ...(active ? { background: tc.bg, color: tc.color, borderColor: 'transparent' } : {}),
                }}
                onClick={() => setCat(c)}
              >
                <TypeIcon size={14} /> {c}
              </button>
            );
          })}
        </div>

        {/* Priority */}
        <span style={tasksStyles.detailLabel}>اولویت</span>
        <div style={{ ...tasksStyles.chipGroup, marginBottom: 18 }}>
          {['urgent','important','normal'].map(p => {
            const pd = PRIORITY_DEFS[p];
            const active = priority === p;
            return (
              <button key={p}
                style={{
                  ...tasksStyles.detailChip,
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                  ...(active ? { background: pd.color, color: '#fff', borderColor: 'transparent' } : {}),
                }}
                onClick={() => setPriority(p)}
              >
                {pd.dot && <span style={{ width: 8, height: 8, borderRadius: '50%', background: active ? 'rgba(255,255,255,0.8)' : pd.dot }} />}
                {pd.label}
              </button>
            );
          })}
        </div>

        {/* Project */}
        {projects.length > 0 && (<>
          <span style={tasksStyles.detailLabel}>پروژه</span>
          <div style={{ ...tasksStyles.chipGroup, marginBottom: 18, flexWrap: 'wrap' }}>
            <button
              style={{ ...tasksStyles.detailChip, ...(projectId === null ? tasksStyles.detailChipActive : {}) }}
              onClick={() => setProjectId(null)}
            >بدون پروژه</button>
            {projects.map(p => (
              <button key={p.id}
                style={{ ...tasksStyles.detailChip, display: 'inline-flex', alignItems: 'center', gap: 6,
                  ...(projectId === p.id ? { background: p.color, color: '#fff', borderColor: 'transparent' } : {}) }}
                onClick={() => setProjectId(p.id)}
              >
                <span style={{ width: 8, height: 8, borderRadius: '50%', background: projectId === p.id ? 'rgba(255,255,255,0.7)' : p.color }} />
                {p.name}
              </button>
            ))}
          </div>
        </>)}

        {/* Date */}
        <span style={tasksStyles.detailLabel}>تاریخ</span>
        <div style={{ ...tasksStyles.chipGroup, marginBottom: 10 }}>
          {quickDates.map(qd => (
            <button key={qd.key}
              style={{ ...tasksStyles.detailChip, ...(dueDate === qd.key && !showDateInput ? tasksStyles.detailChipActive : {}) }}
              onClick={() => { setDueDate(qd.key); setShowDateInput(false); }}
            >{qd.label}</button>
          ))}
          <button
            style={{
              ...tasksStyles.detailChip,
              display: 'inline-flex', alignItems: 'center', gap: 5,
              ...(!isQuick || showDateInput ? tasksStyles.detailChipActive : {}),
            }}
            onClick={() => setShowDateInput(v => !v)}
          >
            <Icons.Calendar size={13} /> دیگر…
          </button>
        </div>
        {showDateInput && (
          <div style={{ marginBottom: 12 }}>
            <PersianDatePicker value={dueDate} onChange={setDueDate} />
          </div>
        )}
        {!showDateInput && (
          <div style={{ font: "400 12px 'Estedad', sans-serif", color: 'var(--ink-3)', marginBottom: 18, direction: 'rtl' }}>
            {getDueLabel(dueDate)}
          </div>
        )}

        {/* Time */}
        <span style={tasksStyles.detailLabel}>ساعت (اختیاری)</span>
        <div style={{ marginBottom: 18 }}>
          <PersianTimePicker value={dueTime} onChange={setDueTime} />
        </div>

        {/* Recurrence */}
        <span style={tasksStyles.detailLabel}>تکرار</span>
        <div style={{ marginBottom: 18 }}>
          <RecurrencePicker value={recurrence} onChange={setRecurrence} />
        </div>

        <textarea
          value={notes}
          onChange={e => setNotes(e.target.value)}
          placeholder="یادداشت (اختیاری)…"
          rows={3}
          style={tasksStyles.notesArea}
        />

        <button
          style={{ ...tasksStyles.primaryBtn, opacity: title.trim() ? 1 : 0.5 }}
          onClick={handleAdd}
        >
          اضافه کردن
        </button>
      </div>
    </div>
  );
}

// ── Task detail screen ────────────────────────────────────────────
function TaskDetail({ task, onBack, onUpdate, onDelete, onOpenConv, projects = [] }) {
  const { Icons } = window;
  const [title, setTitle]           = React.useState(task.title);
  const [notes, setNotes]           = React.useState(task.notes || '');
  const [dueDate, setDueDate]       = React.useState(task.dueDate || getDateKey(new Date()));
  const [dueTime, setDueTime]       = React.useState(task.dueTime || '');
  const [recurrence, setRecurrence] = React.useState(task.recurrence || { type: 'none' });

  const update = fields => onUpdate(task.id, fields);
  const status   = taskStatus(task);
  const priority = taskPriority(task);
  const setStatus = s => update({ status: s, done: s === 'done' });

  const saveTitle = () => {
    const t = title.trim();
    if (t && t !== task.title) update({ title: t });
  };

  const saveNotes = () => {
    if (notes !== (task.notes || '')) update({ notes });
  };

  const createdStr = task.createdAt
    ? new Intl.DateTimeFormat('fa-IR', { month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }).format(new Date(task.createdAt))
    : null;

  return (
    <div style={tasksStyles.detail}>
      {/* Header */}
      <div style={tasksStyles.detailHeader}>
        <button style={tasksStyles.backBtn} onClick={onBack} aria-label="بازگشت">
          <Icons.Chev size={24} />
        </button>
        <span style={{ font: "600 17px 'Estedad', sans-serif", color: 'var(--ink)', flex: 1 }}>
          جزئیات تسک
        </span>
      </div>

      <div style={tasksStyles.detailScroll}>
        {/* Done toggle + editable title */}
        <div style={tasksStyles.titleRow}>
          <TaskCheck done={status === 'done'} size={28} onToggle={() => setStatus(status === 'done' ? 'pending' : 'done')} />
          <textarea
            value={title}
            onChange={e => setTitle(e.target.value)}
            onBlur={saveTitle}
            rows={2}
            style={{
              ...tasksStyles.titleArea,
              ...(status === 'done' || status === 'cancelled' ? { color: 'var(--ink-3)', textDecoration: 'line-through' } : {}),
            }}
          />
        </div>

        {/* Status */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>وضعیت</span>
          <div style={tasksStyles.chipGroup}>
            {STATUS_ORDER.map(s => {
              const sd = STATUS_DEFS[s];
              const active = status === s;
              return (
                <button key={s}
                  style={{
                    ...tasksStyles.detailChip,
                    ...(active ? { background: sd.bg, color: sd.color, borderColor: 'transparent', fontWeight: 600 } : {}),
                  }}
                  onClick={() => setStatus(s)}
                >{sd.label}</button>
              );
            })}
          </div>
        </div>

        {/* Priority */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>اولویت</span>
          <div style={tasksStyles.chipGroup}>
            {['urgent','important','normal'].map(p => {
              const pd = PRIORITY_DEFS[p];
              const active = priority === p;
              return (
                <button key={p}
                  style={{
                    ...tasksStyles.detailChip,
                    display: 'inline-flex', alignItems: 'center', gap: 6,
                    ...(active ? { background: pd.color, color: '#fff', borderColor: 'transparent' } : {}),
                  }}
                  onClick={() => update({ priority: p })}
                >
                  {pd.dot && <span style={{ width: 8, height: 8, borderRadius: '50%', background: active ? 'rgba(255,255,255,0.8)' : pd.dot }} />}
                  {pd.label}
                </button>
              );
            })}
          </div>
        </div>

        {/* Type */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>نوع</span>
          <div style={tasksStyles.chipGroup}>
            {typeList.map(c => {
              const TypeIcon = Icons[typeIconMap[c]];
              const active = task.cat === c;
              const tc = typeColors[c];
              return (
                <button key={c}
                  style={{
                    ...tasksStyles.detailChip,
                    display: 'inline-flex', alignItems: 'center', gap: 6,
                    ...(active ? { background: tc.bg, color: tc.color, borderColor: 'transparent' } : {}),
                  }}
                  onClick={() => update({ cat: c })}
                >
                  <TypeIcon size={14} /> {c}
                </button>
              );
            })}
          </div>
        </div>

        {/* Project */}
        {projects.length > 0 && (
          <div style={tasksStyles.detailBlock}>
            <span style={tasksStyles.detailLabel}>پروژه</span>
            <div style={{ ...tasksStyles.chipGroup, flexWrap: 'wrap' }}>
              <button
                style={{ ...tasksStyles.detailChip, ...(!task.projectId ? tasksStyles.detailChipActive : {}) }}
                onClick={() => update({ projectId: undefined })}
              >بدون پروژه</button>
              {projects.map(p => (
                <button key={p.id}
                  style={{ ...tasksStyles.detailChip, display: 'inline-flex', alignItems: 'center', gap: 6,
                    ...(task.projectId === p.id ? { background: p.color, color: '#fff', borderColor: 'transparent' } : {}) }}
                  onClick={() => update({ projectId: p.id })}
                >
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: task.projectId === p.id ? 'rgba(255,255,255,0.7)' : p.color }} />
                  {p.name}
                </button>
              ))}
            </div>
          </div>
        )}

        {/* Date */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>تاریخ</span>
          <div style={{ ...tasksStyles.chipGroup, marginBottom: 10 }}>
            {[
              { label: 'امروز',   key: getDateKey(new Date()) },
              { label: 'فردا',    key: getDateKey(new Date(Date.now() + 86400000)) },
              { label: 'پس‌فردا', key: getDateKey(new Date(Date.now() + 172800000)) },
            ].map(qd => (
              <button key={qd.key}
                style={{ ...tasksStyles.detailChip, ...(dueDate === qd.key ? tasksStyles.detailChipActive : {}) }}
                onClick={() => { setDueDate(qd.key); update({ dueDate: qd.key, section: qd.key <= getDateKey(new Date()) ? 'today' : 'upcoming' }); }}
              >{qd.label}</button>
            ))}
          </div>
          <PersianDatePicker
            value={dueDate}
            onChange={v => { setDueDate(v); update({ dueDate: v, section: v <= getDateKey(new Date()) ? 'today' : 'upcoming' }); }}
          />
        </div>

        {/* Time */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>ساعت</span>
          <PersianTimePicker
            value={dueTime}
            onChange={v => { setDueTime(v); update({ dueTime: v || undefined }); }}
          />
        </div>

        {/* Recurrence */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>تکرار</span>
          {getRecurrenceLabel(recurrence) && (
            <div style={{ ...tasksStyles.recurBanner, marginBottom: 10 }}>
              ↻ {getRecurrenceLabel(recurrence)}
            </div>
          )}
          <RecurrencePicker
            value={recurrence}
            onChange={rec => {
              setRecurrence(rec);
              update({ recurrence: rec.type !== 'none' ? rec : undefined });
            }}
          />
          {recurrence?.type && recurrence.type !== 'none' && (() => {
            const nextDate = window._calcNextRecurrence?.({ ...task, dueDate, recurrence });
            if (!nextDate) return null;
            const fmt = new Intl.DateTimeFormat('fa-IR', { year: 'numeric', month: 'long', day: 'numeric' });
            return (
              <div style={{ marginTop: 8, font: "400 12px 'Estedad', sans-serif", color: 'var(--firoozeh-deep)', display: 'flex', alignItems: 'center', gap: 6 }}>
                <span>↻</span>
                <span>تکرار بعدی: {fmt.format(new Date(nextDate + 'T12:00:00'))}</span>
              </div>
            );
          })()}
        </div>

        {/* Notes */}
        <div style={tasksStyles.detailBlock}>
          <span style={tasksStyles.detailLabel}>یادداشت</span>
          <textarea
            value={notes}
            onChange={e => setNotes(e.target.value)}
            onBlur={saveNotes}
            placeholder="یادداشتی برای این تسک بنویس…"
            rows={4}
            style={tasksStyles.notesArea}
          />
        </div>

        {/* Created date */}
        {createdStr && (
          <div style={tasksStyles.metaText}>ساخته شده: {createdStr}</div>
        )}

        {/* Source conversation link */}
        {task.sourceConvId && onOpenConv && (
          <button
            style={{
              width: '100%', padding: '13px', marginBottom: 12,
              background: 'var(--firoozeh-soft)',
              border: '1px solid rgba(42,157,143,0.18)',
              borderRadius: 12, cursor: 'pointer',
              font: "500 14px 'Estedad', sans-serif",
              color: 'var(--firoozeh-deep)',
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
              direction: 'rtl',
            }}
            onClick={() => onOpenConv(task.sourceConvId)}
          >
            <Icons.Chat size={16} />
            مشاهده مکالمه منشأ
          </button>
        )}

        {/* Delete */}
        <button style={tasksStyles.deleteBtn} onClick={() => confirmDelete('این تسک حذف شود؟', () => onDelete(task.id))}>
          <Icons.Trash size={16} />
          حذف تسک
        </button>
      </div>
    </div>
  );
}

// ── Task row in list ──────────────────────────────────────────────
function TaskRow({ task, isLast, onToggle, onOpen }) {
  const { Icons } = window;
  const TypeIcon = Icons[typeIconMap[task.cat]] || Icons.Tag;
  const tc = typeColors[task.cat] || typeColors['تسک'];
  const status   = taskStatus(task);
  const priority = taskPriority(task);
  const pd = PRIORITY_DEFS[priority];
  const muted = status === 'done' || status === 'cancelled';

  return (
    <div
      className="sb-animated-card"
      style={{ ...tasksStyles.row, ...(isLast ? tasksStyles.rowLast : {}), ...(status === 'cancelled' ? { opacity: 0.6 } : {}) }}
      onClick={() => onOpen(task.id)}
      role="button"
    >
      <TaskCheck
        done={status === 'done'}
        urgent={priority === 'urgent'}
        onToggle={() => onToggle(task.id)}
      />
      <div style={{ minWidth: 0 }}>
        <div style={{ ...tasksStyles.rowTitle, ...(muted ? tasksStyles.rowTitleDone : {}), display: 'flex', alignItems: 'center', gap: 6 }}>
          {pd.dot && status !== 'done' && status !== 'cancelled' && (
            <span style={{ width: 7, height: 7, borderRadius: '50%', background: pd.dot, flex: 'none' }} title={pd.label} />
          )}
          <span style={{ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis' }}>{task.title}</span>
        </div>
        <div style={tasksStyles.subRow}>
          {status === 'in-progress' && (
            <span style={{ ...tasksStyles.catTag, background: STATUS_DEFS['in-progress'].bg, color: STATUS_DEFS['in-progress'].color, padding: '2px 8px', borderRadius: 999 }}>
              {STATUS_DEFS['in-progress'].label}
            </span>
          )}
          {status === 'cancelled' && (
            <span style={{ ...tasksStyles.catTag, background: STATUS_DEFS.cancelled.bg, color: STATUS_DEFS.cancelled.color, padding: '2px 8px', borderRadius: 999 }}>
              {STATUS_DEFS.cancelled.label}
            </span>
          )}
          <span style={{
            ...tasksStyles.catTag,
            background: tc.bg, color: tc.color,
            padding: '2px 8px', borderRadius: 999,
          }}>
            <TypeIcon size={11} /> {task.cat || 'تسک'}
          </span>
          {task.dueTime && (
            <span style={tasksStyles.timeBadge}>
              <Icons.Clock size={11} /> {toFaTime(task.dueTime)}
            </span>
          )}
          {task.sub && <><span style={tasksStyles.metaDot} /><span style={tasksStyles.subText}>{task.sub}</span></>}
          {task.recurrence?.type && task.recurrence.type !== 'none' && (
            <span style={{ font: "500 11px 'Estedad', sans-serif", color: 'var(--firoozeh-deep)', background: 'var(--firoozeh-soft)', padding: '2px 7px', borderRadius: 999 }}>↻</span>
          )}
        </div>
      </div>
      <Icons.ChevLeft size={16} style={{ color: 'var(--ink-4)' }} />
    </div>
  );
}

// ── Week calendar view ────────────────────────────────────────────
function WeekView({ tasks, weekOffset, onWeekChange, onToggle, onOpenTask }) {
  const { Icons } = window;
  const todayKey = getDateKey(new Date());

  const weekStart = (() => {
    const now = new Date(); now.setHours(0, 0, 0, 0);
    const pDay = (now.getDay() + 1) % 7;
    return new Date(now.getTime() - pDay * 86400000 + weekOffset * 7 * 86400000);
  })();

  const defaultSel = (() => {
    for (let i = 0; i < 7; i++) {
      if (getDateKey(new Date(weekStart.getTime() + i * 86400000)) === todayKey) return i;
    }
    return 0;
  })();
  const [selDay, setSelDay] = React.useState(defaultSel);
  React.useEffect(() => { setSelDay(defaultSel); }, [weekOffset]);

  const WDAYS = ['ش','ی','د','س','چ','پ','ج'];
  const days = Array.from({ length: 7 }, (_, i) => {
    const d = new Date(weekStart.getTime() + i * 86400000);
    const key = getDateKey(d);
    const [,,jd] = _toJalali(d.getFullYear(), d.getMonth() + 1, d.getDate());
    return { key, jd, tasks: tasks.filter(t => isTaskOpen(t) && t.dueDate === key), isToday: key === todayKey };
  });

  const startJ = _toJalali(weekStart.getFullYear(), weekStart.getMonth() + 1, weekStart.getDate());
  const endD   = new Date(weekStart.getTime() + 6 * 86400000);
  const endJ   = _toJalali(endD.getFullYear(), endD.getMonth() + 1, endD.getDate());
  const label  = weekOffset === 0 ? 'این هفته' :
    `${_jn(startJ[2])} ${J_MONTHS[startJ[1]-1]} – ${_jn(endJ[2])} ${J_MONTHS[endJ[1]-1]}`;
  const selTasks = days[selDay]?.tasks || [];

  return (
    <div style={{ direction: 'rtl' }}>
      <div style={tasksStyles.calNav}>
        <button style={tasksStyles.calNavBtn} onClick={() => onWeekChange(weekOffset - 1)}>
          <Icons.Chev size={15} /> هفته قبل
        </button>
        <span style={tasksStyles.calNavLbl}>{label}</span>
        <button style={tasksStyles.calNavBtn} onClick={() => onWeekChange(weekOffset + 1)}>
          <Icons.ChevLeft size={15} /> هفته بعد
        </button>
      </div>
      <div style={tasksStyles.calStrip}>
        {days.map((day, i) => {
          const isOn = selDay === i;
          return (
            <button key={day.key}
              style={{ ...tasksStyles.calDay, ...(isOn ? tasksStyles.calDayOn : day.isToday ? tasksStyles.calDayTdy : {}) }}
              onClick={() => setSelDay(i)}
            >
              <span style={{ ...tasksStyles.calDayName, color: isOn ? 'rgba(255,255,255,0.75)' : day.isToday ? 'var(--firoozeh-deep)' : 'var(--ink-3)' }}>
                {WDAYS[i]}
              </span>
              <span style={{ ...tasksStyles.calDayNum, color: isOn ? '#fff' : 'var(--ink)' }}>
                {_jn(day.jd)}
              </span>
              {day.tasks.length > 0 && (
                <span style={{ ...tasksStyles.calDot, background: isOn ? 'rgba(255,255,255,0.6)' : 'var(--saffron)' }} />
              )}
            </button>
          );
        })}
      </div>
      {selTasks.length === 0 ? (
        <div style={{ ...tasksStyles.empty, padding: '28px 16px' }}>تسکی برای این روز ثبت نشده</div>
      ) : (
        <div className="sb-animated-card" style={tasksStyles.card}>
          {selTasks.map((t, i) => (
            <TaskRow key={t.id} task={t} isLast={i === selTasks.length - 1} onToggle={onToggle} onOpen={onOpenTask} />
          ))}
        </div>
      )}
    </div>
  );
}

// ── Month calendar view ───────────────────────────────────────────
function MonthView({ tasks, monthOffset, onMonthChange, onToggle, onOpenTask }) {
  const { Icons } = window;
  const todayKey = getDateKey(new Date());
  const [selKey, setSelKey] = React.useState(todayKey);

  const now = new Date();
  const [todayJy, todayJm] = _toJalali(now.getFullYear(), now.getMonth() + 1, now.getDate());
  let viewM = todayJm + monthOffset, viewY = todayJy;
  while (viewM > 12) { viewM -= 12; viewY++; }
  while (viewM < 1)  { viewM += 12; viewY--; }

  const [gy0, gm0, gd0] = _toGregorian(viewY, viewM, 1);
  const firstDate   = new Date(gy0, gm0 - 1, gd0);
  const startOffset = _pwIdx(firstDate.getDay());
  const daysInMonth = _jDays(viewY, viewM);
  const cells = [...Array(startOffset).fill(null), ...Array.from({ length: daysInMonth }, (_, i) => i + 1)];
  while (cells.length % 7 !== 0) cells.push(null);

  const WDAYS = ['ش','ی','د','س','چ','پ','ج'];
  const selTasks = tasks.filter(t => isTaskOpen(t) && t.dueDate === selKey);

  return (
    <div style={{ direction: 'rtl' }}>
      <div style={tasksStyles.calNav}>
        <button style={tasksStyles.calNavBtn} onClick={() => onMonthChange(monthOffset - 1)}>
          <Icons.Chev size={15} /> ماه قبل
        </button>
        <span style={tasksStyles.calNavLbl}>{J_MONTHS[viewM - 1]} {_jn(viewY)}</span>
        <button style={tasksStyles.calNavBtn} onClick={() => onMonthChange(monthOffset + 1)}>
          <Icons.ChevLeft size={15} /> ماه بعد
        </button>
      </div>
      <div style={tasksStyles.monthGrid}>
        {WDAYS.map(d => <div key={d} style={tasksStyles.monthWdHd}>{d}</div>)}
        {cells.map((d, i) => {
          if (!d) return <div key={`_${i}`} />;
          const [gy2, gm2, gd2] = _toGregorian(viewY, viewM, d);
          const key   = _toIso(gy2, gm2, gd2);
          const count = tasks.filter(t => isTaskOpen(t) && t.dueDate === key).length;
          const isToday = key === todayKey;
          const isSel   = key === selKey;
          return (
            <button key={d}
              style={{ ...tasksStyles.monthCell, ...(isToday ? tasksStyles.monthTdy : isSel ? tasksStyles.monthSel : {}) }}
              onClick={() => setSelKey(key)}
            >
              <span style={{ ...tasksStyles.monthNum, color: isToday ? '#fff' : 'var(--ink)' }}>{_jn(d)}</span>
              {count > 0 && (
                <span style={{ ...tasksStyles.monthBadge, ...(isToday ? { background: 'rgba(255,255,255,0.25)', color: '#fff' } : {}) }}>
                  {_jn(count)}
                </span>
              )}
            </button>
          );
        })}
      </div>
      {selTasks.length > 0 ? (
        <div className="sb-animated-card" style={tasksStyles.card}>
          {selTasks.map((t, i) => (
            <TaskRow key={t.id} task={t} isLast={i === selTasks.length - 1} onToggle={onToggle} onOpen={onOpenTask} />
          ))}
        </div>
      ) : (
        <div style={{ ...tasksStyles.empty, padding: '20px 16px' }}>تسکی برای این روز ثبت نشده</div>
      )}
    </div>
  );
}

// ── Add project sheet ─────────────────────────────────────────────
function AddProjectSheet({ onClose, onAdd }) {
  const { Icons } = window;
  const [name, setName] = React.useState('');
  const [color, setColor] = React.useState(PROJECT_PALETTES[0]);
  const inputRef = React.useRef(null);
  React.useEffect(() => { inputRef.current?.focus(); }, []);

  const handleAdd = () => { if (name.trim()) { onAdd({ name: name.trim(), color }); onClose(); } };

  return (
    <div style={tasksStyles.overlay} onClick={onClose}>
      <div style={tasksStyles.sheet} onClick={e => e.stopPropagation()}>
        <div style={tasksStyles.sheetHeader}>
          <span style={tasksStyles.sheetTitle}>پروژه جدید</span>
          <button style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-2)', padding: 4 }} onClick={onClose}>
            <Icons.X size={20} />
          </button>
        </div>
        <input ref={inputRef} value={name} onChange={e => setName(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && handleAdd()}
          placeholder="نام پروژه…" style={tasksStyles.addInput} />
        <span style={tasksStyles.detailLabel}>رنگ</span>
        <div style={{ display: 'flex', gap: 10, marginBottom: 24, flexWrap: 'wrap' }}>
          {PROJECT_PALETTES.map(c => (
            <button key={c} onClick={() => setColor(c)}
              style={{ width: 30, height: 30, borderRadius: '50%', background: c, border: color === c ? '3px solid var(--ink)' : '3px solid transparent', cursor: 'pointer', boxSizing: 'border-box' }}
            />
          ))}
        </div>
        <button style={{ ...tasksStyles.primaryBtn, opacity: name.trim() ? 1 : 0.5 }} onClick={handleAdd}>
          ساختن پروژه
        </button>
      </div>
    </div>
  );
}

// ── Project gallery ────────────────────────────────────────────────
function ProjectGallery({ projects, tasks, onOpen, onAdd }) {
  const { Icons } = window;
  const [addOpen, setAddOpen] = React.useState(false);

  return (
    <div style={{ direction: 'rtl' }}>
      <div style={tasksStyles.projGrid}>
        {projects.map(proj => {
          const pt = tasks.filter(t => t.projectId === proj.id);
          const done = pt.filter(isTaskDone).length;
          const total = pt.length;
          const pct = total > 0 ? done / total : 0;
          return (
            <div key={proj.id} style={tasksStyles.projCard} onClick={() => onOpen(proj.id)}>
              <div style={{ height: 6, background: proj.color }} />
              <div style={tasksStyles.projBody}>
                <div style={tasksStyles.projName}>{proj.name}</div>
                <div style={tasksStyles.projMeta}>
                  {total === 0 ? 'بدون تسک' : `${_jn(total - done)} باقی‌مانده از ${_jn(total)}`}
                </div>
                {total > 0 && (
                  <div style={tasksStyles.projBar}>
                    <div style={{ height: '100%', width: `${pct * 100}%`, background: proj.color, borderRadius: 999, transition: 'width 400ms' }} />
                  </div>
                )}
              </div>
            </div>
          );
        })}
        <button style={tasksStyles.projAddCard} onClick={() => setAddOpen(true)}>
          <Icons.Plus size={22} style={{ color: 'var(--ink-3)' }} />
          <span style={{ font: "500 12px 'Estedad', sans-serif", color: 'var(--ink-3)' }}>پروژه جدید</span>
        </button>
      </div>
      {projects.length === 0 && (
        <div style={{ ...tasksStyles.empty, paddingTop: 16 }}>
          <div style={{ fontSize: 13, marginTop: 4, color: 'var(--ink-4)' }}>پروژه‌ای هنوز نساختی</div>
        </div>
      )}
      {addOpen && <AddProjectSheet onClose={() => setAddOpen(false)} onAdd={p => { onAdd(p); setAddOpen(false); }} />}
    </div>
  );
}

// ── Project detail ─────────────────────────────────────────────────
function ProjectDetail({ project, tasks, onBack, onToggle, onOpenTask, onUpdateProject, onDeleteProject, onAddTask }) {
  const { Icons } = window;
  const [editing, setEditing] = React.useState(false);
  const [editName, setEditName] = React.useState(project.name);
  const [editColor, setEditColor] = React.useState(project.color);

  const pt = tasks.filter(t => t.projectId === project.id);
  const pending = pt.filter(isTaskOpen);
  const done    = pt.filter(t => !isTaskOpen(t));
  const pct = pt.length > 0 ? done.length / pt.length : 0;

  const saveEdit = () => {
    if (editName.trim() && onUpdateProject) {
      onUpdateProject(project.id, { name: editName.trim(), color: editColor });
    }
    setEditing(false);
  };

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden', direction: 'rtl' }}>
      <div style={{ ...tasksStyles.detailHeader, flexDirection: 'column', alignItems: 'flex-start', gap: 10 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%' }}>
          <button style={tasksStyles.backBtn} onClick={onBack}><Icons.Chev size={24} /></button>
          <span style={{ ...tasksStyles.projDot, background: editing ? editColor : project.color }} />
          {editing ? (
            <input
              autoFocus
              value={editName}
              onChange={e => setEditName(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') saveEdit(); if (e.key === 'Escape') setEditing(false); }}
              style={{ flex: 1, font: "600 17px 'Estedad', sans-serif", color: 'var(--ink)', border: 'none', outline: 'none', background: 'transparent', textAlign: 'right' }}
            />
          ) : (
            <span style={{ font: "600 17px 'Estedad', sans-serif", color: 'var(--ink)', flex: 1 }}>{project.name}</span>
          )}
          <button
            style={{ ...tasksStyles.backBtn, color: editing ? 'var(--firoozeh)' : 'var(--ink-3)' }}
            onClick={() => { if (editing) saveEdit(); else { setEditName(project.name); setEditColor(project.color); setEditing(true); } }}
          >
            {editing ? <Icons.CheckCircle size={20} /> : <Icons.Edit size={18} />}
          </button>
        </div>
        {editing && (
          <div style={{ display: 'flex', gap: 8, paddingRight: 2, paddingBottom: 4 }}>
            {PROJECT_PALETTES.map(c => (
              <button key={c} onClick={() => setEditColor(c)} style={{ width: 22, height: 22, borderRadius: '50%', background: c, border: editColor === c ? '3px solid var(--ink)' : '2px solid transparent', cursor: 'pointer', boxSizing: 'border-box' }} />
            ))}
          </div>
        )}
        <div style={{ paddingRight: 2, width: '100%' }}>
          <div style={{ ...tasksStyles.projBar, marginBottom: 5 }}>
            <div style={{ height: '100%', width: `${pct * 100}%`, background: project.color, borderRadius: 999, transition: 'width 400ms' }} />
          </div>
          <div style={{ font: "400 11px 'Estedad', sans-serif", color: 'var(--ink-3)', paddingRight: 2 }}>
            {_jn(done.length)} از {_jn(pt.length)} تسک انجام شده
          </div>
        </div>
      </div>
      <div style={{ ...tasksStyles.detailScroll, padding: '12px 16px 140px' }}>
        {pending.length > 0 && (
          <div className="sb-animated-card" style={tasksStyles.card}>
            {pending.map((t, i) => (
              <TaskRow key={t.id} task={t} isLast={i === pending.length - 1} onToggle={onToggle} onOpen={onOpenTask} />
            ))}
          </div>
        )}
        {done.length > 0 && (
          <div style={{ ...tasksStyles.section, marginTop: 16 }}>
            <div style={tasksStyles.sectionHead}>
              <div style={tasksStyles.sectionTitle}>انجام‌شده</div>
            </div>
            <div className="sb-animated-card" style={tasksStyles.card}>
              {done.map((t, i) => (
                <TaskRow key={t.id} task={t} isLast={i === done.length - 1} onToggle={onToggle} onOpen={onOpenTask} />
              ))}
            </div>
          </div>
        )}
        {pt.length === 0 && (
          <div style={{ ...tasksStyles.empty, paddingTop: 32 }}>
            <div style={{ fontSize: 32, marginBottom: 8 }}>📋</div>
            <div>هنوز تسکی در این پروژه نیست</div>
          </div>
        )}
        <button style={tasksStyles.addBtn} onClick={onAddTask}>
          <Icons.Plus size={18} />
          تسک جدید
        </button>
        <button style={{ ...tasksStyles.deleteBtn, marginTop: 12 }} onClick={() => confirmDelete('این پروژه حذف شود؟ تسک‌ها باقی می‌مانند.', () => onDeleteProject(project.id))}>
          <Icons.Trash size={16} /> حذف پروژه
        </button>
      </div>
    </div>
  );
}

// ── Kanban board view ─────────────────────────────────────────────
const KANBAN_COLS = ['pending', 'in-progress', 'done'];
function KanbanView({ tasks, onUpdate, onOpenTask }) {
  const { Icons } = window;
  const setStatus = (id, s) => onUpdate(id, { status: s, done: s === 'done' });
  const board = tasks.filter(t => taskStatus(t) !== 'cancelled');

  return (
    <div style={tasksStyles.kanbanWrap}>
      {KANBAN_COLS.map(col => {
        const sd = STATUS_DEFS[col];
        const items = board
          .filter(t => taskStatus(t) === col)
          .sort((a, b) => (a.dueDate || '9999').localeCompare(b.dueDate || '9999'));
        const colIdx = KANBAN_COLS.indexOf(col);
        return (
          <div key={col} style={tasksStyles.kanbanCol}>
            <div style={tasksStyles.kanbanColHead}>
              <span style={{ ...tasksStyles.kanbanColDot, background: sd.color }} />
              <span style={tasksStyles.kanbanColTitle}>{sd.label}</span>
              <span style={tasksStyles.kanbanColCount}>{_jn(items.length)}</span>
            </div>
            {items.length === 0 && (
              <div style={{ font: "400 12px 'Estedad', sans-serif", color: 'var(--ink-4)', textAlign: 'center', padding: '14px 0' }}>—</div>
            )}
            {items.map(t => {
              const pd = PRIORITY_DEFS[taskPriority(t)];
              return (
                <div key={t.id} style={tasksStyles.kanbanCard}>
                  <div style={tasksStyles.kanbanCardTitle} onClick={() => onOpenTask(t.id)}>
                    {pd.dot && <span style={{ width: 7, height: 7, borderRadius: '50%', background: pd.dot, flex: 'none' }} />}
                    <span style={{ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis' }}>{t.title}</span>
                  </div>
                  <div style={tasksStyles.kanbanCardMeta}>
                    {t.cat || 'تسک'}{t.dueTime ? ` · ${toFaTime(t.dueTime)}` : ''}
                  </div>
                  <div style={tasksStyles.kanbanMoveRow}>
                    <button
                      style={{ ...tasksStyles.kanbanMoveBtn, ...(colIdx === 0 ? tasksStyles.kanbanMoveBtnOff : {}) }}
                      onClick={() => colIdx > 0 && setStatus(t.id, KANBAN_COLS[colIdx - 1])}
                      aria-label="ستون قبل"
                    ><Icons.Chev size={14} /></button>
                    <button
                      style={{ ...tasksStyles.kanbanMoveBtn, ...(colIdx === KANBAN_COLS.length - 1 ? tasksStyles.kanbanMoveBtnOff : {}) }}
                      onClick={() => colIdx < KANBAN_COLS.length - 1 && setStatus(t.id, KANBAN_COLS[colIdx + 1])}
                      aria-label="ستون بعد"
                    ><Icons.ChevLeft size={14} /></button>
                    <button
                      style={{ ...tasksStyles.kanbanMoveBtn, color: 'var(--garnet)', flexShrink: 0 }}
                      onClick={() => setStatus(t.id, 'cancelled')}
                      aria-label="لغو"
                      title="لغو تسک"
                    ><Icons.X size={13} /></button>
                  </div>
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}

// ── Tasks screen ──────────────────────────────────────────────────
function Tasks({ tasks, gamify, onToggle, onUpdate, onDelete, onAdd, isDesktop, onOpenConv,
                 projects = [], onAddProject, onUpdateProject, onDeleteProject,
                 sortOpen = false, onSortClose, highlightId }) {
  const { Icons } = window;
  const [filter, setFilter] = React.useState('all');
  const [detail, setDetail] = React.useState(null);
  const [addOpen, setAddOpen] = React.useState(false);
  const [viewMode, setViewMode] = React.useState('list');
  // PRD-005: persist sort preference across tab switches
  const [sortBy, setSortByState] = React.useState(() => window.DB?.load('taskSort', 'date') || 'date');
  const setSortBy = (v) => { setSortByState(v); window.DB?.save('taskSort', v); };

  // R04: scroll to highlighted item
  React.useEffect(() => {
    if (!highlightId) return;
    const el = document.getElementById('task-item-' + highlightId);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' });
  }, [highlightId]);
  const [calOffset, setCalOffset] = React.useState(0);
  const [openProjectId, setOpenProjectId] = React.useState(null);

  // Show task detail (full-screen override)
  if (detail) {
    const task = tasks.find(t => t.id === detail);
    if (!task) { setDetail(null); return null; }
    return (
      <TaskDetail
        task={task}
        onBack={() => setDetail(null)}
        onUpdate={onUpdate}
        onDelete={id => { onDelete(id); setDetail(null); }}
        onOpenConv={onOpenConv}
        projects={projects}
      />
    );
  }

  // Show project detail (full-screen override)
  if (filter === 'projects' && openProjectId) {
    const proj = projects.find(p => p.id === openProjectId);
    if (!proj) { setOpenProjectId(null); return null; }
    return (
      <div style={{ height: '100%', position: 'relative' }}>
        <ProjectDetail
          project={proj}
          tasks={tasks}
          onBack={() => setOpenProjectId(null)}
          onToggle={onToggle}
          onOpenTask={setDetail}
          onUpdateProject={onUpdateProject}
          onDeleteProject={id => { onDeleteProject(id); setOpenProjectId(null); }}
          onAddTask={() => setAddOpen(true)}
        />
        {addOpen && (
          <AddTaskSheet onClose={() => setAddOpen(false)} onAdd={onAdd}
            projects={projects} defaultProjectId={openProjectId} />
        )}
      </div>
    );
  }

  const filterDefs = [
    { key: 'all',       label: 'همه',       icon: null },
    { key: 'important', label: 'مهم',       icon: 'Bolt' },
    { key: 'projects',  label: 'پروژه‌ها',  icon: 'Tag' },
    { key: 'تسک',       label: 'تسک',       icon: 'CheckCircle' },
    { key: 'جلسه',      label: 'جلسه',      icon: 'Calendar' },
    { key: 'یادآوری',   label: 'یادآوری',   icon: 'Bell' },
    { key: 'ایده',      label: 'ایده',      icon: 'Bolt' },
    { key: 'cancelled', label: 'لغو شده',   icon: 'X' },
  ];

  const filtered = tasks.filter(t => {
    if (filter === 'cancelled') return taskStatus(t) === 'cancelled';
    if (taskStatus(t) === 'cancelled') return false; // hide cancelled from all other filters
    if (filter === 'all' || filter === 'projects') return true;
    if (filter === 'important') return taskPriority(t) === 'important' || taskPriority(t) === 'urgent';
    return t.cat === filter;
  });

  // Build dynamic groups by exact due date
  const applySortBy = arr => {
    if (sortBy === 'priority') {
      const order = { urgent: 0, important: 1, normal: 2 };
      return arr.slice().sort((a, b) => (order[taskPriority(a)] || 2) - (order[taskPriority(b)] || 2));
    }
    if (sortBy === 'created') return arr.slice().sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
    return arr; // 'date' = default grouping order
  };

  const pendingItems = applySortBy(filtered.filter(isTaskOpen));
  const doneItems    = filtered.filter(t => !isTaskOpen(t) && taskStatus(t) !== 'cancelled');
  const todayKey = getDateKey(new Date());
  const todayTasks = tasks.filter(t =>
    taskStatus(t) !== 'cancelled' && (t.dueDate === todayKey || (!t.dueDate && t.section === 'today'))
  );
  const todayDone = todayTasks.filter(isTaskDone).length;
  const todayWins = Math.max(todayDone, gamify?.todayDoneCount || 0);
  const todayTarget = Math.max(3, todayTasks.length, todayWins);
  const todayPct = Math.min(100, Math.round((todayWins / todayTarget) * 100));
  const activeStreak = gamify?.streak || 0;

  const dateGroupMap = new Map();
  for (const t of pendingItems) {
    const key = getTaskDueKey(t);
    if (!dateGroupMap.has(key)) dateGroupMap.set(key, []);
    dateGroupMap.get(key).push(t);
  }
  const sortedDateKeys = sortBy === 'date'
    ? [...dateGroupMap.keys()].sort((a, b) => { if (a === 'later') return 1; if (b === 'later') return -1; return a < b ? -1 : 1; })
    : [...dateGroupMap.keys()];

  const pad = isDesktop ? '0 24px 80px' : '0 16px 140px';

  return (
    <div style={{ height: '100%', position: 'relative' }}>
      <div className="sb-flow" style={{ ...tasksStyles.scroll, padding: pad }}>
        {/* Filter chips + view toggle */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '12px 0 8px' }}>
          <div style={{ flex: 1, display: 'flex', gap: 6, overflowX: 'auto', scrollbarWidth: 'none' }}>
            {filterDefs.map(f => {
              const active = filter === f.key;
              const FIcon = f.icon ? Icons[f.icon] : null;
              const tc = typeColors[f.key];
              return (
                <button key={f.key}
                  style={{
                    ...tasksStyles.chip,
                    display: 'inline-flex', alignItems: 'center', gap: 5,
                    ...(active && tc ? { background: tc.bg, color: tc.color, borderColor: 'transparent' } : {}),
                    ...(active && !tc ? tasksStyles.chipActive : {}),
                  }}
                  onClick={() => { setFilter(f.key); if (f.key !== 'projects') setOpenProjectId(null); }}
                >
                  {FIcon && <FIcon size={12} />}{f.label}
                </button>
              );
            })}
          </div>
          {filter !== 'projects' && (
            <div style={tasksStyles.viewToggle}>
              {[{k:'list',l:'لیست'},{k:'kanban',l:'کانبان'},{k:'week',l:'هفته'},{k:'month',l:'ماه'}].map(v => (
                <button key={v.k}
                  style={{ ...tasksStyles.viewBtn, ...(viewMode === v.k ? tasksStyles.viewBtnOn : {}) }}
                  onClick={() => { setViewMode(v.k); setCalOffset(0); }}
                >{v.l}</button>
              ))}
            </div>
          )}
        </div>

        {gamify && filter !== 'cancelled' && filter !== 'projects' && (
          <div className="sb-gamify-card sb-animated-card" style={{
            background: 'var(--surface-glass)', border: '1px solid var(--c-border-xs)', borderRadius: 16,
            boxShadow: 'var(--shadow-lift), var(--shadow-press)', padding: '13px 14px', margin: '6px 0 14px',
            display: 'grid', gap: 10,
            backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{
                width: 36, height: 36, borderRadius: 10, background: 'var(--firoozeh-soft)',
                color: 'var(--firoozeh-deep)', display: 'grid', placeItems: 'center', flexShrink: 0,
              }}>
                <Icons.CheckCircle size={18} />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 10 }}>
                  <span style={{ font: "600 13.5px 'Estedad', sans-serif", color: 'var(--ink)' }}>بردهای امروز</span>
                  <span style={{ font: "500 11px 'Estedad', sans-serif", color: 'var(--ink-3)', whiteSpace: 'nowrap' }}>
                    سطح {_jn(gamify.level)} · {_jn(gamify.xp)} XP
                  </span>
                </div>
                <div className="sb-progress-track" style={{ height: 7, borderRadius: 999, background: 'var(--paper-2)', overflow: 'hidden', marginTop: 7 }}>
                  <div className="sb-progress-bar" style={{ height: '100%', width: `${todayPct}%`, borderRadius: 999, background: 'var(--moss)', transition: 'width 300ms ease' }} />
                </div>
              </div>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
              <span style={{ font: "500 12px 'Estedad', sans-serif", color: 'var(--ink-2)' }}>
                {_jn(todayWins)} از {_jn(todayTarget)} کار امروز انجام شده
              </span>
              <span className={activeStreak ? 'sb-streak-chip' : ''} style={{ font: "500 12px 'Estedad', sans-serif", color: activeStreak ? 'var(--saffron)' : 'var(--ink-3)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                <Icons.Flame size={13} /> {activeStreak ? `${_jn(activeStreak)} روز پیوسته` : 'شروع زنجیره امروز'}
              </span>
            </div>
          </div>
        )}

        {filter === 'cancelled' && (
          <>
            {filtered.length === 0 ? (
              <div style={tasksStyles.empty}>
                <div style={{ fontSize: 36, marginBottom: 10 }}>✓</div>
                <div>تسک لغو شده‌ای وجود ندارد</div>
              </div>
            ) : (
              <>
                <div className="sb-animated-card" style={tasksStyles.card}>
                  {filtered.map((t, i) => (
                    <div key={t.id} style={{ ...tasksStyles.row, ...(i > 0 ? tasksStyles.rowDivided : {}), display: 'flex', alignItems: 'center', gap: 10 }}>
                      <div style={{ flex: 1, opacity: 0.55 }}>
                        <div style={{ font: "400 15px/1.5 'Estedad', sans-serif", color: 'var(--ink)', textDecoration: 'line-through' }}>{t.title}</div>
                        {t.dueDate && <div style={{ font: "400 12px 'Estedad', sans-serif", color: 'var(--ink-3)', marginTop: 2 }}>{t.dueDate}</div>}
                      </div>
                      <button
                        style={{ flex: 'none', padding: '6px 12px', borderRadius: 999, border: '1px solid var(--firoozeh)', background: 'transparent', color: 'var(--firoozeh)', font: "500 13px 'Estedad', sans-serif", cursor: 'pointer' }}
                        onClick={() => onUpdate(t.id, { status: 'pending', done: false })}
                      >بازگردانی</button>
                      <button
                        style={{ flex: 'none', width: 32, height: 32, borderRadius: 999, border: 'none', background: 'var(--paper-2)', color: 'var(--ink-3)', cursor: 'pointer', display: 'grid', placeItems: 'center' }}
                        onClick={() => window.confirmAction('این تسک حذف شود؟', () => onDelete(t.id))}
                      ><Icons.Trash size={14} /></button>
                    </div>
                  ))}
                </div>
                <button
                  style={{ ...tasksStyles.deleteBtn, marginTop: 16 }}
                  onClick={() => window.confirmAction(`${String(filtered.length).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d])} تسک لغو شده حذف شوند؟`, () => filtered.forEach(t => onDelete(t.id)))}
                >
                  <Icons.Trash size={16} /> حذف همه لغو شده‌ها
                </button>
              </>
            )}
          </>
        )}
        {filter === 'projects' && (
          <ProjectGallery projects={projects} tasks={tasks}
            onOpen={id => setOpenProjectId(id)}
            onAdd={onAddProject}
          />
        )}
        {filter !== 'projects' && filter !== 'cancelled' && viewMode === 'kanban' && (
          <KanbanView tasks={filtered} onUpdate={onUpdate} onOpenTask={setDetail} />
        )}
        {filter !== 'projects' && filter !== 'cancelled' && viewMode === 'week' && (
          <WeekView tasks={tasks} weekOffset={calOffset} onWeekChange={setCalOffset} onToggle={onToggle} onOpenTask={setDetail} />
        )}
        {filter !== 'projects' && filter !== 'cancelled' && viewMode === 'month' && (
          <MonthView tasks={tasks} monthOffset={calOffset} onMonthChange={setCalOffset} onToggle={onToggle} onOpenTask={setDetail} />
        )}
        {filter !== 'projects' && filter !== 'cancelled' && viewMode === 'list' && (<>
          {/* Task groups by exact date */}
          {sortedDateKeys.map(key => {
            const items = dateGroupMap.get(key);
            return (
              <div key={key} style={tasksStyles.section}>
                <div style={tasksStyles.sectionHead}>
                  <div style={tasksStyles.sectionTitle}>{getDueLabel(key)}</div>
                  {getDueMeta(key) && <div style={tasksStyles.sectionMeta}>{getDueMeta(key)}</div>}
                </div>
                <div className="sb-animated-card" style={tasksStyles.card}>
                  {items.map((t, i) => (
                    <div key={t.id} id={'task-item-' + t.id} style={highlightId === t.id ? { background: 'var(--firoozeh-soft)', borderRadius: 12, transition: 'background 0.5s' } : {}}>
                      <TaskRow task={t} isLast={i === items.length - 1} onToggle={onToggle} onOpen={setDetail} />
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
          {doneItems.length > 0 && (
            <div style={tasksStyles.section}>
              <div style={tasksStyles.sectionHead}>
                <div style={tasksStyles.sectionTitle}>انجام‌شده</div>
              </div>
              <div className="sb-animated-card" style={tasksStyles.card}>
                {doneItems.map((t, i) => (
                  <div key={t.id} id={'task-item-' + t.id} style={highlightId === t.id ? { background: 'var(--firoozeh-soft)', borderRadius: 12, transition: 'background 0.5s' } : {}}>
                    <TaskRow task={t} isLast={i === doneItems.length - 1} onToggle={onToggle} onOpen={setDetail} />
                  </div>
                ))}
              </div>
            </div>
          )}
          {filtered.length === 0 && (
            <div style={tasksStyles.empty}>
              <div style={{ fontSize: 36, marginBottom: 10 }}>✓</div>
              <div>تسکی پیدا نشد</div>
              <div style={{ fontSize: 12, marginTop: 6, color: 'var(--ink-4)' }}>از دکمه زیر یک تسک اضافه کن</div>
            </div>
          )}
        </>)}

        {/* Add task button */}
        <button style={tasksStyles.addBtn} onClick={() => setAddOpen(true)}>
          <Icons.Plus size={18} />
          تسک جدید
        </button>
      </div>

      {addOpen && (
        <AddTaskSheet onClose={() => setAddOpen(false)} onAdd={onAdd} projects={projects} />
      )}

      {/* R03 — Sort sheet */}
      {sortOpen && (
        <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.45)', backdropFilter:'blur(4px)', WebkitBackdropFilter:'blur(4px)', zIndex:300, display:'flex', alignItems:'flex-end', justifyContent:'center', direction:'rtl' }}
          onClick={onSortClose}>
          <div style={{ width:'100%', maxWidth:600, background:'var(--paper)', borderRadius:'22px 22px 0 0', padding:'0 20px calc(28px + env(safe-area-inset-bottom))', boxShadow:'0 -8px 32px rgba(0,0,0,0.18)' }}
            onClick={e => e.stopPropagation()}>
            <div style={{ width:36, height:4, borderRadius:999, background:'var(--c-inactive)', margin:'12px auto 20px' }} />
            <div style={{ font:"600 16px 'Estedad', sans-serif", color:'var(--ink)', marginBottom:18 }}>مرتب‌سازی</div>
            {[['date','بر اساس سررسید'],['priority','بر اساس اولویت'],['created','بر اساس تاریخ ایجاد']].map(([k,l]) => (
              <button key={k}
                style={{ display:'flex', alignItems:'center', justifyContent:'space-between', width:'100%', padding:'14px 0', background:'none', border:'none', borderBottom:'1px solid var(--c-border-xs)', cursor:'pointer', direction:'rtl', font:"500 15px 'Estedad', sans-serif", color:'var(--ink)' }}
                onClick={() => { setSortBy(k); onSortClose?.(); }}>
                {l}
                {sortBy === k && <span style={{ width:18, height:18, borderRadius:'50%', background:'var(--firoozeh)', display:'grid', placeItems:'center' }}><Icons.CheckCircle size={12} style={{ color:'#fff' }} /></span>}
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

window._calcNextRecurrence = _calcNextRecurrence;
window.Tasks = Tasks;
