/* Tasks board — gated, role-switchable.
   Admin: create + review + pay.
   Delaney: claim + submit. */

const { useState: useStateT, useEffect: useEffectT, useMemo: useMemoT } = React;

const PASSWORD = "starthere";

function TasksPage() {
  const [unlocked, setUnlocked] = useStateT(() => {
    try { return sessionStorage.getItem("bydelaney.unlocked") === "1"; } catch { return false; }
  });

  if (!unlocked) {
    return <TasksGate onUnlock={() => {
      try { sessionStorage.setItem("bydelaney.unlocked", "1"); } catch {}
      setUnlocked(true);
    }} />;
  }
  return <TasksBoard />;
}

/* ───────── Gate ───────── */
function TasksGate({ onUnlock }) {
  const [val, setVal] = useStateT("");
  const [err, setErr] = useStateT(false);
  const submit = (e) => {
    e.preventDefault();
    if (val.trim().toLowerCase() === PASSWORD) onUnlock();
    else { setErr(true); setTimeout(() => setErr(false), 1400); }
  };
  return (
    <main className="page-enter gate-wrap" data-screen-label="Tasks gate">
      <div className="shell">
        <div className="gate">
          <div className="gate-mark serif">¹</div>
          <div className="eyebrow">Internal</div>
          <h1 className="gate-h serif">The tasks board.</h1>
          <p className="gate-p">
            This is where work comes in and goes out. Not meant for the public.
            If you have the password, you know.
          </p>
          <form onSubmit={submit} className="gate-form">
            <input
              type="password"
              className="input gate-input"
              value={val}
              placeholder="Password"
              onChange={(e) => setVal(e.target.value)}
              autoFocus
            />
            <button className="btn" type="submit">
              Enter <span aria-hidden="true">→</span>
            </button>
          </form>
          {err && <div className="gate-err">Not quite. Try again.</div>}
          <div className="gate-hint">
            <span className="kbd">starthere</span> — for the prototype
          </div>
        </div>
      </div>
      <style>{`
        .gate-wrap { padding: clamp(72px, 12vw, 160px) 0; }
        .gate {
          max-width: 480px;
          margin: 0 auto;
          padding: 56px 48px;
          border: 1px solid var(--line);
          border-radius: 4px;
          background: var(--cream);
          text-align: center;
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 12px;
        }
        .gate-mark { font-size: 64px; line-height: 1; color: var(--terracotta-deep); font-style: italic; }
        .gate-h { font-size: clamp(36px, 4.5vw, 52px); line-height: 1.1; margin-top: 4px; }
        .gate-p { color: var(--ink-2); font-family: var(--serif); font-size: 18px; max-width: 320px; margin: 0; }
        .gate-form { display: flex; gap: 10px; width: 100%; margin-top: 16px; }
        .gate-input { flex: 1; }
        .gate-err { color: var(--terracotta-deep); font-size: 13px; margin-top: 4px; }
        .gate-hint { font-size: 12px; color: var(--ink-3); margin-top: 24px; }
      `}</style>
    </main>
  );
}

