// =============================================================
// AM client setup — full configuration workspace shown when an
// AM clicks the gear icon in the AM ribbon. Three pass-1 tabs:
//   • Connections     — link external accounts (paid, analytics,
//                        commerce, CRM, notifications)
//   • Performance Targets — CRUD for the KPIs we report against
//   • AI Suggestions  — triage every open ClickyAI suggestion
//                        before it surfaces to the client
//
// All edits persist to localStorage under `clicky_am_setup_<id>`
// per client. First read seeds defaults from existing portal data
// (ACCOUNTS, AGREED_KPIS) so the AM has something realistic to
// work against.
// =============================================================

const { useState: useStateSetup, useEffect: useEffectSetup } = React;

// --- Supported platforms / integrations grouped by category --------
const PLATFORMS = [
  { id: 'google-ads',     name: 'Google Ads',         category: 'Paid media',  icon: 'google',    keyField: 'Account ID',   placeholder: 'XXX-XXX-XXXX' },
  { id: 'microsoft-ads',  name: 'Microsoft Ads',      category: 'Paid media',  icon: 'microsoft', keyField: 'Account ID',   placeholder: 'Bing customer ID' },
  { id: 'meta-ads',       name: 'Meta Ads',           category: 'Paid media',  icon: 'meta',      keyField: 'Ad Account',   placeholder: 'act_xxxxxxxxxx' },
  { id: 'tiktok-ads',     name: 'TikTok Ads',         category: 'Paid media',  icon: 'tiktok',    keyField: 'Advertiser ID',placeholder: '7012345678901234567' },
  { id: 'linkedin-ads',   name: 'LinkedIn Ads',       category: 'Paid media',  icon: 'linkedin',  keyField: 'Account URN',  placeholder: 'urn:li:sponsoredAccount:...' },
  { id: 'reddit-ads',     name: 'Reddit Ads',         category: 'Paid media',  icon: 'reddit',    keyField: 'Account ID',   placeholder: 'a2_xxxxxx' },

  { id: 'ga4',            name: 'Google Analytics 4', category: 'Analytics',   icon: 'ga4',       keyField: 'Property ID',  placeholder: '123456789' },
  { id: 'search-console', name: 'Search Console',     category: 'Analytics',   icon: 'gsc',       keyField: 'Property',     placeholder: 'sc-domain:example.com' },
  { id: 'gtm',            name: 'Tag Manager',        category: 'Analytics',   icon: 'gtm',       keyField: 'Container',    placeholder: 'GTM-XXXXXXX' },

  { id: 'shopify',        name: 'Shopify',            category: 'Commerce / CMS', icon: 'shopify',    keyField: 'Store domain', placeholder: 'shop.myshopify.com' },
  { id: 'webflow',        name: 'Webflow',            category: 'Commerce / CMS', icon: 'webflow',    keyField: 'Site ID',      placeholder: 'wf_xxxx' },
  { id: 'wordpress',      name: 'WordPress',          category: 'Commerce / CMS', icon: 'wordpress',  keyField: 'REST endpoint',placeholder: 'https://site.com/wp-json' },

  { id: 'hubspot',        name: 'HubSpot CRM',        category: 'CRM / Email', icon: 'hubspot',   keyField: 'Portal ID',    placeholder: '12345678' },
  { id: 'klaviyo',        name: 'Klaviyo',            category: 'CRM / Email', icon: 'klaviyo',   keyField: 'Public Key',   placeholder: 'pk_xxxxxx' },
  { id: 'mailchimp',      name: 'Mailchimp',          category: 'CRM / Email', icon: 'mailchimp', keyField: 'List ID',      placeholder: 'us21-xxxxxx' },

  { id: 'slack',          name: 'Slack',              category: 'Notifications', icon: 'slack',   keyField: 'Channel',      placeholder: '#evergreen-clicky' },
];

// Tiny inline brand-mark — same simple two-letter chip we use elsewhere
// when an icon isn't bundled. Letters stay readable in light + dark.
const PlatformMark = ({ id, name, size = 28 }) => {
  const initials = name
    .replace(/Ads$|CRM$/, '')
    .trim()
    .split(/\s+/)
    .slice(0, 2)
    .map(w => w[0]?.toUpperCase())
    .join('');
  // Brand-ish hues per platform so the wall of integrations stays scannable.
  const hue = ({
    'google-ads':     '#4285f4',
    'microsoft-ads':  '#00a4ef',
    'meta-ads':       '#0866ff',
    'tiktok-ads':     '#ff0050',
    'linkedin-ads':   '#0a66c2',
    'reddit-ads':     '#ff4500',
    'ga4':            '#f9ab00',
    'search-console': '#4285f4',
    'gtm':            '#246fdb',
    'shopify':        '#95bf47',
    'webflow':        '#4353ff',
    'wordpress':      '#21759b',
    'hubspot':        '#ff7a59',
    'klaviyo':        '#000000',
    'mailchimp':      '#ffe01b',
    'slack':          '#611f69',
  })[id] || '#52525b';
  return (
    <div style={{
      width: size, height: size, borderRadius: 6,
      background: 'color-mix(in oklab, ' + hue + ' 14%, transparent)',
      color: hue, display: 'grid', placeItems: 'center',
      fontSize: size * 0.4, fontWeight: 700, letterSpacing: '-0.02em',
      flexShrink: 0,
    }}>{initials}</div>
  );
};

// --- Default seed suggestions (4-6 per client). Keep generic so we
//     don't have to hand-author per-client lists for the prototype.
const DEFAULT_SUGGESTIONS = [
  {
    id: 'sug-pmax-prune',
    title: 'Pause underperforming Performance Max asset group',
    impact: 'High',
    confidence: 'High',
    source: 'Google Ads',
    body: 'Asset Group "Spring Lodges" is spending 22% of Pmax budget at 0.8× ROAS. Suggest pausing and reallocating to top-performing group "Family Stays" (3.4× ROAS).',
    suggestedAction: 'Pause asset group, reallocate £180/day budget',
    status: 'open',
  },
  {
    id: 'sug-meta-lookalike',
    title: 'Test Lookalike audiences from past-90-day buyers',
    impact: 'Medium',
    confidence: 'High',
    source: 'Meta Ads',
    body: 'No Lookalikes currently running. Past-90-day buyer list is 1,847 contacts — large enough to seed 1% / 3% / 5% LALs and run a structured test against current Interest stack.',
    suggestedAction: 'Create 3 LAL audiences, A/B against Interest baseline for 14 days',
    status: 'open',
  },
  {
    id: 'sug-negs',
    title: 'Add 14 negative keywords to Branded campaign',
    impact: 'Low',
    confidence: 'High',
    source: 'Google Ads',
    body: 'Search-terms report shows 14 high-impression terms with 0 conversions in 30 days, eating 4.8% of Branded spend. Mostly unrelated brand-similar queries.',
    suggestedAction: 'Add 14 exact-match negatives to Branded shared list',
    status: 'open',
  },
  {
    id: 'sug-ga4-conv',
    title: 'Migrate to GA4 enhanced conversions',
    impact: 'Medium',
    confidence: 'Medium',
    source: 'GA4',
    body: 'Currently sending hashed-email-only. Adding name + phone + address would lift match rate ~22-28% based on internal benchmarks across similar accounts.',
    suggestedAction: 'Update GTM data layer to include first/last name, phone and city',
    status: 'open',
  },
  {
    id: 'sug-cro-cta',
    title: 'A/B test booking CTA above the fold',
    impact: 'Medium',
    confidence: 'Medium',
    source: 'CRO',
    body: 'Heatmap shows 68% of users never scroll to the current "Book a stay" CTA. Moving it above the fold on the homepage hero is a low-effort test.',
    suggestedAction: 'Build variant in Webflow, run for 21 days at 50/50 split',
    status: 'open',
  },
  {
    id: 'sug-seo-internal-links',
    title: 'Add 6 internal links from blog to lodge pages',
    impact: 'Low',
    confidence: 'Medium',
    source: 'SEO',
    body: 'Top-3-traffic blog posts have no internal links to commercial pages. Adding contextual links to "Stay" / "Ownership" pages should improve assisted conversions.',
    suggestedAction: 'Edit 3 blog posts, add 2 internal links each',
    status: 'open',
  },
];

