// =========================================================
// DESKTOP VIEW — Today + Inbox + Processing.
// The "Tony Stark" feel: precise mono readouts, generous space,
// hairline dividers, one accent used sparingly.
// =========================================================

function HairLine({ T, style = {} }) {
  return <div style={{ height: 1, background: T.line, ...style }} />;
}

function MonoLabel({ T, children, style = {} }) {
  return (
    <div style={{
      fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
      textTransform: 'uppercase', color: T.fg3, ...style,
    }}>{children}</div>
  );
}

// ---------- System readout bar ----------
function SystemBar({ T, now, taskCount, doneCount, focus }) {
  const pct = taskCount === 0 ? 0 : Math.round((doneCount / taskCount) * 100);
  const Row = ({ k, v, mono = true }) => (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.12em', color: T.fg3, textTransform: 'uppercase' }}>{k}</span>
      <span style={{ fontFamily: mono ? 'var(--mono)' : 'var(--sans)', fontSize: 11, color: T.fg2, letterSpacing: mono ? '0.05em' : 0 }}>{v}</span>
    </div>
  );
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 28,
      padding: '14px 28px', borderBottom: `1px solid ${T.line}`,
      background: T.panel,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 8, height: 8, background: T.accent, borderRadius: 1 }} />
        <span style={{ fontFamily: 'var(--mono)', fontSize: 11, color: T.fg, letterSpacing: '0.18em' }}>OPERATOR</span>
      </div>
      <HairLine T={T} style={{ width: 1, height: 16, background: T.line }} />
      <Row k="TIME" v={fmtTime(now)} />
      <Row k="DATE" v={now.toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit' })} />
      <Row k="FOCUS" v={focus || '—'} mono={false} />
      <div style={{ flex: 1 }} />
      <Row k="PROGRESS" v={`${doneCount}/${taskCount}`} />
      <div style={{ width: 120, height: 4, background: T.line, position: 'relative' }}>
        <div style={{
          position: 'absolute', left: 0, top: 0, bottom: 0, width: `${pct}%`,
          background: T.accent,
        }} />
      </div>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 11, color: T.fg2, minWidth: 34, textAlign: 'right' }}>{pct}%</span>
    </div>
  );
}

// ---------- Capture input ----------
function CaptureBar({ T, D, placeholder, onAdd, contexts, value, setValue }) {
  const inputRef = useRef(null);
  const [ctxOpen, setCtxOpen] = useState(false);
  const [ctx, setCtx] = useState('');
  const [star, setStar] = useState(false);

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        inputRef.current?.focus();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  const submit = () => {
    if (!value.trim()) return;
    onAdd({ title: value.trim(), context: ctx, starred: star });
    setValue('');
    setCtx('');
    setStar(false);
  };

  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 12,
      padding: `${D.rowPY + 2}px ${D.rowPX + 10}px`,
      borderBottom: `1px solid ${T.line}`,
      background: T.panel,
    }}>
      <div style={{
        fontFamily: 'var(--mono)', fontSize: 13, color: T.accent,
        letterSpacing: '0.05em', userSelect: 'none',
      }}>›</div>
      <input
        ref={inputRef}
        value={value}
        onChange={(e) => setValue(e.target.value)}
        onKeyDown={(e) => { if (e.key === 'Enter') submit(); }}
        placeholder={placeholder}
        style={{
          flex: 1, border: 'none', outline: 'none', background: 'transparent',
          fontFamily: 'var(--sans)', fontSize: D.fontBase + 1, color: T.fg,
          letterSpacing: '-0.005em',
        }}
      />
      {/* star toggle */}
      <button
        onClick={() => setStar(!star)}
        title="Star"
        style={{
          border: 'none', background: 'transparent', cursor: 'pointer',
          color: star ? T.star : T.fg3, padding: 4, fontSize: 14,
        }}
      >{star ? '★' : '☆'}</button>
      {/* context selector */}
      <div style={{ position: 'relative' }}>
        <button
          onClick={() => setCtxOpen(!ctxOpen)}
          style={{
            border: `1px solid ${T.line}`, background: ctx ? T.accentSoft : 'transparent',
            color: ctx ? T.accent : T.fg3,
            fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
            padding: '5px 10px', cursor: 'pointer',
            textTransform: 'uppercase',
          }}
        >{ctx || '+ context'}</button>
        {ctxOpen && (
          <div style={{
            position: 'absolute', top: '100%', right: 0, marginTop: 4,
            background: T.panel, border: `1px solid ${T.line}`, zIndex: 10,
            minWidth: 140,
          }}>
            {['', ...CONTEXTS].map((c) => (
              <div
                key={c || 'none'}
                onClick={() => { setCtx(c); setCtxOpen(false); }}
                style={{
                  padding: '8px 12px', cursor: 'pointer',
                  fontFamily: 'var(--mono)', fontSize: 11, color: c ? T.fg2 : T.fg3,
                  letterSpacing: '0.05em',
                }}
                onMouseEnter={(e) => e.currentTarget.style.background = T.panel2}
                onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
              >{c || '— none —'}</div>
            ))}
          </div>
        )}
      </div>
      <div style={{
        fontFamily: 'var(--mono)', fontSize: 10, color: T.fg3,
        letterSpacing: '0.08em', padding: '4px 8px',
        border: `1px solid ${T.line}`,
      }}>⏎ ADD</div>
    </div>
  );
}