/* ───────── Board ───────── */
function TasksBoard() {
  const [tasks, setTasksLocal] = useStateT(loadTasks);
  const [role, setRole] = useStateT(() => {
    try { return localStorage.getItem("bydelaney.role") || "admin"; } catch { return "admin"; }
  });
  const [filter, setFilter] = useStateT("all");
  const [composerOpen, setComposerOpen] = useStateT(false);
  const [paid, setPaid] = useStateT(null); // { taskId, link } when venmo just fired

  useEffectT(() => { saveTasks(tasks); }, [tasks]);
  useEffectT(() => { try { localStorage.setItem("bydelaney.role", role); } catch {} }, [role]);

  // Mutations
  const updateTask = (id, patch) => {
    setTasksLocal((all) => all.map((t) => t.id === id ? { ...t, ...patch } : t));
  };
  const addTask = (t) => setTasksLocal((all) => [t, ...all]);
  const removeTask = (id) => setTasksLocal((all) => all.filter((t) => t.id !== id));

  // Derived counts
  const counts = useMemoT(() => {
    const c = { all: tasks.length, open: 0, claimed_delaney: 0, submitted: 0, approved: 0, paid: 0 };
    tasks.forEach((t) => { if (c[t.status] !== undefined) c[t.status] += 1; });
    return c;
  }, [tasks]);

  // Filtering by role
  const visible = useMemoT(() => {
    let v = tasks;
    if (role === "delaney") {
      v = v.filter((t) => t.status === "open" || t.status === "claimed_delaney" || t.status === "submitted");
    }
    if (filter !== "all") v = v.filter((t) => t.status === filter);
    return v;
  }, [tasks, role, filter]);

  // Earnings for Delaney view
  const earnings = useMemoT(() => {
    const pending = tasks.filter((t) => t.status === "submitted" || t.status === "approved")
      .reduce((s, t) => s + (t.payout_usd || 0), 0);
    const paid = tasks.filter((t) => t.status === "paid")
      .reduce((s, t) => s + (t.payout_usd || 0), 0);
    const inProgress = tasks.filter((t) => t.status === "claimed_delaney")
      .reduce((s, t) => s + (t.payout_usd || 0), 0);
    return { pending, paid, inProgress };
  }, [tasks]);

  // Actions
  const claim = (id) => updateTask(id, { status: "claimed_delaney", claimed_at: new Date().toISOString() });
  const release = (id) => updateTask(id, { status: "open", claimed_at: undefined });
  const submit = (id, deliverable_url) => updateTask(id, { status: "submitted", submitted_at: new Date().toISOString(), deliverable_url });
  const approve = (id) => updateTask(id, { status: "approved", approved_at: new Date().toISOString() });
  const requestRevision = (id, note) => updateTask(id, { status: "claimed_delaney", revision_note: note });
  const pay = (task) => {
    const link = "venmo://paycharge?txn=pay&recipients=@delaney-ingalls&amount=" + (task.payout_usd || 15) + "&note=" + encodeURIComponent(task.id + " · " + task.title);
    // Mark paid optimistically
    updateTask(task.id, { status: "paid", paid_at: new Date().toISOString() });
    setPaid({ taskId: task.id, link, amount: task.payout_usd || 15 });
    // Attempt to open the venmo deep link
    try { window.location.href = link; } catch {}
  };
  const togglePublic = (id, v) => updateTask(id, { is_public: v });

  const filters = role === "admin"
    ? [
        ["all", "All", counts.all],
        ["open", "Open", counts.open],
        ["claimed_delaney", "In progress", counts.claimed_delaney],
        ["submitted", "Awaiting review", counts.submitted],
        ["approved", "Approved", counts.approved],
        ["paid", "Paid", counts.paid],
      ]
    : [
        ["all", "All", counts.open + counts.claimed_delaney + counts.submitted],
        ["open", "Open for me", counts.open],
        ["claimed_delaney", "Working on", counts.claimed_delaney],
        ["submitted", "Submitted", counts.submitted],
      ];

  return (
    <main className="page-enter board-wrap" data-screen-label="Tasks board">
      <div className="shell">
        {/* Header */}
        <div className="board-head">
          <div>
            <div className="eyebrow">Internal · /tasks</div>
            <h1 className="board-h1 serif">
              {role === "admin" ? "The task board." : "What's open."}
            </h1>
            <p className="board-sub">
              {role === "admin"
                ? <>Drop a task. Delaney sees it. She works on it. You review. You pay. The portfolio fills itself.</>
                : <>Pick something up. Most of these take an afternoon. $15 each. Paid same day on approve.</>}
            </p>
          </div>
          <div className="role-toggle">
            <span className="eyebrow" style={{ marginRight: 12 }}>Viewing as</span>
            <button
              className={"role-btn" + (role === "admin" ? " is-on" : "")}
              onClick={() => setRole("admin")}
            >Admin</button>
            <button
              className={"role-btn" + (role === "delaney" ? " is-on" : "")}
              onClick={() => setRole("delaney")}
            >Delaney</button>
          </div>
        </div>

        {/* Summary strip — different per role */}
        {role === "admin" ? (
          <AdminSummary
            counts={counts}
            onNew={() => setComposerOpen(true)}
            onReset={() => { resetTasks(); setTasksLocal(loadTasks()); }}
          />
        ) : (
          <DelaneySummary earnings={earnings} />
        )}

        {/* Filter tabs */}
        <div className="board-filters">
          {filters.map(([k, label, n]) => (
            <button
              key={k}
              className={"filter-tab" + (filter === k ? " is-on" : "")}
              onClick={() => setFilter(k)}
            >
              {label}
              <span className="filter-count mono-num">{n}</span>
            </button>
          ))}
        </div>

        {/* List */}
        <div className="task-list">
          {visible.length === 0 ? (
            <EmptyState role={role} filter={filter} />
          ) : (
            visible.map((task) => (
              <TaskRow
                key={task.id}
                task={task}
                role={role}
                onClaim={() => claim(task.id)}
                onRelease={() => release(task.id)}
                onSubmit={(url) => submit(task.id, url)}
                onApprove={() => approve(task.id)}
                onRequestRevision={(note) => requestRevision(task.id, note)}
                onPay={() => pay(task)}
                onTogglePublic={(v) => togglePublic(task.id, v)}
                onDelete={() => removeTask(task.id)}
              />
            ))
          )}
        </div>
      </div>

      {composerOpen && (
        <ComposerModal
          onClose={() => setComposerOpen(false)}
          onCreate={(t) => { addTask(t); setComposerOpen(false); }}
          existingCount={tasks.length}
        />
      )}

      {paid && (
        <PaidConfirm
          info={paid}
          onClose={() => setPaid(null)}
        />
      )}

      <style>{`
        .board-wrap { padding: clamp(40px, 5vw, 64px) 0 32px; }
        .board-head {
          display: flex;
          gap: 32px;
          justify-content: space-between;
          align-items: flex-start;
          flex-wrap: wrap;
          margin-bottom: 40px;
        }
        .board-h1 {
          font-size: clamp(40px, 5.5vw, 72px);
          line-height: 1.05;
          margin: 16px 0 0;
        }
        .board-sub {
          font-family: var(--serif);
          font-size: 18px;
          color: var(--ink-2);
          max-width: 540px;
          margin: 16px 0 0;
          line-height: 1.5;
        }
        .role-toggle {
          display: inline-flex;
          align-items: center;
          padding: 6px;
          border: 1px solid var(--line);
          border-radius: 999px;
          background: var(--cream-deep);
        }
        .role-btn {
          background: none;
          border: 0;
          padding: 8px 16px;
          border-radius: 999px;
          font-size: 13px;
          color: var(--ink-3);
        }
        .role-btn.is-on { background: var(--charcoal); color: var(--cream); }

        .board-filters {
          display: flex;
          gap: 4px;
          flex-wrap: wrap;
          margin: 32px 0 24px;
          padding-bottom: 16px;
          border-bottom: 1px solid var(--line);
        }
        .filter-tab {
          background: none;
          border: 0;
          padding: 8px 14px;
          border-radius: 999px;
          font-size: 13px;
          color: var(--ink-3);
          display: inline-flex;
          align-items: center;
          gap: 8px;
          transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
        }
        .filter-tab:hover { color: var(--charcoal); }
        .filter-tab.is-on { background: var(--charcoal); color: var(--cream); }
        .filter-count {
          font-size: 11px;
          opacity: 0.7;
          padding: 1px 6px;
          border-radius: 999px;
          background: rgba(0,0,0,0.05);
        }
        .filter-tab.is-on .filter-count { background: rgba(255,255,255,0.12); }

        .task-list { display: flex; flex-direction: column; gap: 12px; }
      `}</style>
    </main>
  );
}

