/* Dump — tasks.jsx: the task board + Not now shelf */

function isActiveTask(t) { return !t.done && (!t.status || t.status === 'active'); }
window.isActiveTask = isActiveTask;

function QuickChip({ minutes }) {
  if (!minutes || minutes > 10 || minutes <= 2) return null;
  return <span className="est-chip neutral">{Icons.bolt(11)} ~{minutes} min</span>;
}

function childNameFor(id) {
  if (!id) return null;
  const children = (DumpStore.getState().settings.children) || [];
  const c = children.find((x) => x.id === id);
  return c ? c.name : null;
}
function ChildChip({ childId }) {
  const name = childNameFor(childId);
  if (!name) return null;
  return <span className="child-tag" title="This task is for this child">{name}</span>;
}
/* A prerequisite card shows what it unblocks — the context lives in the data
   (other tasks' blockedBy points here), so this is derived, never invented. */
function UnblocksChip({ task }) {
  const blocked = DumpStore.getState().tasks.filter((t) => t.blockedBy === task.id);
  if (!blocked.length) return null;
  const label = blocked.length === 1 ? blocked[0].text : (blocked.length + ' waiting tasks');
  return <span className="unblocks-chip" title={'Finishing this frees: ' + blocked.map((t) => t.text).join(' · ')}>unblocks: {label}</span>;
}
function OriginChip({ task }) {
  const [open, setOpen] = useState(false);
  const o = task.origin;
  if (!o || o.kind === 'dump') return null;
  const kindLabel = { letter: 'letter', file: 'file', gmail: 'email', slack: 'Slack', whatsapp: 'WhatsApp' }[o.kind] || o.kind;
  const label = o.label || (kindLabel.charAt(0).toUpperCase() + kindLabel.slice(1));
  const related = (DumpStore.getState().tasks || []).filter((t) => t.origin && o.ref && t.origin.ref === o.ref && t.id !== task.id && !t.done);
  return (
    <span className="src-wrap">
      <button className={'src-chip' + (open ? ' open' : '')} onClick={() => setOpen((v) => !v)} title={'From this ' + kindLabel}>
        {Icons.file(11)} {label}{related.length ? ' \u00b7 ' + (related.length + 1) : ''}
      </button>
      {open ? (
        <div className="src-related">
          <p className="src-related-head">{related.length ? 'From this ' + kindLabel + ':' : 'Only task from this ' + kindLabel + '.'}</p>
          {related.length ? (
            <ul>
              <li className="cur">{task.text}</li>
              {related.map((t) => <li key={t.id}>{t.text}</li>)}
            </ul>
          ) : null}
        </div>
      ) : null}
    </span>
  );
}