// ---------- Task row ----------
function TaskRow({ T, D, task, onToggle, onStar, onDelete, onEdit }) {
  const [hover, setHover] = useState(false);
  const [editing, setEditing] = useState(false);
  const [val, setVal] = useState(task.title);

  const commit = () => {
    setEditing(false);
    if (val.trim() && val !== task.title) onEdit(task.id, val.trim());
    else setVal(task.title);
  };

  return (
    <div
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        display: 'flex', alignItems: 'center', gap: 14,
        padding: `${D.rowPY}px ${D.rowPX + 10}px`,
        borderBottom: `1px solid ${T.line}`,
        background: hover ? T.panel2 : 'transparent',
        transition: 'background 0.12s',
        position: 'relative',
      }}
    >
      {/* checkbox */}
      <button
        onClick={() => onToggle(task.id)}
        style={{
          width: 16, height: 16, flexShrink: 0,
          border: `1px solid ${task.done ? T.accent : T.fg3}`,
          background: task.done ? T.accent : 'transparent',
          cursor: 'pointer', padding: 0, position: 'relative',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}
      >
        {task.done && (
          <svg width="10" height="10" viewBox="0 0 10 10">
            <path d="M1.5 5 L4 7.5 L8.5 2.5" stroke={T.panel} strokeWidth="1.6" fill="none" strokeLinecap="square" />
          </svg>
        )}
      </button>

      {/* title */}
      {editing ? (
        <input
          value={val}
          onChange={(e) => setVal(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setVal(task.title); setEditing(false); } }}
          autoFocus
          style={{
            flex: 1, border: 'none', outline: 'none', background: 'transparent',
            fontFamily: 'var(--sans)', fontSize: D.fontBase, color: T.fg,
          }}
        />
      ) : (
        <div
          onDoubleClick={() => setEditing(true)}
          style={{
            flex: 1,
            fontFamily: 'var(--sans)', fontSize: D.fontBase,
            color: task.done ? T.done : T.fg,
            textDecoration: task.done ? 'line-through' : 'none',
            textDecorationColor: T.fg3,
            letterSpacing: '-0.005em',
            cursor: 'text',
          }}
        >{task.title}</div>
      )}

      {/* star */}
      {(task.starred || hover) && (
        <button
          onClick={() => onStar(task.id)}
          style={{
            border: 'none', background: 'transparent', cursor: 'pointer',
            color: task.starred ? T.star : T.fg3, fontSize: 13, padding: 2,
          }}
        >{task.starred ? '★' : '☆'}</button>
      )}

      {/* context pill */}
      {task.context && (
        <div style={{
          fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
          color: task.done ? T.fg3 : T.fg2,
          padding: '3px 8px', border: `1px solid ${T.line}`,
          textTransform: 'lowercase', minWidth: 72, textAlign: 'center',
        }}>{task.context}</div>
      )}

      {/* delete on hover */}
      {hover && !editing && (
        <button
          onClick={() => onDelete(task.id)}
          style={{
            border: 'none', background: 'transparent', cursor: 'pointer',
            color: T.fg3, fontSize: 14, padding: 2,
            fontFamily: 'var(--mono)',
          }}
          title="Delete"
        >×</button>
      )}
    </div>
  );
}