/* ───────── Summaries ───────── */
function AdminSummary({ counts, onNew, onReset }) {
  return (
    <div className="admin-summary">
      <div className="summary-stats">
        <div className="stat">
          <div className="stat-num serif mono-num">{counts.submitted}</div>
          <div className="stat-label">awaiting your review</div>
        </div>
        <div className="stat">
          <div className="stat-num serif mono-num">{counts.open + counts.claimed_delaney}</div>
          <div className="stat-label">in flight</div>
        </div>
        <div className="stat">
          <div className="stat-num serif mono-num">{counts.paid}</div>
          <div className="stat-label">paid · all-time</div>
        </div>
      </div>
      <div className="summary-actions">
        <button className="btn btn--terracotta" onClick={onNew}>
          New task <span aria-hidden="true">→</span>
        </button>
        <button className="btn btn--ghost btn--sm" onClick={onReset} title="Reset to seed tasks">
          Reset
        </button>
      </div>
      <style>{`
        .admin-summary {
          display: flex;
          gap: 24px;
          justify-content: space-between;
          align-items: center;
          flex-wrap: wrap;
          padding: 28px 32px;
          border: 1px solid var(--line);
          border-radius: 4px;
          background: var(--cream-deep);
        }
        .summary-stats { display: flex; gap: clamp(24px, 5vw, 56px); }
        .stat { display: flex; flex-direction: column; gap: 2px; }
        .stat-num { font-size: 44px; line-height: 1; color: var(--charcoal); }
        .stat-label {
          font-size: 11px;
          letter-spacing: 0.15em;
          text-transform: uppercase;
          color: var(--ink-3);
        }
        .summary-actions { display: flex; gap: 10px; align-items: center; }
      `}</style>
    </div>
  );
}

