/* === Tags, Stats, Goals, Settings === */

function TagsScreen({ state, setState }) {
  const { tags, expenses, activeMonth } = state;

  // Active month spending per tag
  const monthSpend = {};
  const monthCount = {};
  expenses.forEach(e => {
    monthSpend[e.tagId] = (monthSpend[e.tagId] || 0) + e.amount;
    monthCount[e.tagId] = (monthCount[e.tagId] || 0) + 1;
  });

  const [editingId, setEditingId] = React.useState(null);
  const [draftName, setDraftName] = React.useState('');
  const [draftColor, setDraftColor] = React.useState('terracotta');
  const [draftBudget, setDraftBudget] = React.useState(0);
  const [draftMode, setDraftMode] = React.useState('tracked'); // 'tracked' | 'budgeted'

  const [newName, setNewName] = React.useState('');
  const [newColor, setNewColor] = React.useState('terracotta');
  const [newBudget, setNewBudget] = React.useState('');
  const [newMode, setNewMode] = React.useState('tracked');

  const [filterMode, setFilterMode] = React.useState('all'); // 'all' | 'budgeted' | 'tracked'

  const startEdit = (t) => {
    setEditingId(t.id);
    setDraftName(t.name);
    setDraftColor(t.color);
    setDraftBudget(t.budget || 0);
    setDraftMode((t.budget || 0) > 0 ? 'budgeted' : 'tracked');
  };
  const saveEdit = () => {
    setState(s => ({
      ...s,
      tags: s.tags.map(t => t.id === editingId
        ? {
            ...t,
            name: draftName,
            color: draftColor,
            budget: draftMode === 'budgeted' ? (parseFloat(draftBudget) || 0) : 0
          }
        : t)
    }));
    setEditingId(null);
  };
  const cancelEdit = () => setEditingId(null);

  const addTag = () => {
    if (!newName.trim()) return;
    const id = newName.toLowerCase().replace(/\s+/g, '-') + '-' + Date.now().toString(36).slice(-3);
    setState(s => ({ ...s, tags: [...s.tags, {
      id,
      name: newName.trim(),
      color: newColor,
      budget: newMode === 'budgeted' ? (parseFloat(newBudget) || 0) : 0
    }] }));
    setNewName(''); setNewBudget(''); setNewMode('tracked');
  };

  // Totals
  const budgetedTags = tags.filter(t => (t.budget || 0) > 0);
  const trackedTags = tags.filter(t => !(t.budget > 0));
  const budgetTotal = budgetedTags.reduce((s, t) => s + t.budget, 0);
  const spentTotal = tags.reduce((s, t) => s + (monthSpend[t.id] || 0), 0);
  const overCount = budgetedTags.filter(t => (monthSpend[t.id] || 0) > t.budget).length;

  // Filtered + sorted
  const visible = tags.filter(t => {
    if (filterMode === 'budgeted') return (t.budget || 0) > 0;
    if (filterMode === 'tracked')  return !(t.budget > 0);
    return true;
  });
  const sorted = [...visible].sort((a, b) => {
    const aHas = (a.budget || 0) > 0, bHas = (b.budget || 0) > 0;
    if (aHas && !bHas) return -1;
    if (!aHas && bHas) return 1;
    if (aHas && bHas) return ((monthSpend[b.id] || 0) / b.budget) - ((monthSpend[a.id] || 0) / a.budget);
    return (monthSpend[b.id] || 0) - (monthSpend[a.id] || 0);
  });

  return (
    <>
      <div className="page-head">
        <div>
          <div className="page-sub">{formatMonthKey(activeMonth)} · {budgetedTags.length} budgeted · {trackedTags.length} tracked{overCount > 0 ? ` · ${overCount} over` : ''}</div>
          <h1 className="page-title">Tags &amp; budgets</h1>
        </div>
        <div className="seg seg-sm">
          <button className={`seg-btn ${filterMode === 'all' ? 'active' : ''}`}      onClick={() => setFilterMode('all')}>All <span className="seg-count">{tags.length}</span></button>
          <button className={`seg-btn ${filterMode === 'budgeted' ? 'active' : ''}`} onClick={() => setFilterMode('budgeted')}>Budgeted <span className="seg-count">{budgetedTags.length}</span></button>
          <button className={`seg-btn ${filterMode === 'tracked' ? 'active' : ''}`}  onClick={() => setFilterMode('tracked')}>Tracked <span className="seg-count">{trackedTags.length}</span></button>
        </div>
      </div>

      <div style={{ padding: '20px 28px 28px', display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) 320px', gap: 22, alignItems: 'start' }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {sorted.map(t => {
            const spent = monthSpend[t.id] || 0;
            const count = monthCount[t.id] || 0;
            const budget = t.budget || 0;
            const hasBudget = budget > 0;
            const pct = hasBudget ? Math.min((spent / budget) * 100, 130) : 0;
            const over = hasBudget && spent > budget;
            const status = !hasBudget ? 'tracked' : over ? 'over' : pct >= 85 ? 'warn' : pct >= 50 ? 'good' : 'low';
            const isEditing = editingId === t.id;
            const accent = TAG_COLORS[t.color];

            if (isEditing) {
              return (
                <div key={t.id} className="tag-card editing">
                  <span className="tag-card-accent" style={{ background: TAG_COLORS[draftColor] }} />
                  <div className="tag-edit-row">
                    <input className="input" value={draftName} onChange={e => setDraftName(e.target.value)} placeholder="Tag name" />
                    <div className="seg seg-sm">
                      <button className={`seg-btn ${draftMode === 'tracked' ? 'active' : ''}`}  onClick={() => setDraftMode('tracked')}>Tracked</button>
                      <button className={`seg-btn ${draftMode === 'budgeted' ? 'active' : ''}`} onClick={() => setDraftMode('budgeted')}>Budgeted</button>
                    </div>
                    {draftMode === 'budgeted' && (
                      <div className="amount-wrap" style={{ width: 110 }}>
                        <input className="input amount" type="number" step="10" value={draftBudget}
                          onChange={e => setDraftBudget(e.target.value)} placeholder="0" autoFocus />
                      </div>
                    )}
                  </div>
                  <div className="tag-edit-row">
                    <div className="color-grid" style={{ gridTemplateColumns: 'repeat(10, 1fr)', gap: 5, flex: 1 }}>
                      {Object.entries(TAG_COLORS).map(([key, hex]) => (
                        <div key={key}
                          className={`color-swatch ${draftColor === key ? 'selected' : ''}`}
                          style={{ background: hex }}
                          onClick={() => setDraftColor(key)} />
                      ))}
                    </div>
                    <div className="row gap-sm">
                      <button className="btn ghost" onClick={cancelEdit}>Cancel</button>
                      <button className="btn primary" onClick={saveEdit}>Save</button>
                    </div>
                  </div>
                </div>
              );
            }

            return (
              <div key={t.id} className={`tag-card ${status}`}>
                <span className="tag-card-accent" style={{ background: accent }} />

                <div className="tag-card-head">
                  <div className="tag-card-id">
                    <Tag tag={t} />
                    {!hasBudget && <span className="kind-pill tracked">Tracked</span>}
                    <span className="muted mono" style={{ fontSize: 10.5 }}>
                      {count} {count === 1 ? 'txn' : 'txns'} · {formatMonthKeyShort(activeMonth)}
                    </span>
                  </div>

                  {/* Inline edit/delete sit at the far left of the right column,
                      with the figures pinned to the right. No overlap. */}
                  <div className="tag-card-right">
                    <div className="tag-card-actions">
                      <button className="btn ghost icon-btn" title="Edit tag" onClick={() => startEdit(t)}>
                        <svg width="11" height="11" viewBox="0 0 12 12" fill="none">
                          <path d="M8.5 1.5l2 2L4 10l-2.5.5L2 8l6.5-6.5z" stroke="currentColor" strokeWidth="1" strokeLinejoin="round"/>
                        </svg>
                      </button>
                      <button className="btn ghost icon-btn danger" title="Delete tag"
                        onClick={() => setState(s => ({ ...s, tags: s.tags.filter(x => x.id !== t.id) }))}>×</button>
                    </div>
                    <div className="tag-card-amount">
                      <span className="num" style={{ fontSize: 14, color: over ? 'var(--neg)' : 'var(--ink)' }}>
                        {fmt(spent, { cents: false })}
                      </span>
                      {hasBudget && (
                        <span className="muted num" style={{ fontSize: 11, marginLeft: 4 }}>
                          / {fmt(budget, { cents: false })}
                        </span>
                      )}
                    </div>
                  </div>
                </div>

                {hasBudget ? (
                  <div className="tag-budget-bar">
                    <div className="bar-track">
                      <div className={`bar-progress ${status}`}
                        style={{ width: Math.min(pct, 100) + '%', background: over ? 'var(--neg)' : accent }} />
                      {over && (
                        <div className="bar-overflow"
                          style={{ width: Math.min(pct - 100, 30) + '%' }} />
                      )}
                    </div>
                    <div className="bar-meta">
                      <span className={`pill ${status}`}>
                        {over
                          ? `${fmt(spent - budget, { cents: false })} over`
                          : pct >= 85 ? 'near limit'
                          : pct >= 50 ? 'on track'
                          : 'plenty left'}
                      </span>
                      <span className="muted num" style={{ fontSize: 10.5 }}>
                        {Math.round(pct)}% · {fmt(Math.max(0, budget - spent), { cents: false })} left
                      </span>
                    </div>
                  </div>
                ) : (
                  <div className="tag-tracked-meta">
                    <span className="muted" style={{ fontSize: 11 }}>
                      No budget — spending is tracked only.
                    </span>
                    <button className="btn ghost set-budget-link" onClick={() => startEdit(t)}>
                      Set monthly budget →
                    </button>
                  </div>
                )}
              </div>
            );
          })}
          {sorted.length === 0 && (
            <div className="muted" style={{ padding: '40px 0', textAlign: 'center', fontSize: 12 }}>
              No {filterMode === 'budgeted' ? 'budgeted' : filterMode === 'tracked' ? 'tracked-only' : ''} tags yet.
            </div>
          )}
        </div>

        <div className="card" style={{ position: 'sticky', top: 0 }}>
          <div className="card-section">New tag</div>
          <div className="field" style={{ marginBottom: 12 }}>
            <span className="field-label">Name</span>
            <input className="input" value={newName} onChange={e => setNewName(e.target.value)} placeholder="e.g. Coffee" />
          </div>
          <div className="field" style={{ marginBottom: 12 }}>
            <span className="field-label">Type</span>
            <div className="seg seg-sm" style={{ width: '100%' }}>
              <button className={`seg-btn ${newMode === 'tracked' ? 'active' : ''}`}  style={{ flex: 1 }} onClick={() => setNewMode('tracked')}>Tracked only</button>
              <button className={`seg-btn ${newMode === 'budgeted' ? 'active' : ''}`} style={{ flex: 1 }} onClick={() => setNewMode('budgeted')}>Budgeted</button>
            </div>
            <div className="muted" style={{ fontSize: 10.5, marginTop: 6, lineHeight: 1.4 }}>
              {newMode === 'tracked'
                ? 'Just labels expenses. No monthly limit.'
                : 'Sets a monthly cap. Shows progress bars and over-budget alerts.'}
            </div>
          </div>
          {newMode === 'budgeted' && (
            <div className="field" style={{ marginBottom: 12 }}>
              <span className="field-label">Monthly budget</span>
              <div className="amount-wrap">
                <input className="input amount" type="number" step="10" value={newBudget}
                  onChange={e => setNewBudget(e.target.value)} placeholder="0" />
              </div>
            </div>
          )}
          <div className="field" style={{ marginBottom: 16 }}>
            <span className="field-label">Color</span>
            <div className="color-grid">
              {Object.entries(TAG_COLORS).map(([key, hex]) => (
                <div
                  key={key}
                  className={`color-swatch ${newColor === key ? 'selected' : ''}`}
                  style={{ background: hex }}
                  onClick={() => setNewColor(key)}
                />
              ))}
            </div>
          </div>
          <div style={{ marginBottom: 16 }}>
            <span className="field-label" style={{ display: 'block', marginBottom: 6 }}>Preview</span>
            <Tag tag={{ name: newName || 'tag name', color: newColor }} />
          </div>
          <button className="btn primary" style={{ width: '100%', justifyContent: 'center' }} onClick={addTag}>
            Add tag
          </button>

          <div className="divider" />
          <div className="eyebrow" style={{ marginBottom: 8 }}>This month</div>
          <div className="between" style={{ fontSize: 12 }}>
            <span className="muted">Total budgeted</span>
            <span className="num">{fmt(budgetTotal, { cents: false })}</span>
          </div>
          <div className="between" style={{ fontSize: 12, marginTop: 4 }}>
            <span className="muted">Total spent</span>
            <span className="num" style={{ color: spentTotal > budgetTotal && budgetTotal > 0 ? 'var(--neg)' : 'var(--ink)' }}>
              {fmt(spentTotal, { cents: false })}
            </span>
          </div>
          <div className="between" style={{ fontSize: 12, marginTop: 4 }}>
            <span className="muted">Tags over budget</span>
            <span className="num" style={{ color: overCount > 0 ? 'var(--neg)' : 'var(--ink-3)' }}>{overCount}</span>
          </div>
        </div>
      </div>
    </>
  );
}

