// Direction A — Task detail slide-over panel + Shell (app chrome + nav + filter bar)

function ATaskPanel({ taskId, store, onClose }) {
  const task = store.tasks.find((t) => t.id === taskId);
  const [comment, setComment] = React.useState('');
  const [editing, setEditing] = React.useState(false);
  const [confirmingDelete, setConfirmingDelete] = React.useState(false);
  const [attachments, setAttachments] = React.useState([]);
  const [uploading, setUploading] = React.useState(false);
  const fileRef = React.useRef(null);
  const textareaRef = React.useRef(null);

  React.useEffect(() => {
    if (!taskId) return;
    fetch(`/api/tasks/${taskId}/attachments`, { credentials: 'same-origin' })
      .then((r) => r.ok ? r.json() : [])
      .then(setAttachments)
      .catch(() => setAttachments([]));
  }, [taskId]);

  const uploadFile = async (file) => {
    if (!file) return;
    const fd = new FormData();
    fd.append('file', file);
    setUploading(true);
    try {
      const r = await fetch(`/api/tasks/${taskId}/attachments`, {
        method: 'POST', credentials: 'same-origin', body: fd,
      });
      if (r.ok) {
        const data = await r.json();
        setAttachments(data.attachments || []);
        if (store.refresh) store.refresh();
      }
    } finally { setUploading(false); if (fileRef.current) fileRef.current.value = ''; }
  };

  const removeAttachment = async (id) => {
    const r = await fetch(`/api/attachments/${id}`, { method: 'DELETE', credentials: 'same-origin' });
    if (r.ok) {
      const data = await r.json();
      setAttachments(data.attachments || []);
    }
  };

  if (!task) return null;
  const taskUpdates = store.updates.filter((u) => u.task_id === task.id);

  const submitComment = () => {
    if (!comment.trim()) return;
    store.addUpdate(task.id, comment.trim());
    setComment('');
  };

  const insertMention = () => {
    const who = store.me === 'Phil' ? 'Bob' : 'Phil';
    setComment((c) => (c ? `${c} @${who} ` : `@${who} `));
    setTimeout(() => textareaRef.current && textareaRef.current.focus(), 0);
  };

  const handleDelete = () => {
    if (confirmingDelete) {
      store.deleteTask(task.id);
      onClose();
    } else {
      setConfirmingDelete(true);
      setTimeout(() => setConfirmingDelete(false), 3000);
    }
  };

  return (
    <>
      <div onClick={onClose} style={{
        position: 'absolute', inset: 0, background: 'rgba(20,16,10,.3)', backdropFilter: 'blur(2px)',
        zIndex: 40,
      }} />
      <div style={{
        position: 'absolute', top: 0, right: 0, bottom: 0, width: 480,
        background: A_TOKENS.paper, borderLeft: `1px solid ${A_TOKENS.line}`,
        boxShadow: '-10px 0 30px rgba(0,0,0,.08)',
        display: 'flex', flexDirection: 'column', zIndex: 41,
        animation: 'slideIn .18s ease-out',
      }}>
        <div style={{ padding: '14px 20px 12px', borderBottom: `1px solid ${A_TOKENS.line}`, display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--mono)', color: A_TOKENS.inkFaint, letterSpacing: 0.5 }}>
            TASK #{String(task.id).padStart(3, '0')}
          </span>
          <span style={{ color: A_TOKENS.line }}>·</span>
          <span style={{ fontSize: 10, fontFamily: 'var(--mono)', color: A_CAT_COLOR[task.category], letterSpacing: 0.5, textTransform: 'uppercase' }}>
            {task.category}
          </span>
          <div style={{ flex: 1 }} />
          <button
            onClick={handleDelete}
            title={confirmingDelete ? 'Click again within 3s to confirm' : 'Delete task'}
            style={{
              border: 'none', cursor: 'pointer',
              background: confirmingDelete ? A_TOKENS.accent : 'transparent',
              color: confirmingDelete ? '#fff' : A_TOKENS.inkSoft,
              fontSize: 10.5, letterSpacing: 0.6, textTransform: 'uppercase', fontWeight: 600,
              fontFamily: 'var(--mono)',
              padding: '4px 8px', borderRadius: 3, marginRight: 4,
            }}
            onMouseEnter={(e) => { if (!confirmingDelete) e.currentTarget.style.color = A_TOKENS.accent; }}
            onMouseLeave={(e) => { if (!confirmingDelete) e.currentTarget.style.color = A_TOKENS.inkSoft; }}
          >{confirmingDelete ? 'Confirm delete' : 'Delete'}</button>
          <button onClick={onClose} style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: A_TOKENS.inkSoft, fontSize: 18, padding: 4 }}>×</button>
        </div>

        <div style={{ padding: '16px 20px 20px', borderBottom: `1px solid ${A_TOKENS.line}` }}>
          {editing ? (
            <input
              autoFocus
              defaultValue={task.title}
              onBlur={(e) => { store.updateTask(task.id, { title: e.target.value }); setEditing(false); }}
              onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur(); if (e.key === 'Escape') setEditing(false); }}
              style={{ width: '100%', fontSize: 18, fontWeight: 600, color: A_TOKENS.ink, border: `1px solid ${A_TOKENS.accent}`, background: A_TOKENS.card, padding: '6px 8px', fontFamily: 'var(--body)' }}
            />
          ) : (
            <div onClick={() => setEditing(true)} style={{ fontSize: 18, fontWeight: 600, color: A_TOKENS.ink, letterSpacing: -0.2, lineHeight: 1.25, cursor: 'text' }}>
              {task.title}
            </div>
          )}
        </div>

        {/* Fields */}
        <div style={{ padding: '14px 20px', borderBottom: `1px solid ${A_TOKENS.line}` }}>
          <Row label="Status">
            <select value={task.status} onChange={(e) => store.updateTask(task.id, { status: e.target.value })} style={selectS}>
              {window.MOCK.STATUSES.map((s) => <option key={s}>{s}</option>)}
            </select>
          </Row>
          <Row label="Owner">
            <select value={task.owner} onChange={(e) => store.updateTask(task.id, { owner: e.target.value })} style={selectS}>
              {window.MOCK.OWNERS.map((o) => <option key={o}>{o}</option>)}
            </select>
          </Row>
          <Row label="Priority">
            <select value={task.priority} onChange={(e) => store.updateTask(task.id, { priority: e.target.value })} style={selectS}>
              {window.MOCK.PRIORITIES.map((p) => <option key={p}>{p}</option>)}
            </select>
          </Row>
          <Row label="Due">
            <input type="date" value={task.due_date || ''} onChange={(e) => store.updateTask(task.id, { due_date: e.target.value || null })} style={selectS} />
          </Row>
          <Row label="Next step">
            <input value={task.next_step} onChange={(e) => store.updateTask(task.id, { next_step: e.target.value })} placeholder="What's the next move?" style={{ ...selectS, fontStyle: task.next_step ? 'normal' : 'italic' }} />
          </Row>
        </div>

        {/* Comments */}
        <div style={{ flex: 1, overflowY: 'auto', padding: '14px 20px' }}>

          {/* Attachments */}
          <div style={{ marginBottom: 18 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
              <span style={{ fontSize: 10, fontFamily: 'var(--mono)', color: A_TOKENS.inkFaint, letterSpacing: 0.5, textTransform: 'uppercase' }}>
                Attachments · {attachments.length}
              </span>
              <div style={{ flex: 1 }} />
              <input
                ref={fileRef}
                type="file"
                onChange={(e) => uploadFile(e.target.files && e.target.files[0])}
                style={{ display: 'none' }}
              />
              <button
                onClick={() => fileRef.current && fileRef.current.click()}
                disabled={uploading}
                style={{
                  fontSize: 10.5, fontFamily: 'var(--mono)', letterSpacing: 0.5, textTransform: 'uppercase',
                  border: `1px solid ${A_TOKENS.line}`, background: A_TOKENS.card, color: A_TOKENS.inkSoft,
                  padding: '3px 8px', borderRadius: 3, cursor: uploading ? 'default' : 'pointer',
                  opacity: uploading ? 0.5 : 1,
                }}
              >{uploading ? 'Uploading…' : '+ Upload'}</button>
            </div>
            {attachments.map((a) => (
              <div key={a.id} style={{
                display: 'flex', alignItems: 'center', gap: 8,
                padding: '6px 10px', background: A_TOKENS.paperDeep, borderRadius: 4, marginBottom: 4,
                fontSize: 12,
              }}>
                <a href={`/attachments/${a.id}/download`} style={{ color: A_TOKENS.ink, textDecoration: 'none', fontWeight: 500, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.original_name}</a>
                <span style={{ fontSize: 10.5, fontFamily: 'var(--mono)', color: A_TOKENS.inkFaint }}>
                  {(a.size / 1024).toFixed(0)} KB · {a.uploader}
                </span>
                <button onClick={() => removeAttachment(a.id)} title="Remove" style={{
                  border: 'none', background: 'transparent', color: A_TOKENS.inkFaint, cursor: 'pointer', fontSize: 14, padding: 2,
                }}>×</button>
              </div>
            ))}
            {attachments.length === 0 && (
              <div style={{ fontSize: 11.5, color: A_TOKENS.inkFaint, fontStyle: 'italic' }}>No files attached.</div>
            )}
          </div>

          <div style={{ fontSize: 10, fontFamily: 'var(--mono)', color: A_TOKENS.inkFaint, letterSpacing: 0.5, textTransform: 'uppercase', marginBottom: 10 }}>
            Activity · {taskUpdates.length}
          </div>
          {taskUpdates.length === 0 && (
            <div style={{ fontSize: 12, color: A_TOKENS.inkFaint, fontStyle: 'italic', textAlign: 'center', padding: 20 }}>No activity yet</div>
          )}
          {taskUpdates.map((u) => (
            <div key={u.id} style={{ marginBottom: 14 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
                <AAvatar name={u.author} size={18} />
                <span style={{ fontSize: 12, fontWeight: 600, color: A_TOKENS.ink }}>{u.author}</span>
                <span style={{ fontSize: 10.5, color: A_TOKENS.inkFaint, fontFamily: 'var(--mono)' }}>{window.relativeTime(u.created_at)}</span>
              </div>
              <div style={{ fontSize: 12.5, color: A_TOKENS.ink, lineHeight: 1.5, paddingLeft: 24 }}>
                {window.renderBody(u.body, 'mention-a')}
              </div>
              <div style={{ paddingLeft: 24, marginTop: 6, display: 'flex', gap: 4, flexWrap: 'wrap' }}>
                {Object.entries(u.reactions || {}).map(([emoji, users]) => (
                  <button key={emoji} onClick={() => store.toggleReaction(u.id, emoji)} style={{
                    fontSize: 11, padding: '2px 6px', borderRadius: 10,
                    border: `1px solid ${users.includes(store.me) ? A_TOKENS.accent : A_TOKENS.line}`,
                    background: users.includes(store.me) ? A_TOKENS.accentSoft : A_TOKENS.card,
                    cursor: 'pointer', fontFamily: 'var(--mono)',
                    display: 'inline-flex', alignItems: 'center', gap: 3,
                  }}>
                    <span>{emoji}</span>
                    <span style={{ color: A_TOKENS.inkSoft }}>{users.length}</span>
                  </button>
                ))}
                <button onClick={() => store.toggleReaction(u.id, '👍')} style={{
                  fontSize: 11, padding: '2px 6px', borderRadius: 10, border: `1px dashed ${A_TOKENS.line}`,
                  background: 'transparent', cursor: 'pointer', color: A_TOKENS.inkFaint,
                }}>＋</button>
              </div>
            </div>
          ))}
        </div>

        <div style={{ padding: 16, borderTop: `1px solid ${A_TOKENS.line}`, background: A_TOKENS.card }}>
          <textarea
            ref={textareaRef}
            value={comment}
            onChange={(e) => setComment(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) submitComment(); }}
            placeholder="Add an update… Enter @Bob or @Phil to notify"
            style={{
              width: '100%', minHeight: 56, resize: 'vertical',
              border: `1px solid ${A_TOKENS.line}`, background: A_TOKENS.paper,
              padding: '8px 10px', fontSize: 12.5, fontFamily: 'var(--body)',
              color: A_TOKENS.ink, outline: 'none',
            }}
            onFocus={(e) => (e.target.style.borderColor = A_TOKENS.accent)}
            onBlur={(e) => (e.target.style.borderColor = A_TOKENS.line)}
          />
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
            <button onClick={insertMention} style={btnGhost}>＠ mention</button>
            <div style={{ flex: 1 }} />
            <span style={{ fontSize: 10, color: A_TOKENS.inkFaint, fontFamily: 'var(--mono)' }}>⌘↵</span>
            <button onClick={submitComment} style={btnPrimary}>Post update</button>
          </div>
        </div>
      </div>
    </>
  );
}

const selectS = {
  width: '100%', padding: '4px 6px', fontSize: 12, fontFamily: 'var(--body)',
  border: `1px solid transparent`, background: 'transparent', color: A_TOKENS.ink,
  outline: 'none', borderRadius: 2, cursor: 'pointer',
};

const btnGhost = {
  fontSize: 11, padding: '4px 8px', border: `1px solid ${A_TOKENS.line}`,
  background: 'transparent', color: A_TOKENS.inkSoft, cursor: 'pointer', fontFamily: 'var(--body)',
  borderRadius: 2,
};
const btnPrimary = {
  fontSize: 11, padding: '5px 12px', border: `1px solid ${A_TOKENS.accent}`,
  background: A_TOKENS.accent, color: '#fff', cursor: 'pointer', fontWeight: 500, fontFamily: 'var(--body)',
  borderRadius: 2, letterSpacing: 0.3,
};

function Row({ label, children }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '3px 0' }}>
      <div style={{ width: 70, fontSize: 10.5, fontFamily: 'var(--mono)', color: A_TOKENS.inkFaint, letterSpacing: 0.5, textTransform: 'uppercase' }}>{label}</div>
      <div style={{ flex: 1 }}>{children}</div>
    </div>
  );
}