function DelaneySummary({ earnings }) {
  return (
    <div className="delaney-summary">
      <div className="summary-stats">
        <div className="stat">
          <div className="stat-num serif mono-num">${earnings.inProgress}</div>
          <div className="stat-label">on your plate</div>
        </div>
        <div className="stat">
          <div className="stat-num serif mono-num" style={{ color: "var(--terracotta-deep)" }}>${earnings.pending}</div>
          <div className="stat-label">pending payment</div>
        </div>
        <div className="stat">
          <div className="stat-num serif mono-num" style={{ color: "var(--sage-deep)" }}>${earnings.paid}</div>
          <div className="stat-label">earned · all-time</div>
        </div>
      </div>
      <div className="delaney-note serif">
        <span className="script delaney-hi">hi del —</span>
        <span> nothing today is more than 90 minutes.</span>
      </div>
      <style>{`
        .delaney-summary {
          display: flex;
          gap: 24px;
          justify-content: space-between;
          align-items: center;
          flex-wrap: wrap;
          padding: 28px 32px;
          border: 1px solid var(--line);
          border-radius: 4px;
          background: var(--cream-deep);
        }
        .delaney-note { font-size: 16px; color: var(--ink-2); max-width: 280px; text-align: right; }
        .delaney-hi { color: var(--terracotta-deep); font-size: 22px; display: inline-block; margin-right: 4px; }
      `}</style>
    </div>
  );
}