// ---------- Inbox item ----------
function InboxItem({ T, D, item, onProcess, onDelete }) {
  const [hover, setHover] = useState(false);
  const [processing, setProcessing] = useState(false);
  const [ctx, setCtx] = useState('');

  const toTask = () => {
    if (!processing) { setProcessing(true); return; }
    onProcess(item.id, ctx);
  };

  const agoMin = Math.max(1, Math.round((Date.now() - item.created) / 60000));
  const ago = agoMin < 60 ? `${agoMin}m` : `${Math.round(agoMin/60)}h`;

  return (
    <div
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        padding: `${D.rowPY}px ${D.rowPX}px`,
        borderBottom: `1px solid ${T.line}`,
        background: hover ? T.panel2 : 'transparent',
      }}
    >
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{
          fontFamily: 'var(--mono)', fontSize: 9, color: T.fg3,
          letterSpacing: '0.1em', minWidth: 28,
        }}>{ago}</div>
        <div style={{
          flex: 1, fontFamily: 'var(--sans)', fontSize: D.fontBase - 1, color: T.fg,
          letterSpacing: '-0.005em',
        }}>{item.title}</div>
        {hover && !processing && (
          <>
            <button
              onClick={toTask}
              style={{
                border: `1px solid ${T.accent}`, background: 'transparent',
                color: T.accent, fontFamily: 'var(--mono)', fontSize: 10,
                letterSpacing: '0.08em', padding: '4px 10px', cursor: 'pointer',
              }}
            >→ TASK</button>
            <button
              onClick={() => onDelete(item.id)}
              style={{
                border: 'none', background: 'transparent',
                color: T.fg3, fontSize: 14, padding: 2, cursor: 'pointer',
                fontFamily: 'var(--mono)',
              }}
            >×</button>
          </>
        )}
      </div>
      {processing && (
        <div style={{ display: 'flex', gap: 6, marginTop: 8, flexWrap: 'wrap' }}>
          {CONTEXTS.map(c => (
            <button
              key={c}
              onClick={() => setCtx(c)}
              style={{
                border: `1px solid ${ctx === c ? T.accent : T.line}`,
                background: ctx === c ? T.accentSoft : 'transparent',
                color: ctx === c ? T.accent : T.fg2,
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
                padding: '4px 8px', cursor: 'pointer',
              }}
            >{c}</button>
          ))}
          <button
            onClick={toTask}
            style={{
              border: `1px solid ${T.accent}`, background: T.accent,
              color: T.panel, fontFamily: 'var(--mono)', fontSize: 10,
              letterSpacing: '0.1em', padding: '4px 10px', cursor: 'pointer',
              marginLeft: 'auto',
            }}
          >CONFIRM ⏎</button>
          <button
            onClick={() => { setProcessing(false); setCtx(''); }}
            style={{
              border: 'none', background: 'transparent', color: T.fg3,
              fontFamily: 'var(--mono)', fontSize: 10, cursor: 'pointer',
            }}
          >cancel</button>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { HairLine, MonoLabel, SystemBar, CaptureBar, TaskRow, InboxItem, TodayColumn, KeyboardInbox });

// ---------- TodayColumn — Now/Next/Later ----------
function TodayColumn({ T, D, now, nowTask, nextTasks, laterTasks, doneTasks, contexts, onToggle, onStar, onDelete, onEdit, onEditDescription, onSetNow, onMoveBucket, onAdd, capture, setCapture }) {
  const CTX = contexts || CONTEXTS;
  const [laterOpen, setLaterOpen] = useState(false);

  return (
    <>
      <div style={{ padding: '22px 28px 16px' }}>
        <MonoLabel T={T}>TODAY ░ {fmtDate(now).toUpperCase()}</MonoLabel>
        <div style={{
          fontFamily: 'var(--sans)', fontSize: 34, color: T.fg,
          letterSpacing: 'var(--display-tight)', marginTop: 8,
          fontWeight: 'var(--hw)', lineHeight: 1.05,
        }}>
          {nowTask ? nowTask.title : nextTasks[0] ? 'Pick a Now.' : 'Inbox zero. Ship something.'}
        </div>
        <div style={{ marginTop: 8, fontFamily: 'var(--mono)', fontSize: 10, color: T.fg3, letterSpacing: '0.1em' }}>
          {nowTask ? '◉ LOCKED ░ ' : '○ NO TARGET ░ '}
          {nextTasks.length} NEXT ░ {laterTasks.length} LATER ░ {doneTasks.length} DONE
        </div>
      </div>

      <CaptureBar
        T={T} D={D}
        value={capture} setValue={setCapture}
        placeholder="Add a task — try 'Call Sam at 3pm'"
        onAdd={(t) => onAdd({ ...t, bucket: 'next' })}
        contexts={CTX}
      />

      <div style={{ flex: 1, overflowY: 'auto' }}>
        {/* NOW bucket */}
        <div style={{ padding: '16px 28px 8px', display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
          <MonoLabel T={T}>◉ NOW</MonoLabel>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: T.fg3, letterSpacing: '0.1em' }}>SINGLE TARGET LOCK</span>
        </div>
        {nowTask ? (
          <div style={{
            margin: '0 28px 6px', padding: `${D.rowPY + 4}px ${D.rowPX + 2}px`,
            border: `1px solid ${T.accent}`, background: T.accentSoft,
            display: 'flex', alignItems: 'flex-start', gap: 14,
          }}>
            <button
              onClick={() => onToggle(nowTask.id)}
              style={{
                width: 18, height: 18, flexShrink: 0, marginTop: 4,
                border: `1px solid ${T.accent}`, background: 'transparent',
                cursor: 'pointer', padding: 0,
              }}
            />
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4 }}>
              <div style={{
                fontFamily: 'var(--sans)', fontSize: D.fontBase + 2, color: T.fg,
                letterSpacing: 'var(--tight)', fontWeight: 'var(--hw)',
              }}>{nowTask.title}</div>
              {nowTask.description && nowTask.description.trim() && (
                <div style={{
                  fontFamily: 'var(--sans)', fontSize: 13, color: T.fg2,
                  lineHeight: 1.5, whiteSpace: 'pre-wrap',
                }}>{nowTask.description}</div>
              )}
            </div>
            {nowTask.isHabit && (
              <div style={{
                fontFamily: 'var(--mono)', fontSize: 9, color: T.accent,
                letterSpacing: '0.1em', padding: '3px 8px', border: `1px solid ${T.accent}`,
              }}>HABIT · {nowTask.streak}</div>
            )}
            {nowTask.dueAt && (
              <div style={{
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.05em',
                color: T.accent, padding: '3px 8px', border: `1px solid ${T.accent}`,
              }}>⏱ {fmtDueLabel(nowTask.dueAt)}</div>
            )}
            {nowTask.context && (
              <div style={{
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
                color: T.fg2, padding: '3px 8px', border: `1px solid ${T.line}`,
              }}>{nowTask.context}</div>
            )}
            {!nowTask.isHabit && (
              <button
                onClick={() => onMoveBucket(nowTask.id, 'next')}
                style={{
                  border: 'none', background: 'transparent', color: T.fg3, cursor: 'pointer',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.1em',
                }}
              >RELEASE</button>
            )}
          </div>
        ) : (
          <div style={{
            margin: '0 28px 6px', padding: '22px 20px',
            border: `1px dashed ${T.line}`,
            textAlign: 'center', fontFamily: 'var(--mono)', fontSize: 10,
            color: T.fg3, letterSpacing: '0.14em',
          }}>
            ─── SELECT A TARGET FROM NEXT ───
          </div>
        )}

        {/* NEXT bucket — dimmed when Now is locked */}
        <div style={{
          padding: '18px 28px 6px',
          opacity: nowTask ? 0.55 : 1,
          transition: 'opacity 0.2s',
        }}>
          <MonoLabel T={T}>▸ NEXT · {nextTasks.length}</MonoLabel>
        </div>
        <div style={{ opacity: nowTask ? 0.55 : 1, transition: 'opacity 0.2s' }}>
          {nextTasks.map(t => (
            <BucketedTaskRow key={t.id} T={T} D={D} task={t} now={now}
              onToggle={onToggle} onStar={onStar} onDelete={onDelete} onEdit={onEdit}
              onEditDescription={onEditDescription}
              onSetNow={onSetNow} onMoveBucket={onMoveBucket} />
          ))}
          {nextTasks.length === 0 && (
            <div style={{ padding: '12px 28px 4px', fontFamily: 'var(--mono)', fontSize: 10, color: T.fg3, letterSpacing: '0.1em' }}>
              empty.
            </div>
          )}
        </div>

        {/* LATER bucket — collapsed */}
        <div
          onClick={() => setLaterOpen(!laterOpen)}
          style={{
            padding: '18px 28px 10px', cursor: 'pointer',
            display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
            opacity: nowTask ? 0.55 : 1,
          }}
        >
          <MonoLabel T={T}>⇣ LATER · {laterTasks.length}</MonoLabel>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: T.fg3, letterSpacing: '0.1em' }}>
            {laterOpen ? '▾ HIDE' : '▸ SHOW'}
          </span>
        </div>
        {laterOpen && (
          <div style={{ opacity: nowTask ? 0.55 : 1 }}>
            {laterTasks.map(t => (
              <BucketedTaskRow key={t.id} T={T} D={D} task={t} now={now}
                onToggle={onToggle} onStar={onStar} onDelete={onDelete} onEdit={onEdit}
                onEditDescription={onEditDescription}
                onSetNow={onSetNow} onMoveBucket={onMoveBucket} />
            ))}
          </div>
        )}

        {/* DONE */}
        {doneTasks.length > 0 && (
          <>
            <div style={{ padding: '22px 28px 6px' }}>
              <MonoLabel T={T}>✓ DONE · {doneTasks.length}</MonoLabel>
            </div>
            {doneTasks.map(t => (
              <BucketedTaskRow key={t.id} T={T} D={D} task={t} now={now}
                onToggle={onToggle} onStar={onStar} onDelete={onDelete} onEdit={onEdit}
                onEditDescription={onEditDescription}
                onSetNow={onSetNow} onMoveBucket={onMoveBucket} />
            ))}
          </>
        )}
        <div style={{ height: 60 }} />
      </div>
    </>
  );
}