// --- Per-client setup persistence ----------------------------------
const SETUP_KEY = (id) => 'clicky_am_setup_' + id;

const loadSetup = (clientId) => {
  try {
    const raw = localStorage.getItem(SETUP_KEY(clientId));
    if (raw) {
      const parsed = JSON.parse(raw);
      // Backfill any new sections added after the saved blob was written.
      return {
        connections: parsed.connections || seedConnections(),
        cpts:        parsed.cpts        || seedCpts(),
        suggestions: parsed.suggestions || seedSuggestions(),
        profile:     parsed.profile     || seedProfile(clientId),
        users:       parsed.users       || seedUsers(clientId),
        contracts:   parsed.contracts   || seedContracts(),
        invoices:    parsed.invoices    || seedInvoices(),
      };
    }
  } catch (e) {}
  return {
    connections: seedConnections(),
    cpts:        seedCpts(),
    suggestions: seedSuggestions(),
    profile:     seedProfile(clientId),
    users:       seedUsers(clientId),
    contracts:   seedContracts(),
    invoices:    seedInvoices(),
  };
};

// --- Seed helpers --------------------------------------------------
const seedConnections = () => {
  const connectedSeed = ['google-ads', 'meta-ads', 'ga4', 'search-console'];
  const connections = {};
  PLATFORMS.forEach(p => {
    connections[p.id] = connectedSeed.includes(p.id)
      ? { connected: true,  accountId: '—', lastSync: '2 min ago', primary: connectedSeed.indexOf(p.id) === 0 }
      : { connected: false, accountId: '',  lastSync: null,        primary: false };
  });
  if (window.ACCOUNTS && window.ACCOUNTS.length) {
    connections['google-ads'].accountId = window.ACCOUNTS[0].id;
  }
  return connections;
};

const seedCpts = () => (window.AGREED_KPIS || []).slice(0, 6).map((k, i) => ({
  id: 'cpt-' + (i + 1),
  name: k.label || k.name || 'Untitled target',
  source: k.source || 'Cross-channel',
  metric: k.metric || k.label || '—',
  target: k.target || '',
  direction: k.direction || 'higher',
  cadence: 'monthly',
  owner: 'Joe Marshall',
  definition: k.definition || '',
  baseline: k.baseline || '',
}));

const seedSuggestions = () => DEFAULT_SUGGESTIONS.map(s => ({ ...s, amNote: '', triage: null, decidedAt: null }));

const seedProfile = (clientId) => {
  const c = (window.AM_CLIENTS || []).find(x => x.id === clientId) || {};
  return {
    brand: {
      name: c.name || '',
      shortName: c.shortName || '',
      url: c.url || '',
      tagline: c.industry || '',
      primaryColor: '#2563eb',
    },
    registered: {
      address1: '',
      address2: '',
      city: '',
      postcode: '',
      country: 'United Kingdom',
      companyNumber: '',
      vat: '',
    },
    contacts: {
      primary:   { name: c.contact || '',     role: c.contactRole || 'Owner', email: c.contact ? c.contact.toLowerCase().split(' ').join('.') + '@' + (c.url || 'client.co.uk') : '', phone: '' },
      billing:   { name: '', role: 'Billing contact',    email: 'accounts@' + (c.url || 'client.co.uk'), phone: '' },
      technical: { name: '', role: 'Technical contact',  email: '', phone: '' },
      marketing: { name: '', role: 'Marketing contact',  email: '', phone: '' },
    },
  };
};

const seedUsers = (clientId) => {
  const c = (window.AM_CLIENTS || []).find(x => x.id === clientId) || {};
  const domain = (c.url || 'client.co.uk').replace(/\/.*$/, '');
  const slug = (n) => n.toLowerCase().replace(/[^a-z]/g, '.').replace(/\.+/g, '.').replace(/^\.|\.$/g, '');
  return [
    { id: 'u-1', name: c.contact || 'Daniel Trevethan', email: (c.contact ? slug(c.contact) : 'daniel.trevethan') + '@' + domain, role: 'Owner',          status: 'active',  lastLogin: '2 hours ago', mfa: true,  invitedBy: 'Joe Marshall', joined: '12 Jan 2025' },
    { id: 'u-2', name: 'Emma Holloway',                 email: 'emma@' + domain,        role: 'Marketing lead', status: 'active',  lastLogin: 'Yesterday',   mfa: true,  invitedBy: c.contact || 'Daniel Trevethan', joined: '14 Feb 2025' },
    { id: 'u-3', name: 'Tom Brennan',                   email: 'tom@' + domain,         role: 'Viewer',         status: 'invited', lastLogin: null,           mfa: false, invitedBy: c.contact || 'Daniel Trevethan', joined: 'pending' },
  ];
};

const seedContracts = () => {
  const existing = (window.CONTRACTS || []).map((c, i) => ({
    ...c,
    pendingApproval: false,
    services: c.name,
    autoRenew: i % 2 === 0,
    signedBy: 'Daniel Trevethan',
    notes: '',
  }));
  // Add one synthetic pending contract so the AM has something to approve.
  existing.unshift({
    id: 'C-PEND-001',
    name: 'Meta Ads — Q3 expansion',
    services: 'Meta Ads creative + media buying expansion',
    start: '01 Jul 2026',
    renews: '01 Jul 2027',
    term: '12 months',
    monthly: '£1,250.00',
    status: 'Pending approval',
    pendingApproval: true,
    autoRenew: true,
    signedBy: 'Awaiting client e-sign',
    notes: 'Drafted after April performance review. Waiting on Daniel to e-sign.',
  });
  return existing;
};

const seedInvoices = () => (window.INVOICES || []).map(inv => ({
  ...inv,
  amNote: '',
  reminderSentAt: null,
}));

const saveSetup = (clientId, setup) => {
  try { localStorage.setItem(SETUP_KEY(clientId), JSON.stringify(setup)); } catch (e) {}
};