/* ───────── Task row ───────── */
function TaskRow({ task, role, onClaim, onRelease, onSubmit, onApprove, onRequestRevision, onPay, onTogglePublic, onDelete }) {
  const [open, setOpen] = useStateT(task.status === "submitted" || task.status === "claimed_delaney");
  const [submitUrl, setSubmitUrl] = useStateT(task.deliverable_url || "");
  const [revisionNote, setRevisionNote] = useStateT("");
  const [showRev, setShowRev] = useStateT(false);

  return (
    <article className={"task-row task-row--" + task.status}>
      {/* Compact header */}
      <button className="task-head" onClick={() => setOpen((o) => !o)}>
        <div className="task-head-l">
          <span className="task-id mono-num">{task.id}</span>
          <StatusPill status={task.status} />
        </div>
        <div className="task-head-c serif">{task.title}</div>
        <div className="task-head-r">
          <span className="task-amount serif mono-num">${task.payout_usd}</span>
          <span className="task-when">{fmtRelative(task.created_at)}</span>
          <span className={"task-chev" + (open ? " is-open" : "")} aria-hidden="true">▾</span>
        </div>
      </button>

      {open && (
        <div className="task-body">
          {/* brief */}
          <div className="task-body-grid">
            <div>
              <div className="field-label">Brief</div>
              <p className="task-brief">{task.brief}</p>

              {task.links && task.links.length > 0 && (
                <>
                  <div className="field-label" style={{ marginTop: 20 }}>Links</div>
                  <ul className="task-links">
                    {task.links.map((l, i) => (
                      <li key={i}><a className="link-underline" href={l.url}>{l.label}</a></li>
                    ))}
                  </ul>
                </>
              )}

              {task.revision_note && task.status === "claimed_delaney" && (
                <div className="rev-note">
                  <div className="field-label" style={{ color: "var(--terracotta-deep)" }}>Revision requested</div>
                  <p>{task.revision_note}</p>
                </div>
              )}
            </div>

            <aside className="task-meta">
              <MetaLine label="Posted" value={fmtDate(task.created_at)} />
              {task.claimed_at && <MetaLine label="Claimed" value={fmtDate(task.claimed_at)} />}
              {task.submitted_at && <MetaLine label="Submitted" value={fmtDate(task.submitted_at)} />}
              {task.approved_at && <MetaLine label="Approved" value={fmtDate(task.approved_at)} />}
              {task.paid_at && <MetaLine label="Paid" value={fmtDate(task.paid_at)} />}

              {role === "admin" && (
                <label className="public-toggle">
                  <input
                    type="checkbox"
                    checked={!!task.is_public}
                    onChange={(e) => onTogglePublic(e.target.checked)}
                  />
                  <span>Auto-archive to portfolio when approved</span>
                </label>
              )}
            </aside>
          </div>

          {/* Action row */}
          <div className="task-actions">
            {/* DELANEY actions */}
            {role === "delaney" && task.status === "open" && (
              <button className="btn btn--terracotta" onClick={onClaim}>
                Claim this <span aria-hidden="true">→</span>
              </button>
            )}
            {role === "delaney" && task.status === "claimed_delaney" && (
              <div className="submit-form">
                <input
                  className="input"
                  placeholder="Paste deliverable URL (Google Doc, Figma, etc.)"
                  value={submitUrl}
                  onChange={(e) => setSubmitUrl(e.target.value)}
                />
                <button
                  className="btn"
                  onClick={() => submitUrl.trim() && onSubmit(submitUrl.trim())}
                  disabled={!submitUrl.trim()}
                  style={!submitUrl.trim() ? { opacity: 0.5, cursor: "not-allowed" } : undefined}
                >
                  Mark submitted <span aria-hidden="true">→</span>
                </button>
                <button className="btn btn--ghost btn--sm" onClick={onRelease}>
                  Release
                </button>
              </div>
            )}
            {role === "delaney" && task.status === "submitted" && (
              <div className="task-note">
                Submitted — waiting on review.
                {task.deliverable_url && <> <a className="link-underline" href={task.deliverable_url}>View deliverable</a></>}
              </div>
            )}

            {/* ADMIN actions */}
            {role === "admin" && task.status === "open" && (
              <div className="task-note">
                Posted. Waiting on Delaney to claim.
                <button className="btn btn--ghost btn--sm" onClick={onDelete} style={{ marginLeft: 12 }}>
                  Delete
                </button>
              </div>
            )}
            {role === "admin" && task.status === "claimed_delaney" && (
              <div className="task-note">
                In progress with Delaney since {fmtRelative(task.claimed_at)}.
              </div>
            )}
            {role === "admin" && task.status === "submitted" && (
              <div className="submit-form">
                {task.deliverable_url && (
                  <a className="btn btn--ghost" href={task.deliverable_url} target="_blank" rel="noopener noreferrer">
                    Open deliverable <span aria-hidden="true">↗</span>
                  </a>
                )}
                <button className="btn" onClick={onApprove}>
                  Approve <span aria-hidden="true">→</span>
                </button>
                <button
                  className="btn btn--ghost btn--sm"
                  onClick={() => setShowRev((s) => !s)}
                >
                  Request revision
                </button>
                {showRev && (
                  <div className="rev-input">
                    <textarea
                      className="textarea"
                      placeholder="What needs another pass?"
                      value={revisionNote}
                      onChange={(e) => setRevisionNote(e.target.value)}
                    />
                    <button
                      className="btn btn--sm"
                      onClick={() => { onRequestRevision(revisionNote); setShowRev(false); setRevisionNote(""); }}
                      disabled={!revisionNote.trim()}
                    >
                      Send back
                    </button>
                  </div>
                )}
              </div>
            )}
            {role === "admin" && task.status === "approved" && (
              <div className="submit-form">
                <div className="pay-amount serif">
                  <span className="eyebrow">Owe Delaney</span>
                  <span className="pay-amount-num mono-num">${task.payout_usd}</span>
                </div>
                <button className="btn btn--terracotta" onClick={onPay}>
                  Pay ${task.payout_usd} via Venmo <span aria-hidden="true">→</span>
                </button>
                <span className="task-note-inline">
                  → @delaney-ingalls
                </span>
              </div>
            )}
            {role === "admin" && task.status === "paid" && (
              <div className="task-note">
                Paid {fmtRelative(task.paid_at)} · ${task.payout_usd} sent to @delaney-ingalls
                {task.is_public && <span className="public-mark"> · auto-archived to portfolio</span>}
              </div>
            )}
          </div>
        </div>
      )}

      <style>{`
        .task-row {
          border: 1px solid var(--line);
          border-radius: 4px;
          background: var(--cream);
          overflow: hidden;
          transition: border-color var(--dur) var(--ease);
        }
        .task-row:hover { border-color: var(--line-strong); }
        .task-row--submitted { border-left: 3px solid var(--charcoal); }
        .task-row--approved { border-left: 3px solid var(--terracotta); }
        .task-row--paid { background: var(--cream-deep); }
        .task-row--paid .task-head-c { color: var(--ink-3); }

        .task-head {
          width: 100%;
          background: none;
          border: 0;
          padding: 20px 24px;
          display: grid;
          grid-template-columns: auto 1fr auto;
          gap: 24px;
          align-items: center;
          text-align: left;
          cursor: pointer;
          color: inherit;
        }
        .task-head-l { display: inline-flex; align-items: center; gap: 12px; }
        .task-id {
          font-size: 11px;
          letter-spacing: 0.08em;
          color: var(--ink-muted);
        }
        .task-head-c {
          font-size: 18px;
          color: var(--charcoal);
          line-height: 1.35;
        }
        .task-head-r {
          display: inline-flex;
          align-items: baseline;
          gap: 16px;
        }
        .task-amount { font-size: 22px; color: var(--charcoal); }
        .task-when { font-size: 12px; color: var(--ink-3); }
        .task-chev {
          font-size: 12px;
          color: var(--ink-3);
          transition: transform var(--dur) var(--ease);
        }
        .task-chev.is-open { transform: rotate(180deg); }

        .task-body {
          padding: 4px 24px 28px;
          border-top: 1px solid var(--line-soft);
        }
        .task-body-grid {
          display: grid;
          grid-template-columns: 1fr 220px;
          gap: 40px;
          margin: 16px 0 24px;
        }
        .task-brief {
          font-family: var(--serif);
          font-size: 17px;
          line-height: 1.55;
          color: var(--ink-2);
          margin: 0;
        }
        .task-links { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-direction: column; gap: 6px; font-size: 14px; }
        .task-meta { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; border-left: 1px solid var(--line); padding-left: 24px; }
        .public-toggle {
          display: flex;
          gap: 8px;
          font-size: 13px;
          color: var(--ink-2);
          margin-top: 16px;
          cursor: pointer;
          align-items: flex-start;
        }
        .public-toggle input { margin-top: 4px; accent-color: var(--terracotta); }
        .rev-note {
          margin-top: 20px;
          padding: 14px 16px;
          background: rgba(232, 199, 182, 0.4);
          border-left: 3px solid var(--terracotta);
          border-radius: 0 4px 4px 0;
          font-size: 14px;
        }
        .rev-note p { margin: 4px 0 0; color: var(--ink-2); font-family: var(--serif); font-size: 16px; line-height: 1.4; }

        .task-actions {
          padding-top: 20px;
          border-top: 1px dashed var(--line);
        }
        .submit-form {
          display: flex;
          align-items: center;
          gap: 12px;
          flex-wrap: wrap;
        }
        .submit-form .input { flex: 1; min-width: 240px; }
        .task-note { color: var(--ink-2); font-size: 14px; }
        .task-note-inline { color: var(--ink-3); font-size: 13px; }
        .pay-amount {
          display: inline-flex;
          flex-direction: column;
          padding-right: 16px;
          border-right: 1px solid var(--line);
        }
        .pay-amount-num { font-size: 28px; color: var(--charcoal); line-height: 1; margin-top: 2px; }
        .rev-input { flex-basis: 100%; display: flex; gap: 12px; align-items: flex-end; margin-top: 8px; }
        .rev-input .textarea { flex: 1; min-height: 64px; }
        .public-mark { color: var(--sage-deep); }

        @media (max-width: 720px) {
          .task-head { grid-template-columns: 1fr auto; }
          .task-head-c { grid-column: 1 / -1; }
          .task-body-grid { grid-template-columns: 1fr; gap: 20px; }
          .task-meta { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 16px; }
          .submit-form .input { min-width: 0; width: 100%; }
        }
      `}</style>
    </article>
  );
}