// Enhanced TaskRow with Now/Later promote buttons on hover
function BucketedTaskRow({ T, D, task, onToggle, onStar, onDelete, onEdit, onEditDescription, onSetNow, onMoveBucket, now }) {
  const [hover, setHover] = useState(false);
  const [editing, setEditing] = useState(false);
  const [val, setVal] = useState(task.title);
  const [descOpen, setDescOpen] = useState(false);
  const [desc, setDesc] = useState(task.description || '');
  const isHabit = task.isHabit;
  const hasTime = !!task.dueAt;
  const imminent = hasTime && now && (task.dueAt - now.getTime() < 15 * 60 * 1000) && (task.dueAt - now.getTime() > 0);
  const hasDesc = !!(task.description && task.description.trim());

  const commit = () => {
    setEditing(false);
    if (val.trim() && val !== task.title) onEdit(task.id, val.trim());
    else setVal(task.title);
  };
  const commitDesc = () => {
    if ((desc || '') !== (task.description || '') && onEditDescription) {
      onEditDescription(task.id, desc);
    }
  };

  return (
    <div style={{ borderBottom: `1px solid ${T.line}`, borderLeft: task.starred ? `2px solid ${T.star}` : '2px solid transparent' }}>
    <div
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        display: 'flex', alignItems: 'center', gap: 14,
        padding: `${D.rowPY}px ${D.rowPX + 14}px`,
        background: hover ? T.panel2 : 'transparent',
        transition: 'background 0.12s',
        position: 'relative',
      }}
    >
      <button
        onClick={() => onToggle(task.id)}
        style={{
          width: 16, height: 16, flexShrink: 0,
          border: `1px solid ${task.done ? T.accent : T.fg3}`,
          background: task.done ? T.accent : 'transparent',
          cursor: 'pointer', padding: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          transition: 'all 0.15s',
        }}
      >
        {task.done && (
          <svg width="10" height="10" viewBox="0 0 10 10">
            <path d="M1.5 5 L4 7.5 L8.5 2.5" stroke={T.panel} strokeWidth="1.6" fill="none" strokeLinecap="square" />
          </svg>
        )}
      </button>

      {editing ? (
        <input value={val}
          onChange={(e) => setVal(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setVal(task.title); setEditing(false); } }}
          autoFocus
          style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', fontFamily: 'var(--sans)', fontSize: D.fontBase, color: T.fg }}
        />
      ) : (
        <div
          onDoubleClick={() => !isHabit && setEditing(true)}
          style={{
            flex: 1,
            fontFamily: 'var(--sans)', fontSize: D.fontBase,
            color: task.done ? T.done : T.fg,
            textDecoration: task.done ? 'line-through' : 'none',
            letterSpacing: '-0.005em', cursor: isHabit ? 'default' : 'text',
          }}
        >{task.title}</div>
      )}

      {hover && !task.done && !isHabit && task.bucket !== 'now' && (
        <button onClick={() => onSetNow(task.id)}
          style={{
            border: `1px solid ${T.accent}`, background: 'transparent', color: T.accent,
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.1em',
            padding: '3px 8px', cursor: 'pointer',
          }}
        >→ NOW</button>
      )}
      {hover && !task.done && !isHabit && task.bucket === 'next' && (
        <button onClick={() => onMoveBucket(task.id, 'later')}
          style={{
            border: 'none', background: 'transparent', color: T.fg3,
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.1em',
            padding: '3px 6px', cursor: 'pointer',
          }}
        >↓ LATER</button>
      )}
      {hover && !task.done && !isHabit && task.bucket === 'later' && (
        <button onClick={() => onMoveBucket(task.id, 'next')}
          style={{
            border: 'none', background: 'transparent', color: T.fg3,
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.1em',
            padding: '3px 6px', cursor: 'pointer',
          }}
        >↑ NEXT</button>
      )}

      {!isHabit && (task.starred || hover) && (
        <button onClick={() => onStar(task.id)}
          style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: task.starred ? T.star : T.fg3, fontSize: 13, padding: 2 }}
        >{task.starred ? '★' : '☆'}</button>
      )}

      {isHabit && (
        <div style={{
          fontFamily: 'var(--mono)', fontSize: 9, color: T.accent,
          letterSpacing: '0.1em', padding: '3px 8px', border: `1px solid ${T.accent}`,
        }}>HABIT · {task.streak}</div>
      )}

      {hasTime && (
        <div style={{
          fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.05em',
          color: imminent ? T.accent : T.fg2,
          padding: '3px 8px', border: `1px solid ${imminent ? T.accent : T.line}`,
          background: imminent ? T.accentSoft : 'transparent',
          minWidth: 84, textAlign: 'center',
        }}>
          {imminent && now ? fmtCountdown(task.dueAt, now) : fmtDueLabel(task.dueAt)}
        </div>
      )}

      {task.context && !isHabit && (
        <div style={{
          fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
          color: task.done ? T.fg3 : T.fg2,
          padding: '3px 8px', border: `1px solid ${T.line}`,
          textTransform: 'lowercase', minWidth: 72, textAlign: 'center',
        }}>{task.context}</div>
      )}

      {!isHabit && (hasDesc || hover || descOpen) && (
        <button onClick={() => setDescOpen(o => !o)}
          title={hasDesc ? 'Show / edit note' : 'Add note'}
          style={{
            border: 'none', background: 'transparent', cursor: 'pointer',
            color: hasDesc ? T.accent : T.fg3,
            fontFamily: 'var(--mono)', fontSize: 11, padding: 2,
          }}
        >{descOpen ? '▾' : (hasDesc ? '▸●' : '▸')}</button>
      )}

      {hover && !editing && !isHabit && (
        <button onClick={() => onDelete(task.id)}
          style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: T.fg3, fontSize: 14, padding: 2, fontFamily: 'var(--mono)' }}
          title="Delete"
        >×</button>
      )}
    </div>
    {descOpen && !isHabit && (
      <div style={{ padding: `0 ${D.rowPX + 14}px ${D.rowPY}px`, background: T.panel2 }}>
        <textarea
          value={desc}
          onChange={(e) => setDesc(e.target.value)}
          onBlur={commitDesc}
          placeholder="Optional note — add anything you want to remember for this task."
          rows={3}
          style={{
            width: '100%', resize: 'vertical', minHeight: 60,
            border: `1px solid ${T.line}`, outline: 'none', background: T.panel,
            fontFamily: 'var(--sans)', fontSize: 13, color: T.fg,
            padding: 10, marginTop: 2,
          }}
        />
      </div>
    )}
    </div>
  );
}