// --- The setup screen ----------------------------------------------
const AmClientSetupScreen = ({ clientId, onClose }) => {
  const client = (window.AM_CLIENTS || []).find(c => c.id === clientId);
  const [tab, setTab] = useStateSetup('connections');
  const [setup, setSetup] = useStateSetup(() => loadSetup(clientId));

  // Persist on every change. Cheap and fine for a prototype.
  useEffectSetup(() => { saveSetup(clientId, setup); }, [clientId, setup]);

  // Re-seed when switching clients via the rail/ribbon while setup is open.
  useEffectSetup(() => { setSetup(loadSetup(clientId)); }, [clientId]);

  const updateConnection = (id, patch) => {
    setSetup(prev => ({
      ...prev,
      connections: { ...prev.connections, [id]: { ...prev.connections[id], ...patch } },
    }));
  };

  const upsertCpt = (cpt) => {
    setSetup(prev => {
      const exists = prev.cpts.find(c => c.id === cpt.id);
      const cpts = exists
        ? prev.cpts.map(c => c.id === cpt.id ? cpt : c)
        : [...prev.cpts, cpt];
      return { ...prev, cpts };
    });
  };
  const deleteCpt = (id) => setSetup(prev => ({ ...prev, cpts: prev.cpts.filter(c => c.id !== id) }));

  const triageSuggestion = (id, triage, amNote) => {
    setSetup(prev => ({
      ...prev,
      suggestions: prev.suggestions.map(s => s.id === id
        ? { ...s, triage, amNote: amNote ?? s.amNote, status: triage === 'approve' ? 'approved' : triage === 'decline' ? 'declined' : triage === 'hold' ? 'hold' : 'open', decidedAt: new Date().toLocaleString('en-GB') }
        : s),
    }));
  };

  const updateProfile = (path, value) => {
    setSetup(prev => {
      const profile = JSON.parse(JSON.stringify(prev.profile));
      // path like "brand.name" or "contacts.billing.email"
      const parts = path.split('.');
      let target = profile;
      for (let i = 0; i < parts.length - 1; i++) {
        target[parts[i]] = target[parts[i]] || {};
        target = target[parts[i]];
      }
      target[parts[parts.length - 1]] = value;
      return { ...prev, profile };
    });
  };

  const upsertUser = (user) => {
    setSetup(prev => {
      const exists = prev.users.find(u => u.id === user.id);
      const users = exists
        ? prev.users.map(u => u.id === user.id ? user : u)
        : [...prev.users, user];
      return { ...prev, users };
    });
  };
  const removeUser = (id) => setSetup(prev => ({ ...prev, users: prev.users.filter(u => u.id !== id) }));

  const decideContract = (id, decision, amNote) => {
    setSetup(prev => ({
      ...prev,
      contracts: prev.contracts.map(c => c.id === id
        ? {
            ...c,
            status: decision === 'approve' ? 'Active' : decision === 'decline' ? 'Declined' : c.status,
            pendingApproval: false,
            decidedAt: new Date().toLocaleString('en-GB'),
            decidedBy: AM_USER.firstName,
            notes: amNote ?? c.notes,
          }
        : c),
    }));
  };
  const updateInvoice = (id, patch) => {
    setSetup(prev => ({
      ...prev,
      invoices: prev.invoices.map(i => i.id === id ? { ...i, ...patch } : i),
    }));
  };

  const outstandingCount = setup.invoices.filter(i => /Outstanding|Overdue|Pending/i.test(i.status || '')).length;
  const pendingContracts = setup.contracts.filter(c => c.pendingApproval).length;

  const tabs = [
    { id: 'profile',      label: 'Profile' },
    { id: 'users',        label: 'Users',               count: setup.users.length },
    { id: 'connections',  label: 'Connections',         count: Object.values(setup.connections).filter(c => c.connected).length, total: PLATFORMS.length },
    { id: 'cpts',         label: 'Performance targets', count: setup.cpts.length },
    { id: 'contracts',    label: 'Contracts',           count: pendingContracts > 0 ? pendingContracts : setup.contracts.length, badge: pendingContracts > 0 },
    { id: 'invoices',     label: 'Invoices',            count: outstandingCount > 0 ? outstandingCount : setup.invoices.length, badge: outstandingCount > 0 },
    { id: 'suggestions',  label: 'AI suggestions',      count: setup.suggestions.filter(s => s.status === 'open').length, badge: setup.suggestions.filter(s => s.status === 'open').length > 0 },
  ];

  return (
    <div>
      {/* Header */}
      <div style={{
        padding: '20px 24px 16px', borderBottom: '1px solid var(--border)',
        background: 'var(--surface)',
        display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap',
      }}>
        <div style={{
          width: 36, height: 36, borderRadius: 8,
          background: 'color-mix(in oklab, #0f172a 92%, transparent)',
          color: '#fff', display: 'grid', placeItems: 'center',
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
        </div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 9.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.10em' }}>
            Client setup · AM only
          </div>
          <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: '-0.01em', marginTop: 2 }}>
            {client?.name || 'Client'}
          </div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 1 }}>
            All changes save automatically. Internal-only — never visible to the client.
          </div>
        </div>
        <button onClick={onClose} style={{
          padding: '7px 14px', borderRadius: 6,
          background: 'var(--surface-2)', color: 'var(--text)',
          border: '1px solid var(--border)', fontSize: 12, fontWeight: 500, fontFamily: 'inherit',
          cursor: 'pointer',
        }}>Done</button>
      </div>

      {/* Tab strip */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 4,
        padding: '8px 24px', background: 'var(--surface)',
        borderBottom: '1px solid var(--border)',
      }}>
        {tabs.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)} style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '7px 14px', borderRadius: 6,
            background: tab === t.id ? '#0f172a' : 'transparent',
            color: tab === t.id ? '#fff' : 'var(--text-muted)',
            border: 'none', fontFamily: 'inherit',
            fontSize: 12.5, fontWeight: 500, cursor: 'pointer',
          }}>
            {t.label}
            <span style={{
              fontSize: 10.5, fontWeight: 600,
              padding: '1px 6px', borderRadius: 99,
              background: tab === t.id ? 'rgba(255,255,255,0.16)' : 'var(--surface-2)',
              color: tab === t.id ? '#fff' : 'var(--text-muted)',
            }}>
              {t.total != null ? `${t.count}/${t.total}` : t.count}
            </span>
            {t.badge && <span style={{ width: 6, height: 6, borderRadius: '50%', background: '#ef4444' }}/>}
          </button>
        ))}
        <div style={{ flex: 1 }}/>
        <div style={{ fontSize: 11, color: 'var(--text-faint)' }}>
          Saved · {client?.name}
        </div>
      </div>

      {/* Tab body */}
      <div style={{ padding: '20px 24px 40px', maxWidth: 1100, margin: '0 auto' }}>
        {tab === 'profile'      && <ProfileTab        profile={setup.profile}          onUpdate={updateProfile} />}
        {tab === 'users'        && <UsersTab          users={setup.users}              onUpsert={upsertUser}    onRemove={removeUser} clientName={client?.name} />}
        {tab === 'connections'  && <ConnectionsTab    connections={setup.connections}  onUpdate={updateConnection} />}
        {tab === 'cpts'         && <CptsTab           cpts={setup.cpts}                onUpsert={upsertCpt}     onDelete={deleteCpt} />}
        {tab === 'contracts'    && <ContractsTab      contracts={setup.contracts}      onDecide={decideContract} />}
        {tab === 'invoices'     && <InvoicesTab       invoices={setup.invoices}        onUpdate={updateInvoice} />}
        {tab === 'suggestions'  && <SuggestionsTab    suggestions={setup.suggestions}  onTriage={triageSuggestion} />}
      </div>
    </div>
  );
};

// =============================================================
// Connections tab
// =============================================================
const ConnectionsTab = ({ connections, onUpdate }) => {
  const grouped = PLATFORMS.reduce((acc, p) => {
    (acc[p.category] = acc[p.category] || []).push(p);
    return acc;
  }, {});

  const toggleConnect = (p) => {
    const cur = connections[p.id];
    if (cur.connected) {
      onUpdate(p.id, { connected: false, lastSync: null, primary: false });
    } else {
      onUpdate(p.id, { connected: true, lastSync: 'just now' });
    }
  };

  return (
    <>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>Account connections</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            Wire up every platform we report against. Status, account ID and last sync show inline.
          </div>
        </div>
        <button style={{
          padding: '7px 12px', borderRadius: 6,
          background: 'var(--surface-2)', color: 'var(--text)',
          border: '1px solid var(--border)', fontSize: 12, fontFamily: 'inherit',
          fontWeight: 500, cursor: 'pointer',
        }}>Sync all</button>
      </div>

      {Object.entries(grouped).map(([cat, items]) => (
        <div key={cat} style={{ marginBottom: 18 }}>
          <div style={{
            fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
            textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 8,
          }}>{cat}</div>
          <Card padding={0}>
            {items.map((p, i) => {
              const c = connections[p.id] || {};
              return (
                <div key={p.id} style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: '12px 16px',
                  borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                }}>
                  <PlatformMark id={p.id} name={p.name} />
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{p.name}</div>
                      {c.connected ? (
                        <span style={{
                          display: 'inline-flex', alignItems: 'center', gap: 5,
                          padding: '1px 7px', borderRadius: 99,
                          background: 'color-mix(in oklab, #16a34a 12%, transparent)', color: '#16a34a',
                          fontSize: 10.5, fontWeight: 600,
                        }}>
                          <span style={{ width: 5, height: 5, borderRadius: '50%', background: '#16a34a' }}/>
                          Connected{c.primary ? ' · primary' : ''}
                        </span>
                      ) : (
                        <span style={{
                          padding: '1px 7px', borderRadius: 99,
                          background: 'var(--surface-2)', color: 'var(--text-muted)',
                          fontSize: 10.5, fontWeight: 600,
                        }}>Not connected</span>
                      )}
                    </div>
                    <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 3, display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                      <span>{p.keyField}:</span>
                      {c.connected ? (
                        <input
                          value={c.accountId || ''}
                          onChange={e => onUpdate(p.id, { accountId: e.target.value })}
                          placeholder={p.placeholder}
                          style={{
                            border: '1px solid var(--border)', borderRadius: 4,
                            padding: '2px 6px', fontSize: 11, fontFamily: 'JetBrains Mono', minWidth: 160,
                            background: 'var(--surface)', color: 'var(--text)',
                          }}
                        />
                      ) : (
                        <span style={{ color: 'var(--text-faint)', fontStyle: 'italic' }}>—</span>
                      )}
                      {c.connected && c.lastSync && (
                        <span style={{ color: 'var(--text-faint)' }}>· last sync {c.lastSync}</span>
                      )}
                    </div>
                  </div>

                  {/* Actions */}
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexShrink: 0 }}>
                    {c.connected && (
                      <label style={{
                        display: 'inline-flex', alignItems: 'center', gap: 5,
                        fontSize: 10.5, color: 'var(--text-muted)',
                        cursor: 'pointer', userSelect: 'none',
                      }}>
                        <input type="checkbox" checked={!!c.primary}
                          onChange={e => onUpdate(p.id, { primary: e.target.checked })} />
                        Primary
                      </label>
                    )}
                    <button onClick={() => toggleConnect(p)} style={{
                      padding: '5px 10px', borderRadius: 6,
                      background: c.connected ? 'var(--surface-2)' : '#0f172a',
                      color: c.connected ? 'var(--text)' : '#fff',
                      border: '1px solid ' + (c.connected ? 'var(--border)' : '#0f172a'),
                      fontSize: 11.5, fontWeight: 500, fontFamily: 'inherit',
                      cursor: 'pointer', whiteSpace: 'nowrap',
                    }}>
                      {c.connected ? 'Disconnect' : 'Connect'}
                    </button>
                  </div>
                </div>
              );
            })}
          </Card>
        </div>
      ))}
    </>
  );
};