// ─────── Category filter chip with hover-to-delete ───────
function ACategoryChip({ name, active, count, onFilter, onDelete }) {
  const [hovered, setHovered] = React.useState(false);
  const [confirming, setConfirming] = React.useState(false);
  React.useEffect(() => { if (!hovered) setConfirming(false); }, [hovered]);
  const canDelete = name !== 'Other' && onDelete;

  return (
    <span
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{ position: 'relative', display: 'inline-flex' }}
    >
      <button onClick={onFilter} style={{
        padding: '5px 11px', fontSize: 12.5, border: 'none',
        background: active ? A_CAT_COLOR[name] : 'transparent',
        color: active ? '#fff' : A_CAT_COLOR[name],
        cursor: 'pointer', borderRadius: 999, fontFamily: 'var(--body)', fontWeight: active ? 600 : 550,
        display: 'inline-flex', alignItems: 'center', gap: 7,
        transition: 'background .1s',
        letterSpacing: -0.1,
      }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: active ? '#fff' : A_CAT_COLOR[name], opacity: active ? 0.9 : 1 }} />
        {name} <span style={{ opacity: 0.65, fontFamily: 'var(--mono)', fontSize: 10.5, fontVariantNumeric: 'tabular-nums' }}>{count || 0}</span>
      </button>
      {canDelete && hovered && (
        <button
          onClick={(e) => {
            e.stopPropagation();
            if (confirming) { onDelete(name); setConfirming(false); }
            else setConfirming(true);
          }}
          title={confirming ? 'Click to confirm — tasks move to Other' : 'Delete category'}
          style={{
            position: 'absolute', top: -6, right: -6, zIndex: 2,
            width: confirming ? 'auto' : 18, height: 18,
            padding: confirming ? '0 6px' : 0,
            borderRadius: 999, border: `1px solid ${A_TOKENS.card}`,
            background: confirming ? A_TOKENS.bad : A_TOKENS.inkSoft,
            color: '#fff',
            fontSize: confirming ? 9.5 : 11, lineHeight: 1, cursor: 'pointer',
            fontFamily: confirming ? 'var(--mono)' : 'inherit',
            letterSpacing: confirming ? 0.5 : 0, textTransform: confirming ? 'uppercase' : 'none',
            fontWeight: confirming ? 600 : 400,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: '0 1px 2px rgba(0,0,0,.15)',
          }}
        >{confirming ? 'Delete?' : '×'}</button>
      )}
    </span>
  );
}