// ---------- KeyboardInbox ----------
function KeyboardInbox({ T, D, inbox, contexts, selIdx, setSelIdx, ctx, setCtx, onProcess, onDelete }) {
  const CTX = contexts || CONTEXTS;
  if (inbox.length === 0) {
    return (
      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ padding: '40px 22px', textAlign: 'center', color: T.fg3, fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.12em' }}>
          ─── INBOX CLEAR ───
        </div>
      </div>
    );
  }
  return (
    <div style={{ flex: 1, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
      {/* keyboard legend */}
      <div style={{
        padding: '10px 22px', background: T.panel2,
        display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
        borderBottom: `1px solid ${T.line}`,
      }}>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: T.fg3, letterSpacing: '0.1em' }}>CTX</span>
        {CTX.map((c, i) => (
          <button key={c} onClick={() => setCtx(c === ctx ? '' : c)}
            style={{
              border: `1px solid ${ctx === c ? T.accent : T.line}`,
              background: ctx === c ? T.accentSoft : 'transparent',
              color: ctx === c ? T.accent : T.fg2,
              fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.06em',
              padding: '3px 6px', cursor: 'pointer',
            }}
          ><span style={{ color: T.fg3, marginRight: 4 }}>{i+1}</span>{c}</button>
        ))}
        <div style={{ flex: 1 }} />
        <span style={{ fontFamily: 'var(--mono)', fontSize: 9, color: T.fg3, letterSpacing: '0.1em' }}>T→TASK · X→DEL</span>
      </div>

      {inbox.map((it, i) => {
        const sel = i === selIdx;
        const agoMin = Math.max(1, Math.round((Date.now() - it.created) / 60000));
        const ago = agoMin < 60 ? `${agoMin}m` : `${Math.round(agoMin/60)}h`;
        return (
          <div key={it.id}
            onClick={() => setSelIdx(i)}
            style={{
              padding: `${D.rowPY}px ${D.rowPX}px`,
              borderBottom: `1px solid ${T.line}`,
              background: sel ? T.accentSoft : 'transparent',
              borderLeft: sel ? `2px solid ${T.accent}` : '2px solid transparent',
              display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer',
            }}
          >
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9, color: sel ? T.accent : T.fg3, letterSpacing: '0.1em', minWidth: 28 }}>{ago}</div>
            <div style={{ flex: 1, fontFamily: 'var(--sans)', fontSize: D.fontBase - 1, color: T.fg }}>{it.title}</div>
            {sel && ctx && (
              <div style={{
                fontFamily: 'var(--mono)', fontSize: 9, color: T.accent,
                letterSpacing: '0.08em', padding: '3px 6px', border: `1px solid ${T.accent}`,
              }}>{ctx}</div>
            )}
            {sel && (
              <>
                <button onClick={(e) => { e.stopPropagation(); onProcess(it.id, ctx); setCtx(''); }}
                  style={{
                    border: `1px solid ${T.accent}`, background: T.accent, color: T.panel,
                    fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.1em',
                    padding: '3px 8px', cursor: 'pointer',
                  }}
                >T ⟶</button>
                <button onClick={(e) => { e.stopPropagation(); onDelete(it.id); }}
                  style={{
                    border: 'none', background: 'transparent', color: T.fg3,
                    fontFamily: 'var(--mono)', fontSize: 11, cursor: 'pointer', padding: 2,
                  }}
                >×</button>
              </>
            )}
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, { TodayColumn, BucketedTaskRow, KeyboardInbox });