// =============================================================
// CPTs (Performance Targets) tab
// =============================================================
const CptsTab = ({ cpts, onUpsert, onDelete }) => {
  const [editing, setEditing] = useStateSetup(null); // either a cpt object or 'new'

  const startNew = () => setEditing({
    id: 'cpt-' + Date.now(),
    name: '',
    source: 'Cross-channel',
    metric: '',
    target: '',
    direction: 'higher',
    cadence: 'monthly',
    owner: 'Joe Marshall',
    definition: '',
    baseline: '',
  });

  return (
    <>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>Performance targets</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            The KPIs Clicky and the client agreed to track. Edits flow through to the client portal's CPTs tab.
          </div>
        </div>
        <button onClick={startNew} style={{
          padding: '7px 12px', borderRadius: 6,
          background: '#0f172a', color: '#fff',
          border: '1px solid #0f172a', fontSize: 12, fontFamily: 'inherit',
          fontWeight: 500, cursor: 'pointer',
        }}>+ Add target</button>
      </div>

      {cpts.length === 0 ? (
        <div style={{
          padding: '50px 20px', textAlign: 'center',
          background: 'var(--surface)', border: '1px dashed var(--border)', borderRadius: 'var(--radius)',
          color: 'var(--text-muted)', fontSize: 13,
        }}>
          No performance targets yet. Click "+ Add target" to define the first one.
        </div>
      ) : (
        <Card padding={0}>
          <div style={{
            display: 'grid',
            gridTemplateColumns: 'minmax(180px, 1.6fr) 1fr 1fr 0.6fr 0.8fr 80px',
            padding: '10px 16px', background: 'var(--surface-2)',
            fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
            textTransform: 'uppercase', letterSpacing: '0.06em',
            borderBottom: '1px solid var(--border)',
          }}>
            <div>Target</div><div>Source</div><div>Metric</div><div>Target</div><div>Cadence</div><div></div>
          </div>
          {cpts.map(c => (
            <div key={c.id} style={{
              display: 'grid',
              gridTemplateColumns: 'minmax(180px, 1.6fr) 1fr 1fr 0.6fr 0.8fr 80px',
              padding: '12px 16px', alignItems: 'center',
              borderBottom: '1px solid var(--border)', gap: 10,
              fontSize: 12.5,
            }}>
              <div>
                <div style={{ fontWeight: 600, color: 'var(--text)' }}>{c.name || <em style={{ color: 'var(--text-faint)' }}>Untitled</em>}</div>
                {c.definition && <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.definition}</div>}
              </div>
              <div style={{ color: 'var(--text-muted)' }}>{c.source}</div>
              <div style={{ color: 'var(--text-muted)' }}>{c.metric || '—'}</div>
              <div style={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>
                {c.target || '—'}
                <span style={{ color: 'var(--text-faint)', fontWeight: 400, fontSize: 10, marginLeft: 4 }}>
                  {c.direction === 'higher' ? '↑' : c.direction === 'lower' ? '↓' : ''}
                </span>
              </div>
              <div style={{ color: 'var(--text-muted)', textTransform: 'capitalize' }}>{c.cadence}</div>
              <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
                <button onClick={() => setEditing(c)} title="Edit" style={iconBtn()}>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>
                </button>
                <button onClick={() => { if (confirm('Delete "' + (c.name || 'this target') + '"?')) onDelete(c.id); }}
                  title="Delete" style={iconBtn('var(--negative)')}>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>
                </button>
              </div>
            </div>
          ))}
        </Card>
      )}

      {editing && (
        <CptEditModal
          cpt={editing}
          onClose={() => setEditing(null)}
          onSave={(c) => { onUpsert(c); setEditing(null); }}
        />
      )}
    </>
  );
};

const iconBtn = (color) => ({
  width: 26, height: 26, display: 'grid', placeItems: 'center',
  background: 'transparent', border: '1px solid var(--border)',
  borderRadius: 4, cursor: 'pointer',
  color: color || 'var(--text-muted)',
});

const CptEditModal = ({ cpt, onClose, onSave }) => {
  const [c, setC] = useStateSetup(cpt);
  const update = (patch) => setC(prev => ({ ...prev, ...patch }));

  return (
    <div style={{
      position: 'fixed', inset: 0,
      background: 'rgba(15,23,42,0.5)',
      display: 'grid', placeItems: 'center', padding: 24, zIndex: 100,
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 560,
        background: 'var(--surface)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--radius)',
        boxShadow: '0 12px 40px rgba(0,0,0,0.18)',
        display: 'flex', flexDirection: 'column', maxHeight: '90vh',
      }}>
        <div style={{ padding: '16px 20px 12px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ fontSize: 9.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.10em' }}>
            Performance target
          </div>
          <div style={{ fontSize: 16, fontWeight: 700, marginTop: 2 }}>
            {cpt.name ? 'Edit "' + cpt.name + '"' : 'New target'}
          </div>
        </div>
        <div style={{ padding: 20, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 12 }}>
          <Field label="Name">
            <input value={c.name} onChange={e => update({ name: e.target.value })}
              placeholder="e.g. Bookings · 30d" style={input()} />
          </Field>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field label="Source">
              <select value={c.source} onChange={e => update({ source: e.target.value })} style={input()}>
                {['Cross-channel','Google Ads','Meta Ads','SEO','GA4','Bookings','CRO','Maintenance','Email/CRM'].map(s => <option key={s}>{s}</option>)}
              </select>
            </Field>
            <Field label="Cadence">
              <select value={c.cadence} onChange={e => update({ cadence: e.target.value })} style={input()}>
                {['daily','weekly','monthly','quarterly'].map(s => <option key={s}>{s}</option>)}
              </select>
            </Field>
          </div>
          <Field label="Metric">
            <input value={c.metric} onChange={e => update({ metric: e.target.value })}
              placeholder="e.g. Total bookings, ROAS, CPA" style={input()} />
          </Field>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
            <Field label="Target">
              <input value={c.target} onChange={e => update({ target: e.target.value })}
                placeholder="e.g. 100" style={input()} />
            </Field>
            <Field label="Direction">
              <select value={c.direction} onChange={e => update({ direction: e.target.value })} style={input()}>
                <option value="higher">Higher is better ↑</option>
                <option value="lower">Lower is better ↓</option>
                <option value="exact">Exact target</option>
              </select>
            </Field>
            <Field label="Baseline">
              <input value={c.baseline} onChange={e => update({ baseline: e.target.value })}
                placeholder="last 30d" style={input()} />
            </Field>
          </div>
          <Field label="Owner">
            <input value={c.owner} onChange={e => update({ owner: e.target.value })} style={input()} />
          </Field>
          <Field label="Definition (shown to client)">
            <textarea value={c.definition} onChange={e => update({ definition: e.target.value })}
              placeholder="Plain-English description of what counts and what doesn't"
              style={{ ...input(), minHeight: 70, resize: 'vertical', fontFamily: 'inherit' }} />
          </Field>
        </div>
        <div style={{ padding: '12px 20px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button onClick={onClose} style={{
            padding: '7px 14px', borderRadius: 6,
            background: 'var(--surface-2)', color: 'var(--text)',
            border: '1px solid var(--border)', fontSize: 12, fontFamily: 'inherit', fontWeight: 500, cursor: 'pointer',
          }}>Cancel</button>
          <button onClick={() => onSave(c)} disabled={!c.name.trim()} style={{
            padding: '7px 14px', borderRadius: 6,
            background: c.name.trim() ? '#0f172a' : 'var(--surface-2)',
            color: c.name.trim() ? '#fff' : 'var(--text-faint)',
            border: '1px solid ' + (c.name.trim() ? '#0f172a' : 'var(--border)'),
            fontSize: 12, fontFamily: 'inherit', fontWeight: 500,
            cursor: c.name.trim() ? 'pointer' : 'not-allowed',
          }}>Save target</button>
        </div>
      </div>
    </div>
  );
};