function MetaLine({ label, value }) {
  return (
    <div className="meta-line">
      <span className="meta-label">{label}</span>
      <span className="meta-value mono-num">{value}</span>
      <style>{`
        .meta-line { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
        .meta-label { color: var(--ink-3); }
        .meta-value { color: var(--charcoal); }
      `}</style>
    </div>
  );
}

/* ───────── Empty ───────── */
function EmptyState({ role, filter }) {
  const msg = role === "delaney"
    ? (filter === "open" ? "Nothing open right now. Check back later — usually a couple per day."
      : filter === "claimed_delaney" ? "Nothing on your plate. Pull from the open list."
      : filter === "submitted" ? "Nothing waiting on review."
      : "All clear.")
    : (filter === "submitted" ? "No submissions waiting on you."
      : filter === "open" ? "Nothing open. Drop a new task."
      : "Nothing here yet.");
  return (
    <div className="empty">
      <div className="empty-mark serif">¹</div>
      <p>{msg}</p>
      <style>{`
        .empty {
          padding: 80px 24px;
          border: 1px dashed var(--line-strong);
          border-radius: 4px;
          text-align: center;
          color: var(--ink-2);
          background: var(--cream-deep);
        }
        .empty-mark {
          font-size: 56px;
          color: var(--terracotta-deep);
          font-style: italic;
          margin-bottom: 8px;
        }
        .empty p { font-family: var(--serif); font-size: 18px; margin: 0; }
      `}</style>
    </div>
  );
}