// ─────── Add-category inline control ───────
function ACategoryAdd({ store }) {
  const [open, setOpen] = React.useState(false);
  const [name, setName] = React.useState('');
  const [color, setColor] = React.useState('#8b4a1e');
  const [err, setErr] = React.useState('');
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const onDocClick = (e) => {
      if (ref.current && !ref.current.contains(e.target)) { setOpen(false); setName(''); setErr(''); }
    };
    document.addEventListener('mousedown', onDocClick);
    return () => document.removeEventListener('mousedown', onDocClick);
  }, [open]);

  const palette = ['#8b4a1e', '#2d5269', '#5e3a6f', '#3c6248', '#934a62', '#6b655c', '#c43a3a', '#1e6e4a', '#4a5e8f', '#7a5a1e'];

  const submit = async () => {
    const clean = name.trim();
    if (!clean) return;
    setErr('');
    const res = await store.addCategory(clean, color);
    if (res && res.error) setErr(res.error);
    else { setOpen(false); setName(''); }
  };

  if (!open) {
    return (
      <button onClick={() => setOpen(true)} title="Add category" style={{
        padding: '5px 11px', fontSize: 12.5, border: `1px dashed ${A_TOKENS.line}`,
        background: 'transparent', color: A_TOKENS.inkFaint,
        cursor: 'pointer', borderRadius: 999, fontFamily: 'var(--body)', fontWeight: 550,
        display: 'inline-flex', alignItems: 'center', gap: 5,
        letterSpacing: -0.1,
      }}
      onMouseEnter={(e) => { e.currentTarget.style.color = A_TOKENS.ink; e.currentTarget.style.borderColor = A_TOKENS.accent; }}
      onMouseLeave={(e) => { e.currentTarget.style.color = A_TOKENS.inkFaint; e.currentTarget.style.borderColor = A_TOKENS.line; }}>
        + Category
      </button>
    );
  }

  return (
    <div ref={ref} style={{
      position: 'relative', display: 'inline-flex', alignItems: 'center', gap: 6,
      background: A_TOKENS.card, border: `1px solid ${A_TOKENS.accent}`, padding: '3px 6px 3px 8px', borderRadius: 999,
    }}>
      <span style={{ width: 8, height: 8, borderRadius: '50%', background: color }} />
      <input
        autoFocus
        value={name}
        onChange={(e) => setName(e.target.value)}
        onKeyDown={(e) => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') { setOpen(false); setName(''); setErr(''); } }}
        placeholder="Name"
        maxLength={24}
        style={{
          border: 'none', outline: 'none', background: 'transparent', color: A_TOKENS.ink,
          fontSize: 12.5, fontFamily: 'var(--body)', width: 110, padding: 0, letterSpacing: -0.1,
        }}
      />
      <div style={{ display: 'flex', gap: 3 }}>
        {palette.map((c) => (
          <button key={c} onClick={() => setColor(c)} title={c} style={{
            width: 16, height: 16, borderRadius: '50%', background: c,
            border: color === c ? `2px solid ${A_TOKENS.ink}` : '2px solid transparent',
            cursor: 'pointer', padding: 0,
          }} />
        ))}
      </div>
      <button onClick={submit} style={{
        fontSize: 10.5, fontFamily: 'var(--mono)', letterSpacing: 0.5, textTransform: 'uppercase',
        border: 'none', background: A_TOKENS.accent, color: '#fff',
        padding: '3px 8px', borderRadius: 999, cursor: 'pointer', fontWeight: 600,
      }}>Add</button>
      {err && (
        <span style={{
          position: 'absolute', top: '100%', left: 0, marginTop: 4,
          fontSize: 10.5, color: A_TOKENS.bad, fontFamily: 'var(--mono)', whiteSpace: 'nowrap',
        }}>{err}</span>
      )}
    </div>
  );
}