const Field = ({ label, children }) => (
  <label style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
    <span style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{label}</span>
    {children}
  </label>
);
const input = () => ({
  padding: '7px 10px', fontSize: 12.5,
  background: 'var(--surface)', color: 'var(--text)',
  border: '1px solid var(--border)', borderRadius: 6,
  fontFamily: 'inherit', outline: 'none',
});

// =============================================================
// AI Suggestions tab — triage queue
// =============================================================
const SuggestionsTab = ({ suggestions, onTriage }) => {
  const [filter, setFilter] = useStateSetup('open');
  const counts = {
    open:     suggestions.filter(s => s.status === 'open').length,
    approved: suggestions.filter(s => s.status === 'approved').length,
    declined: suggestions.filter(s => s.status === 'declined').length,
    hold:     suggestions.filter(s => s.status === 'hold').length,
  };
  const view = filter === 'all' ? suggestions : suggestions.filter(s => s.status === filter);

  return (
    <>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>AI suggestions queue</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            Triage every ClickyAI™ suggestion before it's surfaced to the client. Approved items show on their Growth Opportunities screen with your byline.
          </div>
        </div>
        <div style={{
          display: 'inline-flex', background: 'var(--surface-2)',
          border: '1px solid var(--border)', borderRadius: 6, padding: 2,
        }}>
          {[
            { id: 'open',     label: 'Open',     n: counts.open },
            { id: 'approved', label: 'Approved', n: counts.approved },
            { id: 'declined', label: 'Declined', n: counts.declined },
            { id: 'hold',     label: 'On hold',  n: counts.hold },
            { id: 'all',      label: 'All',      n: suggestions.length },
          ].map(t => (
            <button key={t.id} onClick={() => setFilter(t.id)} style={{
              padding: '5px 10px', fontSize: 11.5, fontWeight: 500, fontFamily: 'inherit',
              background: filter === t.id ? 'var(--surface)' : 'transparent',
              color: filter === t.id ? 'var(--text)' : 'var(--text-muted)',
              border: 'none', borderRadius: 4, cursor: 'pointer',
              boxShadow: filter === t.id ? 'var(--shadow-sm)' : 'none',
              display: 'inline-flex', alignItems: 'center', gap: 5,
            }}>
              {t.label}
              <span style={{ fontSize: 10, color: 'var(--text-faint)' }}>{t.n}</span>
            </button>
          ))}
        </div>
      </div>

      {view.length === 0 ? (
        <div style={{
          padding: '50px 20px', textAlign: 'center',
          background: 'var(--surface)', border: '1px dashed var(--border)', borderRadius: 'var(--radius)',
          color: 'var(--text-muted)', fontSize: 13,
        }}>
          {filter === 'open' ? 'Inbox zero. Nothing waiting on you.' : 'Nothing in this view.'}
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {view.map(s => <SuggestionRow key={s.id} s={s} onTriage={onTriage} />)}
        </div>
      )}
    </>
  );
};