function GoalsScreen({ state, setState, setOpenModal, setEditingGoal }) {
  const { goals, pool, poolLedger, closedMonths, activeMonth, income, fixed, expenses, extra, _allExpenses, _allExtra } = state;

  const goalsTotal = goals.reduce((s, g) => s + g.saved, 0);
  const liquidTotal = pool + goalsTotal;
  const goalsTarget = goals.reduce((s, g) => s + g.target, 0);

  // Active month P&L (uses month-filtered viewState data)
  const fixedTotal = fixed.reduce((s, f) => s + monthlyEquiv(f), 0);
  const expensesTotal = expenses.reduce((s, e) => s + e.amount, 0);
  const extraTotal = (extra || []).reduce((s, x) => s + x.amount, 0);
  const monthRemaining = income + extraTotal - fixedTotal - expensesTotal;
  const isMonthClosed = (closedMonths || []).includes(activeMonth);

  // Modals
  const [showCloseout, setShowCloseout] = React.useState(false);
  const [showAdjust, setShowAdjust] = React.useState(false);
  const [adjustMode, setAdjustMode] = React.useState('add'); // add | withdraw | set
  const [adjustAmount, setAdjustAmount] = React.useState('');
  const [adjustNote, setAdjustNote] = React.useState('');

  const commitCloseout = () => {
    const amount = monthRemaining;
    setState(s => ({
      ...s,
      pool: s.pool + amount,
      poolLedger: [
        { id: 'p' + Date.now().toString(36), date: TODAY.toISOString().slice(0, 10),
          amount, kind: 'closeout', monthKey: activeMonth,
          note: amount >= 0 ? `${formatMonthKeyShort(activeMonth)} surplus` : `${formatMonthKeyShort(activeMonth)} overspend` },
        ...s.poolLedger,
      ],
      closedMonths: [...s.closedMonths, activeMonth],
    }));
  };

  const commitAdjust = () => {
    const n = parseFloat(adjustAmount);
    if (isNaN(n)) return;
    let delta, kind;
    if (adjustMode === 'set') { delta = n - pool; kind = 'adjust'; }
    else if (adjustMode === 'withdraw') { delta = -Math.abs(n); kind = 'adjust'; }
    else { delta = Math.abs(n); kind = 'adjust'; }
    setState(s => ({
      ...s,
      pool: s.pool + delta,
      poolLedger: [
        { id: 'p' + Date.now().toString(36), date: TODAY.toISOString().slice(0, 10),
          amount: delta, kind, note: adjustNote || (adjustMode === 'set' ? `Set to ${fmt(n, { cents: false })}` : adjustMode === 'withdraw' ? 'Manual withdrawal' : 'Manual deposit') },
        ...s.poolLedger,
      ],
    }));
    setAdjustAmount(''); setAdjustNote(''); setAdjustMode('add');
  };

  const deposit = (gid, amount) => {
    if (amount > pool) return; // could allow negative pool but lets keep simple
    setState(s => ({
      ...s,
      pool: s.pool - amount,
      goals: s.goals.map(g => g.id === gid ? { ...g, saved: g.saved + amount } : g),
      poolLedger: [
        { id: 'p' + Date.now().toString(36), date: TODAY.toISOString().slice(0, 10),
          amount: -amount, kind: 'goal-deposit', goalId: gid,
          note: 'Deposit → ' + s.goals.find(g => g.id === gid).name },
        ...s.poolLedger,
      ],
    }));
  };

  // Pool activity: collapsed shows 8 most recent; expanded shows full history.
  const [showAllLedger, setShowAllLedger] = React.useState(false);
  const fullLedger = poolLedger || [];
  const recentLedger = showAllLedger ? fullLedger : fullLedger.slice(0, 8);

  return (
    <>
      <div className="page-head">
        <div>
          <div className="page-sub">Liquid total · {goals.length} goals · pool {fmt(pool, { cents: false })}</div>
          <h1 className="page-title">Savings</h1>
        </div>
        <div className="row gap-sm">
          {!isMonthClosed && (
            <button className="btn primary" onClick={() => setShowCloseout(true)}>
              Close out {formatMonthKeyShort(activeMonth)}
            </button>
          )}
          <button className="btn" onClick={() => setOpenModal('goal')}>+ New goal</button>
        </div>
      </div>

      <div style={{ padding: '20px 28px 28px' }}>
        {/* Big-picture liquid total */}
        <div className="savings-hero">
          <div className="savings-hero-main">
            <div className="eyebrow">Total liquid savings</div>
            <div className="savings-hero-amount">
              {fmt(liquidTotal, { cents: false })}
            </div>
            <div className="savings-hero-split">
              <div className="split-cell">
                <div className="split-label">Unallocated pool</div>
                <div className="split-amt num">{fmt(pool, { cents: false })}</div>
                <div className="split-bar"><div className="split-fill pool" style={{ width: liquidTotal > 0 ? (pool / liquidTotal) * 100 + '%' : 0 }} /></div>
              </div>
              <div className="split-cell">
                <div className="split-label">Across {goals.length} goals</div>
                <div className="split-amt num">{fmt(goalsTotal, { cents: false })}</div>
                <div className="split-bar"><div className="split-fill goals" style={{ width: liquidTotal > 0 ? (goalsTotal / liquidTotal) * 100 + '%' : 0 }} /></div>
              </div>
              <div className="split-cell">
                <div className="split-label">Combined target</div>
                <div className="split-amt num muted">{fmt(goalsTarget, { cents: false })}</div>
                <div className="split-bar"><div className="split-fill" style={{ width: goalsTarget > 0 ? Math.min((goalsTotal / goalsTarget) * 100, 100) + '%' : 0, background: 'var(--ink-3)' }} /></div>
              </div>
            </div>
          </div>

          <div className="savings-hero-side">
            {!isMonthClosed ? (
              <div className="closeout-preview">
                <div className="eyebrow">{formatMonthKeyShort(activeMonth)} pending close-out</div>
                <div className="closeout-amount num" style={{ color: monthRemaining >= 0 ? 'var(--pos)' : 'var(--neg)' }}>
                  {monthRemaining >= 0 ? '+' : '−'}{fmt(Math.abs(monthRemaining), { cents: false })}
                </div>
                <div className="muted" style={{ fontSize: 11, marginBottom: 10 }}>
                  {monthRemaining >= 0
                    ? `Surplus moves to your savings pool when you close out.`
                    : `Overspend deducts from your pool when you close out.`}
                </div>
                <button className="btn primary" style={{ width: '100%', justifyContent: 'center' }}
                  onClick={() => setShowCloseout(true)}>
                  Close out {formatMonthKeyShort(activeMonth)}
                </button>
              </div>
            ) : (
              <div className="closeout-preview closed">
                <div className="eyebrow">{formatMonthKeyShort(activeMonth)}</div>
                <div className="closeout-amount num" style={{ color: 'var(--ink-3)' }}>Closed</div>
                <div className="muted" style={{ fontSize: 11 }}>
                  This month has already been settled to your savings pool.
                </div>
              </div>
            )}
          </div>
        </div>

        {/* Pool actions row */}
        <div className="pool-actions">
          <button className="btn" onClick={() => { setAdjustMode('add'); setShowAdjust(true); }}>+ Add to pool</button>
          <button className="btn" onClick={() => { setAdjustMode('withdraw'); setShowAdjust(true); }}>− Withdraw</button>
          <button className="btn" onClick={() => { setAdjustMode('set'); setAdjustAmount(String(pool)); setShowAdjust(true); }}>Set pool balance…</button>
        </div>

        {/* Two columns: goals + recent ledger */}
        <div className="goals-layout">
          <div>
            <div className="section-head"><span>Savings goals</span><span className="muted">{fmt(goalsTotal, { cents: false })} of {fmt(goalsTarget, { cents: false })}</span></div>
            <div className="goals-grid">
              {goals.map(g => {
                const pct = Math.min((g.saved / g.target) * 100, 100);
                const remaining = g.target - g.saved;
                const months = monthsUntil(g.deadline);
                const requiredMonthly = months > 0 ? remaining / months : remaining;
                const onTrack = g.monthly >= requiredMonthly;
                const projDate = new Date(TODAY);
                projDate.setMonth(projDate.getMonth() + Math.ceil(remaining / g.monthly));
                const projStr = projDate.toLocaleDateString('en', { month: 'short', year: 'numeric' });
                const targetStr = new Date(g.deadline + 'T00:00:00').toLocaleDateString('en', { month: 'short', year: 'numeric' });

                const setGoalPhoto = async (file) => {
                  if (!file) return;
                  try {
                    const dataUrl = await resizeImageFile(file);
                    setState(s => ({ ...s, goals: s.goals.map(x => x.id === g.id ? { ...x, photo: dataUrl } : x) }));
                  } catch (err) { /* swallow — quietly ignore non-images */ }
                };
                const clearGoalPhoto = () => {
                  setState(s => ({ ...s, goals: s.goals.map(x => x.id === g.id ? { ...x, photo: null } : x) }));
                };

                return (
                  <div key={g.id} className={`goal ${g.photo ? 'has-photo' : ''}`}>
                    {g.photo ? (
                      <label
                        className="goal-photo-banner"
                        style={{ backgroundImage: `url(${g.photo})` }}
                        title="Click to replace photo · right-click to remove"
                        onContextMenu={e => { e.preventDefault(); clearGoalPhoto(); }}>
                        <input type="file" accept="image/*" style={{ display: 'none' }}
                          onChange={e => setGoalPhoto(e.target.files?.[0])} />
                      </label>
                    ) : (
                      <label
                        className="goal-emblem"
                        style={{ background: TAG_COLORS[g.color] }}
                        title="Click to add a photo">
                        <input type="file" accept="image/*" style={{ display: 'none' }}
                          onChange={e => setGoalPhoto(e.target.files?.[0])} />
                      </label>
                    )}
                    <div>
                      <div className="goal-name">{g.name}</div>
                      <div className="goal-target">target {targetStr}</div>
                    </div>
                    <div>
                      <div className="goal-amt">
                        {fmt(g.saved, { cents: false })}
                        <span className="of">/ {fmt(g.target, { cents: false })}</span>
                      </div>
                      <div className="progress" style={{ marginTop: 8 }}>
                        <div className="progress-bar" style={{ width: pct + '%', background: TAG_COLORS[g.color] }} />
                      </div>
                    </div>
                    <div className="goal-projection">
                      <span>contributing <strong className="num" style={{ color: 'var(--ink)' }}>{fmt(g.monthly, { cents: false })}</strong>/mo</span>
                      <span className={onTrack ? 'ok' : 'late'}>
                        {onTrack ? 'on track · ' : 'short · '} reach {projStr}
                      </span>
                    </div>
                    <div className="row gap-sm">
                      <button className="btn primary" style={{ flex: 1, justifyContent: 'center' }}
                        onClick={() => deposit(g.id, g.monthly)}
                        disabled={pool < g.monthly}
                        title={pool < g.monthly ? 'Pool balance is too low' : ''}>
                        + Deposit {fmt(g.monthly, { cents: false })}
                      </button>
                      <button className="btn" onClick={() => {
                        const v = prompt('Amount to move from pool to ' + g.name + ':', '50');
                        const n = parseFloat(v);
                        if (!isNaN(n) && n > 0) deposit(g.id, n);
                      }}>Custom</button>
                      <button className="btn ghost" title="Edit goal"
                        onClick={() => { setEditingGoal(g); setOpenModal('goal'); }}>Edit</button>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>

          {/* Pool ledger */}
          <div className="card pool-ledger-card">
            <div className="card-section">Pool activity</div>
            {recentLedger.length === 0 && (
              <div className="muted" style={{ fontSize: 12, padding: '8px 0' }}>No activity yet.</div>
            )}
            {recentLedger.map(entry => {
              const positive = entry.amount >= 0;
              const kindLabel =
                entry.kind === 'closeout'      ? 'Month close-out'
              : entry.kind === 'goal-deposit' ? 'Goal deposit'
              : entry.kind === 'goal-withdraw'? 'Goal withdrawal'
              :                                  'Adjustment';
              return (
                <div key={entry.id} className="ledger-entry">
                  <div className="ledger-meta">
                    <div className="ledger-kind">
                      <span className={`ledger-dot ${entry.kind}`} />
                      {kindLabel}
                    </div>
                    <div className="ledger-note muted">{entry.note}</div>
                    <div className="ledger-date muted mono">{entry.date}</div>
                  </div>
                  <div className={`ledger-amt num ${positive ? 'pos' : 'neg'}`}>
                    {positive ? '+' : '−'}{fmt(Math.abs(entry.amount), { cents: false })}
                  </div>
                </div>
              );
            })}
            {fullLedger.length > 8 && (
              <div style={{ marginTop: 6, textAlign: 'center' }}>
                <button className="btn ghost" style={{ height: 24, fontSize: 11, padding: '0 10px' }}
                  onClick={() => setShowAllLedger(v => !v)}>
                  {showAllLedger ? 'Show less' : `View all (${fullLedger.length})`}
                </button>
              </div>
            )}
            <div className="divider" />
            <div className="between" style={{ fontSize: 11.5 }}>
              <span className="muted">Pool balance</span>
              <span className="num" style={{ fontWeight: 600 }}>{fmt(pool, { cents: false })}</span>
            </div>
          </div>
        </div>
      </div>

      {/* Close-out modal */}
      {showCloseout && (
        <Sheet onClose={() => setShowCloseout(false)} modalStyle={{ width: 460 }}>
          {(closeSheet) => (<>
            <div className="modal-header">
              <div className="modal-sub">Settle the month to your pool</div>
              <div className="modal-title">Close out {formatMonthKey(activeMonth)}</div>
            </div>
            <div className="modal-body">
              <div>
                <div className="closeout-row">
                  <span className="label">Income</span>
                  <span className="num">{fmt(income)}</span>
                </div>
                {extraTotal > 0 && (
                  <div className="closeout-row">
                    <span className="label">+ Extra income</span>
                    <span className="num pos">+{fmt(extraTotal)}</span>
                  </div>
                )}
                <div className="closeout-row">
                  <span className="label">− Fixed costs</span>
                  <span className="num neg">−{fmt(fixedTotal)}</span>
                </div>
                <div className="closeout-row">
                  <span className="label">− Variable spending</span>
                  <span className="num neg">−{fmt(expensesTotal)}</span>
                </div>
                <div className="closeout-row total">
                  <span className="label">Net for the month</span>
                  <span className="num" style={{ color: monthRemaining >= 0 ? 'var(--pos)' : 'var(--neg)' }}>
                    {monthRemaining >= 0 ? '+' : '−'}{fmt(Math.abs(monthRemaining))}
                  </span>
                </div>
              </div>

              <div className="pool-effect">
                <div className="effect-cell">
                  <div className="effect-label">Pool now</div>
                  <div className="effect-num">{fmt(pool, { cents: false })}</div>
                </div>
                <div className="effect-arrow">→</div>
                <div className="effect-cell">
                  <div className="effect-label">After close-out</div>
                  <div className="effect-num strong" style={{ color: monthRemaining >= 0 ? 'var(--pos)' : 'var(--neg)' }}>
                    {fmt(pool + monthRemaining, { cents: false })}
                  </div>
                </div>
              </div>

              <p className="modal-helper">
                Closing out moves your {monthRemaining >= 0 ? 'surplus into' : 'overspend out of'} your savings pool and locks the month so it can't be re-counted.
              </p>
            </div>
            <div className="modal-footer">
              <button className="btn ghost" onClick={closeSheet}>Cancel</button>
              <button className="btn primary" onClick={() => { commitCloseout(); closeSheet(); }}>
                {monthRemaining >= 0 ? 'Move to pool' : 'Subtract from pool'}
              </button>
            </div>
          </>)}
        </Sheet>
      )}

      {/* Adjust pool modal */}
      {showAdjust && (() => {
        const n = parseFloat(adjustAmount);
        const hasN = !isNaN(n);
        const after = !hasN ? pool
          : adjustMode === 'set'      ? n
          : adjustMode === 'withdraw' ? pool - Math.abs(n)
          :                              pool + Math.abs(n);
        const delta = after - pool;
        const subMap = {
          add:      'Manual deposit · increases your pool',
          withdraw: 'Manual withdrawal · decreases your pool',
          set:      'Reconcile your pool to a known balance',
        };
        const titleMap = {
          add:      'Add to savings pool',
          withdraw: 'Withdraw from pool',
          set:      'Set pool balance',
        };
        return (
          <Sheet onClose={() => setShowAdjust(false)} modalStyle={{ width: 420 }}>
            {(closeSheet) => (<>
              <div className="modal-header">
                <div className="modal-sub">{subMap[adjustMode]}</div>
                <div className="modal-title">{titleMap[adjustMode]}</div>
              </div>
              <div className="modal-body">
                <div className="seg seg-sm pool-mode-seg">
                  <button className={`seg-btn ${adjustMode === 'add' ? 'active' : ''}`}      onClick={() => setAdjustMode('add')}>+ Add</button>
                  <button className={`seg-btn ${adjustMode === 'withdraw' ? 'active' : ''}`} onClick={() => setAdjustMode('withdraw')}>− Withdraw</button>
                  <button className={`seg-btn ${adjustMode === 'set' ? 'active' : ''}`}      onClick={() => { setAdjustMode('set'); setAdjustAmount(String(pool)); }}>Set total</button>
                </div>

                <div className="field">
                  <span className="field-label">{adjustMode === 'set' ? 'New pool balance' : 'Amount'}</span>
                  <div className="amount-wrap">
                    <input className="input amount" type="number" step="10" autoFocus
                      value={adjustAmount} onChange={e => setAdjustAmount(e.target.value)} placeholder="0.00" />
                  </div>
                </div>

                <div className="field">
                  <span className="field-label">Note <span className="muted" style={{ textTransform: 'none', letterSpacing: 0, fontWeight: 400 }}>(optional)</span></span>
                  <input className="input" value={adjustNote} onChange={e => setAdjustNote(e.target.value)}
                    placeholder={
                      adjustMode === 'set'      ? 'e.g. Reconciled with bank'
                    : adjustMode === 'add'      ? 'e.g. Tax refund'
                    :                             'e.g. Emergency expense'
                    } />
                </div>

                <div className="pool-effect">
                  <div className="effect-cell">
                    <div className="effect-label">Pool now</div>
                    <div className="effect-num">{fmt(pool, { cents: false })}</div>
                  </div>
                  <div className="effect-arrow">→</div>
                  <div className="effect-cell">
                    <div className="effect-label">
                      {hasN
                        ? (delta >= 0
                            ? `Pool after (+${fmt(Math.abs(delta), { cents: false })})`
                            : `Pool after (−${fmt(Math.abs(delta), { cents: false })})`)
                        : 'Pool after'}
                    </div>
                    <div className="effect-num strong" style={{ color: !hasN ? 'var(--ink-3)' : delta >= 0 ? 'var(--pos)' : 'var(--neg)' }}>
                      {fmt(after, { cents: false })}
                    </div>
                  </div>
                </div>
              </div>
              <div className="modal-footer">
                <button className="btn ghost" onClick={closeSheet}>Cancel</button>
                <button className="btn primary" onClick={() => { commitAdjust(); closeSheet(); }} disabled={!hasN}>
                  {adjustMode === 'set' ? 'Set balance' : adjustMode === 'withdraw' ? 'Withdraw' : 'Add to pool'}
                </button>
              </div>
            </>)}
          </Sheet>
        );
      })()}
    </>
  );
}

function SettingsScreen({ state, setState, theme, setTheme }) {
  const primary = (state.family || []).find(m => m.role === 'primary') || (state.family || []).find(m => m.id === 'self');
  const lastName = (() => {
    const parts = (primary?.name || '').trim().split(/\s+/);
    return parts.length > 1 ? parts[parts.length - 1] : '';
  })();
  const householdLabel = lastName ? `${lastName} Homebook` : 'Homebook';

  return (
    <>
      <div className="page-head">
        <div>
          <div className="page-sub">Preferences</div>
          <h1 className="page-title">Settings</h1>
        </div>
      </div>
      <div style={{ padding: '24px 28px', maxWidth: 560, display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div className="card">
          <div className="card-section">Household</div>
          <div className="between">
            <div>
              <div style={{ fontSize: 13 }}>{householdLabel}</div>
              <div className="muted mono" style={{ fontSize: 11, marginTop: 2 }}>
                {primary?.name ? `Primary · ${primary.name}` : 'Add a primary family member to personalize this name'}
              </div>
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-section">Appearance</div>
          <div className="between">
            <div>
              <div style={{ fontSize: 13 }}>Theme</div>
              <div className="muted mono" style={{ fontSize: 11, marginTop: 2 }}>light or dark, warm paper either way</div>
            </div>
            <div className="row gap-sm">
              <button className={`btn ${theme === 'light' ? 'primary' : ''}`} onClick={() => setTheme('light')}>Light</button>
              <button className={`btn ${theme === 'dark' ? 'primary' : ''}`} onClick={() => setTheme('dark')}>Dark</button>
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-section">Data</div>
          <div className="between">
            <div>
              <div style={{ fontSize: 13 }}>Export your homebook</div>
              <div className="muted mono" style={{ fontSize: 11, marginTop: 2 }}>CSV of expenses, fixed costs, income, goals, tasks, recipes</div>
            </div>
            <button className="btn">Export…</button>
          </div>
        </div>

        <div className="card">
          <div className="card-section">How months work</div>
          <div className="muted mono" style={{ fontSize: 11.5, lineHeight: 1.7 }}>
            The current month is detected from the system clock; on the 1st a new month opens automatically with your fixed costs carried over. Use the month picker in the toolbar to browse closed months — closed months are read-only by default but you can still edit historical entries from the Expenses screen.
          </div>
        </div>

        <div className="card">
          <div className="card-section">What's inside</div>
          <div className="muted mono" style={{ fontSize: 11.5, lineHeight: 1.7 }}>
            Accounting · Meals · Tasks · Family · Goals · Pantry · Shopping list. Tools share the household but keep their own books — meal plan estimates stay independent of your actual grocery expenses, the pantry feeds your shopping list, and tasks know who's in the family.
          </div>
        </div>

        <div className="card">
          <div className="card-section">About</div>
          <div className="muted mono" style={{ fontSize: 11.5, lineHeight: 1.7 }}>
            Homebook 1.0<br/>
            Unity, clarity, and direction for household life.
          </div>
        </div>
      </div>
    </>
  );
}

Object.assign(window, { TagsScreen, GoalsScreen, SettingsScreen, FamilyScreen });

function FamilyScreen({ state, setState, setOpenModal }) {
  const { family, expenses, fixed, tags, activeMonth } = state;
  const [editing, setEditing] = React.useState(null);
  const [draftName, setDraftName] = React.useState('');
  const [draftBudget, setDraftBudget] = React.useState(0);
  const [draftRole, setDraftRole] = React.useState('partner');
  const [draftColor, setDraftColor] = React.useState('teal');

  // Spend by member (variable + fixed) for active month
  const spendByMember = {};
  expenses.forEach(e => { spendByMember[e.memberId] = (spendByMember[e.memberId] || 0) + e.amount; });
  const fixedByMember = {};
  fixed.forEach(f => { fixedByMember[f.memberId] = (fixedByMember[f.memberId] || 0) + monthlyEquiv(f); });

  const totalBudget = family.reduce((s, m) => s + (m.budget || 0), 0);
  const totalSpent = family.reduce((s, m) => s + (spendByMember[m.id] || 0), 0);
  const totalFixed = family.reduce((s, m) => s + (fixedByMember[m.id] || 0), 0);

  const startEdit = (m) => {
    setEditing(m.id);
    setDraftName(m.name); setDraftBudget(m.budget); setDraftRole(m.role); setDraftColor(m.color);
  };
  const saveEdit = () => {
    setState(s => ({ ...s, family: s.family.map(m => m.id === editing ? { ...m, name: draftName, budget: parseFloat(draftBudget) || 0, role: draftRole, color: draftColor } : m) }));
    setEditing(null);
  };
  const removeMember = (id) => {
    if (id === 'self' || id === 'shared') return;
    setState(s => ({
      ...s,
      family: s.family.filter(m => m.id !== id),
      expenses: s.expenses.map(e => e.memberId === id ? { ...e, memberId: 'self' } : e),
      fixed: s.fixed.map(f => f.memberId === id ? { ...f, memberId: 'shared' } : f),
    }));
  };

  // Top categories per member
  const topByMember = {};
  family.forEach(m => {
    const tally = {};
    expenses.filter(e => e.memberId === m.id).forEach(e => { tally[e.tagId] = (tally[e.tagId] || 0) + e.amount; });
    topByMember[m.id] = Object.entries(tally).sort((a, b) => b[1] - a[1]).slice(0, 3);
  });

  return (
    <>
      <div className="page-head">
        <div>
          <div className="page-sub">{formatMonthKey(activeMonth)} · {family.length} members · {fmt(totalBudget, { cents: false })} budgeted</div>
          <h1 className="page-title">Family</h1>
        </div>
        <button className="btn" onClick={() => setOpenModal('member')}>+ Add member</button>
      </div>

      <div style={{ padding: '20px 28px 28px' }}>
        {/* Summary strip */}
        <div className="card" style={{ marginBottom: 18 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 22 }}>
            <div>
              <div className="eyebrow" style={{ marginBottom: 4 }}>Combined budget</div>
              <div className="num" style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--ink)', letterSpacing: '-0.02em' }}>{fmt(totalBudget, { cents: false })}</div>
            </div>
            <div>
              <div className="eyebrow" style={{ marginBottom: 4 }}>Variable spent</div>
              <div className="num" style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--terracotta)', letterSpacing: '-0.02em' }}>{fmt(totalSpent, { cents: false })}</div>
            </div>
            <div>
              <div className="eyebrow" style={{ marginBottom: 4 }}>Fixed allocated</div>
              <div className="num" style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--ink-2)', letterSpacing: '-0.02em' }}>{fmt(totalFixed, { cents: false })}</div>
            </div>
            <div>
              <div className="eyebrow" style={{ marginBottom: 4 }}>Remaining</div>
              <div className="num" style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: totalBudget - totalSpent >= 0 ? 'var(--pos)' : 'var(--neg)', letterSpacing: '-0.02em' }}>
                {fmt(totalBudget - totalSpent, { cents: false })}
              </div>
            </div>
          </div>
          {/* Stacked allocation */}
          <div style={{ marginTop: 18 }}>
            <div className="eyebrow" style={{ marginBottom: 8 }}>Variable spend share</div>
            <div style={{ display: 'flex', height: 10, borderRadius: 5, overflow: 'hidden', background: 'var(--paper-3)' }}>
              {family.map(m => {
                const v = spendByMember[m.id] || 0;
                const pct = totalSpent ? (v / totalSpent) * 100 : 0;
                if (pct < 0.5) return null;
                return <div key={m.id} title={`${m.name} · ${fmt(v, { cents: false })}`}
                  style={{ width: pct + '%', background: TAG_COLORS[m.color] }} />;
              })}
            </div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 14, marginTop: 10 }}>
              {family.map(m => (
                <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11 }}>
                  <span style={{ width: 8, height: 8, background: TAG_COLORS[m.color], borderRadius: 2 }} />
                  <span style={{ color: 'var(--ink-2)' }}>{m.name}</span>
                  <span className="num muted">{fmt(spendByMember[m.id] || 0, { cents: false })}</span>
                </div>
              ))}
            </div>
          </div>
        </div>

        {/* Member cards */}
        <div className="family-grid">
          {family.map(m => {
            const spent = spendByMember[m.id] || 0;
            const fixedAlloc = fixedByMember[m.id] || 0;
            const totalCharged = spent + fixedAlloc;
            const budget = m.budget || 0;
            const pct = budget > 0 ? Math.min((spent / budget) * 100, 120) : 0;
            const over = spent > budget && budget > 0;
            const remaining = budget - spent;
            const isEditing = editing === m.id;

            return (
              <div key={m.id} className="member-card">
                <div className="accent-bar" style={{ background: TAG_COLORS[m.color] }} />
                <div className="member-card-head">
                  <div className="member-chip xl" style={{ background: TAG_COLORS[m.color] }}>{nameInitials(m.name)}</div>
                  <div style={{ flex: 1 }}>
                    {isEditing ? (
                      <input className="input" value={draftName} onChange={e => setDraftName(e.target.value)} style={{ fontSize: 16, marginBottom: 4 }} />
                    ) : (
                      <h3>{m.name}</h3>
                    )}
                    <div className="role">{m.role}</div>
                  </div>
                  {!isEditing && (
                    <div className="row gap-sm">
                      <button className="btn ghost" style={{ height: 24, fontSize: 11 }} onClick={() => startEdit(m)}>Edit</button>
                      {m.id !== 'self' && m.id !== 'shared' && (
                        <button className="btn ghost" style={{ height: 24, fontSize: 11, color: 'var(--neg)' }} onClick={() => removeMember(m.id)}>×</button>
                      )}
                    </div>
                  )}
                </div>

                {isEditing ? (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                    <div className="field">
                      <span className="field-label">Monthly budget</span>
                      <div className="amount-wrap">
                        <input className="input amount" type="number" step="10" value={draftBudget} onChange={e => setDraftBudget(e.target.value)} />
                      </div>
                    </div>
                    <div className="field">
                      <span className="field-label">Role</span>
                      <select className="input" value={draftRole} onChange={e => setDraftRole(e.target.value)}>
                        <option value="primary">Primary</option>
                        <option value="partner">Partner</option>
                        <option value="child">Child</option>
                        <option value="shared">Shared</option>
                        <option value="other">Other</option>
                      </select>
                    </div>
                    <div className="field">
                      <span className="field-label">Color</span>
                      <div className="color-grid">
                        {Object.entries(TAG_COLORS).map(([key, hex]) => (
                          <div key={key}
                            className={`color-swatch ${draftColor === key ? 'selected' : ''}`}
                            style={{ background: hex }}
                            onClick={() => setDraftColor(key)} />
                        ))}
                      </div>
                    </div>
                    <div className="row gap-sm" style={{ justifyContent: 'flex-end', marginTop: 4 }}>
                      <button className="btn ghost" onClick={() => setEditing(null)}>Cancel</button>
                      <button className="btn primary" onClick={saveEdit}>Save</button>
                    </div>
                  </div>
                ) : (
                  <>
                    <div className="between" style={{ marginBottom: 4 }}>
                      <span className="eyebrow">Budget · {formatMonthKeyShort(activeMonth)}</span>
                      <span className="num" style={{ fontSize: 12 }}>
                        <span style={{ color: over ? 'var(--neg)' : 'var(--ink)' }}>{fmt(spent, { cents: false })}</span>
                        <span className="muted"> / {fmt(budget, { cents: false })}</span>
                      </span>
                    </div>
                    <div className="budget-bar">
                      <div className={`budget-bar-fill ${over ? 'over' : ''}`}
                        style={{ width: pct + '%', background: TAG_COLORS[m.color] }} />
                    </div>
                    <div className="between" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>
                      <span>{over ? `${fmt(spent - budget, { cents: false })} over` : `${fmt(remaining, { cents: false })} remaining`}</span>
                      <span className="num">{budget ? Math.round((spent / budget) * 100) + '%' : '—'}</span>
                    </div>

                    <div className="divider" />

                    <div className="between" style={{ fontSize: 11.5, marginBottom: 6 }}>
                      <span className="muted">Fixed allocations</span>
                      <span className="num">{fmt(fixedAlloc, { cents: false })}</span>
                    </div>
                    <div className="between" style={{ fontSize: 11.5, marginBottom: 10 }}>
                      <span className="muted">Total charged</span>
                      <span className="num" style={{ color: 'var(--ink)' }}>{fmt(totalCharged, { cents: false })}</span>
                    </div>

                    {topByMember[m.id]?.length > 0 && (
                      <>
                        <div className="eyebrow" style={{ marginBottom: 6 }}>Top categories</div>
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                          {topByMember[m.id].map(([tagId, v]) => {
                            const t = tagById(tags, tagId);
                            return (
                              <div key={tagId} className="between" style={{ fontSize: 11 }}>
                                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                                  <span style={{ width: 6, height: 6, borderRadius: '50%', background: TAG_COLORS[t.color] }} />
                                  <span style={{ color: 'var(--ink-2)' }}>{t.name}</span>
                                </div>
                                <span className="num muted">{fmt(v, { cents: false })}</span>
                              </div>
                            );
                          })}
                        </div>
                      </>
                    )}
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}