/* ───────── Composer modal ───────── */
function ComposerModal({ onClose, onCreate, existingCount }) {
  const [title, setTitle] = useStateT("");
  const [brief, setBrief] = useStateT("");
  const [linkLabel, setLinkLabel] = useStateT("");
  const [linkUrl, setLinkUrl] = useStateT("");
  const [payout, setPayout] = useStateT(15);
  const [isPublic, setIsPublic] = useStateT(true);

  const create = () => {
    if (!title.trim()) return;
    const t = {
      id: "T-" + String(existingCount + 15).padStart(3, "0"),
      title: title.trim(),
      brief: brief.trim(),
      links: linkUrl.trim() ? [{ label: linkLabel.trim() || "Reference", url: linkUrl.trim() }] : [],
      payout_usd: Number(payout) || 15,
      status: "open",
      created_at: new Date().toISOString(),
      is_public: isPublic,
    };
    onCreate(t);
  };

  return (
    <div className="modal-bg" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <div className="eyebrow">New task</div>
            <h2 className="serif modal-h">Drop something on the board.</h2>
          </div>
          <button className="modal-close" onClick={onClose} aria-label="Close">×</button>
        </div>

        <div className="modal-body">
          <div className="field">
            <label className="field-label">Title</label>
            <input
              className="input"
              placeholder="e.g. Rewrite About page — Reed & Co."
              value={title}
              onChange={(e) => setTitle(e.target.value)}
              autoFocus
            />
          </div>
          <div className="field">
            <label className="field-label">Brief</label>
            <textarea
              className="textarea"
              placeholder="What's needed, who it's for, any constraints. The shorter the better — leave room for her to ask."
              value={brief}
              onChange={(e) => setBrief(e.target.value)}
            />
          </div>
          <div className="field-row">
            <div className="field">
              <label className="field-label">Link label</label>
              <input
                className="input"
                placeholder="Brand doc, wireframe, etc."
                value={linkLabel}
                onChange={(e) => setLinkLabel(e.target.value)}
              />
            </div>
            <div className="field">
              <label className="field-label">Link URL</label>
              <input
                className="input"
                placeholder="https://…"
                value={linkUrl}
                onChange={(e) => setLinkUrl(e.target.value)}
              />
            </div>
          </div>
          <div className="field-row">
            <div className="field">
              <label className="field-label">Payout (USD)</label>
              <input
                className="input"
                type="number"
                min={5}
                step={5}
                value={payout}
                onChange={(e) => setPayout(e.target.value)}
              />
            </div>
            <div className="field" style={{ display: "flex", alignItems: "flex-end" }}>
              <label className="public-toggle" style={{ marginTop: 0 }}>
                <input
                  type="checkbox"
                  checked={isPublic}
                  onChange={(e) => setIsPublic(e.target.checked)}
                />
                <span>Auto-archive to portfolio when approved</span>
              </label>
            </div>
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn btn--ghost" onClick={onClose}>Cancel</button>
          <button
            className="btn btn--terracotta"
            onClick={create}
            disabled={!title.trim()}
            style={!title.trim() ? { opacity: 0.5, cursor: "not-allowed" } : undefined}
          >
            Post task <span aria-hidden="true">→</span>
          </button>
        </div>
      </div>
      <style>{`
        .modal-bg {
          position: fixed;
          inset: 0;
          z-index: 100;
          background: rgba(42, 42, 42, 0.4);
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 24px;
          animation: fade-in 200ms var(--ease) both;
        }
        @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
        .modal {
          width: 100%;
          max-width: 640px;
          max-height: 90vh;
          overflow: auto;
          background: var(--cream);
          border: 1px solid var(--line);
          border-radius: 6px;
          display: flex;
          flex-direction: column;
          animation: rise-in 240ms var(--ease) both;
        }
        @keyframes rise-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
        .modal-head {
          display: flex;
          justify-content: space-between;
          align-items: flex-start;
          padding: 28px 32px 16px;
          gap: 24px;
        }
        .modal-h { font-size: 28px; line-height: 1.1; margin-top: 6px; }
        .modal-close {
          background: none;
          border: 0;
          font-size: 28px;
          line-height: 1;
          color: var(--ink-3);
          padding: 4px 10px;
        }
        .modal-close:hover { color: var(--charcoal); }
        .modal-body {
          padding: 8px 32px 24px;
          display: flex;
          flex-direction: column;
          gap: 18px;
        }
        .field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
        .field { display: flex; flex-direction: column; }
        .modal-foot {
          padding: 20px 32px;
          border-top: 1px solid var(--line);
          display: flex;
          justify-content: flex-end;
          gap: 12px;
        }
        @media (max-width: 540px) {
          .field-row { grid-template-columns: 1fr; }
        }
      `}</style>
    </div>
  );
}