const SuggestionRow = ({ s, onTriage }) => {
  const [note, setNote] = useStateSetup(s.amNote || '');
  const [open, setOpen] = useStateSetup(s.status === 'open');
  const statusToken = {
    open:     { label: 'Awaiting review', color: '#d97706', bg: 'color-mix(in oklab, #d97706 14%, transparent)' },
    approved: { label: 'Approved · sent to client', color: '#16a34a', bg: 'color-mix(in oklab, #16a34a 12%, transparent)' },
    declined: { label: 'Declined · not surfaced',   color: '#dc2626', bg: 'color-mix(in oklab, #dc2626 12%, transparent)' },
    hold:     { label: 'On hold',                   color: '#52525b', bg: 'var(--surface-2)' },
  }[s.status] || { label: s.status, color: 'var(--text-muted)', bg: 'var(--surface-2)' };

  const impactToken = {
    High:   '#dc2626',
    Medium: '#d97706',
    Low:    '#52525b',
  }[s.impact] || '#52525b';

  return (
    <Card padding={0}>
      <div style={{ padding: '14px 16px', borderBottom: open ? '1px solid var(--border)' : 'none' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
              <span style={{
                padding: '1px 8px', borderRadius: 99,
                background: statusToken.bg, color: statusToken.color,
                fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>{statusToken.label}</span>
              <span style={{
                padding: '1px 7px', borderRadius: 99,
                background: 'color-mix(in oklab, ' + impactToken + ' 12%, transparent)',
                color: impactToken,
                fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>Impact: {s.impact}</span>
              <span style={{ fontSize: 10.5, color: 'var(--text-faint)' }}>· {s.source} · {s.confidence} confidence</span>
            </div>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)', marginTop: 6 }}>{s.title}</div>
          </div>
          <button onClick={() => setOpen(v => !v)} style={{
            padding: '4px 8px', fontSize: 11, fontFamily: 'inherit',
            background: 'transparent', color: 'var(--text-muted)',
            border: '1px solid var(--border)', borderRadius: 4, cursor: 'pointer', flexShrink: 0,
          }}>{open ? 'Collapse' : 'Open'}</button>
        </div>
        {s.decidedAt && (
          <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 6 }}>
            Decided {s.decidedAt} by {AM_USER.firstName}
          </div>
        )}
      </div>

      {open && (
        <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div style={{ fontSize: 12.5, color: 'var(--text)', lineHeight: 1.55 }}>{s.body}</div>
          <div style={{
            padding: 10, borderRadius: 6,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
            fontSize: 11.5, color: 'var(--text-muted)',
          }}>
            <span style={{ fontWeight: 600, color: 'var(--text)' }}>Suggested action:</span> {s.suggestedAction}
          </div>
          <Field label="Internal note (visible to Clicky team only)">
            <textarea value={note} onChange={e => setNote(e.target.value)}
              placeholder="Why are you approving / declining? Anything the team should know."
              style={{ ...input(), minHeight: 60, resize: 'vertical', fontFamily: 'inherit' }} />
          </Field>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <button onClick={() => onTriage(s.id, 'approve', note)} style={pillBtn('#16a34a', s.status === 'approved')}>
              ✓ Approve & ship to client
            </button>
            <button onClick={() => onTriage(s.id, 'hold', note)} style={pillBtn('#52525b', s.status === 'hold')}>
              ⏸ Hold for client call
            </button>
            <button onClick={() => onTriage(s.id, 'decline', note)} style={pillBtn('#dc2626', s.status === 'declined')}>
              ✕ Decline
            </button>
          </div>
        </div>
      )}
    </Card>
  );
};

const pillBtn = (color, active) => ({
  padding: '7px 12px', borderRadius: 6,
  background: active ? color : 'var(--surface-2)',
  color: active ? '#fff' : color,
  border: '1px solid ' + (active ? color : 'color-mix(in oklab, ' + color + ' 30%, var(--border))'),
  fontSize: 12, fontFamily: 'inherit', fontWeight: 600, cursor: 'pointer',
  display: 'inline-flex', alignItems: 'center', gap: 4,
});

// =============================================================
// Profile tab — brand identity, registered details, contacts
// =============================================================
const SectionHeader = ({ title, sub }) => (
  <div style={{ marginBottom: 8, marginTop: 6 }}>
    <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>
    {sub && <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 2 }}>{sub}</div>}
  </div>
);

const ProfileTab = ({ profile, onUpdate }) => (
  <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
    <SectionHeader title="Brand identity" sub="Used across the client portal, reports and ClickyAI™ output." />
    <Card>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <Field label="Display name">
          <input value={profile.brand.name} onChange={e => onUpdate('brand.name', e.target.value)} style={input()} />
        </Field>
        <Field label="Short name (for sidebars / breadcrumbs)">
          <input value={profile.brand.shortName} onChange={e => onUpdate('brand.shortName', e.target.value)} style={input()} />
        </Field>
        <Field label="Primary URL">
          <input value={profile.brand.url} onChange={e => onUpdate('brand.url', e.target.value)} style={input()} />
        </Field>
        <Field label="Tagline / one-line description">
          <input value={profile.brand.tagline} onChange={e => onUpdate('brand.tagline', e.target.value)} style={input()} />
        </Field>
        <Field label="Brand primary colour">
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <input type="color" value={profile.brand.primaryColor} onChange={e => onUpdate('brand.primaryColor', e.target.value)}
              style={{ width: 40, height: 30, padding: 0, border: '1px solid var(--border)', borderRadius: 6, background: 'transparent', cursor: 'pointer' }} />
            <input value={profile.brand.primaryColor} onChange={e => onUpdate('brand.primaryColor', e.target.value)}
              style={{ ...input(), fontFamily: 'JetBrains Mono', flex: 1 }} />
          </div>
        </Field>
      </div>
    </Card>

    <SectionHeader title="Registered details" sub="Used on contracts and invoices." />
    <Card>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <Field label="Address line 1">
          <input value={profile.registered.address1} onChange={e => onUpdate('registered.address1', e.target.value)} style={input()} />
        </Field>
        <Field label="Address line 2">
          <input value={profile.registered.address2} onChange={e => onUpdate('registered.address2', e.target.value)} style={input()} />
        </Field>
        <Field label="City">
          <input value={profile.registered.city} onChange={e => onUpdate('registered.city', e.target.value)} style={input()} />
        </Field>
        <Field label="Postcode">
          <input value={profile.registered.postcode} onChange={e => onUpdate('registered.postcode', e.target.value)} style={input()} />
        </Field>
        <Field label="Country">
          <input value={profile.registered.country} onChange={e => onUpdate('registered.country', e.target.value)} style={input()} />
        </Field>
        <Field label="Companies House number">
          <input value={profile.registered.companyNumber} onChange={e => onUpdate('registered.companyNumber', e.target.value)} placeholder="e.g. 12345678" style={input()} />
        </Field>
        <Field label="VAT registration">
          <input value={profile.registered.vat} onChange={e => onUpdate('registered.vat', e.target.value)} placeholder="e.g. GB123456789" style={input()} />
        </Field>
      </div>
    </Card>

    <SectionHeader title="Contacts" sub="The right person for each purpose. Billing contact receives invoice copies and payment reminders." />
    {[
      { id: 'primary',   title: 'Primary contact',   sub: 'Day-to-day decision maker' },
      { id: 'billing',   title: 'Billing contact',   sub: 'Receives invoices and payment reminders' },
      { id: 'technical', title: 'Technical contact', sub: 'Tag/tracking implementation, integrations' },
      { id: 'marketing', title: 'Marketing contact', sub: 'Campaign briefs, creative approvals' },
    ].map(group => {
      const c = profile.contacts[group.id] || {};
      return (
        <Card key={group.id}>
          <div style={{ marginBottom: 10 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600 }}>{group.title}</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>{group.sub}</div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field label="Name">
              <input value={c.name || ''} onChange={e => onUpdate('contacts.' + group.id + '.name', e.target.value)} style={input()} />
            </Field>
            <Field label="Role / title">
              <input value={c.role || ''} onChange={e => onUpdate('contacts.' + group.id + '.role', e.target.value)} style={input()} />
            </Field>
            <Field label="Email">
              <input type="email" value={c.email || ''} onChange={e => onUpdate('contacts.' + group.id + '.email', e.target.value)} style={input()} />
            </Field>
            <Field label="Phone">
              <input value={c.phone || ''} onChange={e => onUpdate('contacts.' + group.id + '.phone', e.target.value)} style={input()} />
            </Field>
          </div>
        </Card>
      );
    })}
  </div>
);

// =============================================================
// Users tab — manage who at the client side has portal access
// =============================================================
const ROLE_OPTIONS = [
  { value: 'Owner',          desc: 'Full access — billing, contracts, settings, all reports' },
  { value: 'Admin',          desc: 'All reports + settings; cannot approve contracts or edit billing' },
  { value: 'Marketing lead', desc: 'View all reports, comment on suggestions, no settings' },
  { value: 'Viewer',         desc: 'Read-only access to reports and dashboards' },
  { value: 'Billing',        desc: 'Billing area only — invoices, contracts, payment methods' },
];

const UsersTab = ({ users, onUpsert, onRemove, clientName }) => {
  const [editing, setEditing] = useStateSetup(null);
  const startInvite = () => setEditing({
    id: 'u-' + Date.now(),
    name: '',
    email: '',
    role: 'Viewer',
    status: 'invited',
    lastLogin: null,
    mfa: false,
    invitedBy: AM_USER.name,
    joined: 'pending',
    isNew: true,
  });

  return (
    <>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>Client-side users</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            {users.length} user{users.length === 1 ? '' : 's'} can sign in to {clientName || 'this client'}'s portal.
          </div>
        </div>
        <button onClick={startInvite} style={{
          padding: '7px 12px', borderRadius: 6,
          background: '#0f172a', color: '#fff',
          border: '1px solid #0f172a', fontSize: 12, fontFamily: 'inherit',
          fontWeight: 500, cursor: 'pointer',
        }}>+ Invite user</button>
      </div>

      <Card padding={0}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'minmax(180px, 1.5fr) 1.4fr 1fr 1fr 0.8fr 70px',
          padding: '10px 16px', background: 'var(--surface-2)',
          fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
          textTransform: 'uppercase', letterSpacing: '0.06em',
          borderBottom: '1px solid var(--border)',
        }}>
          <div>User</div><div>Email</div><div>Role</div><div>Status</div><div>Last login</div><div></div>
        </div>
        {users.map(u => (
          <div key={u.id} style={{
            display: 'grid',
            gridTemplateColumns: 'minmax(180px, 1.5fr) 1.4fr 1fr 1fr 0.8fr 70px',
            padding: '12px 16px', alignItems: 'center', gap: 10,
            borderBottom: '1px solid var(--border)',
            fontSize: 12.5,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <PersonAvatar name={u.name} size={26} hue={(u.name?.charCodeAt(0) || 0) * 7 % 360} />
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 600, color: 'var(--text)' }}>{u.name || <em style={{ color: 'var(--text-faint)' }}>Pending invite</em>}</div>
                {u.mfa && <div style={{ fontSize: 10, color: 'var(--positive)', display: 'inline-flex', alignItems: 'center', gap: 3, marginTop: 1 }}>
                  <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
                  2FA on
                </div>}
              </div>
            </div>
            <div style={{ color: 'var(--text-muted)', fontFamily: 'JetBrains Mono', fontSize: 11.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{u.email}</div>
            <div>
              <span style={{
                padding: '2px 8px', borderRadius: 99,
                background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
                color: 'var(--primary)',
                fontSize: 11, fontWeight: 600,
              }}>{u.role}</span>
            </div>
            <div>
              {u.status === 'active' && (
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--positive)', fontWeight: 600 }}>
                  <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--positive)' }}/> Active
                </span>
              )}
              {u.status === 'invited' && (
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--warning)', fontWeight: 600 }}>
                  <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--warning)' }}/> Invited
                </span>
              )}
              {u.status === 'suspended' && (
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, color: 'var(--text-muted)', fontWeight: 600 }}>
                  <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--text-faint)' }}/> Suspended
                </span>
              )}
            </div>
            <div style={{ color: 'var(--text-muted)', fontSize: 11.5 }}>{u.lastLogin || '—'}</div>
            <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
              <button onClick={() => setEditing(u)} title="Edit" style={iconBtn()}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>
              </button>
              <button onClick={() => { if (confirm('Remove ' + (u.name || 'this user') + ' from the client portal?')) onRemove(u.id); }}
                title="Remove" style={iconBtn('var(--negative)')}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>
              </button>
            </div>
          </div>
        ))}
      </Card>

      {editing && (
        <UserEditModal user={editing} onClose={() => setEditing(null)}
          onSave={(u) => { onUpsert(u); setEditing(null); }} />
      )}
    </>
  );
};