function TaskCard({ task, isFocus }) {
  const state = useDumpStore();
  const [leaving, setLeaving] = useState(false);
  const [editing, setEditing] = useState(false);
  const [datePick, setDatePick] = useState(false);
  const [notNow, setNotNow] = useState(false);
  const [waitWho, setWaitWho] = useState('');
  const [breaking, setBreaking] = useState(false);
  const [draft, setDraft] = useState(null);
  const [focusNudge, setFocusNudge] = useState(false);
  const [showDone, setShowDone] = useState(false);
  const [showUp, setShowUp] = useState(false);
  const [editStepId, setEditStepId] = useState(null);
  const [stepEditDraft, setStepEditDraft] = useState('');
  const [editOutcome, setEditOutcome] = useState(false);
  const [outcomeDraft, setOutcomeDraft] = useState('');
  const [suggesting, setSuggesting] = useState(false);
  const [suggestion, setSuggestion] = useState(null);
  const [stepDraft, setStepDraft] = useState('');
  const [planConfirm, setPlanConfirm] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [recurPulse, setRecurPulse] = useState(false);
  const [showNotes, setShowNotes] = useState(false);
  const [menuUp, setMenuUp] = useState(true);
  const [prereqOpen, setPrereqOpen] = useState(false);
  const [prereqDraft, setPrereqDraft] = useState('');
  const [whoOpen, setWhoOpen] = useState(false);
  const [whoDraft, setWhoDraft] = useState('');
  const menuRef = useRef(null);
  const dx = state.settings.dx || {};
  const focusBtn = dx.focusBtn || 'coral';

  const update = (patch) => {
    DumpStore.set((s) => ({
      tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, ...patch } : t))
    }));
  };

  const complete = () => {
    // Recurring tasks regenerate in place — they don't leave the board.
    if (task.recurrence) {
      setRecurPulse(true);
      setTimeout(() => setRecurPulse(false), 720);
      DumpAPI.completeTask(task);
      return;
    }
    setLeaving(true);
    setTimeout(() => {
      DumpAPI.completeTask(task);
    }, 430);
  };

  const exitBoard = (patch, msg) => {
    setLeaving(true);
    setTimeout(() => {
      DumpStore.set((s) => ({
        tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, ...patch, fresh: false } : t)),
        focus: { ...s.focus, ids: s.focus.ids.filter((id) => id !== task.id) }
      }));
      DumpAPI.toast(msg, {
        action: {
          label: 'Undo',
          fn: () => DumpStore.set((s) => ({
            tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, status: 'active', waitingOn: null, binnedAt: null } : t))
          }))
        }
      });
    }, 430);
  };

  const toss = () => exitBoard({ status: 'binned', binnedAt: new Date().toISOString() }, 'Tossed — recoverable from the bin for 30 days.');
  const someday = () => exitBoard({ status: 'someday' }, 'Parked under Someday. No guilt.');
  const waiting = () => exitBoard({ status: 'waiting', waitingOn: waitWho.trim() || null }, 'Moved to Waiting — off your plate for now.');

  // Manual prerequisite: user states a thing they need first. Creates a real
  // "Buy X" task on the board and drops THIS task into Waiting behind it —
  // the same blockedBy stack as an imported or clarified dependency.
  // Optional context: who / what a task is for. Never asked — offered as a chip.
  // Matches a child by name (tags them); otherwise stored as a free "for …" note.
  const setWhoFor = () => {
    const v = whoDraft.trim();
    if (!v) { setWhoOpen(false); setWhoDraft(''); return; }
    const kids = (DumpStore.getState().settings.children) || [];
    const match = kids.find((c) => c.name && c.name.toLowerCase() === v.toLowerCase());
    if (match) update({ childId: match.id, forWhom: null });
    else update({ forWhom: v });
    setWhoOpen(false); setWhoDraft('');
    DumpAPI.toast(match ? ('Tagged for ' + match.name + '.') : ('Marked “for ' + v + '”.'));
  };

  const addPrereqStep = () => {
    let label = prereqDraft.trim().replace(/[.!]+$/, '');
    if (!label) return;
    // "need to X" / "I need to X" → X. The prefix itself PROVES X is an action —
    // whatever follows must never get "Buy " bolted on.
    const hadActionPrefix = /^(i\s+)?(need to|have to|got to|gotta|must|should|remember to|want to)\s+/i.test(label);
    label = label.replace(/^(i\s+)?(need to|have to|got to|gotta|must|should|remember to|want to)\s+/i, '');
    const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
    const wordCount = label.split(/\s+/).length;
    // A thing is a bare noun phrase: short, no verb lead, no action prefix, and no
    // connecting words ("talk TO friend", "chat WITH mum" are actions, not things).
    const thingShaped = !hadActionPrefix && wordCount <= 4 && !/\b(to|with|for|about|at)\b/i.test(label);
    let preTitle;
    let aiTidy = false;
    if (DumpAPI.startsWithVerb(label)) {
      preTitle = cap(label);          // user led with a verb — their words, verbatim
    } else if (thingShaped) {
      preTitle = 'Buy ' + label;      // "flour", "blue paint" — the designed case
    } else {
      preTitle = cap(label);          // action-shaped or unclassifiable — keep, never mangle
      aiTidy = true;                  // …but let AI tidy it quietly if available
    }
    const preId = DumpUtil.uid();
    const prevBucket = task.bucket || 'next-action';
    DumpStore.set((s) => ({
      tasks: s.tasks.map((t) => (t.id === task.id
        ? { ...t, status: 'waiting', bucket: 'waiting-for', waitingOn: 'After: ' + preTitle, blockedBy: preId, fresh: false }
        : t)).concat([{
          id: preId, text: preTitle, category: task.category || null,
          level: task.level === 'high' ? 'high' : 'normal', priority: !!task.priority,
          notes: '', done: false, doneAt: null, dueDate: task.dueDate || null, minutes: null, big: false,
          status: 'active', bucket: 'next-action', waitingOn: null, binnedAt: null, steps: null,
          outcome: null, recurrence: null, childId: task.childId || null, origin: task.origin || null,
          blockedBy: null, clarifyKind: null, clarifyAsk: null, clarify: false, source: 'prereq',
          createdAt: new Date().toISOString(), fresh: true, parentTaskId: null
        }]),
      focus: { ...s.focus, ids: s.focus.ids.filter((id) => id !== task.id) }
    }));
    setPrereqOpen(false); setPrereqDraft('');
    // #4 + context-fold: quiet AI title rewrite. For unclassifiable entries it
    // adds a leading verb; for ALL entries it folds in the parent task's context
    // ("Talk to friend" → "Talk to friend about food for the hike"). The user's
    // own verb and words are always kept — only the missing referent is added.
    if (DumpAPI.aiOn()) {
      DumpAPI.runAI(
        'refine',
        { parentText: task.text, aiTidy: aiTidy },
        preTitle, 100
      ).then((reply) => {
        const tidy = String(reply || '').trim().replace(/^["\u201c]|["\u201d]$/g, '');
        if (!tidy || tidy.toLowerCase() === preTitle.toLowerCase()) return;
        DumpStore.set((s) => ({
          tasks: s.tasks.map((t) => {
            if (t.id === preId && t.text === preTitle) return { ...t, text: cap(tidy) };
            if (t.id === task.id && t.blockedBy === preId) return { ...t, waitingOn: 'After: ' + cap(tidy) };
            return t;
          })
        }));
      }).catch(() => {}); // silent — the un-tidied title is already fine
    }
    DumpAPI.toast('Added “' + preTitle + '” first — “' + task.text + '” is waiting on it.', {
      action: { label: 'Undo', fn: () => DumpStore.set((s) => ({
        tasks: s.tasks.filter((t) => t.id !== preId).map((t) => (t.id === task.id ? { ...t, status: 'active', bucket: prevBucket, waitingOn: null, blockedBy: null } : t))
      })) }
    });
  };

  const toggleFocus = () => {
    const s = DumpStore.getState();
    const ids = s.focus.ids.slice();
    const i = ids.indexOf(task.id);
    if (i !== -1) {
      ids.splice(i, 1);
    } else {
      ids.push(task.id);
      if (ids.length > 3) {
        DumpAPI.toast('That’s ' + ids.length + ' for today — realistic? You can take one off on the Today screen.');
      }
    }
    DumpStore.set({ focus: { ...s.focus, date: DumpUtil.todayISO(), ids } });
  };

  const steps = task.steps || [];
  const incompleteSteps = steps.filter((s) => !s.done);
  const doneSteps = steps.filter((s) => s.done);
  const nextStep = incompleteSteps[0] || null;

  const toggleStep = (id) => update({ steps: steps.map((s) => (s.id === id ? { ...s, done: !s.done } : s)) });
  const addStep = (text) => {
    const v = (text || '').trim();
    if (!v) return;
    update({ steps: steps.concat([{ id: DumpUtil.uid(), text: v, done: false, minutes: null }]) });
  };
  const startEditStep = (s) => { setEditStepId(s.id); setStepEditDraft(s.text); };
  const saveStepEdit = () => {
    if (editStepId == null) return;
    const v = stepEditDraft.trim();
    if (v) update({ steps: steps.map((s) => (s.id === editStepId ? { ...s, text: v } : s)) });
    setEditStepId(null);
  };
  const deleteStep = (id) => {
    setEditStepId(null);
    const prev = steps;
    update({ steps: steps.filter((s) => s.id !== id) });
    DumpAPI.toast('Step deleted', { action: { label: 'Undo', fn: () => update({ steps: prev }) } });
  };
  const saveOutcome = () => { update({ outcome: outcomeDraft.trim() || null }); setEditOutcome(false); };
  const whatsNext = async () => {
    if (!DumpAPI.aiOn()) { setSuggestion({ needAI: true }); return; }
    setSuggesting(true); setSuggestion(null);
    try {
      const sug = await DumpAPI.suggestNextAction(task);
      setSuggestion(sug ? { text: sug } : { needAI: true });
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Could not suggest a step — try again.');
    } finally { setSuggesting(false); }
  };
  const acceptSuggestion = () => { if (suggestion && suggestion.text) addStep(suggestion.text); setSuggestion(null); };
  const suggestIntoInput = async () => {
    if (!DumpAPI.aiOn()) return;
    setSuggesting(true);
    try {
      const sug = await DumpAPI.suggestNextAction(task);
      if (sug) setStepDraft(sug);
      else DumpAPI.toast('No suggestion this time — type the next step yourself.');
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Could not suggest a step — try again.');
    } finally { setSuggesting(false); }
  };
  const planItAll = async () => {
    setPlanConfirm(false);
    setBreaking(true);
    try {
      await DumpAPI.breakDownTask(task);
    } catch (e) {
      DumpAPI.toast(e.friendly ? e.message : 'Something went wrong — try again.',
        e.parse ? { retry: planItAll } : undefined);
    } finally {
      setBreaking(false);
    }
  };

  const startEdit = () => {
    setDraft({ text: task.text, level: task.level, category: task.category || '', minutes: task.minutes || null, notes: task.notes || '', dueDate: task.dueDate || '' });
    setEditing(true);
    setDatePick(false);
    setNotNow(false);
  };
  const saveEdit = () => {
    if (!draft.text.trim()) { DumpAPI.toast("A task needs some words — or just complete it."); return; }
    update({
      text: draft.text.trim(),
      level: draft.level,
      priority: draft.level === 'high',
      category: draft.category || null,
      minutes: draft.minutes || null,
      notes: draft.notes,
      dueDate: draft.dueDate || null
    });
    setEditing(false);
  };

  useEffect(() => {
    const onEsc = (e) => {
      if (e.key === 'Escape') { setEditing(false); setNotNow(false); setDatePick(false); setMenuOpen(false); }
    };
    const onDoc = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false); };
    if (editing || notNow || datePick || menuOpen) {
      document.addEventListener('keydown', onEsc);
      if (menuOpen) document.addEventListener('mousedown', onDoc);
      return () => { document.removeEventListener('keydown', onEsc); document.removeEventListener('mousedown', onDoc); };
    }
  }, [editing, notNow, datePick, menuOpen]);

  const overdue = task.dueDate && task.dueDate < DumpUtil.todayISO();
  const googleOn = state.google.connected;
  const pomo = state.pomodoro;

  const handleFocus = () => {
    // Too-quick nudge: small, single-step tasks rarely need a timer.
    if (task.minutes && task.minutes <= 10 && !task.big) { setFocusNudge(true); return; }
    // Already on a break? Warn before starting a fresh session.
    if (pomo.status === 'break' || pomo.status === 'longbreak') { setFocusNudge('break'); return; }
    DumpAPI.startPomodoro(task.id);
  };
  const startAnyway = () => { setFocusNudge(false); DumpAPI.startPomodoro(task.id); };

  const addToCalendar = async () => {
    if (window.GoogleHelper) {
      await window.GoogleHelper.addTaskEvent(task);
    }
  };

  return (
    <div className={'task-card' + (task.priority ? ' high' : '') + (leaving ? ' leaving' : '') + (task.fresh ? ' entering' : '') + (menuOpen ? ' menu-open' : '') + (recurPulse ? ' recurred' : '')}>
      <button
        className={'task-check task-check-lg' + (leaving ? ' checked' : '')}
        onClick={complete}
        aria-label="Complete task"
        style={{ position: 'absolute', top: 14, left: 14 }}
      >
        {Icons.check(15)}
      </button>
      <div className="task-row" style={{ paddingLeft: 46 }}>
        <div className="task-body">
          <p className="task-text">{task.priority ? <span className="flag-mark" title="High priority">{Icons.flag(13)}</span> : null}{task.text}</p>
          {(task.big || steps.length) ? (
            <div className="project-block">
              {task.big ? (
                editOutcome ? (
                  <div className="outcome-edit">
                    <input type="text" autoFocus value={outcomeDraft} placeholder="Project is done when…"
                      onChange={(e) => setOutcomeDraft(e.target.value)}
                      onKeyDown={(e) => { if (e.key === 'Enter') saveOutcome(); if (e.key === 'Escape') setEditOutcome(false); }} />
                    <button className="btn btn-primary btn-sm" onClick={saveOutcome}>Save</button>
                    <button className="btn btn-ghost btn-sm" onClick={() => setEditOutcome(false)}>Cancel</button>
                  </div>
                ) : task.outcome ? (
                  <p className="project-outcome" onClick={() => { setOutcomeDraft(task.outcome); setEditOutcome(true); }} title="Edit outcome">{task.outcome}</p>
                ) : (
                  <button className="linklike outcome-prompt" onClick={() => { setOutcomeDraft(''); setEditOutcome(true); }}>+ What does done look like?</button>
                )
              ) : null}

              {nextStep ? (
                <div className="project-now">
                  <button className="step-check" onClick={() => toggleStep(nextStep.id)} aria-label="Mark step done">{Icons.check(12)}</button>
                  <span className="now-label">Now</span>
                  {editStepId === nextStep.id ? (
                    <input type="text" autoFocus className="step-input step-edit-input" value={stepEditDraft}
                      onChange={(e) => setStepEditDraft(e.target.value)}
                      onBlur={saveStepEdit}
                      onKeyDown={(e) => { if (e.key === 'Enter') saveStepEdit(); if (e.key === 'Escape') setEditStepId(null); }} />
                  ) : (
                    <span className="now-text" onClick={() => startEditStep(nextStep)} title="Click to edit">{nextStep.text}</span>
                  )}
                  {editStepId === nextStep.id ? null : (
                    <button className="step-del" onClick={() => deleteStep(nextStep.id)} aria-label="Delete step" title="Delete step">×</button>
                  )}
                </div>
              ) : steps.length ? (
                <div className="project-now done-all">
                  <span className="now-text">All steps done — complete the project when you’re ready.</span>
                </div>
              ) : (
                <div className="next-step-row">
                  <input type="text" className="step-input" value={stepDraft} placeholder="What’s the next step?"
                    onChange={(e) => setStepDraft(e.target.value)}
                    onKeyDown={(e) => { if (e.key === 'Enter') { addStep(stepDraft); setStepDraft(''); } if (e.key === 'Escape') setStepDraft(''); }} />
                  {DumpAPI.aiOn() ? (
                    <button className="ai-suggest" onClick={suggestIntoInput} disabled={suggesting}
                      aria-label="Suggest the next step with AI" title="Suggest the next step">
                      {suggesting ? <span className="spinner dark"></span> : Icons.sparkle(16)}
                    </button>
                  ) : (
                    <Tooltip text="Connect AI in Settings to suggest steps">
                      <span className="ai-suggest off" aria-label="AI suggestions — connect AI in Settings" tabIndex={0}>{Icons.sparkle(16)}</span>
                    </Tooltip>
                  )}
                </div>
              )}

              {nextStep ? (
                <div className="next-step-row add-more-step">
                  <input type="text" className="step-input" value={stepDraft} placeholder="＋ Add another step"
                    onChange={(e) => setStepDraft(e.target.value)}
                    onKeyDown={(e) => { if (e.key === 'Enter' && stepDraft.trim()) { addStep(stepDraft); setStepDraft(''); } if (e.key === 'Escape') setStepDraft(''); }} />
                </div>
              ) : null}

              {incompleteSteps.length > 1 ? (
                <div className="project-upcoming">
                  <button className={'linklike steps-toggle' + (showUp ? ' open' : '')} onClick={() => setShowUp((c) => !c)}>
                    <span className="tw-chev">{Icons.chevR(13)}</span> {incompleteSteps.length - 1} more step{incompleteSteps.length - 1 === 1 ? '' : 's'}
                  </button>
                  {showUp ? (
                    <ul className="step-upcoming">
                      {incompleteSteps.slice(1).map((s) => (
                        <li key={s.id}>
                          <button className="step-check sm" onClick={() => toggleStep(s.id)} aria-label="Mark step done">{Icons.check(11)}</button>
                          {editStepId === s.id ? (
                            <input type="text" autoFocus className="step-input step-edit-input" value={stepEditDraft}
                              onChange={(e) => setStepEditDraft(e.target.value)}
                              onBlur={saveStepEdit}
                              onKeyDown={(e) => { if (e.key === 'Enter') saveStepEdit(); if (e.key === 'Escape') setEditStepId(null); }} />
                          ) : (
                            <span className="up-text" onClick={() => startEditStep(s)} title="Click to edit">{s.text}{s.minutes ? <span className="step-min">~{s.minutes} min</span> : null}</span>
                          )}
                          {editStepId === s.id ? null : (
                            <button className="step-del" onClick={() => deleteStep(s.id)} aria-label="Delete step" title="Delete step">×</button>
                          )}
                        </li>
                      ))}
                    </ul>
                  ) : null}
                </div>
              ) : null}

              {planConfirm ? (
                <div className="plan-caveat">
                  <p>Best for projects where the steps are predictable. For uncertain ones, “What’s next?” works better.</p>
                  <div className="suggest-actions">
                    <button className="btn btn-primary btn-sm" onClick={planItAll} disabled={breaking}>{breaking ? 'Generating…' : 'Generate plan'}</button>
                    <button className="btn btn-ghost btn-sm" onClick={() => setPlanConfirm(false)}>Cancel</button>
                  </div>
                </div>
              ) : null}

              {doneSteps.length ? (
                <div className="project-done">
                  <button className={'linklike steps-toggle' + (showDone ? ' open' : '')} onClick={() => setShowDone((c) => !c)}>
                    <span className="tw-chev">{Icons.chevR(13)}</span> {doneSteps.length} step{doneSteps.length === 1 ? '' : 's'} done
                  </button>
                  {showDone ? (
                    <ul className="step-done-list">
                      {doneSteps.map((s) => (
                        <li key={s.id}>
                          <button className="step-check sm checked" onClick={() => toggleStep(s.id)} aria-label="Mark not done">{Icons.check(11)}</button>
                          <span className="done-text">{s.text}</span>
                        </li>
                      ))}
                    </ul>
                  ) : null}
                </div>
              ) : null}
            </div>
          ) : null}
          <div className="meta-row meta-primary">
            {task.dueDate ? (              <button className={'due-chip due-chip-btn' + (overdue ? ' overdue' : '')}
                onClick={() => { setDatePick((v) => !v); setEditing(false); setNotNow(false); setMenuOpen(false); }}
                title="Change date">
                {Icons.calendar(12)} {DumpUtil.dueLabel(task.dueDate)}
              </button>
            ) : null}
            {task.recurrence ? (
              <span className="recur-badge" title={DumpUtil.recurrenceLabel(task.recurrence)}>
                {Icons.repeat(11)} {DumpUtil.recurrenceShort(task.recurrence)}
              </span>
            ) : null}
          </div>
          <div className="meta-row meta-ref">
            <CatPill name={task.category} />
            <ChildChip childId={task.childId} />
            {task.forWhom ? <span className="child-tag for-tag" title="Who or what this is for">for {task.forWhom}</span> : null}
            {task.needsSorting ? (
              <button className="needs-sorting-tag" title="Reopen the quick question"
                onClick={() => DumpStore.set((s) => ({ tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, bucket: 'inbox', needsSorting: false, clarifyKind: t.clarifyKind || 'vague' } : t)), route: 'clarify' }))}>
                Needs sorting ›
              </button>
            ) : (task.bucket === 'inbox' || task.clarify || task.clarifyKind) ? (
              <button className="needs-sorting-tag" title="Answer one quick question in Clarify"
                onClick={() => DumpStore.set({ route: 'clarify' })}>
                Needs a question ›
              </button>
            ) : null}
            {task.big && !task.steps ? <span className="big-chip">Project →</span> : null}
            <UnblocksChip task={task} />
            {task.source !== 'dump' && task.source !== 'manual' && (!task.origin || task.origin.kind === 'dump') ? <span className="src-tag">via {task.source}</span> : null}
            <OriginChip task={task} />
            {task.notes ? (
              <button className={'notes-toggle icon-only' + (showNotes ? ' open' : '')} onClick={() => setShowNotes((c) => !c)} aria-expanded={showNotes} aria-label="Notes" title="Notes">
                {Icons.note(17)}
              </button>
            ) : null}
          </div>
          {task.notes && showNotes ? <p className="notes-body">{task.notes}</p> : null}
        </div>
      </div>

      <button className={'today-toggle' + (isFocus ? ' on' : '')} onClick={toggleFocus}
        aria-label={isFocus ? 'Take off today' : 'Add to today'}
        title={isFocus ? 'On your Today list — tap to take it off' : 'Add to your Today list — aim for about 3'}>
        {isFocus ? Icons.check(12) : Icons.plus(12)}
        <span>{isFocus ? 'On today' : 'Today'}</span>
      </button>

      {editing ? (
        <div className="edit-panel">
          <input type="text" value={draft.text} autoFocus={true}
            onChange={(e) => setDraft({ ...draft, text: e.target.value })} />
          <div className="edit-row">
            <label>Priority</label>
            <button type="button" role="switch" aria-checked={draft.level === 'high'} aria-label="High priority"
              className={'switch' + (draft.level === 'high' ? ' on' : '')}
              onClick={() => setDraft({ ...draft, level: draft.level === 'high' ? 'normal' : 'high' })}></button>
            <span className="switch-cap">High priority</span>
          </div>
          <div className="edit-row">
            <label>Category</label>
            <select className="edit-select" value={draft.category || ''}
              onChange={(e) => setDraft({ ...draft, category: e.target.value })}
              style={{ flex: '0 1 190px' }}>
              <option value="">No category</option>
              {state.settings.categories.map((c) => <option key={c} value={c}>{c}</option>)}
            </select>
          </div>
          <div className="edit-row">
            <label>Due</label>
            <input type="date" style={{ width: 'auto', flex: '0 1 170px' }} value={draft.dueDate}
              onChange={(e) => setDraft({ ...draft, dueDate: e.target.value })} />
          </div>
          <div className="edit-row">
            <label>Quick task</label>
            <div className="seg seg-sm quick-seg">
              {[{ v: null, l: 'Off' }, { v: 2, l: '2 min' }, { v: 5, l: '5 min' }, { v: 10, l: '10 min' }].map((o) => {
                const on = o.v === null ? (!draft.minutes || draft.minutes > 10) : draft.minutes === o.v;
                return (
                  <button key={o.l} type="button" className={on ? 'active' : ''}
                    onClick={() => setDraft({ ...draft, minutes: o.v })}>{o.l}</button>
                );
              })}
            </div>
          </div>
          <p className="quick-seg-hint">2-minute tasks leave the board — do them straight from Today. 5 &amp; 10-min show as quick wins.</p>
          <textarea placeholder="Notes…" value={draft.notes}
            onChange={(e) => setDraft({ ...draft, notes: e.target.value })}></textarea>
          <div className="edit-row">
            <button className="btn btn-primary btn-sm" onClick={saveEdit}>Save</button>
            <button className="btn btn-ghost btn-sm" onClick={() => setEditing(false)}>Cancel</button>
          </div>
        </div>
      ) : datePick ? (
        <DatePickerPanel task={task} onPatch={update} onClose={() => setDatePick(false)} />
      ) : notNow ? (
        <div className="edit-panel">
          <div className="edit-row">
            <button className="btn btn-sm" onClick={someday}>{Icons.pause(14)} Someday — park it</button>
          </div>
          <div className="edit-row">
            <button className="btn btn-sm" onClick={waiting}>{Icons.hourglass(14)} Waiting</button>
            <input type="text" placeholder="on whom / what? (optional)" value={waitWho}
              style={{ flex: 1 }}
              onChange={(e) => setWaitWho(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') waiting(); }} />
          </div>
          <div className="edit-row">
            <button className="btn btn-ghost btn-sm" onClick={() => setNotNow(false)}>Cancel</button>
          </div>
        </div>
      ) : null}

      {focusNudge ? (
        <div className="edit-panel focus-nudge">
          {focusNudge === 'break' ? (
            <React.Fragment>
              <p className="nudge-text">You’re on a break — a real rest makes the next session better.</p>
              <div className="edit-row">
                <button className="btn btn-sm" onClick={startAnyway}>Start anyway</button>
                <button className="btn btn-ghost btn-sm" onClick={() => setFocusNudge(false)}>Keep resting</button>
              </div>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <p className="nudge-text">This one’s quick — you’ll probably finish before the timer. Just do it.</p>
              <div className="edit-row">
                <button className="btn btn-sm" onClick={startAnyway}>Start timer anyway</button>
                <button className="btn btn-ghost btn-sm" onClick={() => setFocusNudge(false)}>Got it — I’ll just do it</button>
              </div>
            </React.Fragment>
          )}
        </div>
      ) : null}

      <div className="card-actions">
        {whoOpen ? (
          <div className="prereq-row">
            <input type="text" className="step-input" autoFocus value={whoDraft}
              placeholder="A child, a person, or an occasion"
              onChange={(e) => setWhoDraft(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') setWhoFor(); if (e.key === 'Escape') { setWhoOpen(false); setWhoDraft(''); } }} />
            <button className="btn btn-primary" onClick={setWhoFor}>Save</button>
            <button className="btn btn-ghost" onClick={() => { setWhoOpen(false); setWhoDraft(''); }}>Cancel</button>
          </div>
        ) : prereqOpen ? (
          <div className="prereq-row">
            <input type="text" className="step-input" autoFocus value={prereqDraft}
              placeholder="What do you need first? (e.g. flour)"
              onChange={(e) => setPrereqDraft(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') addPrereqStep(); if (e.key === 'Escape') { setPrereqOpen(false); setPrereqDraft(''); } }} />
            <button className="btn btn-primary" onClick={addPrereqStep}>Add first step</button>
            <button className="btn btn-ghost" onClick={() => { setPrereqOpen(false); setPrereqDraft(''); }}>Cancel</button>
          </div>
        ) : (
        <React.Fragment>
        <QuickChip minutes={task.minutes} />
        {task.minutes && task.minutes <= 2 ? null : (
          <button className="btn btn-ghost notnow-btn" onClick={() => { setNotNow(!notNow); setEditing(false); setDatePick(false); setMenuOpen(false); setWaitWho(''); }}>{Icons.pause(14)} Later</button>
        )}
        <div className="overflow-wrap" ref={menuRef}>
          <button className="btn btn-ghost overflow-btn" aria-haspopup="true" aria-expanded={menuOpen} aria-label="More actions"
            onClick={() => { const r = menuRef.current && menuRef.current.getBoundingClientRect(); setMenuUp(r ? r.top > 280 : true); setMenuOpen((o) => !o); setEditing(false); setDatePick(false); setNotNow(false); }}>{Icons.more(16)}</button>
          {menuOpen ? (
            <div className={'overflow-menu' + (menuUp ? '' : ' down')} role="menu">
              <button role="menuitem" onClick={() => { startEdit(); setMenuOpen(false); }}>{Icons.capture(15)} Edit</button>
              <button role="menuitem" onClick={() => { setMenuOpen(false); setDatePick(true); setEditing(false); setNotNow(false); }}>{Icons.calendar(15)} {task.dueDate ? 'Change date' : 'Set date'}</button>
              <button role="menuitem" onClick={() => { setMenuOpen(false); handleFocus(); }}>{Icons.timer(15)} Focus now</button>
              <button role="menuitem" onClick={() => { setMenuOpen(false); setPrereqOpen(true); setEditing(false); setNotNow(false); setDatePick(false); }}>{Icons.pause(15)} Add a step before this</button>
              <button role="menuitem" onClick={() => { setMenuOpen(false); setWhoOpen(true); setWhoDraft(task.forWhom || ''); setEditing(false); setNotNow(false); setDatePick(false); }}>{Icons.note(15)} Who’s it for?</button>
              {task.big ? (
                <button role="menuitem" onClick={() => { setMenuOpen(false); if (!DumpAPI.aiOn()) { DumpAPI.toast('Connect AI in Settings to plan a whole project.'); DumpStore.set({ settingsOpen: true }); } else { setPlanConfirm(true); } }}>{Icons.sparkle(15)} Plan the whole project</button>
              ) : null}
              <div className="menu-sep"></div>
              <button role="menuitem" className="danger" onClick={() => { setMenuOpen(false); toss(); }}>{Icons.trash(15)} Toss</button>
            </div>
          ) : null}
        </div>
        </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ---------- Not now shelf ---------- */
function ShelfItem({ task, kind }) {
  const resume = () => {
    DumpStore.set((s) => ({
      tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, status: 'active', waitingOn: null, binnedAt: null } : t))
    }));
    DumpAPI.toast('Back on the board.');
  };
  const complete = () => {
    DumpAPI.completeTask(task);
    if (!task.recurrence) DumpAPI.toast('Done — nice.');
  };
  const toss = () => {
    DumpStore.set((s) => ({
      tasks: s.tasks.map((t) => (t.id === task.id ? { ...t, status: 'binned', binnedAt: new Date().toISOString(), waitingOn: null } : t))
    }));
  };
  const remove = () => {
    DumpStore.set((s) => ({ tasks: s.tasks.filter((t) => t.id !== task.id) }));
    DumpAPI.toast('Gone for good.');
  };

  return (
    <div className={'shelf-item' + (kind === 'binned' ? ' binned' : '')}>
      <div className="shelf-text">
        <p>{task.text}</p>
        <div className="meta-row">
          <CatPill name={task.category} />
          <ChildChip childId={task.childId} />
          {kind === 'waiting' && task.waitingOn ? (
            <span className="due-chip">{Icons.hourglass(11)} {task.waitingOn}</span>
          ) : null}
          {kind === 'binned' && task.binnedAt ? (
            <span className="src-tag">clears {DumpUtil.dueLabel((function () { const d = new Date(task.binnedAt); d.setDate(d.getDate() + 30); return d.toISOString().slice(0, 10); })())}</span>
          ) : null}
        </div>
      </div>
      <div className="shelf-actions">
        {kind === 'binned' ? (
          <React.Fragment>
            <button className="linklike" onClick={resume}>Restore</button>
            <button className="linklike danger" onClick={remove}>Delete now</button>
          </React.Fragment>
        ) : (
          <React.Fragment>
            <button className="linklike" onClick={resume}>Back on board</button>
            <button className="linklike" onClick={complete}>Done</button>
            <button className="linklike danger" onClick={toss}>Toss</button>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

function ShelfView() {
  const { tasks } = useDumpStore();
  const waiting = tasks.filter((t) => !t.done && t.status === 'waiting');
  const someday = tasks.filter((t) => !t.done && t.status === 'someday');

  if (!waiting.length && !someday.length) {
    return (
      <EmptyState icon={Icons.pause(26)} title="Nothing parked">
        "Not now" on any task sends it here — waiting on someone, or someday when you're ready.
      </EmptyState>
    );
  }

  return (
    <div>
      {waiting.length ? (
        <div className="shelf-group">
          <ContextHint id="hint-waiting" icon={Icons.hourglass(16)}>
            <strong>Waiting</strong> = blocked on someone else, not you. Parked here so it's off your mind; the weekly Sweep makes sure it doesn't rot.
          </ContextHint>
          <h2 className="done-day">{Icons.hourglass(15)} Waiting <InfoIcon text="Blocked on someone else — you can't act until they come back to you. Reviewed every weekly Sweep so nothing rots." /><span className="shelf-count">{waiting.length}</span></h2>
          <p className="shelf-hint">Out of your hands — but worth a nudge if it's been a while.</p>
          {waiting.map((t) => <ShelfItem key={t.id} task={t} kind="waiting" />)}
        </div>
      ) : null}

      {someday.length ? (
        <div className="shelf-group">
          <ContextHint id="hint-someday" icon={Icons.pause(16)}>
            <strong>Someday</strong> = not now, not never. No date, no nagging — you'll see it again in the weekly Sweep.
          </ContextHint>
          <h2 className="done-day">{Icons.pause(15)} Someday <InfoIcon text="Things you might do eventually but aren't committing to yet. Reviewed in the weekly Sweep — keep, action, or toss." /><span className="shelf-count">{someday.length}</span></h2>
          <p className="shelf-hint">Safe here. Not forgotten, not nagging.</p>
          {someday.map((t) => <ShelfItem key={t.id} task={t} kind="someday" />)}
        </div>
      ) : null}
    </div>
  );
}

/* ---------- Bin (a quiet utility area, separate from "Not now") ---------- */
function BinSection() {
  const { tasks } = useDumpStore();
  const binned = tasks.filter((t) => t.status === 'binned');

  const emptyBin = () => {
    if (!window.confirm('Empty the bin for good? ' + binned.length + ' item' + (binned.length === 1 ? '' : 's') + ' will be gone.')) return;
    DumpStore.set((s) => ({ tasks: s.tasks.filter((t) => t.status !== 'binned') }));
    DumpAPI.toast('Bin emptied.');
  };

  return (
    <div className="section" data-screen-label="Bin">
      <div className="section-head">
        <h1 className="section-title">Bin</h1>
        {binned.length ? (
          <button className="linklike danger" style={{ fontSize: 13 }} onClick={emptyBin}>Empty bin</button>
        ) : null}
      </div>
      <p className="section-sub">
        {binned.length
          ? 'Tossed items keep for 30 days, then clear themselves — recoverable until then.'
          : 'Empty. Toss a task and it lands here — kept for 30 days before clearing itself.'}
      </p>

      {binned.length ? (
        <div className="shelf-group bin-group" style={{ marginTop: 4 }}>
          {binned.map((t) => <ShelfItem key={t.id} task={t} kind="binned" />)}
        </div>
      ) : (
        <EmptyState icon={Icons.trash(26)} title="Bin is empty">
          Nothing tossed. When you toss a task, it waits here for 30 days in case you change your mind.
        </EmptyState>
      )}
    </div>
  );
}
window.BinSection = BinSection;

/* ---------- Board ---------- */
function ViewToggle({ current }) {
  const { tasks } = useDumpStore();
  const open = tasks.filter((t) => isActiveTask(t) && !t.trackDaily && !(t.minutes && t.minutes <= 2)).length;
  const parked = tasks.filter((t) => !t.done && (t.status === 'waiting' || t.status === 'someday')).length;
  const tab = (key, label, count, go) => (
    <button className={'vt-tab' + (current === key ? ' active' : '')} onClick={go}>
      {label}
      {count > 0 ? <span className={'vt-count' + (current === key ? ' on' : '')}>{count}</span> : null}
    </button>
  );
  return (
    <div className="view-tabs">
      {tab('board', 'Now', open, () => DumpStore.set({ route: 'tasks', tasksView: 'board' }))}
      {tab('shelf', 'Later', parked, () => DumpStore.set({ route: 'tasks', tasksView: 'shelf' }))}
    </div>
  );
}
window.ViewToggle = ViewToggle;

/* Categories collapsed behind a single dropdown — secondary to the GTD lenses. */
function CategoryFilter({ categories, filter, setFilter }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);
  const activeCat = categories.includes(filter) ? filter : null;
  return (
    <div className="cat-filter" ref={ref}>
      <button className={'cat-btn' + (activeCat ? ' active' : '')} onClick={() => setOpen((o) => !o)}>
        {activeCat || 'Category'}
        <svg className="cat-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"></path></svg>
      </button>
      {open ? (
        <div className="cat-menu">
          <button className={'cat-item' + (!activeCat ? ' on' : '')} onClick={() => { setFilter('All'); setOpen(false); }}>All categories</button>
          {categories.map((c) => (
            <button key={c} className={'cat-item' + (filter === c ? ' on' : '')} onClick={() => { setFilter(c); setOpen(false); }}>{c}</button>
          ))}
        </div>
      ) : null}
    </div>
  );
}
window.CategoryFilter = CategoryFilter;

function TasksSection() {
  const state = useDumpStore();
  const { tasks, settings, focus, tasksView } = state;
  const [filter, setFilter] = useState('All');
  const [overwhelmDismissed, setOverwhelmDismissed] = useState(false);
  const [filtersOpen, setFiltersOpen] = useState(false);
  const activeFilterLabel = filter === 'All' ? null : filter === '__quick' ? 'Quick' : filter === '__projects' ? 'Projects' : filter;

  const active = tasks.filter((t) => isActiveTask(t) && !t.trackDaily);
  const board = active.filter((t) => !(t.minutes && t.minutes <= 2)); // 2-min tasks live on Today, not the board
  const quickCount = board.filter((t) => t.minutes && t.minutes > 2 && t.minutes <= 10).length;
  const twoMinCount = active.filter((t) => t.minutes && t.minutes <= 2 && (!t.dueDate || t.dueDate === DumpUtil.todayISO())).length;
  const projectCount = board.filter((t) => t.big === true).length;
  const waitingCount = tasks.filter((t) => t.status === 'waiting' && !t.done).length;
  const filtered = filter === 'All' ? board
    : filter === '__quick' ? board.filter((t) => t.minutes && t.minutes > 2 && t.minutes <= 10)
    : filter === '__projects' ? board.filter((t) => t.big === true)
    : board.filter((t) => t.category === filter);

  const focusIds = focus.ids;
  const sorted = filtered.slice().sort((a, b) => {
    const fa = focusIds.includes(a.id) ? 0 : 1;
    const fb = focusIds.includes(b.id) ? 0 : 1;
    if (fa !== fb) return fa - fb;
    const pa = a.level === 'high' ? 0 : a.level === 'low' ? 2 : 1;
    const pb = b.level === 'high' ? 0 : b.level === 'low' ? 2 : 1;
    if (pa !== pb) return pa - pb;
    // dated tasks in date order (soonest first), undated after
    const da = a.dueDate || '9999-12-31';
    const db = b.dueDate || '9999-12-31';
    if (da !== db) return da.localeCompare(db);
    return (b.createdAt || '').localeCompare(a.createdAt || '');
  });

  const showOverwhelm = board.length >= 8 && focusIds.length === 0 && !overwhelmDismissed && tasksView === 'board';

  // A flag that never lands on Today is a contradiction — surface the oldest one, once per task.
  const staleCutoff = Date.now() - 3 * 864e5;
  const staleFlagTask = board
    .filter((t) => t.level === 'high' && !t.dueDate && !focusIds.includes(t.id) && !t.flagNudged
      && t.createdAt && new Date(t.createdAt).getTime() < staleCutoff)
    .sort((a, b) => (a.createdAt || '').localeCompare(b.createdAt || ''))[0] || null;
  const flagNudgeResolve = (t, patch, msg) => {
    DumpStore.set((s) => ({ tasks: s.tasks.map((x) => (x.id === t.id ? { ...x, ...patch, flagNudged: true } : x)) }));
    if (msg) DumpAPI.toast(msg);
  };
  const flagDoToday = (t) => {
    DumpStore.set((s) => ({
      tasks: s.tasks.map((x) => (x.id === t.id ? { ...x, flagNudged: true } : x)),
      focus: { ...s.focus, date: DumpUtil.todayISO(), ids: s.focus.ids.includes(t.id) ? s.focus.ids : s.focus.ids.concat([t.id]) }
    }));
    DumpAPI.toast('On today.');
  };
  const flagTomorrow = (t) => {
    const d = new Date(Date.now() + 864e5);
    const iso = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
    flagNudgeResolve(t, { dueDate: iso }, 'Dated for tomorrow — it’ll be on the calendar.');
  };

  return (
    <div className="section" data-screen-label="Tasks">
      <div className="section-head">
        <h1 className="section-title">{tasksView === 'shelf' ? 'Later' : 'Tasks'}</h1>
      </div>
      <p className="section-sub">
        {tasksView === 'shelf'
          ? 'Parked on purpose — waiting on others, or saved for someday.'
          : board.length === 0 ? 'Nothing on the board.'
          : <React.Fragment>
              {board.length} open
              <InfoIcon text="Your board holds next actions — single things you can do right now — and projects, each showing its next step. Waiting and Someday live under 'Not now'." />
              {' · sorted so the important stuff is on top.'}
            </React.Fragment>}
      </p>

      <div className="board-controls">
        <ViewToggle current={tasksView === 'shelf' ? 'shelf' : 'board'} />
      </div>
      {tasksView !== 'shelf' ? (
        <div className="filter-bar">
          <button className={'filter-toggle' + (filtersOpen ? ' open' : '') + (activeFilterLabel && !filtersOpen ? ' has-active' : '')}
            onClick={() => setFiltersOpen((o) => !o)} aria-expanded={filtersOpen}>
            {Icons.filter(14)} Filter
          </button>
          {!filtersOpen && activeFilterLabel ? (
            <span className="filter-active-chip">
              {activeFilterLabel}
              <button className="fac-clear" onClick={() => setFilter('All')} aria-label="Clear filter">{Icons.x(12)}</button>
            </span>
          ) : null}
          {filtersOpen ? (
            <React.Fragment>
              <button className={'fpill' + (filter === 'All' ? ' active' : '')}
                onClick={() => setFilter('All')}>All</button>
              <button className={'fpill quick' + (filter === '__quick' ? ' active' : '')}
                onClick={() => setFilter(filter === '__quick' ? 'All' : '__quick')}>
                {Icons.bolt(13)} Quick <span className="fpill-range">5–10m</span>
                {quickCount > 0 ? <span className="fcount">{quickCount}</span> : null}
                <InfoIcon text="5–10 minute tasks — quick to knock out in one go. (2-minute tasks live on Today.)" />
              </button>
              <button className={'fpill' + (filter === '__projects' ? ' active' : '')}
                onClick={() => setFilter(filter === '__projects' ? 'All' : '__projects')}>
                Projects
                {projectCount > 0 ? <span className="fcount">{projectCount}</span> : null}
                <InfoIcon text="Any outcome that needs more than one step. A project without a next action is stuck — open it to break it down." />
              </button>
              <span className="filter-sep" aria-hidden="true"></span>
              <CategoryFilter categories={settings.categories} filter={filter} setFilter={setFilter} />
            </React.Fragment>
          ) : null}
        </div>
      ) : null}

      {tasksView === 'shelf' ? <ShelfView /> : (
        <React.Fragment>
          <SweepNudge />
          {twoMinCount > 0 ? (
            <button className="board-callout" onClick={() => DumpStore.set({ route: 'today' })}>
              {Icons.bolt(14)} <span>{twoMinCount + ' two-minute task' + (twoMinCount === 1 ? '' : 's') + ' — do these on Today'}</span>
              <span className="bc-go">Today →</span>
            </button>
          ) : null}
          {board.length > 0 && !showOverwhelm ? (
            <div className="star-coach">
              {Icons.flag(14)}
              <span><strong>Flag</strong> means important · <strong>＋ Today</strong> means you’ll do it today — aim for 3</span>
              <span className={'star-count' + (focusIds.length ? ' has' : '')}>{focusIds.length} on today</span>
            </div>
          ) : null}
          {staleFlagTask && !showOverwhelm ? (
            <div className="flag-nudge">
              {Icons.flag(14)}
              <span className="fn-text"><b>“{staleFlagTask.text}”</b> has been flagged for a few days but hasn’t made it onto Today.</span>
              <span className="fn-actions">
                <button className="primary" onClick={() => flagDoToday(staleFlagTask)}>Do it today</button>
                <button onClick={() => flagTomorrow(staleFlagTask)}>Tomorrow</button>
                <button onClick={() => flagNudgeResolve(staleFlagTask, { level: 'normal', priority: false }, 'Unflagged — still on your board.')}>Unflag</button>
                <button className="fn-x" aria-label="Dismiss" title="Dismiss" onClick={() => flagNudgeResolve(staleFlagTask, {}, null)}>×</button>
              </span>
            </div>
          ) : null}
          {showOverwhelm ? (
            <Banner onClose={() => setOverwhelmDismissed(true)}>
              Feeling like a lot? Tap <strong>＋ Today</strong> on about 3 that matter most — everything else can wait, or park it under Later.
            </Banner>
          ) : null}

          {sorted.length === 0 ? (
            <EmptyState icon={filter === '__quick' ? Icons.bolt(26) : Icons.tasks(26)}
              title={filter === 'All' ? 'A clear board' : filter === '__quick' ? 'No quick wins right now' : 'Nothing in ' + filter}>
              {filter === 'All'
                ? 'When your head fills up, head to Capture and offload it all.'
                : filter === '__quick'
                  ? 'Tiny tasks (5–10 minutes) get flagged automatically — knock them out between bigger things.'
                  : 'Try another filter, or offload something new.'}
            </EmptyState>
          ) : (
            <div className="task-list">
              {sorted.map((t) => (
                <TaskCard key={t.id} task={t} isFocus={focusIds.includes(t.id)} />
              ))}
            </div>
          )}
        </React.Fragment>
      )}
    </div>
  );
}

window.TasksSection = TasksSection;
window.TaskCard = TaskCard;