/* ───────── Paid confirm popover ───────── */
function PaidConfirm({ info, onClose }) {
  return (
    <div className="paid-bg" onClick={onClose}>
      <div className="paid" onClick={(e) => e.stopPropagation()}>
        <div className="paid-mark serif">✓</div>
        <h3 className="serif paid-h">Venmo opened for ${info.amount}.</h3>
        <p>
          If your phone caught it, the request is on screen.
          If not — click below to retry.
        </p>
        <div className="paid-actions">
          <a className="btn btn--terracotta" href={info.link}>
            Open Venmo again
          </a>
          <button className="btn btn--ghost" onClick={onClose}>
            Close
          </button>
        </div>
        <div className="paid-link mono-num">{info.link}</div>
      </div>
      <style>{`
        .paid-bg {
          position: fixed;
          inset: 0;
          z-index: 100;
          background: rgba(42, 42, 42, 0.4);
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 24px;
          animation: fade-in 200ms var(--ease) both;
        }
        .paid {
          background: var(--cream);
          border: 1px solid var(--line);
          border-radius: 6px;
          padding: 36px 40px;
          max-width: 460px;
          width: 100%;
          text-align: center;
          animation: rise-in 240ms var(--ease) both;
        }
        .paid-mark {
          width: 56px; height: 56px;
          border-radius: 999px;
          background: var(--sage-soft);
          color: var(--sage-deep);
          display: inline-flex;
          align-items: center;
          justify-content: center;
          font-size: 28px;
          margin-bottom: 16px;
        }
        .paid-h { font-size: 26px; line-height: 1.15; }
        .paid p { color: var(--ink-2); margin: 12px 0 20px; font-family: var(--serif); font-size: 17px; }
        .paid-actions { display: flex; gap: 12px; justify-content: center; }
        .paid-link {
          margin-top: 20px;
          font-size: 11px;
          color: var(--ink-3);
          word-break: break-all;
          padding: 10px;
          background: var(--cream-deep);
          border-radius: 4px;
        }
      `}</style>
    </div>
  );
}

Object.assign(window, { TasksPage });