const UserEditModal = ({ user, onClose, onSave }) => {
  const [u, setU] = useStateSetup(user);
  const update = (patch) => setU(prev => ({ ...prev, ...patch }));
  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(15,23,42,0.5)',
      display: 'grid', placeItems: 'center', padding: 24, zIndex: 100,
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 540, background: 'var(--surface)',
        border: '1px solid var(--border)', borderRadius: 'var(--radius)',
        boxShadow: '0 12px 40px rgba(0,0,0,0.18)',
        display: 'flex', flexDirection: 'column', maxHeight: '90vh',
      }}>
        <div style={{ padding: '16px 20px 12px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ fontSize: 9.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.10em' }}>
            Client user
          </div>
          <div style={{ fontSize: 16, fontWeight: 700, marginTop: 2 }}>
            {u.isNew ? 'Invite new user' : 'Edit ' + u.name}
          </div>
        </div>
        <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 12 }}>
          <Field label="Full name">
            <input value={u.name} onChange={e => update({ name: e.target.value })} style={input()} />
          </Field>
          <Field label="Email">
            <input type="email" value={u.email} onChange={e => update({ email: e.target.value })} style={input()} />
          </Field>
          <Field label="Role">
            <select value={u.role} onChange={e => update({ role: e.target.value })} style={input()}>
              {ROLE_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.value}</option>)}
            </select>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>
              {ROLE_OPTIONS.find(o => o.value === u.role)?.desc}
            </div>
          </Field>
          {!u.isNew && (
            <Field label="Status">
              <select value={u.status} onChange={e => update({ status: e.target.value })} style={input()}>
                <option value="active">Active</option>
                <option value="invited">Invited</option>
                <option value="suspended">Suspended</option>
              </select>
            </Field>
          )}
          <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--text)', cursor: 'pointer' }}>
            <input type="checkbox" checked={!!u.mfa} onChange={e => update({ mfa: e.target.checked })} />
            Require two-factor authentication
          </label>
        </div>
        <div style={{ padding: '12px 20px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
          {!u.isNew && u.status === 'invited' && (
            <button style={{
              padding: '7px 12px', borderRadius: 6,
              background: 'transparent', color: 'var(--primary)',
              border: '1px solid color-mix(in oklab, var(--primary) 30%, var(--border))',
              fontSize: 12, fontFamily: 'inherit', fontWeight: 500, cursor: 'pointer',
            }}>Resend invite</button>
          )}
          <div style={{ display: 'flex', gap: 8, marginLeft: 'auto' }}>
            <button onClick={onClose} style={{
              padding: '7px 14px', borderRadius: 6,
              background: 'var(--surface-2)', color: 'var(--text)',
              border: '1px solid var(--border)', fontSize: 12, fontFamily: 'inherit', fontWeight: 500, cursor: 'pointer',
            }}>Cancel</button>
            <button onClick={() => onSave(u)} disabled={!u.email.trim() || !u.name.trim()} style={{
              padding: '7px 14px', borderRadius: 6,
              background: u.email.trim() && u.name.trim() ? '#0f172a' : 'var(--surface-2)',
              color: u.email.trim() && u.name.trim() ? '#fff' : 'var(--text-faint)',
              border: '1px solid ' + (u.email.trim() && u.name.trim() ? '#0f172a' : 'var(--border)'),
              fontSize: 12, fontFamily: 'inherit', fontWeight: 500,
              cursor: u.email.trim() && u.name.trim() ? 'pointer' : 'not-allowed',
            }}>{u.isNew ? 'Send invite' : 'Save changes'}</button>
          </div>
        </div>
      </div>
    </div>
  );
};

// =============================================================
// Contracts tab — pending approvals + active book
// =============================================================
const ContractsTab = ({ contracts, onDecide }) => {
  const pending = contracts.filter(c => c.pendingApproval);
  const active  = contracts.filter(c => c.status === 'Active' && !c.pendingApproval);
  const other   = contracts.filter(c => !c.pendingApproval && c.status !== 'Active');

  return (
    <>
      <div style={{ marginBottom: 14 }}>
        <div style={{ fontSize: 14, fontWeight: 600 }}>Contracts</div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
          Approve new contracts before they go to the client for e-signature. Active contracts are read-only here.
        </div>
      </div>

      {pending.length > 0 && (
        <>
          <SectionHeader title={'Pending your approval · ' + pending.length} sub="Review and approve before sending to the client." />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 18 }}>
            {pending.map(c => <PendingContractCard key={c.id} c={c} onDecide={onDecide} />)}
          </div>
        </>
      )}

      <SectionHeader title={'Active contracts · ' + active.length} />
      {active.length === 0 ? (
        <div style={{
          padding: 30, textAlign: 'center',
          background: 'var(--surface)', border: '1px dashed var(--border)', borderRadius: 'var(--radius)',
          color: 'var(--text-muted)', fontSize: 12.5,
        }}>No active contracts.</div>
      ) : (
        <Card padding={0}>
          {active.map((c, i) => <ActiveContractRow key={c.id} c={c} first={i === 0} />)}
        </Card>
      )}

      {other.length > 0 && (
        <>
          <div style={{ height: 18 }}/>
          <SectionHeader title={'Expired / declined · ' + other.length} />
          <Card padding={0}>
            {other.map((c, i) => <ActiveContractRow key={c.id} c={c} first={i === 0} dim />)}
          </Card>
        </>
      )}
    </>
  );
};

const PendingContractCard = ({ c, onDecide }) => {
  const [note, setNote] = useStateSetup(c.notes || '');
  return (
    <Card padding={0}>
      <div style={{
        padding: '12px 16px', borderBottom: '1px solid var(--border)',
        background: 'color-mix(in oklab, var(--warning) 6%, transparent)',
        display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
      }}>
        <span style={{
          padding: '2px 8px', borderRadius: 99,
          background: 'color-mix(in oklab, var(--warning) 14%, transparent)',
          color: 'var(--warning)',
          fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
        }}>Pending approval</span>
        <div style={{ fontSize: 13, fontWeight: 600 }}>{c.name}</div>
        <div style={{ marginLeft: 'auto', fontSize: 10.5, color: 'var(--text-muted)', fontFamily: 'JetBrains Mono' }}>{c.id}</div>
      </div>
      <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 }}>
          {[
            { label: 'Term',         value: c.term },
            { label: 'Start',        value: c.start },
            { label: 'Renews',       value: c.renews },
            { label: 'Monthly',      value: c.monthly },
          ].map(s => (
            <div key={s.label}>
              <div style={{ fontSize: 9.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>{s.label}</div>
              <div style={{ fontSize: 13, fontWeight: 600, marginTop: 2 }}>{s.value}</div>
            </div>
          ))}
        </div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>
          <strong style={{ color: 'var(--text)' }}>Services:</strong> {c.services}
        </div>
        {c.notes && (
          <div style={{
            padding: 10, borderRadius: 6,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
            fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.5,
          }}>
            <strong style={{ color: 'var(--text)' }}>Drafter's note:</strong> {c.notes}
          </div>
        )}
        <Field label="Internal approval note (optional)">
          <textarea value={note} onChange={e => setNote(e.target.value)}
            placeholder="Anything the team should know about this approval"
            style={{ ...input(), minHeight: 60, resize: 'vertical', fontFamily: 'inherit' }} />
        </Field>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <button onClick={() => onDecide(c.id, 'approve', note)} style={pillBtn('#16a34a')}>
            ✓ Approve & send to client
          </button>
          <button onClick={() => onDecide(c.id, 'decline', note)} style={pillBtn('#dc2626')}>
            ✕ Decline
          </button>
          <div style={{ marginLeft: 'auto', fontSize: 11, color: 'var(--text-muted)', alignSelf: 'center' }}>
            Drafted by {c.signedBy}
          </div>
        </div>
      </div>
    </Card>
  );
};