// ─────── Quick-add bar ───────
function AQuickAdd({ store }) {
  const [value, setValue] = React.useState('');
  const [parsed, setParsed] = React.useState(null);
  const [overrides, setOverrides] = React.useState({});
  const [dismissed, setDismissed] = React.useState(false);
  const containerRef = React.useRef(null);

  React.useEffect(() => {
    if (value.trim()) setParsed(window.parseQuickAdd(value));
    else { setParsed(null); setOverrides({}); }
    setDismissed(false);
  }, [value]);

  React.useEffect(() => {
    if (!parsed || dismissed) return;
    const onDocClick = (e) => {
      if (containerRef.current && !containerRef.current.contains(e.target)) setDismissed(true);
    };
    document.addEventListener('mousedown', onDocClick);
    return () => document.removeEventListener('mousedown', onDocClick);
  }, [parsed, dismissed]);

  const preview = parsed ? { ...parsed, ...overrides } : null;
  const setField = (key, val) => setOverrides((o) => ({ ...o, [key]: val }));

  const submit = () => {
    if (!preview || !preview.title.trim()) return;
    store.addTask(preview);
    setValue('');
    setOverrides({});
    setDismissed(false);
  };

  const selS = {
    fontSize: 10.5, fontFamily: 'var(--body)', fontWeight: 500, letterSpacing: 0.3, textTransform: 'uppercase',
    padding: '3px 7px', border: `1px solid ${A_TOKENS.line}`, background: A_TOKENS.card, color: A_TOKENS.inkSoft,
    borderRadius: 2, cursor: 'pointer', outline: 'none',
  };

  return (
    <div ref={containerRef} style={{ position: 'relative' }}>
      <div style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', color: A_TOKENS.inkFaint, fontSize: 14, fontWeight: 500, lineHeight: 1 }}>+</div>
      <input
        value={value}
        onChange={(e) => setValue(e.target.value)}
        onFocus={() => setDismissed(false)}
        onMouseDown={() => setDismissed(false)}
        onKeyDown={(e) => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') { setValue(''); setDismissed(true); } }}
        placeholder='Add task — try "Call Acme tomorrow" or "high: close LOI fri"'
        style={{
          width: 520, padding: '8px 12px 8px 28px', fontSize: 12.5, fontFamily: 'var(--body)',
          border: `1px solid ${A_TOKENS.line}`, background: A_TOKENS.card, color: A_TOKENS.ink, outline: 'none', borderRadius: 6,
          letterSpacing: -0.1,
          transition: 'border-color .1s, box-shadow .1s',
        }}
        onFocusCapture={(e) => { e.target.style.borderColor = A_TOKENS.accent; e.target.style.boxShadow = `0 0 0 3px ${A_TOKENS.accentFaint}`; }}
        onBlur={(e) => { e.target.style.borderColor = A_TOKENS.line; e.target.style.boxShadow = 'none'; }}
      />
      {!dismissed && preview && preview.title && (
        <div style={{
          position: 'absolute', top: '100%', left: 0, marginTop: 6, zIndex: 10,
          background: A_TOKENS.card, border: `1px solid ${A_TOKENS.line}`,
          padding: 12, borderRadius: 8, width: 520, boxShadow: '0 12px 32px rgba(20,16,10,.10), 0 2px 6px rgba(20,16,10,.05)',
        }}>
          <div style={{ fontSize: 10.5, color: A_TOKENS.inkFaint, letterSpacing: 0.4, marginBottom: 8, fontWeight: 500, textTransform: 'uppercase' }}>Will create</div>
          <div style={{ fontSize: 13.5, fontWeight: 550, color: A_TOKENS.ink, marginBottom: 10, letterSpacing: -0.15 }}>{preview.title}</div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
            <select value={preview.category} onChange={(e) => setField('category', e.target.value)} style={{ ...selS, color: A_CAT_COLOR[preview.category] }}>
              {window.MOCK.CATEGORIES.map((c) => <option key={c} value={c}>{c}</option>)}
            </select>
            <select value={preview.priority} onChange={(e) => setField('priority', e.target.value)} style={selS}>
              {window.MOCK.PRIORITIES.map((p) => <option key={p} value={p}>{p}</option>)}
            </select>
            <select value={preview.owner} onChange={(e) => setField('owner', e.target.value)} style={selS}>
              {window.MOCK.OWNERS.map((o) => <option key={o} value={o}>{o}</option>)}
            </select>
            <input
              type="date"
              value={preview.due_date || ''}
              onChange={(e) => setField('due_date', e.target.value || null)}
              style={{ ...selS, fontFamily: 'var(--mono)', textTransform: 'none' }}
            />
            <div style={{ flex: 1 }} />
            <span style={{ fontSize: 11, color: A_TOKENS.inkFaint, fontFamily: 'var(--mono)' }}>↵ to create</span>
          </div>
        </div>
      )}
    </div>
  );
}

// ─────── Main Dashboard A ───────
function DashboardA() {
  const store = window.useDashboardStore();
  const [view, setView] = React.useState('board');
  const [filter, setFilter] = React.useState({ owner: 'All', category: null, q: '' });
  const [openTaskId, setOpenTaskId] = React.useState(null);

  const views = [
    { id: 'board',    label: 'Board',    glyph: '▤' },
    { id: 'table',    label: 'Table',    glyph: '≡' },
    { id: 'calendar', label: 'Calendar', glyph: '◳' },
    { id: 'pipeline', label: 'Pipeline', glyph: '▸' },
    { id: 'metrics',  label: 'Metrics',  glyph: '◭' },
    { id: 'digest',   label: 'Digest',   glyph: '✉' },
  ];

  const catCounts = window.MOCK.CATEGORIES.reduce((acc, c) => {
    acc[c] = store.tasks.filter((t) => t.category === c && t.status !== 'Done').length;
    return acc;
  }, {});

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: A_TOKENS.paper, color: A_TOKENS.ink,
      fontFamily: 'var(--body)',
      display: 'flex', flexDirection: 'column',
      overflow: 'hidden',
    }}>
      <style>{`
        @keyframes slideIn { from { transform: translateX(12px); opacity: 0 } to { transform: translateX(0); opacity: 1 } }
        .mention-a { background: ${A_TOKENS.accentSoft}; color: ${A_TOKENS.accent}; padding: 1px 4px; border-radius: 2px; font-weight: 500; }
      `}</style>

      {/* ─── Top bar ─── */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 24,
        padding: '16px 36px', borderBottom: `1px solid ${A_TOKENS.line}`,
        background: A_TOKENS.card,
      }}>
        {/* wordmark — two interlocking circles: Bob + Phil */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <svg width="52" height="36" viewBox="0 0 52 36" style={{ display: 'block' }}>
            <defs>
              <linearGradient id="bpA" x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stopColor="#3a6379" />
                <stop offset="100%" stopColor="#254859" />
              </linearGradient>
              <linearGradient id="bpB" x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stopColor="#c9691f" />
                <stop offset="100%" stopColor="#8f3f11" />
              </linearGradient>
            </defs>
            <circle cx="16" cy="18" r="14" fill="url(#bpA)" />
            <circle cx="34" cy="18" r="14" fill="url(#bpB)" style={{ mixBlendMode: 'multiply' }} opacity="0.95" />
          </svg>
          <div>
            <div style={{ fontSize: 17, fontWeight: 600, color: A_TOKENS.ink, letterSpacing: -0.4, lineHeight: 1 }}>Bob <span style={{ color: A_TOKENS.inkFaint, fontWeight: 400 }}>&amp;</span> Phil</div>
            <div style={{ fontSize: 11, color: A_TOKENS.inkFaint, letterSpacing: 0.4, marginTop: 5, fontWeight: 500 }}>Growth · Strategy</div>
          </div>
        </div>

        <div style={{ width: 1, height: 28, background: A_TOKENS.line }} />

        {/* nav */}
        <div style={{ display: 'flex', gap: 1 }}>
          {views.map((v) => (
            <button key={v.id} onClick={() => setView(v.id)} style={{
              padding: '7px 13px', fontSize: 13, fontFamily: 'var(--body)',
              border: 'none', background: view === v.id ? A_TOKENS.paperDeep : 'transparent',
              color: view === v.id ? A_TOKENS.ink : A_TOKENS.inkSoft,
              cursor: 'pointer', borderRadius: 6, fontWeight: view === v.id ? 600 : 500,
              display: 'inline-flex', alignItems: 'center', gap: 7,
              letterSpacing: -0.15,
              transition: 'background .1s, color .1s',
            }}
            onMouseEnter={(e) => { if (view !== v.id) { e.currentTarget.style.color = A_TOKENS.ink; e.currentTarget.style.background = A_TOKENS.paper; } }}
            onMouseLeave={(e) => { if (view !== v.id) { e.currentTarget.style.color = A_TOKENS.inkSoft; e.currentTarget.style.background = 'transparent'; } }}
            >
              <span style={{ fontSize: 12, opacity: view === v.id ? 0.85 : 0.6 }}>{v.glyph}</span>{v.label}
            </button>
          ))}
        </div>

        <div style={{ flex: 1 }} />

        <AQuickAdd store={store} />

        {/* current user + logout */}
        {store.me && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '4px 10px 4px 5px', background: A_TOKENS.paperDeep, borderRadius: 999 }}>
            <AAvatar name={store.me} size={22} />
            <span style={{ fontSize: 12.5, color: A_TOKENS.ink, fontWeight: 600, letterSpacing: -0.1 }}>{store.me}</span>
            <form method="post" action="/logout" style={{ display: 'inline', margin: 0 }}>
              <button type="submit" title="Log out" style={{
                border: 'none', background: 'transparent', color: A_TOKENS.inkFaint,
                cursor: 'pointer', fontSize: 11, fontFamily: 'var(--mono)', letterSpacing: 0.5,
                textTransform: 'uppercase', padding: '2px 4px',
              }}
              onMouseEnter={(e) => e.currentTarget.style.color = A_TOKENS.accent}
              onMouseLeave={(e) => e.currentTarget.style.color = A_TOKENS.inkFaint}
              >out</button>
            </form>
          </div>
        )}
      </div>

      {/* ─── Filter bar ─── */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 6,
        padding: '12px 36px', borderBottom: `1px solid ${A_TOKENS.line}`,
        background: A_TOKENS.paper,
      }}>
        <span style={{ fontSize: 10.5, color: A_TOKENS.inkFaint, letterSpacing: 0.4, marginRight: 8, fontWeight: 500, textTransform: 'uppercase' }}>Who</span>
        {['All', 'Phil', 'Bob'].map((o) => (
          <button key={o} onClick={() => setFilter((f) => ({ ...f, owner: o }))} style={{
            padding: '5px 11px', fontSize: 12.5, border: 'none',
            background: filter.owner === o ? A_TOKENS.ink : 'transparent',
            color: filter.owner === o ? A_TOKENS.paper : A_TOKENS.inkSoft,
            cursor: 'pointer', borderRadius: 999, fontFamily: 'var(--body)', fontWeight: filter.owner === o ? 600 : 500,
            transition: 'background .1s, color .1s',
            letterSpacing: -0.1,
          }}
          onMouseEnter={(e) => { if (filter.owner !== o) e.currentTarget.style.color = A_TOKENS.ink; }}
          onMouseLeave={(e) => { if (filter.owner !== o) e.currentTarget.style.color = A_TOKENS.inkSoft; }}>{o === 'All' ? 'Everyone' : `${o}'s`}</button>
        ))}
        <div style={{ width: 1, height: 20, background: A_TOKENS.line, margin: '0 14px' }} />
        <span style={{ fontSize: 10.5, color: A_TOKENS.inkFaint, letterSpacing: 0.4, marginRight: 8, fontWeight: 500, textTransform: 'uppercase' }}>What</span>
        <button onClick={() => setFilter((f) => ({ ...f, category: null }))} style={{
          padding: '5px 11px', fontSize: 12.5, border: 'none',
          background: filter.category === null ? A_TOKENS.ink : 'transparent',
          color: filter.category === null ? A_TOKENS.paper : A_TOKENS.inkSoft,
          cursor: 'pointer', borderRadius: 999, fontFamily: 'var(--body)', fontWeight: filter.category === null ? 600 : 500,
          letterSpacing: -0.1,
        }}>All</button>
        {window.MOCK.CATEGORIES.map((c) => (
          <ACategoryChip
            key={c}
            name={c}
            active={filter.category === c}
            count={catCounts[c]}
            onFilter={() => setFilter((f) => ({ ...f, category: c }))}
            onDelete={store.removeCategory}
          />
        ))}
        <ACategoryAdd store={store} />
        <div style={{ flex: 1 }} />
        <div style={{ position: 'relative' }}>
          <span style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', fontSize: 12, color: A_TOKENS.inkFaint, pointerEvents: 'none' }}>⌕</span>
          <input
            value={filter.q}
            onChange={(e) => setFilter((f) => ({ ...f, q: e.target.value }))}
            placeholder="Search"
            style={{
              padding: '6px 12px 6px 30px', fontSize: 12.5, border: `1px solid ${A_TOKENS.line}`,
              background: A_TOKENS.card, color: A_TOKENS.ink, outline: 'none', borderRadius: 6,
              width: 200, fontFamily: 'var(--body)', letterSpacing: -0.1,
              transition: 'border-color .1s, box-shadow .1s',
            }}
            onFocus={(e) => { e.currentTarget.style.borderColor = A_TOKENS.accent; e.currentTarget.style.boxShadow = `0 0 0 3px ${A_TOKENS.accentFaint}`; }}
            onBlur={(e) => { e.currentTarget.style.borderColor = A_TOKENS.line; e.currentTarget.style.boxShadow = 'none'; }}
          />
        </div>
      </div>

      {/* ─── View ─── */}
      <div style={{ flex: 1, overflowY: 'auto', paddingTop: 28, position: 'relative' }}>
        {view === 'board'    && <ABoard    store={store} filter={filter} onOpenTask={setOpenTaskId} />}
        {view === 'table'    && <ATable    store={store} filter={filter} onOpenTask={setOpenTaskId} />}
        {view === 'calendar' && <ACalendar store={store} filter={filter} onOpenTask={setOpenTaskId} />}
        {view === 'pipeline' && <APipeline store={store} onOpenTask={setOpenTaskId} />}
        {view === 'metrics'  && <AMetrics  store={store} />}
        {view === 'digest'   && <ADigest   store={store} onOpenTask={setOpenTaskId} />}
      </div>

      {openTaskId && <ATaskPanel taskId={openTaskId} store={store} onClose={() => setOpenTaskId(null)} />}
    </div>
  );
}

Object.assign(window, { ATaskPanel, AQuickAdd, DashboardA });