const ActiveContractRow = ({ c, first, dim }) => (
  <div style={{
    padding: '12px 16px',
    borderTop: first ? 'none' : '1px solid var(--border)',
    display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr 0.8fr', gap: 12, alignItems: 'center',
    opacity: dim ? 0.6 : 1,
    fontSize: 12.5,
  }}>
    <div>
      <div style={{ fontWeight: 600, color: 'var(--text)' }}>{c.name}</div>
      <div style={{ fontSize: 10.5, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', marginTop: 2 }}>{c.id}</div>
    </div>
    <div style={{ color: 'var(--text-muted)' }}>
      <div>{c.start} → {c.renews}</div>
      <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 1 }}>{c.term}</div>
    </div>
    <div style={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{c.monthly}<span style={{ fontWeight: 400, color: 'var(--text-faint)', fontSize: 10.5 }}> /mo</span></div>
    <div>
      <span style={{
        padding: '2px 8px', borderRadius: 99,
        background: c.status === 'Active' ? 'color-mix(in oklab, #16a34a 12%, transparent)' : 'var(--surface-2)',
        color:      c.status === 'Active' ? '#16a34a' : 'var(--text-muted)',
        fontSize: 10.5, fontWeight: 600,
      }}>{c.status}</span>
      {c.autoRenew && c.status === 'Active' && <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 3 }}>auto-renews</div>}
    </div>
    <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
      <button style={{
        padding: '5px 10px', borderRadius: 6,
        background: 'var(--surface-2)', color: 'var(--text)',
        border: '1px solid var(--border)', fontSize: 11, fontFamily: 'inherit',
        fontWeight: 500, cursor: 'pointer',
      }}>View PDF</button>
    </div>
  </div>
);

// =============================================================
// Invoices tab — outstanding, paid, drafts
// =============================================================
const InvoicesTab = ({ invoices, onUpdate }) => {
  const isOutstanding = (i) => /Outstanding|Overdue|Pending|Unpaid/i.test(i.status || '');
  const isPaid        = (i) => /Paid|Settled/i.test(i.status || '');
  const outstanding = invoices.filter(isOutstanding);
  const paid        = invoices.filter(isPaid);
  const other       = invoices.filter(i => !isOutstanding(i) && !isPaid(i));

  const totalOutstanding = outstanding.reduce((sum, i) => {
    const n = parseFloat(String(i.amount || '').replace(/[^0-9.]/g, ''));
    return sum + (isFinite(n) ? n : 0);
  }, 0);

  return (
    <>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>Invoices</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            Outstanding invoices first. Send a reminder or mark as paid in one click.
          </div>
        </div>
        {totalOutstanding > 0 && (
          <div style={{
            padding: '6px 12px', borderRadius: 6,
            background: 'color-mix(in oklab, var(--negative) 8%, transparent)',
            border: '1px solid color-mix(in oklab, var(--negative) 30%, var(--border))',
            color: 'var(--negative)', fontSize: 12, fontWeight: 600,
          }}>
            £{totalOutstanding.toFixed(2)} outstanding
          </div>
        )}
      </div>

      {outstanding.length > 0 && (
        <>
          <SectionHeader title={'Outstanding · ' + outstanding.length} />
          <Card padding={0} style={{ marginBottom: 18 }}>
            {outstanding.map((i, idx) => <InvoiceRow key={i.id} inv={i} first={idx === 0} onUpdate={onUpdate} />)}
          </Card>
        </>
      )}

      {paid.length > 0 && (
        <>
          <SectionHeader title={'Paid · ' + paid.length} />
          <Card padding={0} style={{ marginBottom: 18 }}>
            {paid.map((i, idx) => <InvoiceRow key={i.id} inv={i} first={idx === 0} onUpdate={onUpdate} dim />)}
          </Card>
        </>
      )}

      {other.length > 0 && (
        <>
          <SectionHeader title={'Drafts / other · ' + other.length} />
          <Card padding={0}>
            {other.map((i, idx) => <InvoiceRow key={i.id} inv={i} first={idx === 0} onUpdate={onUpdate} />)}
          </Card>
        </>
      )}

      {invoices.length === 0 && (
        <div style={{
          padding: 40, textAlign: 'center',
          background: 'var(--surface)', border: '1px dashed var(--border)', borderRadius: 'var(--radius)',
          color: 'var(--text-muted)', fontSize: 13,
        }}>No invoices yet.</div>
      )}
    </>
  );
};

const InvoiceRow = ({ inv, first, onUpdate, dim }) => {
  const isOutstanding = /Outstanding|Overdue|Pending|Unpaid/i.test(inv.status || '');
  const isOverdue     = /Overdue/i.test(inv.status || '');
  return (
    <div style={{
      padding: '12px 16px',
      borderTop: first ? 'none' : '1px solid var(--border)',
      display: 'grid', gridTemplateColumns: '0.8fr 1.4fr 1fr 1fr 1fr 1.4fr', gap: 12, alignItems: 'center',
      opacity: dim ? 0.65 : 1,
      fontSize: 12.5,
      background: isOverdue ? 'color-mix(in oklab, var(--negative) 4%, transparent)' : 'transparent',
    }}>
      <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: 'var(--text)' }}>{inv.id}</div>
      <div>
        <div style={{ fontWeight: 600 }}>{inv.period || inv.name || 'Invoice'}</div>
        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 2 }}>{inv.issued || inv.date || ''}</div>
      </div>
      <div style={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{inv.amount || '—'}</div>
      <div style={{ color: 'var(--text-muted)' }}>{inv.due ? 'due ' + inv.due : '—'}</div>
      <div>
        <span style={{
          padding: '2px 8px', borderRadius: 99,
          background: isOverdue
            ? 'color-mix(in oklab, var(--negative) 14%, transparent)'
            : isOutstanding
              ? 'color-mix(in oklab, var(--warning) 14%, transparent)'
              : 'color-mix(in oklab, #16a34a 12%, transparent)',
          color: isOverdue ? 'var(--negative)' : isOutstanding ? 'var(--warning)' : '#16a34a',
          fontSize: 10.5, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
        }}>{inv.status}</span>
        {inv.reminderSentAt && (
          <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 3 }}>reminder sent {inv.reminderSentAt}</div>
        )}
      </div>
      <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end', flexWrap: 'wrap' }}>
        {isOutstanding && (
          <>
            <button onClick={() => onUpdate(inv.id, { reminderSentAt: 'just now' })} style={{
              padding: '5px 10px', borderRadius: 6,
              background: 'var(--surface-2)', color: 'var(--text)',
              border: '1px solid var(--border)', fontSize: 11, fontFamily: 'inherit',
              fontWeight: 500, cursor: 'pointer',
            }}>Send reminder</button>
            <button onClick={() => onUpdate(inv.id, { status: 'Paid', paidAt: new Date().toLocaleDateString('en-GB') })} style={{
              padding: '5px 10px', borderRadius: 6,
              background: '#16a34a', color: '#fff',
              border: '1px solid #16a34a', fontSize: 11, fontFamily: 'inherit',
              fontWeight: 500, cursor: 'pointer',
            }}>Mark paid</button>
          </>
        )}
        <button style={{
          padding: '5px 10px', borderRadius: 6,
          background: 'transparent', color: 'var(--text-muted)',
          border: '1px solid var(--border)', fontSize: 11, fontFamily: 'inherit',
          fontWeight: 500, cursor: 'pointer',
        }}>View</button>
      </div>
    </div>
  );
};

Object.assign(window, { AmClientSetupScreen, PLATFORMS, loadSetup, saveSetup });
