// Screen-level views

const { useState, useEffect, useRef, useMemo } = React;

// ============================================================
// Team & Files (dashboard side cards)
// ============================================================

const TEAM = [
  {
    name: 'Joe Marshall', role: 'Head of Client Strategy', hue: 200, src: 'assets/team/joe.png',
    status: 'online', meta: 'Responds in ~1 hr', primary: true,
    email: 'joe@clicky.co.uk', phone: '0161 808 1888',
    reportsTo: null, joined: '2018',
    focus: ['Strategy', 'Quarterly reviews', 'Roadmap', 'Exec stakeholder'],
    bio: 'Owns the relationship end-to-end. Sets quarterly direction with you and steers the delivery team day-to-day.',
    qualifications: [
      { id: 'q-jm-1', name: 'Google Ads Search Certification',          issuer: 'Google',    issuerSlug: 'google',    issued: 'Aug 2024', verified: true,  source: 'google-api'   },
      { id: 'q-jm-2', name: 'Meta Blueprint — Buying Professional',      issuer: 'Meta',      issuerSlug: 'meta',      issued: 'Mar 2025', verified: true,  source: 'meta-api'     },
      { id: 'q-jm-3', name: 'LinkedIn Marketing Solutions Fundamentals', issuer: 'LinkedIn',  issuerSlug: 'linkedin',  issued: 'Jan 2024', verified: true,  source: 'linkedin-api' },
      { id: 'q-jm-4', name: 'HubSpot Inbound Marketing',                 issuer: 'HubSpot',   issuerSlug: 'hubspot',   issued: 'Sep 2023', verified: false, source: 'manual'       },
    ],
  },
  {
    name: 'Matt Jones', role: 'PPC Team Lead', hue: 30, src: 'assets/team/matt.png',
    status: 'online', meta: 'Google Ads · Bing',
    email: 'matt@clicky.co.uk', phone: '0161 808 1888',
    reportsTo: 'Joe Marshall', joined: '2019',
    focus: ['Google Ads', 'PMax', 'Bing', 'Bidding strategy'],
    bio: 'Leads the paid media pod. Hands-on with bidding, structure and channel mix decisions for ownership + holiday breaks.',
    qualifications: [
      { id: 'q-mj-1', name: 'Google Ads Search Certification',         issuer: 'Google',    issuerSlug: 'google',    issued: 'Feb 2025', verified: true, source: 'google-api' },
      { id: 'q-mj-2', name: 'Google Ads Display Certification',        issuer: 'Google',    issuerSlug: 'google',    issued: 'Feb 2025', verified: true, source: 'google-api' },
      { id: 'q-mj-3', name: 'Google Ads Performance Max',              issuer: 'Google',    issuerSlug: 'google',    issued: 'Mar 2025', verified: true, source: 'google-api' },
      { id: 'q-mj-4', name: 'Google Ads Shopping Certification',       issuer: 'Google',    issuerSlug: 'google',    issued: 'Feb 2025', verified: true, source: 'google-api' },
      { id: 'q-mj-5', name: 'Microsoft Advertising Certified Pro',     issuer: 'Microsoft', issuerSlug: 'microsoft', issued: 'Nov 2024', verified: true, source: 'manual'     },
    ],
  },
  {
    name: 'Nathan Smith', role: 'Agency Systems Manager', hue: 280, src: 'assets/team/nathan.png',
    status: 'online', meta: 'GA4 · Looker',
    email: 'nathan@clicky.co.uk', phone: '0161 808 1888',
    reportsTo: 'Joe Marshall', joined: '2020',
    focus: ['GA4', 'Looker Studio', 'Tag manager', 'Conversion tracking'],
    bio: 'Keeps measurement honest — ships GA4, Looker and conversion-tracking work, and audits data quality before reports go out.',
    qualifications: [
      { id: 'q-ns-1', name: 'Google Analytics Individual Qualification (GAIQ)', issuer: 'Google', issuerSlug: 'google', issued: 'Jan 2025', verified: true, source: 'google-api' },
      { id: 'q-ns-2', name: 'Google Tag Manager Fundamentals',                  issuer: 'Google', issuerSlug: 'google', issued: 'Jan 2025', verified: true, source: 'google-api' },
      { id: 'q-ns-3', name: 'Looker Studio Foundations',                        issuer: 'Google', issuerSlug: 'google', issued: 'Apr 2024', verified: true, source: 'google-api' },
      { id: 'q-ns-4', name: 'Hotjar Foundations',                               issuer: 'Hotjar', issuerSlug: 'manual', issued: 'Oct 2023', verified: false, source: 'manual'    },
    ],
  },
  {
    name: 'Hayley Roberts', role: 'UX Research & Design Manager', hue: 340, src: 'assets/team/hayley.png',
    status: 'away', meta: 'Ads · Landing pages',
    email: 'hayley@clicky.co.uk', phone: '0161 808 1888',
    reportsTo: 'Joe Marshall', joined: '2021',
    focus: ['Ad creative', 'Landing pages', 'CRO', 'Brand'],
    bio: 'Runs design + research. Owns ad creative, landing-page concepts and the CRO experiment backlog.',
    qualifications: [
      { id: 'q-hr-1', name: 'Nielsen Norman UX Certification',     issuer: 'NN/g',       issuerSlug: 'manual',   issued: 'Jul 2023', verified: true,  source: 'manual'     },
      { id: 'q-hr-2', name: 'Optimizely Certified Expert',         issuer: 'Optimizely', issuerSlug: 'manual',   issued: 'Sep 2024', verified: true,  source: 'manual'     },
      { id: 'q-hr-3', name: 'Meta Blueprint — Creative Strategy',  issuer: 'Meta',       issuerSlug: 'meta',     issued: 'May 2024', verified: true,  source: 'meta-api'   },
    ],
  },
  {
    name: 'Shannon May', role: 'Senior Paid Media Specialist', hue: 150, src: 'assets/team/shannon.png',
    status: 'offline', meta: 'Back tomorrow 09:00',
    email: 'shannon@clicky.co.uk', phone: '0161 808 1888',
    reportsTo: 'Matt Jones', joined: '2022',
    focus: ['Day-to-day Google Ads', 'Search', 'Reporting cadence'],
    bio: 'Hands-on day-to-day operator on the Evergreen accounts. First to spot anomalies and triage with Matt.',
    qualifications: [
      { id: 'q-sm-1', name: 'Google Ads Search Certification',  issuer: 'Google', issuerSlug: 'google', issued: 'Mar 2025', verified: true, source: 'google-api' },
      { id: 'q-sm-2', name: 'Google Ads Display Certification', issuer: 'Google', issuerSlug: 'google', issued: 'Mar 2025', verified: true, source: 'google-api' },
      { id: 'q-sm-3', name: 'Meta Blueprint Foundations',       issuer: 'Meta',   issuerSlug: 'meta',   issued: 'Feb 2025', verified: true, source: 'meta-api'   },
      { id: 'q-sm-4', name: 'TikTok Ads Specialist',            issuer: 'TikTok', issuerSlug: 'tiktok', issued: 'Apr 2025', verified: false, source: 'manual'    },
    ],
  },
];

// Issuer brand-mark lookup. Used by the qualifications row everywhere
// (TeamProfilePanel + AM profile editor). Falls back to a generic certificate
// glyph for issuers without an SVG asset.
const ISSUER_LOGO_SRC = {
  google:    'assets/google.svg',
  meta:      'assets/meta.svg',
  microsoft: 'assets/microsoft.svg',
  linkedin:  'assets/linkedin.svg',
  tiktok:    'assets/tiktok.svg',
  reddit:    'assets/reddit.svg',
};
const ISSUER_HUE = {
  google: '#4285f4', meta: '#0866ff', microsoft: '#00a4ef', tiktok: '#000000',
  linkedin: '#0a66c2', hubspot: '#ff7a59', manual: '#52525b',
};
const IssuerMark = ({ slug, size = 20 }) => {
  const src = ISSUER_LOGO_SRC[slug];
  const hue = ISSUER_HUE[slug] || ISSUER_HUE.manual;
  return (
    <span style={{
      width: size, height: size, borderRadius: 5, flexShrink: 0,
      background: 'color-mix(in oklab, ' + hue + ' 12%, var(--surface-2))',
      border: '1px solid color-mix(in oklab, ' + hue + ' 26%, var(--border))',
      display: 'grid', placeItems: 'center',
      color: hue,
    }}>
      {src ? (
        <img src={src} alt="" width={Math.round(size * 0.65)} height={Math.round(size * 0.65)} style={{ display: 'block' }} />
      ) : (
        <svg width={Math.round(size * 0.6)} height={Math.round(size * 0.6)} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="9" r="5"/><path d="M9 14v7l3-2 3 2v-7"/></svg>
      )}
    </span>
  );
};

// Qualifications storage — overlays defaults from TEAM with anything the
// AM has saved/edited. Returns the resolved list for a given person.
const getTeamQualifications = (name) => {
  try {
    const saved = JSON.parse(localStorage.getItem('clicky_team_quals') || '{}');
    if (Array.isArray(saved[name])) return saved[name];
  } catch (e) {}
  const t = TEAM.find(p => p.name === name);
  return (t && t.qualifications) || [];
};
const setTeamQualifications = (name, list) => {
  try {
    const saved = JSON.parse(localStorage.getItem('clicky_team_quals') || '{}');
    saved[name] = list;
    localStorage.setItem('clicky_team_quals', JSON.stringify(saved));
  } catch (e) {}
};

// Reusable qualifications list — used by TeamProfilePanel (read-only)
// and AmProfileScreen (with onEdit / onRemove handlers passed in).
const QualificationsList = ({ qualifications, onEdit, onRemove }) => {
  if (!qualifications || qualifications.length === 0) {
    return (
      <div style={{
        fontSize: 12, color: 'var(--text-muted)', fontStyle: 'italic',
        padding: '8px 10px', background: 'var(--surface-2)',
        border: '1px dashed var(--border)', borderRadius: 6,
      }}>
        No qualifications listed yet.
      </div>
    );
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {qualifications.map(q => (
        <div key={q.id || q.name} style={{
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '8px 10px', borderRadius: 6,
          background: 'var(--surface)', border: '1px solid var(--border)',
        }}>
          <IssuerMark slug={q.issuerSlug} size={28} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)' }}>{q.name}</span>
              {q.verified && (
                <span title={q.source === 'manual' ? 'Verified manually' : `Verified via ${q.issuer} API`}
                  style={{
                  display: 'inline-flex', alignItems: 'center', gap: 3,
                  padding: '1px 6px', borderRadius: 99,
                  background: 'color-mix(in oklab, var(--positive) 12%, transparent)',
                  color: 'var(--positive)',
                  fontSize: 9.5, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>
                  <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
                  Verified
                </span>
              )}
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
              {q.issuer} · Issued {q.issued}
              {q.source !== 'manual' && q.source && (
                <> · <span style={{ color: 'var(--text-faint)' }}>via {q.issuer} API</span></>
              )}
            </div>
          </div>
          {(onEdit || onRemove) && (
            <div style={{ display: 'flex', gap: 4, flexShrink: 0 }}>
              {onEdit && (
                <button onClick={() => onEdit(q)} title="Edit" style={{
                  width: 24, height: 24, display: 'grid', placeItems: 'center',
                  background: 'transparent', border: '1px solid var(--border)',
                  borderRadius: 4, cursor: 'pointer', color: 'var(--text-muted)',
                }}>
                  <svg width="11" height="11" 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>
              )}
              {onRemove && (
                <button onClick={() => onRemove(q.id)} title="Remove" style={{
                  width: 24, height: 24, display: 'grid', placeItems: 'center',
                  background: 'transparent', border: '1px solid var(--border)',
                  borderRadius: 4, cursor: 'pointer', color: 'var(--negative)',
                }}>
                  <svg width="11" height="11" 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>
      ))}
    </div>
  );
};

// Expose helpers + components to other script tags (am.jsx uses them).
Object.assign(window, { TEAM, getTeamQualifications, setTeamQualifications, QualificationsList, IssuerMark, ISSUER_LOGO_SRC, ISSUER_HUE });

const FILES = [
  { name: 'Q2 2026 Strategy Deck.pdf',          kind: 'pdf',    size: '2.4 MB',  updated: '2 days ago', who: 'Joe M.'    },
  { name: 'April Performance Report.xlsx',      kind: 'sheet',  size: '184 KB',  updated: '2 days ago', who: 'Nathan S.' },
  { name: 'Spring Breaks — Ad Creatives',     kind: 'folder', size: '12 files',updated: '5 days ago', who: 'Hayley R.' },
  { name: 'Brand Guidelines v3.pdf',            kind: 'pdf',    size: '6.1 MB',  updated: '3 weeks ago',who: 'You'      },
  { name: 'Conversion Tracking Audit.docx',     kind: 'doc',    size: '92 KB',   updated: '1 month ago',who: 'Nathan S.' },
];

const EXTERNAL_TOOLS = [
  { name: 'Google Ads',          sub: '482-209-7716',                    icon: I.google,  url: '#', kind: 'analytics' },
  { name: 'Google Analytics',    sub: 'GA4 · st-mabyn-escape',           icon: 'ga4',     url: '#', kind: 'analytics' },
  { name: 'Search Console',      sub: 'st-mabyn-escape.co.uk',           icon: 'gsc',     url: '#', kind: 'analytics' },
  { name: 'Looker Studio',       sub: 'Live performance dashboard',      icon: 'looker',  url: '#', kind: 'analytics' },
  { name: 'Basecamp · Evergreen', sub: 'Active project workspace',        icon: 'basecamp',url: '#', kind: 'project' },
  { name: 'Hospitality Vertical Report 2026',  sub: 'Q1 benchmark · Clicky Insider',     icon: 'report',  url: '#', kind: 'report' },
  { name: 'Holiday Park Search Trends Report', sub: 'Updated weekly · st-mabyn-escape',  icon: 'report',  url: '#', kind: 'report' },
];

// ============================================================
// Topbar search — overlay panel that surfaces matching items across
// performance targets, services, websites, team, reports, tickets,
// invoices, contracts, opportunities and insider posts.
// ============================================================

const SearchOverlay = ({ query, onClose, onJump }) => {
  const [phase, setPhase] = useState('loading'); // 'loading' | 'ready'

  useEffect(() => {
    setPhase('loading');
    if (!query.trim()) return;
    const t = setTimeout(() => setPhase('ready'), 280);
    return () => clearTimeout(t);
  }, [query]);

  // Build a lazy index every time so newly-added data flows in. Each entry has
  // { type, title, sub, target, icon } where target is a callback to navigate.
  const buildIndex = () => {
    const idx = [];
    (window.AGREED_KPIS || []).forEach(k => idx.push({
      type: 'Performance Target', title: k.label, sub: k.sub || '',
      target: () => onJump('cpts', { kpi: k.key }),
      iconName: 'target',
    }));
    (window.CLIENT?.sites || []).forEach(s => idx.push({
      type: 'Website', title: s.name, sub: s.url + ' · ' + (s.role || ''),
      target: () => onJump('maintenance', { siteId: s.id }),
      iconName: 'site',
    }));
    (window.TEAM || []).forEach(p => idx.push({
      type: 'Team', title: p.name, sub: p.role,
      target: () => onJump('team'),
      iconName: 'avatar', avatar: p,
    }));
    (window.REPORTS || []).forEach(r => idx.push({
      type: 'Report', title: r.name, sub: `${r.channel} · ${r.period} · ${r.status}`,
      target: () => onJump('reports'),
      iconName: 'file',
    }));
    (window.TICKETS || []).forEach(t => idx.push({
      type: 'Ticket', title: t.subject, sub: `${t.id} · ${t.status} · ${t.assignee}`,
      target: () => onJump('tickets'),
      iconName: 'ticket',
    }));
    (window.CONTRACTS || []).forEach(c => idx.push({
      type: 'Contract', title: c.name, sub: `${c.id} · ${c.term} · ${c.monthly}`,
      target: () => onJump('billing', { tab: 'contracts' }),
      iconName: 'doc',
    }));
    (window.INVOICES || []).forEach(inv => idx.push({
      type: 'Invoice', title: `${inv.id} · ${inv.amount}`, sub: `${inv.period} · due ${inv.due}`,
      target: () => onJump('billing', { tab: 'invoices' }),
      iconName: 'receipt',
    }));
    (window.GROWTH_OPPORTUNITIES || []).forEach(o => idx.push({
      type: 'Opportunity', title: o.title, sub: `${o.category} · ${o.impact?.range || ''} ${o.impact?.cadence || ''}`.trim(),
      target: () => onJump('opportunities'),
      iconName: 'spark',
    }));
    SERVICES.forEach(s => idx.push({
      type: 'Service', title: s.title, sub: `${s.category} · ${s.pricing}`,
      target: () => onJump(s.active ? (s.id === 'google' ? 'google' : s.id === 'seo' ? 'seo' : s.id === 'meta' ? 'meta' : 'channels') : 'growth'),
      iconName: 'service',
    }));
    INSIDER.forEach(i => idx.push({
      type: 'Insider', title: i.title, sub: `${i.tag} · ${i.when} · ${i.by}`,
      target: () => onJump('insider', { articleId: i.id }),
      iconName: 'star',
    }));
    return idx;
  };

  const q = query.trim().toLowerCase();
  const matches = q ? buildIndex().filter(m =>
    (m.title + ' ' + (m.sub || '')).toLowerCase().includes(q)
  ).slice(0, 30) : [];

  // Group matches by type for readable rendering
  const grouped = {};
  matches.forEach(m => {
    if (!grouped[m.type]) grouped[m.type] = [];
    grouped[m.type].push(m);
  });
  const typeOrder = ['Performance Target', 'Website', 'Team', 'Report', 'Ticket', 'Contract', 'Invoice', 'Service', 'Opportunity', 'Insider'];

  const renderIcon = (m) => {
    const tile = (children, color = 'var(--text-muted)', bg = 'var(--surface-2)') => (
      <div style={{
        width: 32, height: 32, borderRadius: 6, flexShrink: 0,
        background: bg, color,
        display: 'grid', placeItems: 'center',
      }}>{children}</div>
    );
    switch (m.iconName) {
      case 'target':  return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.6" fill="currentColor"/></svg>, 'var(--primary)', 'color-mix(in oklab, var(--primary) 12%, transparent)');
      case 'site':    return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>);
      case 'avatar':  return <PersonAvatar name={m.avatar?.name || m.title} size={32} hue={m.avatar?.hue || 200} src={m.avatar?.src} />;
      case 'file':    return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8zM14 3v5h5M9 13h6M9 17h4"/></svg>);
      case 'ticket':  return tile(I.ticket);
      case 'doc':     return tile(I.doc);
      case 'receipt': return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M7 15h2M12 15h5"/></svg>);
      case 'spark':   return tile(<img src="assets/ai-opps.svg" alt="" width="20" height="20"/>, '', 'var(--surface)');
      case 'service': return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>);
      case 'star':    return tile(<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2 14.5 8.5 21 9.3l-5 4.6L17.4 21 12 17.5 6.6 21 8 13.9l-5-4.6 6.5-.8z"/></svg>);
      default:        return tile(I.search);
    }
  };

  // Highlight the matched substring in the title
  const highlight = (text) => {
    if (!q || !text) return text;
    const i = String(text).toLowerCase().indexOf(q);
    if (i < 0) return text;
    return (<>
      {String(text).slice(0, i)}
      <mark style={{ background: 'color-mix(in oklab, var(--primary) 20%, transparent)', color: 'var(--primary)', padding: '0 1px', borderRadius: 2 }}>{String(text).slice(i, i + q.length)}</mark>
      {String(text).slice(i + q.length)}
    </>);
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, top: 56,
      zIndex: 40,
      background: 'rgba(8, 8, 16, 0.45)',
      backdropFilter: 'blur(8px) saturate(110%)',
      WebkitBackdropFilter: 'blur(8px) saturate(110%)',
      animation: 'searchFade 180ms ease',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        maxWidth: 720, margin: '24px auto 0',
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)', boxShadow: '0 24px 48px -12px rgba(0,0,0,0.4)',
        overflow: 'hidden', maxHeight: 'calc(100vh - 100px)',
        display: 'flex', flexDirection: 'column',
      }}>
        {/* Header — search summary */}
        <div style={{
          padding: '12px 16px', borderBottom: '1px solid var(--border)',
          display: 'flex', alignItems: 'center', gap: 10,
          fontSize: 12, color: 'var(--text-muted)',
        }}>
          {phase === 'loading' ? (
            <>
              <span style={{
                width: 12, height: 12, borderRadius: '50%',
                border: '2px solid var(--border)', borderTopColor: 'var(--primary)',
                animation: 'searchSpin 0.7s linear infinite', display: 'inline-block',
              }}/>
              <span>Searching across the account…</span>
            </>
          ) : (
            <>
              <span style={{ color: 'var(--text-faint)', display: 'inline-flex' }}>{I.search}</span>
              <span><strong style={{ color: 'var(--text)', fontWeight: 600 }}>{matches.length}</strong> result{matches.length === 1 ? '' : 's'} for "{query}"</span>
            </>
          )}
          <div style={{ flex: 1 }}/>
          <kbd style={{
            fontSize: 10, padding: '2px 6px', borderRadius: 4,
            background: 'var(--surface-2)', color: 'var(--text-faint)',
            border: '1px solid var(--border)', fontFamily: 'JetBrains Mono',
          }}>esc</kbd>
        </div>

        {/* Body */}
        <div style={{ overflowY: 'auto', flex: 1 }}>
          {phase === 'loading' ? (
            <div style={{ padding: 12, display: 'flex', flexDirection: 'column', gap: 8 }}>
              {[0, 1, 2, 3].map(i => (
                <div key={i} style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: '8px 8px',
                }}>
                  <div style={{ width: 32, height: 32, borderRadius: 6, background: 'var(--surface-2)', flexShrink: 0 }}/>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ width: '60%', height: 10, background: 'var(--surface-2)', borderRadius: 3 }}/>
                    <div style={{ width: '40%', height: 8, background: 'var(--surface-2)', borderRadius: 3, marginTop: 6 }}/>
                  </div>
                </div>
              ))}
            </div>
          ) : matches.length === 0 ? (
            <div style={{ padding: '40px 16px', textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>
              No matches for "<strong style={{ color: 'var(--text)' }}>{query}</strong>".
              <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 6 }}>
                Try a different keyword, or ask <span style={{ color: 'var(--primary)' }}>ClickyAI™</span> to investigate.
              </div>
            </div>
          ) : (
            <div style={{ padding: 6 }}>
              {typeOrder.filter(t => grouped[t]).map(type => (
                <div key={type}>
                  <div style={{
                    padding: '10px 14px 4px', fontSize: 10, fontWeight: 700,
                    color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em',
                  }}>
                    {type}{grouped[type].length > 1 ? 's' : ''} <span style={{ color: 'var(--text-faint)', fontWeight: 600 }}>· {grouped[type].length}</span>
                  </div>
                  {grouped[type].map((m, i) => (
                    <button key={type + i}
                      onClick={() => { m.target(); onClose(); }}
                      style={{
                        display: 'flex', alignItems: 'center', gap: 12,
                        width: '100%', textAlign: 'left',
                        padding: '8px 10px', borderRadius: 6,
                        background: 'transparent', border: 'none', cursor: 'pointer',
                        fontFamily: 'inherit',
                      }}
                      onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                    >
                      {renderIcon(m)}
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{
                          fontSize: 13, fontWeight: 600, color: 'var(--text)',
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{highlight(m.title)}</div>
                        <div style={{
                          fontSize: 11, color: 'var(--text-muted)', marginTop: 1,
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{m.sub}</div>
                      </div>
                      <span style={{ color: 'var(--text-faint)', flexShrink: 0 }}>{I.arrowRight}</span>
                    </button>
                  ))}
                </div>
              ))}
            </div>
          )}
        </div>

        {/* Footer */}
        <div style={{
          padding: '10px 14px', borderTop: '1px solid var(--border)',
          fontSize: 11, color: 'var(--text-faint)',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
        }}>
          <span>Searches your performance, services, sites, team, files, billing and AI surfaces</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
            <kbd style={{
              fontSize: 10, padding: '1px 5px', borderRadius: 3,
              background: 'var(--surface-2)', color: 'var(--text-muted)',
              border: '1px solid var(--border)', fontFamily: 'JetBrains Mono',
            }}>↩</kbd> to open
          </span>
        </div>
      </div>
    </div>
  );
};

window.SearchOverlay = SearchOverlay;

// ============================================================
// Sortable-table helpers — used by every <table> in the app so
// columns can be sorted asc/desc by clicking the header.
// ============================================================

const useTableSort = (data, defaultKey, defaultDir = 'desc') => {
  const [sortKey, setSortKey] = useState(defaultKey);
  const [sortDir, setSortDir] = useState(defaultDir);
  const onSort = (key) => {
    if (key === sortKey) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortKey(key); setSortDir('desc'); }
  };

  const sorted = useMemo(() => {
    if (!sortKey) return data;
    // Strip currency / units so "£1,250.00", "12.4%", "4.8x" compare numerically.
    const toNum = (v) => {
      if (v == null) return null;
      if (typeof v === 'number') return v;
      const cleaned = String(v).replace(/[£,$%]/g, '').replace(/[a-zA-Z]+$/, '').trim();
      const n = parseFloat(cleaned);
      return isFinite(n) ? n : null;
    };
    return [...data].sort((a, b) => {
      const va = a[sortKey];
      const vb = b[sortKey];
      let cmp;
      const na = toNum(va), nb = toNum(vb);
      if (na != null && nb != null && !isNaN(na) && !isNaN(nb)) cmp = na - nb;
      else if (va == null && vb == null) cmp = 0;
      else if (va == null) cmp = 1;
      else if (vb == null) cmp = -1;
      else cmp = String(va).localeCompare(String(vb));
      return sortDir === 'asc' ? cmp : -cmp;
    });
  }, [data, sortKey, sortDir]);

  return { sorted, sortKey, sortDir, onSort };
};

const SortableTh = ({ children, sortKey, currentKey, dir, onSort, align = 'left', width }) => {
  const isActive = currentKey === sortKey;
  return (
    <th
      onClick={() => onSort && onSort(sortKey)}
      style={{
        padding: '12px 14px',
        textAlign: align,
        fontSize: 11, fontWeight: 600, color: isActive ? 'var(--text)' : 'var(--text-muted)',
        textTransform: 'uppercase', letterSpacing: '0.04em',
        borderBottom: '1px solid var(--border)',
        cursor: 'pointer', userSelect: 'none',
        transition: 'color 120ms ease',
        whiteSpace: 'nowrap',
        ...(width != null ? { width } : {}),
      }}
      onMouseEnter={e => e.currentTarget.style.color = 'var(--text)'}
      onMouseLeave={e => e.currentTarget.style.color = isActive ? 'var(--text)' : 'var(--text-muted)'}
    >
      <span style={{
        display: 'inline-flex', alignItems: 'center', gap: 4,
        flexDirection: align === 'right' ? 'row-reverse' : 'row',
      }}>
        {children}
        <span style={{
          display: 'inline-flex', width: 10, height: 10, flexShrink: 0,
          opacity: isActive ? 1 : 0.32,
          color: isActive ? 'var(--primary)' : 'currentColor',
        }}>
          {isActive ? (
            dir === 'asc'
              ? <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="m6 15 6-6 6 6"/></svg>
              : <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/></svg>
          ) : (
            <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6-6 6 6"/><path d="m6 15 6 6 6-6"/></svg>
          )}
        </span>
      </span>
    </th>
  );
};

const StatusDot = ({ status }) => {
  const c = status === 'online' ? 'var(--positive)' : status === 'away' ? 'var(--warning)' : 'var(--text-faint)';
  return <span style={{ width: 8, height: 8, borderRadius: '50%', background: c, display: 'inline-block', boxShadow: '0 0 0 2px var(--surface)' }} />;
};

const TeamCard = ({ setActive }) => {
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', fontWeight: 600, fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
          <span style={{
            width: 32, height: 32, borderRadius: 8,
            background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="8" r="3.5"/><circle cx="17" cy="9" r="2.5"/><path d="M2.5 20a6.5 6.5 0 0 1 13 0"/><path d="M15 20a5 5 0 0 1 6.5-4.8"/></svg>
          </span>
          Your Clicky team
        </span>
        <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{TEAM.length} people</span>
      </div>
      <div style={{ padding: 6 }}>
        {TEAM.map((p, i) => {
          const isLead = !!p.primary;
          const isLastSub = !isLead && i === TEAM.length - 1;
          return (
            <React.Fragment key={p.name}>
              {/* Subheader between Lead and the delivery team — line aligns with tree connector below */}
              {!isLead && i === 1 && (
                <div style={{
                  padding: '10px 12px 6px 18px', fontSize: 10,
                  color: 'var(--text-faint)', fontWeight: 600,
                  textTransform: 'uppercase', letterSpacing: '0.06em',
                  display: 'flex', alignItems: 'center', gap: 8,
                }}>
                  <span style={{ height: 1, width: 10, background: 'var(--border)' }} />
                  Delivery team
                </div>
              )}

              <div style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: isLead ? '10px 12px' : '8px 12px 8px 28px',
                borderRadius: 6,
                cursor: 'pointer',
                position: 'relative',
              }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                {/* Tree connector for indented sub-team rows */}
                {!isLead && (
                  <>
                    <span style={{
                      position: 'absolute', left: 18, top: 0,
                      bottom: isLastSub ? '50%' : 0,
                      width: 1, background: 'var(--border)',
                    }} />
                    <span style={{
                      position: 'absolute', left: 18, top: '50%',
                      width: 8, height: 1, background: 'var(--border)',
                    }} />
                  </>
                )}

                <div style={{ position: 'relative', flexShrink: 0 }}>
                  <PersonAvatar name={p.name} size={isLead ? 36 : 30} hue={p.hue} src={p.src} />
                </div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span style={{ fontSize: isLead ? 13 : 12.5, fontWeight: 600, color: 'var(--text)' }}>{p.name}</span>
                    {isLead && <Badge tone="primary">Lead</Badge>}
                  </div>
                  <div style={{ fontSize: isLead ? 12 : 11.5, color: 'var(--text-muted)', marginTop: 1 }}>{p.role}</div>
                  {isLead && (
                    <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>{p.meta}</div>
                  )}
                </div>
                <button title={`Email ${p.name.split(' ')[0]}`} style={{
                  width: isLead ? 30 : 26, height: isLead ? 30 : 26, borderRadius: 6,
                  border: '1px solid var(--border)',
                  background: 'var(--surface)', color: 'var(--text-muted)',
                  display: 'grid', placeItems: 'center', cursor: 'pointer', flexShrink: 0,
                }}
                  onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface-2)'; e.currentTarget.style.color = 'var(--text)'; }}
                  onMouseLeave={e => { e.currentTarget.style.background = 'var(--surface)'; e.currentTarget.style.color = 'var(--text-muted)'; }}
                >
                  <svg width={isLead ? 14 : 12} height={isLead ? 14 : 12} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>
                </button>
              </div>
            </React.Fragment>
          );
        })}
      </div>
      <div style={{ padding: '10px 12px', borderTop: '1px solid var(--border)', display: 'flex', gap: 8 }}>
        <Btn variant="primary" size="sm" style={{ flex: 1, justifyContent: 'center' }}>Submit ticket</Btn>
        <Btn variant="secondary" size="sm" style={{ flex: 1, justifyContent: 'center' }} onClick={() => setActive && setActive('team')}>Book a call</Btn>
      </div>
    </Card>
  );
};

// Tiny coloured tile icons for external tools (mock brand marks)
const ToolIcon = ({ kind }) => {
  const box = (bg, fg) => ({
    width: 28, height: 28, borderRadius: 6,
    background: bg, color: fg, display: 'grid', placeItems: 'center',
    fontSize: 12, fontWeight: 700, fontFamily: 'Inter', flexShrink: 0,
  });
  if (kind === 'ga4')     return <div style={box('#F9AB00', '#fff')}>A</div>;
  if (kind === 'gsc')     return <div style={box('#458CF5', '#fff')}>S</div>;
  if (kind === 'looker')  return <div style={box('#4285F4', '#fff')}>L</div>;
  if (kind === 'drive')   return <div style={box('#1FA463', '#fff')}>D</div>;
  if (kind === 'basecamp')return <div style={box('#FFCD3F', '#1D2D35')}>B</div>;
  if (kind === 'report')  return (
    <div style={{ ...box('color-mix(in oklab, var(--primary) 12%, transparent)', 'var(--primary)'), border: '1px solid color-mix(in oklab, var(--primary) 25%, var(--border))' }}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M8 13h2v5"/><path d="M14 11v7"/></svg>
    </div>
  );
  // Pass-through for I.google etc — render in a neutral tile
  return <div style={{ ...box('var(--surface-2)', 'var(--text)'), border: '1px solid var(--border)' }}>{kind}</div>;
};

const FileIcon = ({ kind }) => {
  const tone = kind === 'pdf' ? '#E03E3E' : kind === 'sheet' ? '#0F9D58' : kind === 'doc' ? '#2A6DF4' : '#9C7B2D';
  const letter = kind === 'pdf' ? 'PDF' : kind === 'sheet' ? 'XLS' : kind === 'doc' ? 'DOC' : '';
  return (
    <div style={{
      width: 30, height: 36, borderRadius: 4, background: 'var(--surface-2)',
      border: '1px solid var(--border)', position: 'relative', flexShrink: 0,
      display: 'grid', placeItems: 'end center', overflow: 'hidden',
    }}>
      {kind === 'folder' ? (
        <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={tone} strokeWidth="1.6" style={{ marginBottom: 6 }}><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
      ) : (
        <span style={{
          fontSize: 9, fontWeight: 700, color: '#fff', background: tone,
          padding: '1px 4px', borderRadius: 2, marginBottom: 4, fontFamily: 'Inter', letterSpacing: '0.04em',
        }}>{letter}</span>
      )}
    </div>
  );
};

const FilesCard = () => {
  return (
    <Card padding={0}>
      <div style={{ padding: '12px 14px 12px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
          <img src="assets/gdrive.svg" alt="Google Drive" width="18" height="18" style={{ flexShrink: 0 }} />
          <span style={{ fontSize: 13, fontWeight: 600 }}>Files</span>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 4,
            fontSize: 10, fontWeight: 600,
            padding: '2px 6px', borderRadius: 99,
            background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
            color: 'var(--positive)',
          }}>
            <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)' }}/>
            Connected
          </span>
        </div>
        <button style={{
          background: 'none', border: 'none', color: 'var(--primary)', fontSize: 12,
          fontWeight: 500, cursor: 'pointer', padding: 0,
          display: 'inline-flex', alignItems: 'center', gap: 4,
        }}>
          Open in Drive <span style={{ width: 12, height: 12, display: 'inline-flex' }}>{I.external}</span>
        </button>
      </div>

      {/* Drive breadcrumb */}
      <div style={{
        padding: '12px 14px', borderBottom: '1px solid var(--border)',
        fontSize: 11, color: 'var(--text-muted)',
        background: 'color-mix(in oklab, var(--surface-2) 50%, transparent)',
        display: 'flex', alignItems: 'center', gap: 4, whiteSpace: 'nowrap', overflow: 'hidden',
      }}>
        <span style={{ color: 'var(--text-faint)' }}>Drive</span>
        <span style={{ color: 'var(--text-faint)' }}>›</span>
        <span style={{ color: 'var(--text-muted)' }}>Clicky / Evergreen</span>
        <span style={{ color: 'var(--text-faint)' }}>›</span>
        <span style={{ color: 'var(--text)', fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis' }}>Shared with you</span>
      </div>

      <div style={{ padding: 6 }}>
        {FILES.map(f => (
          <a key={f.name} href="#" style={{
            display: 'flex', alignItems: 'center', gap: 12,
            padding: '8px 12px', borderRadius: 6, textDecoration: 'none',
            color: 'inherit',
          }}
            onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
            onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
          >
            <FileIcon kind={f.kind} />
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{f.name}</div>
              <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>
                {f.size} · {f.updated} · edited by {f.who}
              </div>
            </div>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" style={{ color: 'var(--text-faint)', flexShrink: 0 }}><path d="M7 17 17 7M9 7h8v8"/></svg>
          </a>
        ))}
      </div>
    </Card>
  );
};

// External tools — analytics platforms, project workspaces, vertical reports
const ExternalToolsCard = () => {
  const groups = [
    { id: 'analytics', label: 'Analytics & ad platforms' },
    { id: 'project',   label: 'Project workspaces' },
    { id: 'report',    label: 'Vertical reports' },
  ];
  return (
    <Card padding={0}>
      <div style={{ padding: '12px 14px 12px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-muted)' }}><path d="M14 5h5v5"/><path d="M19 5l-9 9"/><path d="M19 13v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6"/></svg>
          <span style={{ fontSize: 13, fontWeight: 600 }}>External tools</span>
        </div>
        <button style={{
          background: 'none', border: 'none', color: 'var(--primary)', fontSize: 12,
          fontWeight: 500, cursor: 'pointer', padding: 0,
        }}>
          Manage
        </button>
      </div>

      {groups.map(g => {
        const items = EXTERNAL_TOOLS.filter(t => t.kind === g.id);
        if (!items.length) return null;
        return (
          <div key={g.id}>
            <div style={{
              padding: '10px 18px 4px', fontSize: 10, fontWeight: 600,
              color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em',
            }}>{g.label}</div>
            <div style={{ padding: '0 6px 6px' }}>
              {items.map(t => (
                <a key={t.name} href={t.url} target="_blank" rel="noreferrer" style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: '8px 12px', borderRadius: 6, textDecoration: 'none',
                  color: 'inherit',
                }}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  {typeof t.icon === 'string'
                    ? <ToolIcon kind={t.icon} />
                    : <div style={{ width: 28, height: 28, borderRadius: 6, background: 'var(--surface-2)', border: '1px solid var(--border)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>{t.icon}</div>
                  }
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--text)' }}>{t.name}</div>
                    <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>{t.sub}</div>
                  </div>
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" style={{ color: 'var(--text-faint)', flexShrink: 0 }}><path d="M7 17 17 7M9 7h8v8"/></svg>
                </a>
              ))}
            </div>
          </div>
        );
      })}
    </Card>
  );
};

window.TeamCard = TeamCard;
window.FilesCard = FilesCard;
window.ExternalToolsCard = ExternalToolsCard;

// ============================================================
// Events Screen — full page; replaces the dashboard EventsCard
// ============================================================

// ============================================================

const CapacityChart = ({ capacity, premium }) => {
  const { total, remaining, unlimited } = capacity;
  const filled = total - remaining;
  const [hover, setHover] = useState(false);
  const w = 100, h = 6;
  const pct = total > 0 ? Math.min(1, Math.max(0, filled / total)) : 0;
  const fillX = pct * w;
  const lineY = h * 0.5;
  const remainPct = total > 0 ? remaining / total : 0;
  const color = premium
    ? 'var(--brand-primary)'
    : remainPct < 0.15 ? '#dc2626'
    : remainPct < 0.4  ? '#d97706'
    : '#10b981';
  const label = unlimited
    ? `${remaining} of ${total} seats available`
    : remaining <= 0
      ? 'Sold out'
      : remaining <= 3
        ? `Only ${remaining} of ${total} seats left`
        : `${remaining} of ${total} seats left`;
  return (
    <div
      style={{ position: 'relative', marginTop: 10, height: h }}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
    >
      <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: 'block' }}>
        <line x1="0" y1={lineY} x2={w} y2={lineY} stroke="var(--border-strong, #d4d4d8)" strokeWidth="1.5" strokeLinecap="round" vectorEffect="non-scaling-stroke" />
        {fillX > 0 && (
          <line x1="0" y1={lineY} x2={fillX} y2={lineY} stroke={color} strokeWidth="1.75" strokeLinecap="round" vectorEffect="non-scaling-stroke" />
        )}
      </svg>
      {hover && (
        <div style={{
          position: 'absolute', bottom: '100%', left: `${pct * 100}%`, transform: 'translate(-50%, -6px)',
          background: 'var(--text)', color: 'var(--surface)',
          fontSize: 11, fontWeight: 500, padding: '4px 8px', borderRadius: 4,
          whiteSpace: 'nowrap', pointerEvents: 'none', zIndex: 5,
        }}>{label}</div>
      )}
    </div>
  );
};

// ============================================================

const EventsScreen = () => {
  const [filter, setFilter] = useState('all');
  const visible = EVENTS.filter(e =>
    filter === 'all' ? true :
    filter === 'in-person' ? e.type === 'In person' :
    filter === 'online' ? e.type === 'Online' :
    filter === 'premium' ? e.premium : true
  );
  return (
    <div>
      <PageHeader
        title="Events" subtitle="Workshops, webinars and in-person meetups hosted by Clicky"
      />
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16, flexWrap: 'wrap' }}>
        {[
          { id: 'all',       label: 'All' },
          { id: 'in-person', label: 'In person' },
          { id: 'online',    label: 'Online' },
          { id: 'premium',   label: 'Premium only' },
        ].map(t => (
          <button key={t.id} onClick={() => setFilter(t.id)} style={{
            padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
            background: filter === t.id ? 'var(--text)' : 'var(--surface)',
            color: filter === t.id ? 'var(--surface)' : 'var(--text-muted)',
            border: '1px solid ' + (filter === t.id ? 'var(--text)' : 'var(--border)'),
            cursor: 'pointer',
          }}>{t.label}</button>
        ))}
        <div style={{ flex: 1 }}/>
        <Btn variant="secondary" size="sm" icon={I.calendar}>Sync to my calendar</Btn>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 16 }}>
        {visible.map(ev => (
          <Card key={ev.id} padding={0} style={{ overflow: 'hidden' }}>
            {/* Hero image */}
            <div style={{ position: 'relative', height: 150, overflow: 'hidden', background: 'var(--surface-2)' }}>
              {ev.image ? (
                <img src={ev.image} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
              ) : (
                <div style={{
                  width: '100%', height: '100%',
                  background: 'linear-gradient(135deg, color-mix(in oklab, var(--primary) 30%, var(--surface-2)) 0%, var(--surface-2) 100%)',
                }}/>
              )}
              {/* Gradient for legibility */}
              <div style={{
                position: 'absolute', inset: 0,
                background: 'linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 35%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.55) 100%)',
                pointerEvents: 'none',
              }}/>
              {/* Date block top-left */}
              <div style={{
                position: 'absolute', top: 12, left: 12,
                background: '#fff', color: 'var(--text)',
                borderRadius: 6, overflow: 'hidden',
                width: 52, textAlign: 'center',
                boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
              }}>
                <div style={{
                  fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em',
                  color: '#fff', background: ev.premium ? '#1a1a1a' : 'var(--primary)',
                  padding: '3px 0',
                }}>{ev.when.month}</div>
                <div style={{ fontSize: 22, fontWeight: 700, padding: '4px 0 6px', fontVariantNumeric: 'tabular-nums', lineHeight: 1, letterSpacing: '-0.02em' }}>{ev.when.day}</div>
              </div>
              {/* Tags top-right */}
              <div style={{ position: 'absolute', top: 12, right: 12, display: 'flex', gap: 6, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
                <span style={{
                  fontSize: 10, fontWeight: 600, padding: '3px 8px', borderRadius: 99,
                  background: 'rgba(255,255,255,0.95)', color: 'var(--text)',
                  display: 'inline-flex', alignItems: 'center', gap: 4,
                  backdropFilter: 'blur(4px)',
                }}>
                  {ev.type === 'In person'
                    ? <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4"><path d="M12 22s7-7 7-12a7 7 0 1 0-14 0c0 5 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></svg>
                    : <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="m16 10 6-3v10l-6-3"/></svg>
                  }
                  {ev.city}
                </span>
                {ev.premium && (
                  <span style={{
                    fontSize: 10, fontWeight: 600, padding: '3px 8px', borderRadius: 99,
                    background: '#1a1a1a', color: '#fff',
                  }}>Premium only</span>
                )}
                {ev.soldOut && (
                  <span style={{
                    fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
                    background: '#dc2626', color: '#fff', textTransform: 'uppercase', letterSpacing: '0.04em',
                  }}>Sold out</span>
                )}
              </div>
              {/* Time bottom-left over gradient */}
              <div style={{
                position: 'absolute', left: 16, bottom: 12,
                fontSize: 11, fontWeight: 500, color: '#fff',
                textShadow: '0 1px 3px rgba(0,0,0,0.5)',
              }}>{ev.when.time}</div>
            </div>

            {/* Body */}
            <div style={{ padding: '14px 18px 16px', display: 'flex', flexDirection: 'column', gap: 6 }}>
              <div style={{ fontSize: 15, fontWeight: 600, lineHeight: 1.3 }}>{ev.title}</div>
              <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{ev.venue}</div>
              <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.5, marginTop: 4 }}>{ev.summary}</div>
              {ev.capacity ? <CapacityChart capacity={ev.capacity} premium={ev.premium} /> : null}
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', marginTop: 8 }}>
                <Btn variant={ev.soldOut ? 'ghost' : (ev.premium ? 'primary' : 'secondary')} size="sm">{ev.cta}</Btn>
              </div>
            </div>
          </Card>
        ))}
      </div>
    </div>
  );
};

window.EventsScreen = EventsScreen;

// ============================================================
// Events & Insider (dashboard side cards)
// ============================================================

const EVENTS = [
  {
    id: 'e-1',
    when: { day: '14', month: 'May', time: '09:30 — 16:00 BST' },
    type: 'In person',
    city: 'Manchester',
    title: 'Clicky Performance Day 2026',
    venue: 'The Bridgewater Hall · Manchester',
    image: 'assets/events/event-audience.jpg',
    summary: 'Annual client day — Google Ads roadmap, GA4 deep dives, and case studies from 6 leading UK brands.',
    capacity: { total: 120, remaining: 0, series: [120, 118, 110, 96, 78, 56, 38, 22, 0] },
    soldOut: true,
    cta: 'Join waitlist',
  },
  {
    id: 'e-2',
    when: { day: '21', month: 'May', time: '13:00 — 14:00 BST' },
    type: 'Online',
    city: 'Webinar',
    title: 'Performance Max — what changed in Q2',
    venue: 'Zoom · 60 min',
    image: 'assets/events/event-talk.jpg',
    summary: 'Walk-through of Google\'s May update: new asset group controls, expanded reporting, and what to test.',
    capacity: { total: 500, remaining: 312, series: [500, 488, 460, 430, 405, 378, 354, 330, 312], unlimited: true },
    cta: 'Register',
  },
  {
    id: 'e-3',
    when: { day: '04', month: 'Jun', time: '18:30 — 21:00 BST' },
    type: 'In person',
    city: 'Manchester',
    title: 'Hospitality Marketers Mixer',
    venue: 'Hawksmoor Deansgate · Manchester',
    image: 'assets/events/event-audience.jpg',
    summary: 'Drinks & canapés with the Clicky hospitality team and 30 invited operators. Hosted by Joe Marshall.',
    capacity: { total: 30, remaining: 2, series: [30, 28, 24, 20, 16, 12, 8, 5, 2] },
    cta: 'Accept invite',
    premium: true,
  },
  {
    id: 'e-4',
    when: { day: '18', month: 'Jun', time: '12:00 — 13:00 BST' },
    type: 'Online',
    city: 'Workshop',
    title: 'GA4: building useful exploration reports',
    venue: 'Zoom · 60 min',
    image: 'assets/events/event-workshop.jpg',
    summary: 'Hands-on workshop with Nathan Smith — bring your GA4 property and leave with 3 saved explorations.',
    capacity: { total: 24, remaining: 8, series: [24, 23, 21, 19, 16, 14, 11, 9, 8] },
    cta: 'Register',
  },
  {
    id: 'e-5',
    when: { day: '25', month: 'Jun', time: '09:30 — 13:00 BST' },
    type: 'In person',
    city: 'Manchester',
    title: 'Marketing as a Profit Centre',
    venue: 'Clicky HQ · King Street, Manchester',
    image: 'assets/events/event-profit.jpg',
    summary: 'Half-day session on shifting marketing reporting from cost-control to P&L contribution. Live financial modelling.',
    capacity: { total: 20, remaining: 6, series: [20, 19, 17, 15, 13, 11, 9, 7, 6] },
    cta: 'Reserve seat',
  },
  {
    id: 'e-6',
    when: { day: '09', month: 'Jul', time: '14:00 — 15:30 BST' },
    type: 'Online',
    city: 'Webinar',
    title: '"It\'ll take work — but the payoff is worth it"',
    venue: 'Zoom · 90 min',
    image: 'assets/events/event-payoff.jpg',
    summary: 'Long-form session with Joe Marshall on building an honest 12-month growth roadmap with your agency.',
    capacity: { total: 500, remaining: 421, series: [500, 495, 488, 478, 466, 452, 440, 430, 421], unlimited: true },
    cta: 'Register',
  },
];

const INSIDER = [
  {
    id: 'i-1',
    tag: 'Beta access', category: 'Beta access',
    title: 'AI bid script — early access for premium clients',
    when: 'Yesterday', readTime: '4 min',
    body: "We're piloting a Clicky-built bid adjustment script that uses GA4 micro-conversions. Evergreen Escapes is on the shortlist — Joe will brief you on Tuesday.",
    by: 'Matt Jones · PPC Team Lead',
    cover: { hue: 220, glyph: 'spark' },
    image: 'assets/insider/insider-1.jpg',
    featured: true,
  },
  {
    id: 'i-2',
    tag: 'Heads-up', category: 'Heads-up',
    title: 'Google CSS programme price change · 1 June',
    when: '2 days ago', readTime: '3 min',
    body: "Comparison Shopping Service fees rise 8% from June. We've already modelled the impact on your Shopping spend — net effect is negligible at current ROAS.",
    by: 'Joe Marshall · Head of Client Strategy',
    cover: { hue: 28, glyph: 'cart' },
    image: 'assets/insider/insider-2.png',
  },
  {
    id: 'i-3',
    tag: 'Benchmark', category: 'Benchmark',
    title: 'Hospitality CPC down 11% MoM across Clicky portfolio',
    when: '4 days ago', readTime: '5 min',
    body: 'Aggregate data from 42 hospitality clients shows softer auction pressure into May. Good window to test broader match types on branded campaigns.',
    by: 'Nathan Smith · Agency Systems',
    cover: { hue: 160, glyph: 'trend' },
    image: 'assets/insider/insider-3.png',
  },
  {
    id: 'i-4',
    tag: 'Playbook', category: 'Playbook',
    title: 'Performance Max for hospitality — the 9-month playbook',
    when: '6 days ago', readTime: '8 min',
    body: 'Asset-group structure, audience signals, and the conversion-value setup that gets PMax to outperform standard Shopping for holiday-park brands. Built from 9 months of testing across 12 client accounts.',
    by: 'Matt Jones · PPC Team Lead',
    cover: { hue: 240, glyph: 'spark' },
  },
  {
    id: 'i-5',
    tag: 'Benchmark', category: 'Benchmark',
    title: 'Easter 2026 demand patterns vs 2025 — what we saw',
    when: '8 days ago', readTime: '4 min',
    body: 'Search demand for "lodge breaks" peaked 9 days earlier than last year. Aggregate impression-share data across 30 Clicky hospitality clients suggests a permanent shift in booking lead times.',
    by: 'Nathan Smith · Agency Systems',
    cover: { hue: 18, glyph: 'trend' },
  },
  {
    id: 'i-6',
    tag: 'Case study', category: 'Case study',
    title: 'How Lakeland Lodges grew direct bookings 38%',
    when: '11 days ago', readTime: '6 min',
    body: 'A 9-month story of swapping OTA reliance for owned demand: brand campaigns, an email reactivation series, and a CRO-led booking flow rebuild. Numbers, screenshots, and the things we got wrong.',
    by: 'Hayley Roberts · UX Research & Design',
    cover: { hue: 150, glyph: 'cart' },
  },
  {
    id: 'i-7',
    tag: 'Industry', category: 'Industry',
    title: 'Search Generative Experience — what travel operators need to know',
    when: '2 weeks ago', readTime: '7 min',
    body: 'Google\'s SGE is now rolling out broadly to UK searches. We tracked 1,200 hospitality queries to understand where AI overviews appear, what they cite, and what it means for your organic strategy.',
    by: 'Joe Marshall · Head of Client Strategy',
    cover: { hue: 280, glyph: 'spark' },
  },
  {
    id: 'i-8',
    tag: 'Beta access', category: 'Beta access',
    title: 'GA4 Booking Engine integration — open beta',
    when: '2 weeks ago', readTime: '3 min',
    body: 'New direct booking-engine connector for Sykes, SuperControl and TravelClick — pulls confirmed booking value into GA4 within 90 seconds. Premium clients can request access from this week.',
    by: 'Nathan Smith · Agency Systems',
    cover: { hue: 200, glyph: 'cog' },
  },
  {
    id: 'i-9',
    tag: 'Industry', category: 'Industry',
    title: 'Q3 booking demand outlook — early signals',
    when: '3 weeks ago', readTime: '5 min',
    body: 'Forecast aggregating Google Trends, Skyscanner inbound flight searches, and our own portfolio booking-curve data. Early read: school-holiday weeks looking strong, shoulder weeks softer than 2025.',
    by: 'Joe Marshall · Head of Client Strategy',
    cover: { hue: 200, glyph: 'trend' },
  },
  {
    id: 'i-10',
    tag: 'Webinar', category: 'Webinar',
    title: 'Webinar: Profitable PMax for travel — 14 May',
    when: '3 weeks ago', readTime: '1 min',
    body: 'Matt and Joe walk through the PMax setup blueprint we use across the Clicky hospitality portfolio. 45-min session, live Q&A. Premium client invites going out next week.',
    by: 'Matt Jones · PPC Team Lead',
    cover: { hue: 340, glyph: 'cog' },
  },
  {
    id: 'i-11',
    tag: 'Heads-up', category: 'Heads-up',
    title: 'Cookie consent: TCF v2.4 changes from 30 June',
    when: '3 weeks ago', readTime: '4 min',
    body: 'IAB TCF 2.4 brings new vendor disclosure rules and stricter purpose mapping. We\'ve audited the top 6 CMP providers and have a 1-page summary of what action (if any) you need to take.',
    by: 'Nathan Smith · Agency Systems',
    cover: { hue: 50, glyph: 'cog' },
  },
  {
    id: 'i-12',
    tag: 'Benchmark', category: 'Benchmark',
    title: 'Brand vs non-brand spend split — 200-account benchmark',
    when: '4 weeks ago', readTime: '6 min',
    body: 'We pulled the brand/non-brand split for 200 hospitality accounts across the UK Clicky network. Median sits at 38/62; top-quartile direct-booking brands sit closer to 28/72. The gap is closing fast.',
    by: 'Matt Jones · PPC Team Lead',
    cover: { hue: 110, glyph: 'trend' },
  },
  {
    id: 'i-13',
    tag: 'Playbook', category: 'Playbook',
    title: 'Reels playbook — 12 shot patterns that drove £3.20 CPM',
    when: '5 weeks ago', readTime: '9 min',
    body: 'After 6 months of Meta Reels testing across 8 hospitality clients, we mapped the 12 shot/copy patterns that consistently outperformed the average. With timing, music guidance, and the briefs we used.',
    by: 'Hayley Roberts · UX Research & Design',
    cover: { hue: 320, glyph: 'spark' },
  },
  {
    id: 'i-14',
    tag: 'Industry', category: 'Industry',
    title: 'Microsoft Ads UK growth report — 2025 wrap',
    when: '6 weeks ago', readTime: '5 min',
    body: 'Microsoft\'s UK ad business grew 18% YoY in 2025, with travel and hospitality leading the surge. Pulling together their own data with our portfolio benchmarks to size the opportunity for clients without a Bing presence.',
    by: 'Nathan Smith · Agency Systems',
    cover: { hue: 200, glyph: 'cart' },
  },
];

const INSIDER_CATEGORIES = ['All', 'Beta access', 'Heads-up', 'Benchmark', 'Playbook', 'Case study', 'Industry', 'Webinar'];

const EventsCard = () => {
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', fontWeight: 600, fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" style={{ color: 'var(--text-muted)' }}><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>
          Upcoming events
        </span>
        <button style={{ background: 'none', border: 'none', color: 'var(--primary)', fontSize: 12, fontWeight: 500, cursor: 'pointer', padding: 0 }}>View calendar</button>
      </div>
      <div style={{ padding: 6 }}>
        {EVENTS.map(ev => (
          <div key={ev.id} style={{
            display: 'grid', gridTemplateColumns: '52px 1fr', gap: 12,
            padding: '12px 12px', borderRadius: 6,
          }}
            onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
            onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
          >
            {/* Date block */}
            <div style={{
              borderRadius: 6, background: 'var(--surface-2)',
              border: '1px solid var(--border)', overflow: 'hidden',
              display: 'flex', flexDirection: 'column', alignItems: 'center',
              height: 'fit-content',
            }}>
              <div style={{
                fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em',
                color: '#fff', background: ev.premium ? 'var(--text)' : 'var(--primary)',
                width: '100%', textAlign: 'center', padding: '2px 0',
              }}>{ev.when.month}</div>
              <div style={{
                fontSize: 20, fontWeight: 700, color: 'var(--text)',
                padding: '4px 0 6px', fontVariantNumeric: 'tabular-nums', lineHeight: 1,
              }}>{ev.when.day}</div>
            </div>
            {/* Body */}
            <div style={{ minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', marginBottom: 3 }}>
                <Badge tone={ev.type === 'In person' ? 'positive' : 'primary'}>
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3 }}>
                    {ev.type === 'In person'
                      ? <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M12 22s7-7 7-12a7 7 0 1 0-14 0c0 5 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></svg>
                      : <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="m16 10 6-3v10l-6-3"/></svg>
                    }
                    {ev.city}
                  </span>
                </Badge>
                {ev.premium && <Badge tone="warning">Premium only</Badge>}
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{ev.when.time}</span>
              </div>
              <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3 }}>{ev.title}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{ev.venue}</div>
              <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 6, lineHeight: 1.45 }}>{ev.summary}</div>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 8, gap: 8 }}>
                <span style={{ fontSize: 11, color: 'var(--text-faint)', fontStyle: 'italic' }}>{ev.capacity ? (ev.capacity.unlimited ? 'Open to all clients' : `${ev.capacity.remaining} of ${ev.capacity.total} seats left`) : ''}</span>
                <Btn variant={ev.premium ? 'primary' : 'secondary'} size="sm">{ev.cta}</Btn>
              </div>
            </div>
          </div>
        ))}
      </div>
    </Card>
  );
};

window.EventsCard = EventsCard;
const InsiderGlyph = ({ kind }) => {
  const stroke = { stroke: 'currentColor', strokeWidth: 1.4, strokeLinecap: 'round', strokeLinejoin: 'round', fill: 'none' };
  if (kind === 'spark') return (
    <svg viewBox="0 0 64 64" width="64" height="64" {...stroke}>
      <path d="M32 8 L36 26 L54 30 L36 34 L32 52 L28 34 L10 30 L28 26 Z" fill="currentColor" fillOpacity="0.35" />
      <path d="M50 12 L52 18 L58 20 L52 22 L50 28 L48 22 L42 20 L48 18 Z" fill="currentColor" fillOpacity="0.55" />
    </svg>
  );
  if (kind === 'cart') return (
    <svg viewBox="0 0 64 64" width="64" height="64" {...stroke}>
      <path d="M10 14 L18 14 L22 40 L52 40 L56 22 L24 22" />
      <circle cx="26" cy="50" r="3.5" />
      <circle cx="46" cy="50" r="3.5" />
      <path d="M30 28 L34 32 L42 24" strokeWidth="1.8" />
    </svg>
  );
  if (kind === 'trend') return (
    <svg viewBox="0 0 64 64" width="64" height="64" {...stroke}>
      <path d="M8 48 L24 32 L34 40 L56 14" strokeWidth="2" />
      <path d="M44 14 L56 14 L56 26" strokeWidth="2" />
      <path d="M8 56 L56 56" strokeOpacity="0.3" />
    </svg>
  );
  return null;
};

const InsiderTiles = ({ setActive, openInsiderArticle }) => {
  return (
    <Card padding={0} style={{
      border: '1px solid var(--border)',
      background: 'var(--surface)',
    }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{
            width: 32, height: 32, borderRadius: 8,
            background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2 14.5 8.5 21 9.3l-5 4.6L17.4 21 12 17.5 6.6 21 8 13.9l-5-4.6 6.5-.8z"/></svg>
          </span>
          <div>
            <div style={{ fontWeight: 600, fontSize: 14, display: 'flex', alignItems: 'center', gap: 8 }}>
              Clicky Insider — Premium <Badge tone="primary">Pro</Badge>
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>
              Confidential briefings for Clicky premium clients
            </div>
          </div>
        </div>
        <Btn variant="secondary" size="sm" iconRight={I.arrowRight} onClick={() => setActive && setActive('insider')}>Read all</Btn>
      </div>

      {/* Tile grid */}
      <div style={{ padding: 14, display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 12 }}>
        {INSIDER.slice(0, 3).map(item => {
          const hue = item.cover?.hue ?? 220;
          const tagTone = item.tag === 'Beta access' ? 'positive' : item.tag === 'Heads-up' ? 'warning' : 'neutral';
          return (
            <div key={item.id}
              onClick={() => {
                if (openInsiderArticle) openInsiderArticle(item.id);
                else if (setActive) setActive('insider');
              }}
              style={{
                border: '1px solid var(--border)', borderRadius: 'var(--radius)',
                background: 'var(--surface)', overflow: 'hidden',
                display: 'flex', flexDirection: 'column',
                cursor: 'pointer',
                transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease',
              }}
              onMouseEnter={e => {
                e.currentTarget.style.borderColor = 'var(--primary)';
                e.currentTarget.style.boxShadow = 'var(--shadow-md)';
                e.currentTarget.style.transform = 'translateY(-1px)';
              }}
              onMouseLeave={e => {
                e.currentTarget.style.borderColor = 'var(--border)';
                e.currentTarget.style.boxShadow = 'none';
                e.currentTarget.style.transform = 'none';
              }}
            >
              {/* Cover */}
              <div style={{
                aspectRatio: '16 / 9',
                position: 'relative',
                background: item.image ? '#000' : `linear-gradient(135deg, oklch(0.68 0.16 ${hue}) 0%, oklch(0.42 0.14 ${hue}) 100%)`,
                color: '#fff',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                overflow: 'hidden',
              }}>
                {item.image ? (
                  <img src={item.image} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                ) : (
                  <>
                    <div style={{
                      position: 'absolute', inset: 0,
                      background: 'radial-gradient(circle at 20% 20%, rgba(255,255,255,0.18), transparent 50%), radial-gradient(circle at 80% 80%, rgba(0,0,0,0.18), transparent 50%)',
                    }}/>
                    <div style={{ color: '#fff', opacity: 0.92, position: 'relative' }}>
                      <InsiderGlyph kind={item.cover?.glyph || 'spark'} />
                    </div>
                  </>
                )}
                {/* Top gradient for legibility when there's an image */}
                {item.image && (
                  <div style={{
                    position: 'absolute', inset: 0,
                    background: 'linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0) 50%)',
                    pointerEvents: 'none',
                  }}/>
                )}
                {/* Corner badge */}
                <span style={{
                  position: 'absolute', top: 10, left: 10,
                  fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
                  background: 'rgba(0,0,0,0.55)', color: '#fff',
                  backdropFilter: 'blur(4px)', letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>{item.tag}</span>
                <span style={{
                  position: 'absolute', top: 10, right: 10,
                  fontSize: 10, fontWeight: 600, padding: '3px 7px', borderRadius: 4,
                  background: 'rgba(0,0,0,0.45)', color: '#fff',
                  backdropFilter: 'blur(4px)',
                }}>{item.when}</span>
              </div>

              {/* Body */}
              <div style={{ padding: '12px 14px 14px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
                <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3, textWrap: 'pretty' }}>{item.title}</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.45, textWrap: 'pretty' }}>{item.body}</div>
                <div style={{ flex: 1 }} />
                <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 4, paddingTop: 8, borderTop: '1px solid var(--border)' }}>{item.by}</div>
              </div>
            </div>
          );
        })}
      </div>

      <div style={{ padding: '10px 18px 14px', fontSize: 11, color: 'var(--text-faint)', borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 6 }}>
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
        Confidential to Clicky premium clients · do not forward
      </div>
    </Card>
  );
};

window.InsiderTiles = InsiderTiles;

// ============================================================
// Clicky Insider — full page (sidebar destination)
// ============================================================

const INSIDER_LONG = {
  'i-1': [
    "We're piloting a Clicky-built bid adjustment script that uses GA4 micro-conversions — add-to-cart, scroll-depth and 60-second engagement — as leading signals to bid against, days before a booking actually completes.",
    "Early results from three premium portfolios show a 14–22% lift in tROAS efficiency in the first four weeks, with the biggest gains on long-consideration purchases (luxury hospitality, B2B, considered DTC).",
    "Evergreen Escapes is on the shortlist for the next cohort. Joe will brief you on Tuesday — bring questions on your assisted-conversion paths and we'll model the impact live.",
  ],
  'i-2': [
    "Google's Comparison Shopping Service fees rise 8% from 1 June. For most accounts the headline number sounds bigger than the impact — at current ROAS your net effective change is well under 1%.",
    "We've already modelled this against your current Shopping mix and the recommendation is no change to bidding strategy this month. We'll revisit at the June review once the new fees are live in the auction.",
    "If you want to see the full sensitivity table — fees vs. ROAS vs. budget — Joe has it ready and can walk you through it in your next monthly.",
  ],
  'i-3': [
    "Aggregate data from 42 hospitality clients across the Clicky portfolio shows a clear softening of auction pressure into May — average CPCs down 11% MoM and impression share up 6 points on branded campaigns.",
    "The market is telling us competitors have pulled budget after a softer Easter. That's a window — not forever, but a window — to test broader match types on brand and capture defensive volume cheaply.",
    "Nathan's running a structured test on three accounts already; we'll share the playbook in next month's Insider once we've got 4 weeks of data.",
  ],
};

// Per-card cover (image or coloured-gradient fallback with a glyph)
const InsiderCover = ({ item, aspect = '16 / 9' }) => {
  const hue = item.cover?.hue ?? 220;
  return (
    <div style={{
      position: 'relative', aspectRatio: aspect,
      background: item.image ? '#000' : `linear-gradient(135deg, oklch(0.68 0.16 ${hue}) 0%, oklch(0.42 0.14 ${hue}) 100%)`,
      color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center',
      overflow: 'hidden',
    }}>
      {item.image ? (
        <img src={item.image} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      ) : (
        <>
          <div style={{
            position: 'absolute', inset: 0,
            background: 'radial-gradient(circle at 20% 20%, rgba(255,255,255,0.18), transparent 50%), radial-gradient(circle at 80% 80%, rgba(0,0,0,0.18), transparent 50%)',
          }}/>
          <div style={{ color: '#fff', opacity: 0.92, position: 'relative' }}>
            <InsiderGlyph kind={item.cover?.glyph || 'spark'} />
          </div>
        </>
      )}
      {item.image && (
        <div style={{
          position: 'absolute', inset: 0,
          background: 'linear-gradient(180deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0) 40%)',
          pointerEvents: 'none',
        }}/>
      )}
      <span style={{
        position: 'absolute', top: 10, left: 10,
        fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
        background: 'rgba(0,0,0,0.55)', color: '#fff',
        backdropFilter: 'blur(4px)', letterSpacing: '0.04em', textTransform: 'uppercase',
      }}>{item.tag}</span>
      <span style={{
        position: 'absolute', top: 10, right: 10,
        fontSize: 10, fontWeight: 600, padding: '3px 7px', borderRadius: 4,
        background: 'rgba(0,0,0,0.45)', color: '#fff',
        backdropFilter: 'blur(4px)',
      }}>{item.when}</span>
    </div>
  );
};

const InsiderCard = ({ item, onOpen }) => (
  <button onClick={() => onOpen(item.id)} style={{
    textAlign: 'left', padding: 0,
    background: 'var(--surface)', border: '1px solid var(--border)',
    borderRadius: 'var(--radius)', overflow: 'hidden',
    display: 'flex', flexDirection: 'column',
    cursor: 'pointer',
    transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease',
  }}
    onMouseEnter={e => {
      e.currentTarget.style.borderColor = 'var(--primary)';
      e.currentTarget.style.boxShadow = 'var(--shadow-md)';
      e.currentTarget.style.transform = 'translateY(-1px)';
    }}
    onMouseLeave={e => {
      e.currentTarget.style.borderColor = 'var(--border)';
      e.currentTarget.style.boxShadow = 'none';
      e.currentTarget.style.transform = 'none';
    }}
  >
    <InsiderCover item={item} />
    <div style={{ padding: '14px 16px 16px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
      <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3, textWrap: 'pretty' }}>{item.title}</div>
      <div style={{ fontSize: 12.5, color: 'var(--text-muted)', lineHeight: 1.5, textWrap: 'pretty',
        display: '-webkit-box', WebkitBoxOrient: 'vertical', WebkitLineClamp: 3, overflow: 'hidden' }}>{item.body}</div>
      <div style={{ flex: 1 }} />
      <div style={{
        fontSize: 11, color: 'var(--text-faint)',
        marginTop: 6, paddingTop: 10, borderTop: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
      }}>
        <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{item.by}</span>
        <span style={{ flexShrink: 0, fontFamily: 'JetBrains Mono', fontSize: 10.5 }}>{item.readTime}</span>
      </div>
    </div>
  </button>
);

const InsiderHero = ({ item, onOpen }) => (
  <button onClick={() => onOpen(item.id)} style={{
    textAlign: 'left', padding: 0, width: '100%',
    background: 'var(--surface)', border: '1px solid var(--border)',
    borderRadius: 'var(--radius)', overflow: 'hidden', cursor: 'pointer',
    transition: 'border-color 120ms ease, box-shadow 120ms ease',
    display: 'grid', gridTemplateColumns: '1.4fr 1fr',
  }}
    onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; }}
    onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; }}
  >
    <InsiderCover item={item} aspect="16 / 10" />
    <div style={{ padding: '24px 28px', display: 'flex', flexDirection: 'column', gap: 10, justifyContent: 'center' }}>
      <span style={{
        fontSize: 10, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase',
        color: 'var(--primary)',
      }}>Featured</span>
      <h2 style={{ fontSize: 24, fontWeight: 700, margin: 0, lineHeight: 1.2, letterSpacing: '-0.01em', textWrap: 'pretty' }}>{item.title}</h2>
      <p style={{ fontSize: 14, color: 'var(--text-muted)', lineHeight: 1.55, margin: 0, textWrap: 'pretty' }}>{item.body}</p>
      <div style={{
        marginTop: 6, paddingTop: 12, borderTop: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <PersonAvatar
          name={item.by.split(' · ')[0]}
          size={32}
          src={
            item.by.startsWith('Matt')   ? 'assets/team/matt.png' :
            item.by.startsWith('Joe')    ? 'assets/team/joe.png' :
            item.by.startsWith('Nathan') ? 'assets/team/nathan.png' :
            item.by.startsWith('Hayley') ? 'assets/team/hayley.png' :
            undefined
          }
        />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, fontWeight: 600 }}>{item.by.split(' · ')[0]}</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{item.by.split(' · ')[1]}</div>
        </div>
        <span style={{ fontSize: 11, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono' }}>{item.readTime}</span>
      </div>
    </div>
  </button>
);

const PAGE_SIZE = 9;

const InsiderArticleView = ({ item, onBack }) => {
  const long = INSIDER_LONG[item.id] || [item.body];
  return (
    <div>
      <div style={{ marginBottom: 16 }}>
        <Btn variant="ghost" size="sm" icon={<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>} onClick={onBack}>
          Back to Insider
        </Btn>
      </div>

      <Card padding={0} style={{ overflow: 'hidden' }}>
        {/* Hero */}
        <div style={{ position: 'relative', aspectRatio: '21 / 9', background: '#000', overflow: 'hidden' }}>
          {item.image
            ? <img src={item.image} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
            : <InsiderCover item={item} aspect="21 / 9" />
          }
          {item.image && (
            <div style={{
              position: 'absolute', inset: 0,
              background: 'linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 35%, rgba(0,0,0,0) 55%, rgba(0,0,0,0.7) 100%)',
              pointerEvents: 'none',
            }}/>
          )}
          {item.image && (
            <>
              <div style={{ position: 'absolute', top: 16, left: 18, right: 18, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <span style={{
                  fontSize: 11, fontWeight: 700, padding: '4px 10px', borderRadius: 99,
                  background: 'rgba(0,0,0,0.55)', color: '#fff',
                  backdropFilter: 'blur(4px)', letterSpacing: '0.06em', textTransform: 'uppercase',
                }}>{item.tag}</span>
                <span style={{ fontSize: 11, color: '#fff', opacity: 0.9, letterSpacing: '0.04em', textTransform: 'uppercase', fontWeight: 600 }}>{item.when}</span>
              </div>
              <div style={{ position: 'absolute', bottom: 18, left: 22, right: 22 }}>
                <div style={{ fontSize: 26, fontWeight: 700, color: '#fff', lineHeight: 1.2, textWrap: 'pretty', textShadow: '0 2px 8px rgba(0,0,0,0.4)' }}>{item.title}</div>
              </div>
            </>
          )}
        </div>

        <div style={{ padding: '22px 28px 26px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {/* Title (when image is absent it isn't already shown over the hero) */}
          {!item.image && (
            <h1 style={{ fontSize: 28, fontWeight: 700, margin: 0, letterSpacing: '-0.01em', lineHeight: 1.2, textWrap: 'pretty' }}>{item.title}</h1>
          )}

          <div style={{ display: 'flex', alignItems: 'center', gap: 10, paddingBottom: 14, borderBottom: '1px solid var(--border)' }}>
            <PersonAvatar
              name={item.by.split(' · ')[0]}
              size={36}
              src={
                item.by.startsWith('Matt')   ? 'assets/team/matt.png' :
                item.by.startsWith('Joe')    ? 'assets/team/joe.png' :
                item.by.startsWith('Nathan') ? 'assets/team/nathan.png' :
                item.by.startsWith('Hayley') ? 'assets/team/hayley.png' :
                undefined
              }
            />
            <div>
              <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{item.by.split(' · ')[0]}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                {item.by.split(' · ')[1]} · {item.when} · {item.readTime} read
              </div>
            </div>
            <div style={{ flex: 1 }}/>
            <Btn variant="secondary" size="sm" icon={<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><path d="M19 14l-7 7-7-7"/><path d="M12 21V3"/></svg>}>Save PDF</Btn>
          </div>

          {long.map((p, i) => (
            <p key={i} style={{
              margin: 0, fontSize: i === 0 ? 16 : 14,
              lineHeight: 1.65,
              color: i === 0 ? 'var(--text)' : 'var(--text-muted)',
              fontWeight: i === 0 ? 500 : 400,
              textWrap: 'pretty',
            }}>{p}</p>
          ))}

          <div style={{
            marginTop: 8, padding: '12px 14px',
            background: 'var(--surface-2)',
            border: '1px solid var(--border)', borderRadius: 8,
            fontSize: 11, color: 'var(--text-faint)',
            display: 'flex', alignItems: 'center', gap: 8,
          }}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
            Confidential to Clicky premium clients · do not forward
          </div>
        </div>
      </Card>
    </div>
  );
};

const InsiderScreen = ({ initialArticleId, clearInitialArticle }) => {
  const [view, setView] = useState(initialArticleId ? 'article' : 'index'); // 'index' | 'article'
  const [activeId, setActiveId] = useState(initialArticleId || null);
  const [category, setCategory] = useState('All');
  const [query, setQuery] = useState('');
  const [page, setPage] = useState(1);
  const [subscribed, setSubscribed] = useState(false);

  // If app-level deep-link arrives later (user clicks another article from
  // the dashboard while we're already on this screen), honour it.
  useEffect(() => {
    if (initialArticleId) {
      setActiveId(initialArticleId);
      setView('article');
      window.scrollTo?.({ top: 0, behavior: 'smooth' });
      if (clearInitialArticle) clearInitialArticle();
    }
  }, [initialArticleId]); // eslint-disable-line

  const open = (id) => { setActiveId(id); setView('article'); window.scrollTo?.({ top: 0, behavior: 'smooth' }); };
  const back = () => { setView('index'); window.scrollTo?.({ top: 0, behavior: 'smooth' }); };

  // Featured = first article tagged featured (or first overall)
  const featured = INSIDER.find(i => i.featured) || INSIDER[0];

  // Filter the rest
  const filtered = INSIDER.filter(a => a.id !== featured.id || category !== 'All' || query.trim())
    .filter(a => category === 'All' || a.category === category)
    .filter(a => !query.trim() || (a.title + ' ' + (a.body || '')).toLowerCase().includes(query.trim().toLowerCase()));

  const visible = filtered.slice(0, page * PAGE_SIZE);
  const moreLeft = filtered.length - visible.length;

  const article = view === 'article' && activeId ? INSIDER.find(i => i.id === activeId) : null;

  return (
    <div>
      <PageHeader
        title={(
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
            <span style={{
              width: 32, height: 32, borderRadius: 8,
              background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
              color: 'var(--primary)', display: 'grid', placeItems: 'center',
            }}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2 14.5 8.5 21 9.3l-5 4.6L17.4 21 12 17.5 6.6 21 8 13.9l-5-4.6 6.5-.8z"/></svg>
            </span>
            Clicky Insider
            <Badge tone="primary">Pro</Badge>
          </span>
        )}
        subtitle="Confidential briefings, betas and benchmarks for Clicky premium clients."
        actions={(
          subscribed ? (
            <Btn
              variant="secondary"
              size="sm"
              onClick={() => setSubscribed(false)}
              icon={<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--positive)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>}
              title="You're subscribed — click to unsubscribe"
            >Email alerts on</Btn>
          ) : (
            <Btn
              variant="secondary"
              size="sm"
              onClick={() => setSubscribed(true)}
              icon={<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>}
            >Sign up for Emails</Btn>
          )
        )}
      />

      {article ? (
        <InsiderArticleView item={article} onBack={back} />
      ) : (
        <>
          {/* Featured hero — only when not filtering */}
          {category === 'All' && !query.trim() && (
            <div style={{ marginBottom: 20 }}>
              <InsiderHero item={featured} onOpen={open} />
            </div>
          )}

          {/* Filter bar */}
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16,
            flexWrap: 'wrap',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
              {INSIDER_CATEGORIES.map(t => {
                const count = t === 'All' ? INSIDER.length : INSIDER.filter(a => a.category === t).length;
                if (count === 0) return null;
                return (
                  <button key={t} onClick={() => { setCategory(t); setPage(1); }} style={{
                    padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
                    background: category === t ? 'var(--text)' : 'var(--surface)',
                    color:      category === t ? 'var(--surface)' : 'var(--text-muted)',
                    border: '1px solid ' + (category === t ? 'var(--text)' : 'var(--border)'),
                    cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 5,
                  }}>
                    {t}
                    <span style={{
                      fontSize: 10, fontWeight: 600,
                      fontVariantNumeric: 'tabular-nums', opacity: 0.7,
                    }}>{count}</span>
                  </button>
                );
              })}
            </div>

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

            <div style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '6px 10px', borderRadius: 8,
              background: 'var(--surface)', border: '1px solid var(--border)',
              minWidth: 240,
            }}>
              <span style={{ color: 'var(--text-faint)', display: 'inline-flex' }}>{I.search}</span>
              <input value={query} onChange={e => { setQuery(e.target.value); setPage(1); }} placeholder="Search briefings"
                style={{
                  border: 'none', outline: 'none', background: 'transparent',
                  color: 'var(--text)', fontSize: 12, flex: 1, fontFamily: 'inherit',
                }}/>
              {query && (
                <button onClick={() => { setQuery(''); setPage(1); }} style={{
                  border: 'none', background: 'transparent', color: 'var(--text-faint)',
                  cursor: 'pointer', padding: 0, fontSize: 14, lineHeight: 1,
                }}>×</button>
              )}
            </div>
          </div>

          {/* Result count */}
          <div style={{
            display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
            marginBottom: 12,
          }}>
            <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
              Showing <strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{visible.length}</strong> of {filtered.length}
            </span>
            <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>Sorted by most recent</span>
          </div>

          {/* Grid */}
          {visible.length === 0 ? (
            <Card>
              <div style={{ padding: '32px 16px', textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>
                No briefings match these filters.
                <div style={{ marginTop: 12 }}>
                  <Btn variant="ghost" size="sm" onClick={() => { setCategory('All'); setQuery(''); setPage(1); }}>Reset filters</Btn>
                </div>
              </div>
            </Card>
          ) : (
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 16,
            }}>
              {visible.map(item => (
                <InsiderCard key={item.id} item={item} onOpen={open} />
              ))}
            </div>
          )}

          {/* Load more */}
          {moreLeft > 0 && (
            <div style={{ marginTop: 20, display: 'flex', justifyContent: 'center' }}>
              <Btn variant="secondary" onClick={() => setPage(p => p + 1)}>
                Load {Math.min(moreLeft, PAGE_SIZE)} more
              </Btn>
            </div>
          )}

          {/* Confidentiality footer */}
          <div style={{
            marginTop: 24, padding: '14px 18px',
            borderRadius: 'var(--radius)', border: '1px dashed var(--border)',
            fontSize: 12, color: 'var(--text-muted)',
            display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
            Every briefing on this page is confidential to Clicky premium clients — please don't forward outside your team.
          </div>
        </>
      )}
    </div>
  );
};

window.InsiderScreen = InsiderScreen;

// ============================================================
// Dashboard (welcome + account manager)
// ============================================================

const SERVICES = [
  // === Discovery & Strategy ===
  { id: 'playbook',   category: 'Discovery & Strategy',         title: 'Clicky Playbook®',          icon: 'book',    blurb: 'Annual strategy deep-dive — market position, platforms, and the year ahead.', pricing: 'From £5,000 + VAT',         timeline: '4–6 weeks',  active: false, isNew: true,  why: 'Your booking funnel and channel mix would benefit from a 12-month plan — half the cost is credited back against future work.' },

  // === Paid Media ===
  { id: 'google',     category: 'Paid Media',                   title: 'Google Ads',                icon: 'google',  blurb: 'Search, Performance Max & Shopping campaigns — managed end-to-end.', pricing: '£1,200 / month retainer',   timeline: 'Active',     active: true,  since: 'Apr 2024' },
  { id: 'microsoft',  category: 'Paid Media',                   title: 'Microsoft Ads',             icon: 'bing',    blurb: 'Bing & Edge audiences — typically older, higher-intent search traffic.', pricing: 'From £450 / month',         timeline: '1 week setup', active: false, why: 'Bing audience skews older with higher disposable income — strong fit for premium lodge stays.' },
  { id: 'aishop',     category: 'Paid Media',                   title: 'Google AI Shopping Ads',    icon: 'cart',    blurb: 'AI-driven Shopping placements across Search, YouTube and Discover.', pricing: 'From £900 / month',         timeline: '2 weeks',    active: false, isNew: true, why: 'Pulls product feeds into AI-curated answers — early-mover advantage while CPCs are still low.' },
  { id: 'meta',       category: 'Paid Media',                   title: 'Meta Ads',                  icon: 'meta',    blurb: 'Facebook & Instagram — creative, targeting and reporting.', pricing: 'From £1,200 / month',       timeline: '2 weeks setup', active: false, why: 'Strong fit for lodge imagery — Meta drives ~38% lower CPA than Google for hospitality clients.' },
  { id: 'youtube',    category: 'Paid Media',                   title: 'YouTube Ads',               icon: 'youtube', blurb: 'Pre-roll, in-stream and shorts — visual storytelling at scale.', pricing: 'From £900 / month',         timeline: '2–3 weeks',  active: false, why: 'Connected-TV viewing is the largest UK travel-research channel — under-utilised in your sector.' },
  { id: 'linkedin',   category: 'Paid Media',                   title: 'LinkedIn Ads',              icon: 'linkedin',blurb: 'B2B targeting by job title, company and seniority.',          pricing: 'From £1,500 / month',       timeline: '2 weeks setup', active: false },
  { id: 'tiktok',     category: 'Paid Media',                   title: 'TikTok Ads',                icon: 'tiktok',  blurb: 'Short-form video for younger, mobile-first audiences.',       pricing: 'From £1,000 / month',       timeline: '2 weeks setup', active: false },
  { id: 'pinterest',  category: 'Paid Media',                   title: 'Pinterest Ads',             icon: 'pinterest',blurb: 'High-intent inspiration searches — strong for travel & home.', pricing: 'From £600 / month',        timeline: '1–2 weeks',  active: false, why: 'Cornish hospitality brands see 3× higher save-rates on Pinterest vs. paid social.' },
  { id: 'chatgpt',    category: 'Paid Media',                   title: 'ChatGPT Ads',               icon: 'spark',   blurb: 'Sponsored placements inside ChatGPT search results.',          pricing: 'From £750 / month',         timeline: '1 week',     active: false, isNew: true },
  { id: 'spotify',    category: 'Paid Media',                   title: 'Spotify Ads',               icon: 'audio',   blurb: 'Audio & display ads served between tracks.',                  pricing: 'From £500 / month',         timeline: '1 week',     active: false },
  { id: 'reddit',     category: 'Paid Media',                   title: 'Reddit Ads',                icon: 'reddit',  blurb: 'Community-driven targeting against UK travel and lifestyle subs.', pricing: 'From £600 / month',     timeline: '2 weeks',    active: false },

  // === SEO & Social ===
  { id: 'seo',        category: 'SEO & Social',                 title: 'SEO',                       icon: 'search',  blurb: 'Technical audits, keyword strategy and ongoing content production.', pricing: 'From £900 / month',         timeline: 'Ongoing',    active: false, why: 'Likely 3× organic bookings within 12 months — your domain has untapped authority.' },
  { id: 'llm',        category: 'SEO & Social',                 title: 'GEO / LLM Optimisation',    icon: 'spark',   blurb: 'Be the answer ChatGPT, Gemini & Copilot give to your category questions.', pricing: 'From £750 / month',         timeline: '6 weeks',    active: false, isNew: true, why: 'AI search is rising fast — getting cited now beats catching up later.' },
  { id: 'organic',    category: 'SEO & Social',                 title: 'Organic Social Media',      icon: 'instagram',blurb: 'Daily content planning, posting and community management.',  pricing: 'From £700 / month',         timeline: '2 weeks setup', active: false, why: 'Lodge imagery is your biggest content asset and it\u2019s sitting unused on a phone.' },
  { id: 'influencer', category: 'SEO & Social',                 title: 'Influencer Marketing',      icon: 'people',  blurb: 'Vetted creator partnerships — content, distribution and reporting.', pricing: 'From £2,000 / campaign',    timeline: '3–4 weeks',  active: false },

  // === Digital Experiences ===
  { id: 'websites',   category: 'Digital Experiences',          title: 'Websites',                  icon: 'page',    blurb: 'End-to-end website builds — design, build and launch.',       pricing: 'From £15,000',              timeline: '8–12 weeks', active: false },
  { id: 'webmgmt',    category: 'Digital Experiences',          title: 'Website Management',        icon: 'wrench',  blurb: 'Hosting, updates, fixes and ongoing improvements.',           pricing: 'From £350 / month',         timeline: 'Ongoing',    active: false },
  { id: 'landing',    category: 'Digital Experiences',          title: 'Landing Pages',             icon: 'page',    blurb: 'Conversion-optimised pages built and A/B tested by our design team.', pricing: 'From £450 / page',         timeline: '2–3 weeks',  active: true,  since: 'Sep 2024', activity: '2 pages live' },
  { id: 'aicreative', category: 'Digital Experiences',          title: 'AI Creative & Automation',  icon: 'spark',   blurb: 'AI-generated and AI-assisted creative production at scale.',  pricing: 'From £1,200 / month',       timeline: '3 weeks setup', active: false, isNew: true, why: 'Your seasonal-shoot cycle is a 6-month process — AI cuts that to days.' },
  { id: 'chatbot',    category: 'Digital Experiences',          title: 'AI Chatbots',               icon: 'chat',    blurb: 'Branded conversational agents for booking, FAQs and support.', pricing: 'From £2,500 setup',         timeline: '4 weeks',    active: false, isNew: true },

  // === Analytics, CRM & AI Automation ===
  { id: 'aicrm',      category: 'Analytics, CRM & AI Automation', title: 'AI & CRM Consultancy',     icon: 'wand',    blurb: 'Bridge marketing and sales with AI-powered automation.',      pricing: 'From £1,800 / month',       timeline: '4 weeks',    active: false, why: 'Your booking enquiries currently sit in email — a CRM with AI triage would 2× response time.' },
  { id: 'salesforce', category: 'Analytics, CRM & AI Automation', title: 'Salesforce',               icon: 'cloud',   blurb: 'Implementation, integration and ongoing admin.',             pricing: 'Custom quote',              timeline: '8–16 weeks', active: false },
  { id: 'hubspot',    category: 'Analytics, CRM & AI Automation', title: 'HubSpot',                  icon: 'cog',     blurb: 'CRM, marketing hub and sales automation setup.',            pricing: 'From £4,500 setup',         timeline: '4–8 weeks',  active: false },
  { id: 'zoho',       category: 'Analytics, CRM & AI Automation', title: 'Zoho CRM',                 icon: 'cog',     blurb: 'Affordable CRM with full Clicky implementation support.',    pricing: 'From £2,500 setup',         timeline: '3–6 weeks',  active: false },
  { id: 'ga4',        category: 'Analytics, CRM & AI Automation', title: 'Google Analytics 4 (GA4)', icon: 'gauge',   blurb: 'Setup, custom events, dashboards and ongoing analysis.',     pricing: '£1,800 fixed setup',         timeline: 'Active',     active: true,  since: 'Mar 2026' },
];

const ServiceIcon = ({ kind, size = 18 }) => {
  const props = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round" };
  switch (kind) {
    case 'page':      return <svg {...props}><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 8h8M8 12h8M8 16h5"/></svg>;
    case 'mail':      return <svg {...props}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 7 9-7"/></svg>;
    case 'search':    return <svg {...props}><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>;
    case 'share':     return <svg {...props}><circle cx="6" cy="12" r="3"/><circle cx="18" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M8.6 10.6l6.8-3.2M8.6 13.4l6.8 3.2"/></svg>;
    case 'film':      return <svg {...props}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M7 5v14M17 5v14M3 9h4M3 15h4M17 9h4M17 15h4"/></svg>;
    case 'gauge':     return <svg {...props}><path d="M12 14l4-4"/><path d="M3 12a9 9 0 0 1 18 0"/><path d="M3 12v3M21 12v3"/></svg>;
    case 'book':      return <svg {...props}><path d="M4 4h12a4 4 0 0 1 4 4v12H8a4 4 0 0 1-4-4V4z"/><path d="M4 16a4 4 0 0 1 4-4h12"/></svg>;
    case 'google':    return <svg {...props}><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>;
    case 'bing':      return <svg {...props}><path d="M7 4v14l5-2 6 2-7-4 1-4 5 2-1-3-7-3z"/></svg>;
    case 'cart':      return <svg {...props}><path d="M3 4h2l2.5 12h11l2-9H7"/><circle cx="9" cy="20" r="1.5"/><circle cx="17" cy="20" r="1.5"/></svg>;
    case 'meta':      return <svg {...props}><path d="M3 12c2-6 5-7 7-3s4 9 6 9 4-3 5-9"/><path d="M3 12c2 6 5 7 7 3s4-9 6-9 4 3 5 9"/></svg>;
    case 'youtube':   return <svg {...props}><rect x="2" y="6" width="20" height="12" rx="3"/><path d="M10 9.5l5 2.5-5 2.5z" fill="currentColor" stroke="none"/></svg>;
    case 'linkedin':  return <svg {...props}><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M8 10v7M8 7v.01M12 17v-4a2 2 0 0 1 4 0v4M12 13v4"/></svg>;
    case 'tiktok':    return <svg {...props}><path d="M14 4v10a4 4 0 1 1-4-4"/><path d="M14 4c0 3 2 5 5 5"/></svg>;
    case 'pinterest': return <svg {...props}><circle cx="12" cy="12" r="9"/><path d="M11 8c2-1 5 0 5 3s-2 4-3 4-2-1-2-2"/><path d="M11 12l-2 9"/></svg>;
    case 'spark':     return <svg {...props}><path d="M12 3l2 5 5 2-5 2-2 5-2-5-5-2 5-2z"/></svg>;
    case 'audio':     return <svg {...props}><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3"/></svg>;
    case 'reddit':    return <svg {...props}><circle cx="12" cy="13" r="7"/><circle cx="9" cy="13" r="1" fill="currentColor"/><circle cx="15" cy="13" r="1" fill="currentColor"/><path d="M9 16c1 1 5 1 6 0"/><path d="M16 7a1.5 1.5 0 1 1 0 3M16 7l-3 1"/></svg>;
    case 'instagram': return <svg {...props}><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="0.6" fill="currentColor"/></svg>;
    case 'people':    return <svg {...props}><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 19c0-3 3-5 6-5s6 2 6 5"/><path d="M14 19c0-2 2-3.5 4-3.5S22 17 22 19"/></svg>;
    case 'wrench':    return <svg {...props}><path d="M14 6a4 4 0 0 1 5 5l-9 9-4-4 9-9z"/><path d="M14 6l-3 3"/></svg>;
    case 'chat':      return <svg {...props}><path d="M4 5h16v11H8l-4 4z"/></svg>;
    case 'wand':      return <svg {...props}><path d="M5 19l9-9"/><path d="M14 5l1 2 2 1-2 1-1 2-1-2-2-1 2-1z"/><path d="M19 14l.5 1 1 .5-1 .5-.5 1-.5-1-1-.5 1-.5z"/></svg>;
    case 'cloud':     return <svg {...props}><path d="M7 18a4 4 0 0 1 .5-7.9 5 5 0 0 1 9.5 1A4 4 0 0 1 17 18z"/></svg>;
    case 'cog':       return <svg {...props}><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M5 5l2 2M17 17l2 2M2 12h3M19 12h3M5 19l2-2M17 7l2-2"/></svg>;
    default: return null;
  }
};

const ServicesSidebar = ({ onPick }) => (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
      <div style={{ fontWeight: 600, fontSize: 14 }}>Explore other services</div>
      <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Tell us what you'd like to grow next.</div>
    </div>
    <div style={{ padding: 6 }}>
      {SERVICES.map(s => (
        <button key={s.id} onClick={() => onPick(s)} style={{
          display: 'flex', alignItems: 'center', gap: 10, width: '100%',
          padding: '10px 12px', borderRadius: 6, textAlign: 'left',
          background: 'transparent', border: 'none', cursor: 'pointer',
        }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
        >
          <div style={{
            width: 32, height: 32, borderRadius: 6, flexShrink: 0,
            background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
            color: 'var(--primary)',
            display: 'grid', placeItems: 'center',
          }}><ServiceIcon kind={s.icon} size={16} /></div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{s.title}</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{s.pricing}</div>
          </div>
          <span style={{ color: 'var(--text-faint)', flexShrink: 0 }}>{I.arrowRight}</span>
        </button>
      ))}
    </div>
    <div style={{ padding: '10px 16px 14px', borderTop: '1px solid var(--border)' }}>
      <button onClick={() => onPick({ id: 'other', title: 'Something else', blurb: 'Tell us what you have in mind.', icon: 'page', pricing: 'Custom quote', timeline: 'Varies' })} style={{
        width: '100%', padding: 10, background: 'transparent',
        border: '1px dashed var(--border-strong)', borderRadius: 6,
        color: 'var(--text-muted)', fontSize: 12, cursor: 'pointer',
      }}>+ Request something else</button>
    </div>
  </Card>
);

const ServicesGrid = ({ onPick }) => (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
      <div>
        <div style={{ fontWeight: 600, fontSize: 14 }}>Explore other services</div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Beyond Google Ads — tell us what you'd like to grow next.</div>
      </div>
      <Badge tone="primary">No commitment · free quote</Badge>
    </div>
    <div style={{ padding: 16, display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 12 }}>
      {SERVICES.map(s => (
        <button key={s.id} onClick={() => onPick(s)} style={{
          display: 'flex', flexDirection: 'column', gap: 10, alignItems: 'flex-start',
          padding: 16, background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 'var(--radius)', cursor: 'pointer', textAlign: 'left',
          transition: 'border-color 0.12s, transform 0.05s, box-shadow 0.12s',
        }}
          onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; }}
          onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; }}
        >
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
            <div style={{
              width: 36, height: 36, borderRadius: 'var(--radius)',
              background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
              color: 'var(--primary)',
              display: 'grid', placeItems: 'center',
            }}><ServiceIcon kind={s.icon} size={18} /></div>
            <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
          </div>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{s.title}</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>{s.blurb}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 'auto', flexWrap: 'wrap' }}>
            <span style={{ fontSize: 11, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{s.pricing}</span>
            <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>·</span>
            <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{s.timeline}</span>
          </div>
        </button>
      ))}
    </div>
    <div style={{ padding: '12px 18px 16px', borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
      <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Don't see what you need? Tell us more.</div>
      <Btn variant="secondary" size="sm" onClick={() => onPick({ id: 'other', title: 'Something else', blurb: 'Tell us what you have in mind.', icon: 'page', pricing: 'Custom quote', timeline: 'Varies' })}>Request something else</Btn>
    </div>
  </Card>
);

// ============================================================
// Growth Opportunities — full Clicky service catalog organised
// by category. Active services are shown in-line, dimmed, with
// an "Active" badge; inactive services pop forward as the
// suggested next step. Recommended (with `why:`) bubbles up.
// ============================================================
const SERVICE_CATEGORIES = [
  'Discovery & Strategy',
  'Paid Media',
  'SEO & Social',
  'Digital Experiences',
  'Analytics, CRM & AI Automation',
];

const GrowthOpportunitiesCard = ({ onPick, manager }) => {
  const [activeCat, setActiveCat] = useState('Recommended');
  const recommended = SERVICES.filter(s => !s.active && s.why);
  const totalActive = SERVICES.filter(s => s.active).length;
  const totalInactive = SERVICES.length - totalActive;

  const visible = activeCat === 'Recommended'
    ? recommended
    : SERVICES.filter(s => s.category === activeCat);

  const tabs = [
    { id: 'Recommended', label: 'Recommended', count: recommended.length, badge: true },
    ...SERVICE_CATEGORIES.map(c => ({
      id: c,
      label: c,
      count: SERVICES.filter(s => s.category === c).length,
    })),
  ];

  return (
    <Card padding={0}>
      {/* Header */}
      <div style={{
        padding: '14px 18px', borderBottom: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
          <div style={{
            width: 32, height: 32, borderRadius: 6,
            background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Clicky services for {CLIENT.shortName}</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
              Everything we offer — recommended additions surface first
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 11, color: 'var(--text-faint)', fontVariantNumeric: 'tabular-nums' }}>
            <span style={{ color: '#16a34a', fontWeight: 600 }}>{totalActive} active</span>
            <span style={{ margin: '0 6px' }}>·</span>
            <span>{totalInactive} available</span>
          </span>
        </div>
      </div>

      {/* Category tabs */}
      <div style={{
        display: 'flex', gap: 4, padding: '8px 12px', overflowX: 'auto',
        borderBottom: '1px solid var(--border)', background: 'var(--surface-2)',
      }}>
        {tabs.map(t => {
          const isActive = activeCat === t.id;
          return (
            <button key={t.id} onClick={() => setActiveCat(t.id)} style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '6px 10px', borderRadius: 6, whiteSpace: 'nowrap',
              border: '1px solid transparent',
              background: isActive ? 'var(--surface)' : 'transparent',
              borderColor: isActive ? 'var(--border)' : 'transparent',
              color: isActive ? 'var(--text)' : 'var(--text-muted)',
              fontSize: 12, fontWeight: 600, cursor: 'pointer',
              boxShadow: isActive ? 'var(--shadow-sm)' : 'none',
            }}>
              {t.badge && <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--primary)' }}/>}
              {t.label}
              <span style={{
                fontSize: 10, fontWeight: 600, color: 'var(--text-faint)',
                fontVariantNumeric: 'tabular-nums',
              }}>{t.count}</span>
            </button>
          );
        })}
      </div>

      {/* Service rows */}
      <div style={{ padding: 8 }}>
        {visible.length === 0 && (
          <div style={{ padding: 24, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>
            Nothing in this category yet.
          </div>
        )}
        {visible.map(s => {
          const isActive = s.active;
          return (
            <div key={s.id} style={{
              display: 'grid',
              gridTemplateColumns: '36px 1fr auto',
              gap: 12, alignItems: 'center',
              padding: '10px 12px', borderRadius: 6,
              opacity: isActive ? 0.55 : 1,
              transition: 'background 0.12s',
            }}
              onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = 'var(--hover)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; }}
            >
              <div style={{
                width: 36, height: 36, borderRadius: 6,
                background: isActive
                  ? 'var(--surface-2)'
                  : 'color-mix(in oklab, var(--primary) 10%, transparent)',
                color: isActive ? 'var(--text-muted)' : 'var(--primary)',
                display: 'grid', placeItems: 'center',
              }}><ServiceIcon kind={s.icon} size={18} /></div>

              <div style={{ minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{s.title}</span>
                  {isActive && (
                    <span style={{
                      fontSize: 9.5, fontWeight: 700, padding: '2px 6px', borderRadius: 3,
                      background: 'color-mix(in oklab, #16a34a 12%, transparent)',
                      color: '#16a34a', letterSpacing: 0.3, textTransform: 'uppercase',
                    }}>Active{s.since ? ` · since ${s.since}` : ''}</span>
                  )}
                  {s.isNew && !isActive && (
                    <span style={{
                      fontSize: 9.5, fontWeight: 700, padding: '2px 6px', borderRadius: 3,
                      background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
                      color: 'var(--primary)', letterSpacing: 0.3, textTransform: 'uppercase',
                    }}>New</span>
                  )}
                  {s.why && !isActive && (
                    <span style={{
                      fontSize: 9.5, fontWeight: 700, padding: '2px 6px', borderRadius: 3,
                      background: 'color-mix(in oklab, #f59e0b 14%, transparent)',
                      color: '#b45309', letterSpacing: 0.3, textTransform: 'uppercase',
                    }}>Recommended</span>
                  )}
                </div>
                <div style={{
                  fontSize: 11.5, color: 'var(--text-muted)', marginTop: 2,
                  whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                }}>
                  {s.why && !isActive ? s.why : s.blurb}
                </div>
                <div style={{
                  fontSize: 10.5, color: 'var(--text-faint)', marginTop: 2,
                  fontVariantNumeric: 'tabular-nums',
                }}>
                  {s.pricing} · {s.timeline}
                </div>
              </div>

              <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                {isActive ? (
                  <Btn variant="ghost" size="sm" onClick={() => onPick(s)}>View</Btn>
                ) : (
                  <>
                    <Btn variant="ghost" size="sm" onClick={() => onPick(s)}>Ask Joe</Btn>
                    <Btn variant="secondary" size="sm" iconRight={I.arrowRight} onClick={() => onPick({ ...s, mode: 'proposal' })}>Get proposal</Btn>
                  </>
                )}
              </div>
            </div>
          );
        })}
      </div>

      {/* Footer */}
      <div style={{
        padding: '12px 16px', borderTop: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
        background: 'var(--surface-2)',
      }}>
        {manager && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
            <PersonAvatar name={manager.name} size={28} src={manager.src} hue={manager.hue} />
            <div style={{ minWidth: 0, fontSize: 12 }}>
              <div style={{ color: 'var(--text-muted)' }}>Your account manager</div>
              <div style={{ color: 'var(--text)', fontWeight: 600 }}>{manager.name}</div>
            </div>
          </div>
        )}
        <div style={{ flex: 1 }}/>
        <Btn variant="ghost" size="sm" onClick={() => onPick({ id: 'other', title: 'Something else', blurb: 'Tell us what you have in mind.', icon: 'page', pricing: 'Custom quote', timeline: 'Varies' })}>
          + Request something else
        </Btn>
        <Btn variant="secondary" size="sm" icon={I.calendar}>Book a 30-min review</Btn>
      </div>
    </Card>
  );
};

window.GrowthOpportunitiesCard = GrowthOpportunitiesCard;
window.SERVICES = SERVICES;

const EnquireModal = ({ service, onClose }) => {
  const [form, setForm] = useState({ goal: '', timeline: service.timeline || 'Within a month', budget: '£1k–£5k', notes: '' });
  const [sent, setSent] = useState(false);
  if (!service) return null;
  const submit = (e) => { e.preventDefault(); setSent(true); };
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)',
      display: 'grid', placeItems: 'center', zIndex: 100, padding: 16,
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 520,
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)', boxShadow: '0 10px 40px rgba(0,0,0,0.3)',
      }}>
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)',
            background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center',
          }}><ServiceIcon kind={service.icon} size={20} /></div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 15, fontWeight: 600 }}>Enquire about {service.title}</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{service.pricing} · {service.timeline}</div>
          </div>
          <button onClick={onClose} aria-label="Close" style={{
            width: 32, height: 32, border: 'none', background: 'transparent', color: 'var(--text-muted)',
            borderRadius: 6, cursor: 'pointer', display: 'grid', placeItems: 'center',
          }}><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
        </div>

        {sent ? (
          <div style={{ padding: 32, textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%', margin: '0 auto 16px',
              background: 'color-mix(in oklab, var(--positive) 18%, transparent)',
              color: 'var(--positive)', display: 'grid', placeItems: 'center',
            }}>{I.check}</div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>Enquiry sent</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 20 }}>
              Joe will be in touch within 1 working day with next steps and a quote.
            </div>
            <Btn variant="primary" onClick={onClose} style={{ margin: '0 auto' }}>Done</Btn>
          </div>
        ) : (
          <form onSubmit={submit} style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 14 }}>
            <FormField label="What are you trying to achieve?" required>
              <textarea required value={form.goal} onChange={e => setForm(f => ({...f, goal: e.target.value}))}
                placeholder={`e.g. ${service.id === 'landing' ? 'A landing page for our new tinnitus assessment quiz' : service.id === 'email' ? 'A welcome series for new newsletter sign-ups' : 'Outline what success looks like for you'}`}
                rows={3}
                style={inputStyle} />
            </FormField>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <FormField label="Timeline">
                <select value={form.timeline} onChange={e => setForm(f => ({...f, timeline: e.target.value}))} style={inputStyle}>
                  {['Urgent (this week)', 'Within a month', '1–3 months', 'Just exploring'].map(o => <option key={o}>{o}</option>)}
                </select>
              </FormField>
              <FormField label="Budget">
                <select value={form.budget} onChange={e => setForm(f => ({...f, budget: e.target.value}))} style={inputStyle}>
                  {['Under £1k', '£1k–£5k', '£5k–£15k', '£15k+', 'Need guidance'].map(o => <option key={o}>{o}</option>)}
                </select>
              </FormField>
            </div>
            <FormField label="Anything else? (optional)">
              <textarea value={form.notes} onChange={e => setForm(f => ({...f, notes: e.target.value}))}
                rows={2} placeholder="Links, references, audience notes…" style={inputStyle} />
            </FormField>
            <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, paddingTop: 4 }}>
              <Btn variant="secondary" onClick={onClose} type="button">Cancel</Btn>
              <Btn variant="primary" iconRight={I.send}>Send enquiry</Btn>
            </div>
          </form>
        )}
      </div>
    </div>
  );
};

const inputStyle = {
  width: '100%', padding: '8px 12px', fontSize: 13,
  background: 'var(--surface-2)', border: '1px solid var(--border)',
  borderRadius: 'var(--radius)', color: 'var(--text)', outline: 'none',
  fontFamily: 'inherit', resize: 'vertical',
};

const FormField = ({ label, required, children }) => (
  <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
    <span style={{ fontSize: 12, fontWeight: 500, color: 'var(--text)' }}>
      {label}{required && <span style={{ color: 'var(--negative)', marginLeft: 2 }}>*</span>}
    </span>
    {children}
  </label>
);

const NEWS = [
  {
    id: 'n-microsoft-ads',
    tag: 'New',
    title: 'Microsoft Ads channel now in beta',
    summary: 'Join the waitlist to connect your Microsoft Ads account.',
    date: 'Apr 28, 2026',
    author: 'Clicky Product',
    readTime: '2 min read',
    body: [
      "We're excited to announce that the Microsoft Ads channel is now available in private beta for Clicky customers.",
      "You'll be able to view spend, conversions, CPC and CTR side-by-side with your Google Ads accounts, with the same KPI cards and trend charts you already use.",
      "We're rolling out access in waves over the next two weeks. To join the waitlist, head to Settings → Channels and click 'Request access' next to Microsoft Ads. Your account manager will follow up within 1 working day.",
      "Coming next: LinkedIn Ads (May), Meta Ads (June), and Reddit Ads later in the summer.",
    ],
  },
  {
    id: 'n-attribution',
    tag: 'Update',
    title: 'Improved attribution windows',
    summary: 'Cross-channel attribution now uses 30-day click + 1-day view.',
    date: 'Apr 22, 2026',
    author: 'Data & Insights',
    readTime: '3 min read',
    body: [
      "We've updated the default attribution model used across the Clicky platform to a 30-day click and 1-day view window — bringing us in line with Google Ads' recommended defaults.",
      "What this means: conversions that happened up to 30 days after a click on one of your ads, or 1 day after an impression, are now credited to the originating campaign. Previously we used a strict 30-day click-only window.",
      "You may notice a small uplift in reported conversions over the last 30 days, particularly for Performance Max and remarketing campaigns where view-through behaviour is more common.",
      "The new model applies retroactively to all historical data, so trend lines remain comparable. If you'd like to revert to the old behaviour for a specific account, contact your account manager.",
    ],
  },
  {
    id: 'n-reports-export',
    tag: 'Update',
    title: 'Reports now export to Google Sheets',
    summary: 'One-click export from any report — including scheduled deliveries.',
    date: 'Apr 14, 2026',
    author: 'Clicky Product',
    readTime: '1 min read',
    body: [
      "You can now export any report directly to a Google Sheet, with formulas and formatting preserved.",
      "Open any report, click the Export button, and choose 'Google Sheets'. The first time you do this you'll be asked to authorise Clicky to write to your Drive.",
      "Scheduled reports can also deliver to a Google Sheet on a recurring basis — useful for keeping a live view in your team's shared workspace.",
    ],
  },
  {
    id: 'n-ask-amplify',
    tag: 'New',
    title: 'ClickyAI™ supports follow-up questions',
    summary: 'The AI assistant now keeps context across a full conversation.',
    date: 'Apr 5, 2026',
    author: 'Clicky Labs',
    readTime: '2 min read',
    body: [
          'ClickyAI™, your in-platform AI assistant, can now keep context across multiple turns in a conversation.',
      "Ask 'Why did conversions jump on 6 April?' and follow up with 'Which keywords drove that?' — ClickyAI™ will remember what you were looking at without having to spell it out again.",
      'Conversations are saved to your account and can be reopened from the ClickyAI™ side panel. As always, please verify any critical numbers in your reports before acting on them.',
    ],
  },
];

window.NEWS = NEWS;

const NewsScreen = ({ initialId, onBack }) => {
  const [selectedId, setSelectedId] = useState(initialId || NEWS[0].id);
  const selected = NEWS.find(n => n.id === selectedId) || NEWS[0];
  return (
    <div>
      <PageHeader
        breadcrumb={<><button onClick={onBack} style={{ background: 'none', border: 'none', color: 'var(--text-muted)', cursor: 'pointer', padding: 0, fontSize: 12 }}>Dashboard</button><span>›</span><span>What's new</span></>}
        title="What's new" subtitle="Product updates, releases and announcements"
      />
      <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: 16, alignItems: 'flex-start' }}>
        <Card padding={0}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>All updates</div>
          <div style={{ padding: 6 }}>
            {NEWS.map(n => {
              const active = n.id === selectedId;
              return (
                <button key={n.id} onClick={() => setSelectedId(n.id)} style={{
                  display: 'flex', flexDirection: 'column', gap: 6, width: '100%',
                  padding: '10px 12px', borderRadius: 6, textAlign: 'left',
                  background: active ? 'color-mix(in oklab, var(--primary) 8%, transparent)' : 'transparent',
                  border: 'none', cursor: 'pointer',
                  borderLeft: `3px solid ${active ? 'var(--primary)' : 'transparent'}`,
                }}
                  onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--hover)'; }}
                  onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}
                >
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                    <Badge tone={n.tag === 'New' ? 'primary' : 'neutral'}>{n.tag}</Badge>
                    <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{n.date}</span>
                  </div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: active ? 'var(--text)' : 'var(--text)', lineHeight: 1.35 }}>{n.title}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', lineHeight: 1.4 }}>{n.summary}</div>
                </button>
              );
            })}
          </div>
        </Card>

        <Card padding={0}>
          <div style={{ padding: '20px 28px', borderBottom: '1px solid var(--border)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
              <Badge tone={selected.tag === 'New' ? 'primary' : 'neutral'}>{selected.tag}</Badge>
              <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{selected.date}</span>
              <span style={{ fontSize: 12, color: 'var(--text-faint)' }}>·</span>
              <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{selected.readTime}</span>
            </div>
            <h2 style={{ fontSize: 24, fontWeight: 700, margin: 0, letterSpacing: '-0.02em', lineHeight: 1.2 }}>{selected.title}</h2>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 8 }}>By {selected.author}</div>
          </div>
          <div style={{ padding: '24px 28px', display: 'flex', flexDirection: 'column', gap: 14 }}>
            {selected.body.map((p, i) => (
              <p key={i} style={{ fontSize: 14, lineHeight: 1.65, color: 'var(--text)', margin: 0 }}>{p}</p>
            ))}
          </div>
          <div style={{ padding: '14px 28px', borderTop: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <Btn variant="ghost" size="sm" onClick={onBack} icon={I.chevLeft}>Back to dashboard</Btn>
            <div style={{ display: 'flex', gap: 8 }}>
              <Btn variant="secondary" size="sm">Share</Btn>
              <Btn variant="primary" size="sm" iconRight={I.arrowRight} onClick={() => {
                const idx = NEWS.findIndex(n => n.id === selected.id);
                setSelectedId(NEWS[(idx + 1) % NEWS.length].id);
              }}>Next update</Btn>
            </div>
          </div>
        </Card>
      </div>
    </div>
  );
};

window.NewsScreen = NewsScreen;

// ============================================================
// InvoiceAlertBanner — severity-tinted indicator on the dashboard
// for outstanding invoices. Hidden when nothing is owed. Click
// jumps to Contracts & Billing → Invoices to pay.
// ============================================================
const InvoiceAlertBanner = ({ setActive, goBilling }) => {
  const [dismissed, setDismissed] = useState(false);
  if (dismissed) return null;
  // Pretend "today" is 2 May 2026 — matches the dashboard greeting
  const today = new Date('2026-05-02T00:00:00');
  const parseDate = (s) => {
    // "15 May 2026" → Date
    const [d, m, y] = s.split(' ');
    const months = { Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11 };
    return new Date(Number(y), months[m], Number(d));
  };
  const outstanding = INVOICES
    .filter(i => i.status !== 'Paid')
    .map(i => {
      const dueDate = parseDate(i.due);
      const days = Math.round((dueDate - today) / 86400000);
      // severity: overdue (red) > due ≤7d (amber) > due (info/blue)
      let severity = 'info';
      if (i.status === 'Overdue' || days < 0) severity = 'overdue';
      else if (days <= 7) severity = 'soon';
      return { ...i, days, dueDate, severity };
    })
    .sort((a, b) => {
      const rank = { overdue: 0, soon: 1, info: 2 };
      return rank[a.severity] - rank[b.severity] || a.dueDate - b.dueDate;
    });

  if (outstanding.length === 0) return null;

  const top = outstanding[0];
  const others = outstanding.length - 1;
  const totalDue = outstanding.reduce((s, i) => s + Number(i.amount.replace(/[£,]/g, '')), 0);

  // Tone tokens per severity
  const tones = {
    overdue: {
      bg:     'color-mix(in oklab, var(--negative) 8%, var(--surface))',
      border: 'color-mix(in oklab, var(--negative) 35%, var(--border))',
      accent: 'var(--negative)',
      icon: (
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
        </svg>
      ),
      label: 'Overdue',
    },
    soon: {
      bg:     'color-mix(in oklab, var(--warning) 9%, var(--surface))',
      border: 'color-mix(in oklab, var(--warning) 38%, var(--border))',
      accent: 'var(--warning)',
      icon: (
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>
        </svg>
      ),
      label: 'Due soon',
    },
    info: {
      bg:     'color-mix(in oklab, var(--primary) 5%, var(--surface))',
      border: 'color-mix(in oklab, var(--primary) 25%, var(--border))',
      accent: 'var(--primary)',
      icon: (
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/>
        </svg>
      ),
      label: 'Upcoming invoice',
    },
  };
  const tone = tones[top.severity];

  // Body copy varies with severity
  const headline = top.severity === 'overdue'
    ? `Invoice ${top.id} is ${Math.abs(top.days)} ${Math.abs(top.days) === 1 ? 'day' : 'days'} overdue`
    : top.severity === 'soon'
      ? `Invoice ${top.id} is due in ${top.days} ${top.days === 1 ? 'day' : 'days'}`
      : `Invoice ${top.id} is due ${top.due}`;

  const sub = top.severity === 'overdue'
    ? `Please pay to keep your services running without interruption.`
    : top.severity === 'soon'
      ? `Auto-charge will run on ${top.due} unless paid sooner.`
      : `${top.period} · auto-charge on the due date.`;

  return (
    <div role="status" style={{
      display: 'flex', alignItems: 'center', gap: 14,
      padding: '14px 16px',
      background: tone.bg,
      border: '1px solid ' + tone.border,
      borderRadius: 'var(--radius)',
    }}>
      <div style={{
        width: 36, height: 36, borderRadius: 8,
        background: 'color-mix(in oklab, ' + tone.accent + ' 14%, transparent)',
        color: tone.accent,
        display: 'grid', placeItems: 'center', flexShrink: 0,
      }}>
        {tone.icon}
      </div>

      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{
            fontSize: 9.5, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase',
            padding: '2px 6px', borderRadius: 3,
            background: tone.accent, color: '#fff',
          }}>{tone.label}</span>
          <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--text)' }}>{headline}</span>
          {others > 0 && (
            <span style={{
              fontSize: 11, color: 'var(--text-muted)', padding: '2px 6px',
              borderRadius: 99, background: 'var(--surface-2)', border: '1px solid var(--border)',
            }}>+{others} more outstanding</span>
          )}
        </div>
        <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 3 }}>
          {sub}
          {others > 0 && (
            <> · Total outstanding <strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>£{totalDue.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</strong></>
          )}
        </div>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontSize: 18, fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'var(--text)', letterSpacing: '-0.01em' }}>£{totalDue.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>{others > 0 ? `Across ${others + 1} invoices` : `Due ${top.due}`}</div>
        </div>
        <Btn
          size="sm"
          variant={top.severity === 'overdue' ? 'primary' : 'secondary'}
          iconRight={I.arrowRight}
          onClick={() => (goBilling ? goBilling('invoices') : setActive('billing'))}
          style={top.severity === 'overdue' ? { background: tone.accent, borderColor: tone.accent } : undefined}
        >
          {top.severity === 'overdue' ? 'Pay now' : 'Review & pay'}
        </Btn>
        <button
          onClick={() => setDismissed(true)}
          aria-label="Dismiss notification"
          title="Dismiss"
          style={{
            width: 28, height: 28, border: 'none', background: 'transparent',
            color: 'var(--text-muted)', borderRadius: 6,
            display: 'grid', placeItems: 'center', cursor: 'pointer',
            flexShrink: 0,
            transition: 'background 0.12s, color 0.12s',
          }}
          onMouseEnter={e => { e.currentTarget.style.background = 'color-mix(in oklab, var(--text) 8%, transparent)'; e.currentTarget.style.color = 'var(--text)'; }}
          onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-muted)'; }}
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
        </button>
      </div>
    </div>
  );
};

window.InvoiceAlertBanner = InvoiceAlertBanner;

const DashboardScreen = ({ setActive, openNews, openKpiDetail, goBilling, openInsiderArticle, openAskLightbox }) => {
  const { AreaChart, Area, ResponsiveContainer, Tooltip } = window.Recharts;
  const [enquireService, setEnquireService] = useState(null);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
      {/* Greeting (full width, above both columns) */}
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>Saturday, 2 May 2026</div>
          <h1 style={{ fontSize: 26, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>
            Good morning, Daniel
          </h1>
          <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 4 }}>
            Here's how <strong style={{ color: 'var(--text)' }}>{CLIENT.name}</strong> is tracking against this quarter's agreed Performance Targets.
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <DefaultDashboardToggle which="classic" />
          <button
            onClick={() => setActive('dashboard-v2')}
            title="Switch to the ClickyAI-led dashboard layout"
            className="clicky-ai-border"
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 8,
              padding: '6px 12px 6px 8px', borderRadius: 99,
              fontFamily: 'inherit', fontSize: 12, fontWeight: 600,
              color: 'var(--text)', cursor: 'pointer',
              transition: 'transform 80ms ease',
            }}
            onMouseDown={e => { e.currentTarget.style.transform = 'translateY(1px)'; }}
            onMouseUp={e => { e.currentTarget.style.transform = 'translateY(0)'; }}
          >
            <span style={{
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              width: 22, height: 22, borderRadius: 6,
              background: 'var(--surface-2)', flexShrink: 0,
            }}>
              <img src="assets/ai-main.svg" alt="" width="14" height="14" style={{ display: 'block' }} />
            </span>
            ClickyAI View
            <span style={{
              display: 'inline-flex', alignItems: 'center',
              padding: '0 5px', borderRadius: 4,
              background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
              color: 'var(--primary)',
              fontSize: 9, fontWeight: 700, letterSpacing: '0.04em',
            }}>NEW</span>
            <span style={{ color: 'var(--text-muted)', marginLeft: 2 }}>→</span>
          </button>
          <AddServicesChannelsButton setActive={setActive} />
        </div>
      </div>

      {/* Outstanding invoice alert — sits first, above the spend & fees strip */}
      <InvoiceAlertBanner setActive={setActive} goBilling={goBilling} />

      {/* Spend & fees overview — full-width strip above the 2-col grid.
          Combines ad spend, Clicky fees, all-in marketing spend, and
          combined cost-per-booking, each with an inline mini-graph. */}
      {(() => {
        // Mock weekly data for the spark/bar mini-graphs
        const adSpendTrend  = [340, 380, 420, 405, 460, 510, 540, 580]; // last 8 weeks
        const feesTrend     = [550, 550, 550, 550, 550, 550, 550, 550]; // weekly equiv of £2,200/mo
        const bookingsTrend = [16, 18, 22, 21, 24, 26, 28, 30];
        const cpbTrend      = [52.4, 49.1, 48.6, 46.2, 47.8, 47.0, 46.5, 47.35];

        // Numbers (must reconcile with the ad-channel pane lower down)
        const adSpend = 2393.14;
        const fees    = 2200;        // £1,250 + £950 monthly retainers
        const allIn   = adSpend + fees;
        const bookings = 97;          // 49 (Google) + 11 (Meta) + 37 (SEO)
        const cpbAllIn = allIn / bookings;

        const tiles = [
          {
            label: 'Ad spend',
            value: '£' + adSpend.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
            sub: '+15.6% vs prev 30d',
            tone: 'positive',
            graph: <MiniLine data={adSpendTrend} color="var(--primary)" height={32} />,
            graphLabel: 'Last 8 weeks',
            icon: (
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
                <path d="M12 1v22M17 5H9.5a3.5 3.5 0 1 0 0 7h5a3.5 3.5 0 1 1 0 7H6"/>
              </svg>
            ),
            color: 'var(--primary)',
          },
          {
            label: 'Clicky fees',
            value: '£' + fees.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
            sub: '2 retainers · auto-charge 15th',
            tone: 'muted',
            graph: <MiniBars data={feesTrend} color="var(--text-muted)" height={32} />,
            graphLabel: 'Steady retainer',
            icon: (
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
                <rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18"/><path d="M7 15h2M12 15h5"/>
              </svg>
            ),
            color: 'var(--text-muted)',
          },
          {
            label: 'All-in marketing',
            value: '£' + allIn.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
            sub: 'ad spend + Clicky fees',
            tone: 'neutral',
            graph: <MiniBars data={adSpendTrend.map((v, i) => v + feesTrend[i])} color="var(--positive)" height={32} />,
            graphLabel: 'Combined · 8 wk',
            icon: (
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
                <path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/>
              </svg>
            ),
            color: 'var(--positive)',
          },
          {
            label: 'Cost / booking',
            value: '£' + cpbAllIn.toFixed(2),
            sub: bookings + ' bookings · paid + organic',
            tone: 'positive',
            graph: <MiniLine data={cpbTrend} color="var(--positive)" height={32} />,
            graphLabel: 'Trending down ↓',
            icon: (
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
                <circle cx="12" cy="12" r="9"/><path d="m9 12 2 2 4-4"/>
              </svg>
            ),
            color: 'var(--positive)',
          },
        ];

        return (
          <Card padding={0}>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }}>
              {tiles.map((t, i) => (
                <div key={t.label} style={{
                  padding: '20px 24px',
                  borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                  display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0,
                }}>
                  <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                    <div style={{
                      width: 32, height: 32, borderRadius: 8, flexShrink: 0,
                      background: `color-mix(in oklab, ${t.color} 14%, transparent)`,
                      color: t.color,
                      display: 'grid', placeItems: 'center',
                    }}>{t.icon}</div>
                    <div style={{ minWidth: 0, flex: 1 }}>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{t.label}</div>
                      <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2, letterSpacing: '-0.02em' }}>{t.value}</div>
                      <div style={{
                        fontSize: 11, marginTop: 1,
                        color: t.tone === 'positive' ? 'var(--positive)'
                             : t.tone === 'warning'  ? 'var(--warning)'
                             : t.tone === 'negative' ? 'var(--negative)'
                             : 'var(--text-muted)',
                      }}>{t.sub}</div>
                    </div>
                  </div>
                  <div style={{ marginTop: 'auto' }}>
                    {t.graph}
                    <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 4, display: 'flex', justifyContent: 'space-between' }}>
                      <span>{t.graphLabel}</span>
                      <span style={{ fontFamily: 'JetBrains Mono' }}>now</span>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </Card>
        );
      })()}

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 360px', gap: 28, alignItems: 'flex-start' }}>
        {/* LEFT COLUMN */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
          {/* (greeting moved above the grid) */}

        {/* AGREED KPI HEADER STRIP */}
        <Card padding={0}>
          <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
              <div style={{
                width: 32, height: 32, borderRadius: 8,
                background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
              }}>{I.target || I.bullseye || '◎'}</div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 600, fontSize: 14 }}>Agreed Performance Targets · Q2 2026</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>The 6 Performance Targets Clicky and {CLIENT.shortName} agreed to track this quarter</div>
              </div>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
              {/* Source breakdown — at-a-glance count of how each CPT is sourced */}
              {(() => {
                const counts = AGREED_KPIS.reduce((acc, k) => {
                  acc[k.source] = (acc[k.source] || 0) + 1;
                  return acc;
                }, {});
                const items = [
                  { key: 'google-ads', label: 'live',    count: counts['google-ads'] || 0 },
                  { key: 'manual',     label: 'manual',  count: counts['manual']     || 0 },
                  { key: 'pending',    label: 'pending', count: counts['pending']    || 0 },
                ].filter(i => i.count > 0);
                return (
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11 }}>
                    {items.map((it, i) => {
                      const meta = SOURCE_META[it.key];
                      return (
                        <React.Fragment key={it.key}>
                          {i > 0 && <span style={{ color: 'var(--text-faint)' }}>·</span>}
                          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color: 'var(--text-muted)' }}>
                            <span style={{
                              width: 7, height: 7, borderRadius: '50%',
                              background: meta.fg,
                              boxShadow: it.key === 'google-ads' ? `0 0 0 3px color-mix(in oklab, ${meta.fg} 22%, transparent)` : 'none',
                            }}/>
                            <span style={{ fontWeight: 600, color: 'var(--text)' }}>{it.count}</span>
                            <span>{it.label}</span>
                          </span>
                        </React.Fragment>
                      );
                    })}
                  </div>
                );
              })()}
              <div style={{ width: 1, height: 18, background: 'var(--border)' }}/>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>67% through quarter</span>
                <div style={{ width: 96, height: 4, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden' }}>
                  <div style={{ width: '67%', height: '100%', background: 'var(--text-faint)' }}/>
                </div>
              </div>
            </div>
          </div>

          {/* KPI cards */}
          <div style={{ padding: 20, display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 14 }}>
            {AGREED_KPIS.map(k => <AgreedKpiCard key={k.key} kpi={k} onClick={() => openKpiDetail && openKpiDetail(k.key)} />)}
          </div>
        </Card>

        {/* Ad channel spend breakdown */}
        <Card padding={0}>
          <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
              <div style={{
                width: 32, height: 32, borderRadius: 8,
                background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
              }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>
              </div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 600, fontSize: 14 }}>Ad channel spend · last 30 days</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Across all channels — active and available</div>
              </div>
            </div>
            <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('channels')}>View all channels</Btn>
          </div>

          {/* Totals strip */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1.4fr', alignItems: 'stretch', borderBottom: '1px solid var(--border)' }}>
            {[
              { label: 'Total spend',  value: '£2,393.14', delta: '+15.6%', tone: 'positive' },
              { label: 'Bookings',     value: '60',        delta: '+27.7%', tone: 'positive' },
              { label: 'Cost / book',  value: '£39.89',    delta: '−9.5%',  tone: 'positive' },
            ].map((m, i) => (
              <div key={i} style={{ padding: '18px 22px', borderRight: '1px solid var(--border)' }}>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{m.label}</div>
                <div style={{ fontSize: 20, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em', marginTop: 2 }}>{m.value}</div>
                <div style={{ fontSize: 11, color: m.tone === 'positive' ? 'var(--positive)' : 'var(--negative)', fontWeight: 600, marginTop: 2 }}>{m.delta}</div>
              </div>
            ))}
            <div style={{ padding: '8px 8px 8px 8px' }}>
              <ResponsiveContainer width="100%" height={70}>
                <AreaChart data={SPEND_TREND} margin={{ top: 6, right: 8, left: 0, bottom: 0 }}>
                  <defs>
                    <linearGradient id="dash-spend" x1="0" x2="0" y1="0" y2="1">
                      <stop offset="0" stopColor="var(--primary)" stopOpacity={0.3}/>
                      <stop offset="1" stopColor="var(--primary)" stopOpacity={0}/>
                    </linearGradient>
                  </defs>
                  <Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 6, fontSize: 11 }} />
                  <Area type="monotone" dataKey="v" stroke="var(--primary)" strokeWidth={1.75} fill="url(#dash-spend)" dot={false} />
                </AreaChart>
              </ResponsiveContainer>
            </div>
          </div>

          {/* Per-channel rows */}
          <div>
            {[
              { id: 'google',    label: 'Google Ads',    icon: I.google,    active: true,
                spend: '£1,550.98', share: 65, bookings: '49',  cpb: '£31.65', delta: '+12.4%', tone: 'positive', go: 'google' },
              { id: 'meta',      label: 'Meta Ads',      icon: I.meta,      active: true,
                spend: '£842.16',   share: 35, bookings: '11',  cpb: '£76.56', delta: '+18.3%', tone: 'positive', go: 'meta' },
            ].map((c, i, arr) => (
              <div key={c.id} style={{
                display: 'grid',
                gridTemplateColumns: c.active ? '220px 1fr 110px 110px 110px 110px' : '220px 1fr 80px',
                alignItems: 'center', gap: 12,
                padding: '12px 18px',
                borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                cursor: c.active ? 'pointer' : 'default',
                opacity: c.active ? 1 : 0.78,
                transition: 'background 120ms ease, opacity 120ms ease',
              }}
                onClick={c.active ? () => setActive(c.go) : undefined}
                onMouseEnter={e => {
                  e.currentTarget.style.background = 'var(--hover)';
                  if (!c.active) e.currentTarget.style.opacity = '1';
                }}
                onMouseLeave={e => {
                  e.currentTarget.style.background = 'transparent';
                  if (!c.active) e.currentTarget.style.opacity = '0.78';
                }}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{
                    width: 28, height: 28, borderRadius: 6,
                    background: 'var(--surface-2)',
                    border: '1px solid var(--border)',
                    display: 'grid', placeItems: 'center',
                    filter: c.active ? 'none' : 'grayscale(1)',
                  }}>{c.icon}</span>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>{c.label}</div>
                    <div style={{ fontSize: 11, color: c.active ? 'var(--positive)' : 'var(--text-faint)', fontWeight: 500 }}>
                      {c.active ? '● Active' : 'Not connected'}
                    </div>
                  </div>
                </div>

                {c.active ? (
                  <>
                    {/* Share bar */}
                    <div>
                      <div style={{ height: 6, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden' }}>
                        <div style={{ width: c.share + '%', height: '100%', background: 'var(--primary)' }}/>
                      </div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 4, textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>
                        {c.share}% of spend
                      </div>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                      <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{c.spend}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>Spend</div>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                      <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{c.bookings}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>Bookings</div>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                      <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{c.cpb}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>Cost / book</div>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: c.tone === 'positive' ? 'var(--positive)' : 'var(--negative)' }}>{c.delta}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>vs prev 30d</div>
                    </div>
                  </>
                ) : (
                  <>
                    <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{c.hint}</div>
                    <div style={{ textAlign: 'right' }}>
                      <Btn variant="ghost" size="sm">Add</Btn>
                    </div>
                  </>
                )}
              </div>
            ))}
          </div>
        </Card>

        {/* Insider — premium briefings, visual tiles */}
        <InsiderTiles setActive={setActive} openInsiderArticle={openInsiderArticle} />

        {/* Growth opportunities moved to its own sidebar section */}
      </div>

      {/* Right column */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
        <WebsitePreviewCard client={CLIENT} />

        <TeamCard setActive={setActive} />
      </div>

      </div>{/* /grid */}

      {enquireService && <EnquireModal service={enquireService} onClose={() => setEnquireService(null)} />}
    </div>
  );
};

// ============================================================
// Dashboard v2 — AI-led, magazine-style alternative.
// Single-column flow leading with the AI's narrative read. Reuses
// the same rainbow-bordered AI panes + AgreedKpiCard so visual
// language stays consistent with the rest of the portal.
// ============================================================
const DashboardV2Screen = ({ setActive, openKpiDetail, goBilling, openInsiderArticle, openAskLightbox }) => {
  const opps = window.GROWTH_OPPORTUNITIES || GROWTH_OPPORTUNITIES || [];
  const topRecs = [...opps]
    .filter(o => !o.active)
    .sort((a, b) => (b.confidence || 0) - (a.confidence || 0))
    .slice(0, 3);

  const am = TEAM.find(p => p.primary) || TEAM.find(p => p.name === 'Joe Marshall');
  const firstName = am?.name?.split(' ')[0] || 'your AM';
  const trackable = AGREED_KPIS.filter(k => k.source !== 'pending').length;
  const onTrackKpis = AGREED_KPIS.filter(k => k.status === 'On track' || k.status === 'Ahead').length;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 22, maxWidth: 1100, margin: '0 auto' }}>
      {/* Greeting + view toggle */}
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>Saturday, 2 May 2026</div>
          <h1 style={{ fontSize: 28, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>
            Good morning, {CLIENT.contact?.split(' ')[0] || 'Daniel'}
          </h1>
          <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 4 }}>
            Here's the AI-led read of <strong style={{ color: 'var(--text)' }}>{CLIENT.name}</strong> — what's working, what to do, and what your team is watching.
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <DefaultDashboardToggle which="ai-led" />
          <button onClick={() => setActive('dashboard')} title="Switch back to the standard dashboard" style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '6px 12px', borderRadius: 99,
            background: 'var(--surface)', color: 'var(--text-muted)',
            border: '1px solid var(--border)', fontFamily: 'inherit',
            fontSize: 12, fontWeight: 500, cursor: 'pointer',
          }}>
            <span>←</span>
            Standard view
          </button>
        </div>
      </div>

      {/* Headline hero — rainbow-bordered, narrative-led, with a soft
          animated radial-mesh background behind the headline so the AI
          treatment carries through to the body of the card, not just the
          border. Big Joe avatar anchors the left edge. */}
      <div className="clicky-ai-border" style={{
        borderRadius: 'var(--radius)',
        boxShadow: '0 8px 24px rgba(15,23,42,0.04), var(--shadow-sm)',
        overflow: 'hidden',
      }}>
        <div style={{
          position: 'relative',
          padding: '24px 28px 26px',
          background: 'var(--surface)',
          display: 'flex', flexDirection: 'column', gap: 20,
          isolation: 'isolate',
        }}>
          {/* Decorative radial-mesh background — three soft tinted blobs */}
          <div aria-hidden="true" style={{
            position: 'absolute', inset: 0, zIndex: -1, pointerEvents: 'none',
            background: `
              radial-gradient(circle at 12% 18%, color-mix(in oklab, #2563eb 18%, transparent) 0%, transparent 35%),
              radial-gradient(circle at 88% 10%, color-mix(in oklab, #db2777 14%, transparent) 0%, transparent 38%),
              radial-gradient(circle at 70% 95%, color-mix(in oklab, #059669 10%, transparent) 0%, transparent 42%)
            `,
            opacity: 0.55,
          }}/>
          {/* Subtle sparkle decorations — tiny floating dots */}
          <div aria-hidden="true" style={{
            position: 'absolute', top: 18, right: 220, zIndex: -1, pointerEvents: 'none',
            width: 4, height: 4, borderRadius: '50%',
            background: 'color-mix(in oklab, var(--primary) 30%, transparent)',
            boxShadow: '0 0 0 4px color-mix(in oklab, var(--primary) 8%, transparent)',
          }}/>
          <div aria-hidden="true" style={{
            position: 'absolute', bottom: 100, right: 60, zIndex: -1, pointerEvents: 'none',
            width: 6, height: 6, borderRadius: '50%',
            background: 'color-mix(in oklab, #db2777 24%, transparent)',
            boxShadow: '0 0 0 5px color-mix(in oklab, #db2777 6%, transparent)',
          }}/>

          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <span style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '3px 10px', borderRadius: 99,
              background: 'color-mix(in oklab, var(--positive) 14%, var(--surface))',
              color: 'var(--positive)',
              border: '1px solid color-mix(in oklab, var(--positive) 26%, var(--border))',
              fontSize: 10.5, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase',
            }}>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7"/></svg>
              Approved by {firstName}
            </span>
            <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>May headline · refreshed today</span>
            <span style={{
              marginLeft: 'auto',
              display: 'inline-flex', alignItems: 'center', gap: 5,
              fontSize: 11, color: 'var(--text-muted)',
              padding: '3px 10px', borderRadius: 99,
              background: 'var(--surface-2)', border: '1px solid var(--border)',
            }}>
              <GeminiMark size={13} /> Powered by Gemini
            </span>
          </div>

          {/* Headline body — AM avatar + huge quote */}
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 18 }}>
            {am && (
              <div style={{ position: 'relative', flexShrink: 0 }}>
                <PersonAvatar name={am.name} size={64} hue={am.hue} src={am.src} />
                {/* Approval check anchored bottom-right of the avatar */}
                <span style={{
                  position: 'absolute', bottom: -2, right: -2,
                  width: 22, height: 22, borderRadius: '50%',
                  background: 'var(--positive)', color: '#fff',
                  display: 'grid', placeItems: 'center',
                  border: '2px solid var(--surface)',
                }}>
                  <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7"/></svg>
                </span>
              </div>
            )}
            <div style={{ minWidth: 0, flex: 1, position: 'relative' }}>
              {/* Decorative oversized opening quote */}
              <span aria-hidden="true" style={{
                position: 'absolute', top: -18, left: -6,
                fontSize: 64, lineHeight: 1, fontFamily: 'Georgia, serif',
                color: 'color-mix(in oklab, var(--primary) 14%, transparent)',
                pointerEvents: 'none', userSelect: 'none',
              }}>“</span>
              <p style={{
                margin: 0, fontSize: 22, lineHeight: 1.45, fontWeight: 600, letterSpacing: '-0.015em',
                color: 'var(--text)', textWrap: 'pretty', position: 'relative',
              }}>
                <span style={{ color: 'var(--positive)' }}>Strong quarter so far.</span>{' '}
                {onTrackKpis} of {trackable} Performance Targets are on or ahead of pace, with paid + organic combined driving <strong style={{ fontWeight: 700 }}>97 bookings</strong> at an all-in cost-per-booking of <strong style={{ fontWeight: 700 }}>£47.35</strong> — down 9.5% on the previous 30 days.
              </p>
            </div>
          </div>

          {/* Inline mini-stats — tile-style with primary tint */}
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10,
          }}>
            {[
              { label: 'Bookings · 30d',  value: '97',     delta: '+27.7% vs prev', tone: 'positive', glyph: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="m9 11 3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg> },
              { label: 'All-in CPB',      value: '£47.35', delta: '−9.5% MoM',      tone: 'positive', glyph: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 6v6l4 2"/></svg> },
              { label: 'Marketing spend', value: '£4,593', delta: '+15.6% MoM',     tone: 'neutral',  glyph: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 1v22M17 5H9.5a3.5 3.5 0 1 0 0 7h5a3.5 3.5 0 1 1 0 7H6"/></svg> },
              { label: 'Targets on pace', value: `${onTrackKpis}/${trackable}`, delta: 'this quarter', tone: 'neutral', glyph: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5" fill="currentColor"/></svg> },
            ].map((s, i) => {
              const tint = s.tone === 'positive' ? 'var(--positive)' : 'var(--primary)';
              return (
                <div key={s.label} style={{
                  position: 'relative',
                  padding: '14px 14px 12px',
                  background: 'color-mix(in oklab, ' + tint + ' 4%, var(--surface))',
                  border: '1px solid color-mix(in oklab, ' + tint + ' 18%, var(--border))',
                  borderRadius: 12,
                  display: 'flex', flexDirection: 'column', gap: 2,
                }}>
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 6 }}>
                    <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
                    <span style={{
                      width: 22, height: 22, borderRadius: 6,
                      background: 'color-mix(in oklab, ' + tint + ' 14%, transparent)',
                      color: tint, display: 'grid', placeItems: 'center', flexShrink: 0,
                    }}>{s.glyph}</span>
                  </div>
                  <div style={{
                    fontSize: 26, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2,
                    letterSpacing: '-0.02em', color: 'var(--text)',
                  }}>{s.value}</div>
                  <div style={{
                    fontSize: 11, marginTop: 1,
                    color: s.tone === 'positive' ? 'var(--positive)' : 'var(--text-muted)',
                    fontWeight: s.tone === 'positive' ? 600 : 500,
                  }}>{s.delta}</div>
                </div>
              );
            })}
          </div>

          {/* AM byline */}
          {am && (
            <div style={{
              display: 'flex', alignItems: 'center', gap: 10,
              paddingTop: 4, borderTop: '1px dashed var(--border)',
            }}>
              <div style={{ fontSize: 11.5, color: 'var(--text-muted)' }}>
                <span style={{ color: 'var(--text)', fontWeight: 600 }}>{am.name}</span> reviewed and signed off this read · {am.role}
              </div>
              <button onClick={() => setActive('insights')} style={{
                marginLeft: 'auto',
                fontSize: 11.5, color: 'var(--primary)', fontWeight: 600,
                background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit',
              }}>Read the full insight →</button>
            </div>
          )}
        </div>
      </div>

      {/* Picked for you — curated mix from Stay in the Loop (Events + Insider).
          Surfaces 2 Insider briefings and 1 upcoming event so the dashboard
          doubles as a discovery surface for the agency's wider content. */}
      {(() => {
        const featuredInsider = (window.INSIDER || INSIDER || []).find(i => i.featured) || (window.INSIDER || INSIDER || [])[0];
        const secondInsider   = (window.INSIDER || INSIDER || []).filter(i => i.id !== featuredInsider?.id)[0];
        const nextEvent       = (window.EVENTS || EVENTS || []).filter(e => !e.soldOut)[0] || (window.EVENTS || EVENTS || [])[0];
        const tagTone = (tag) => ({
          'Beta access':  '#7c3aed',
          'Heads-up':     '#d97706',
          'Benchmark':    '#16a34a',
          'Playbook':     '#2563eb',
          'Case study':   '#db2777',
          'Industry':     '#52525b',
          'Webinar':      '#2563eb',
        })[tag] || 'var(--primary)';

        const InsiderTile = ({ item, large }) => (
          <button
            onClick={() => openInsiderArticle && openInsiderArticle(item.id)}
            style={{
              textAlign: 'left', padding: 0, fontFamily: 'inherit',
              background: 'var(--surface)',
              border: '1px solid var(--border)', borderRadius: 'var(--radius)',
              cursor: 'pointer', overflow: 'hidden',
              display: 'flex', flexDirection: 'column', minWidth: 0,
              transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
            }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
          >
            {/* Cover */}
            <div style={{
              position: 'relative',
              aspectRatio: large ? '16 / 8' : '16 / 9',
              background: `linear-gradient(135deg, oklch(0.62 0.14 ${item.cover?.hue ?? 220}) 0%, oklch(0.38 0.13 ${item.cover?.hue ?? 220}) 100%)`,
              overflow: 'hidden',
            }}>
              {item.image && (
                <img src={item.image} alt="" loading="lazy" onError={e => { e.currentTarget.style.display = 'none'; }}
                  style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
              )}
              <div style={{
                position: 'absolute', inset: 0,
                background: `linear-gradient(135deg, color-mix(in oklab, oklch(0.55 0.16 ${item.cover?.hue ?? 220}) 50%, transparent) 0%, color-mix(in oklab, oklch(0.30 0.14 ${item.cover?.hue ?? 220}) 65%, transparent) 100%)`,
              }}/>
              <span style={{
                position: 'absolute', top: 10, left: 10,
                display: 'inline-flex', alignItems: 'center', gap: 5,
                padding: '3px 8px', borderRadius: 99,
                background: '#fff', color: tagTone(item.tag),
                fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
              }}>
                <span style={{ width: 5, height: 5, borderRadius: '50%', background: tagTone(item.tag) }}/>
                {item.tag}
              </span>
              {item.featured && (
                <span style={{
                  position: 'absolute', top: 10, right: 10,
                  display: 'inline-flex', alignItems: 'center', gap: 4,
                  padding: '3px 8px', borderRadius: 99,
                  background: 'color-mix(in oklab, #fff 80%, transparent)', color: 'var(--text)',
                  fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                  backdropFilter: 'blur(4px)',
                }}>★ Featured</span>
              )}
            </div>
            {/* Body */}
            <div style={{ padding: '12px 14px 14px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
              <div style={{
                fontSize: large ? 14 : 13, fontWeight: 700, lineHeight: 1.3,
                color: 'var(--text)', letterSpacing: '-0.005em', textWrap: 'pretty',
              }}>{item.title}</div>
              {large && (
                <div style={{ fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                  {item.body}
                </div>
              )}
              <div style={{
                marginTop: 'auto', paddingTop: 6,
                fontSize: 10.5, color: 'var(--text-faint)',
                display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap',
              }}>
                <span>{item.by}</span>
                <span>·</span>
                <span>{item.when}</span>
                <span>·</span>
                <span>{item.readTime} read</span>
              </div>
            </div>
          </button>
        );

        const EventTile = ({ event }) => (
          <button
            onClick={() => setActive('events')}
            style={{
              textAlign: 'left', padding: 0, fontFamily: 'inherit',
              background: 'var(--surface)',
              border: '1px solid var(--border)', borderRadius: 'var(--radius)',
              cursor: 'pointer', overflow: 'hidden',
              display: 'flex', flexDirection: 'column', minWidth: 0,
              transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
            }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
          >
            <div style={{ position: 'relative', aspectRatio: '16 / 9', overflow: 'hidden' }}>
              {event?.image && (
                <img src={event.image} alt="" loading="lazy" onError={e => { e.currentTarget.style.display = 'none'; }}
                  style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
              )}
              <div style={{
                position: 'absolute', inset: 0,
                background: 'linear-gradient(180deg, rgba(15,23,42,0.05) 0%, rgba(15,23,42,0.55) 100%)',
              }}/>
              {/* Date stamp */}
              <div style={{
                position: 'absolute', top: 10, left: 10,
                background: '#fff', borderRadius: 8, padding: '6px 10px', minWidth: 48, textAlign: 'center',
                boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
              }}>
                <div style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.06em', lineHeight: 1 }}>{event?.when?.month}</div>
                <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--text)', letterSpacing: '-0.02em', lineHeight: 1.1 }}>{event?.when?.day}</div>
              </div>
              <span style={{
                position: 'absolute', top: 10, right: 10,
                display: 'inline-flex', alignItems: 'center', gap: 5,
                padding: '3px 8px', borderRadius: 99,
                background: '#fff', color: event?.type === 'Online' ? '#2563eb' : '#16a34a',
                fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
              }}>{event?.type}</span>
            </div>
            <div style={{ padding: '12px 14px 14px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
              <div style={{
                fontSize: 13, fontWeight: 700, lineHeight: 1.3,
                color: 'var(--text)', letterSpacing: '-0.005em', textWrap: 'pretty',
              }}>{event?.title}</div>
              <div style={{ fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                {event?.venue}
              </div>
              <div style={{
                marginTop: 'auto', paddingTop: 6,
                fontSize: 10.5, color: 'var(--text-faint)',
                display: 'flex', alignItems: 'center', gap: 6,
              }}>
                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
                {event?.when?.time}
              </div>
            </div>
          </button>
        );

        return (
          <div className="clicky-ai-border" style={{
            borderRadius: 'var(--radius)',
            boxShadow: 'var(--shadow-sm)',
            overflow: 'hidden',
          }}>
            <div style={{
              padding: '12px 18px', borderBottom: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10,
              background: 'color-mix(in oklab, var(--primary) 3%, var(--surface))',
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <div style={{
                  width: 28, height: 28, borderRadius: 6, flexShrink: 0,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center',
                }}>
                  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2 14.5 8.5 21 9.3l-5 4.6L17.4 21 12 17.5 6.6 21 8 13.9l-5-4.6 6.5-.8z"/></svg>
                </div>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 600 }}>Picked for you</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>Briefings and events worth your time this week</div>
                </div>
              </div>
              <div style={{ display: 'flex', gap: 4 }}>
                <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('insider')}>Clicky Insider</Btn>
                <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('events')}>Events</Btn>
              </div>
            </div>
            <div style={{
              padding: 14, display: 'grid',
              gridTemplateColumns: '1.4fr 1fr 1fr', gap: 14,
              background: 'var(--surface)',
            }}>
              {featuredInsider && <InsiderTile item={featuredInsider} large />}
              {nextEvent && <EventTile event={nextEvent} />}
              {secondInsider && <InsiderTile item={secondInsider} />}
            </div>
          </div>
        );
      })()}

      {/* Top Growth Opportunities — 3-up rainbow */}
      <div className="clicky-ai-border" style={{
        borderRadius: 'var(--radius)',
        boxShadow: 'var(--shadow-sm)',
        overflow: 'hidden',
      }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, background: 'var(--surface)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
            <div style={{
              width: 32, height: 32, borderRadius: 8, flexShrink: 0,
              background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
            }}>
              <img src="assets/ai-opps.svg" alt="" width="18" height="18" />
            </div>
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ fontWeight: 600, fontSize: 14 }}>What to do next · Top Growth Opportunities</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                The three highest-impact moves AI flagged this month — approved by your account team
              </div>
            </div>
          </div>
          <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('opportunities')}>See all</Btn>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', background: 'var(--surface)' }}>
          {topRecs.map((o, i) => {
            const accent = o.tone === 'positive' ? 'var(--positive)'
                         : o.tone === 'warning'  ? 'var(--warning)'
                         : o.tone === 'negative' ? 'var(--negative)'
                         : 'var(--primary)';
            return (
              <div key={o.id}
                onClick={() => setActive('opportunities')}
                style={{
                  padding: '16px 18px',
                  borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                  cursor: 'pointer',
                  display: 'flex', flexDirection: 'column', gap: 8,
                  transition: 'background 0.12s',
                }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  {o.serviceIcon && (
                    <span style={{
                      width: 22, height: 22, borderRadius: 5,
                      background: 'var(--surface-2)', border: '1px solid var(--border)',
                      display: 'inline-grid', placeItems: 'center',
                      color: 'var(--text-muted)', flexShrink: 0,
                    }} title={o.service || o.category}>{o.serviceIcon}</span>
                  )}
                  <span style={{
                    fontSize: 10, fontWeight: 700, padding: '2px 7px', borderRadius: 99,
                    background: `color-mix(in oklab, ${accent} 14%, transparent)`,
                    color: accent, textTransform: 'uppercase', letterSpacing: '0.04em',
                  }}>{o.category}</span>
                  <span style={{ fontSize: 10, color: 'var(--text-faint)', fontVariantNumeric: 'tabular-nums' }}>
                    {Math.round((o.confidence || 0) * 100)}% confidence
                  </span>
                </div>
                <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3, textWrap: 'pretty' }}>{o.title}</div>
                <div style={{ fontSize: 14, fontWeight: 700, color: accent, fontVariantNumeric: 'tabular-nums' }}>
                  {o.impact?.range} <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}>/{o.impact?.cadence}</span>
                </div>
                <div style={{ fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.45 }}>{o.impact?.note}</div>
              </div>
            );
          })}
        </div>
      </div>

      {/* Performance Targets · 3-up grid */}
      <Card padding={0}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{
              width: 32, height: 32, borderRadius: 8,
              background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
              color: 'var(--primary)', display: 'grid', placeItems: 'center',
            }}>{I.target || I.bullseye || '◎'}</div>
            <div>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Performance Targets · Q2 2026</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>The 6 targets we agreed to track this quarter</div>
            </div>
          </div>
          <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('cpts')}>View all</Btn>
        </div>
        <div style={{ padding: 18, display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 14 }}>
          {AGREED_KPIS.map(k => <AgreedKpiCard key={k.key} kpi={k} onClick={() => openKpiDetail && openKpiDetail(k.key)} />)}
        </div>
      </Card>

      {/* Channel pulse — 2-col tile grid with channel-brand tints, big
          numbers, and an inline sparkline per channel. */}
      <Card padding={0}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{
              width: 32, height: 32, borderRadius: 8,
              background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
              color: 'var(--primary)', display: 'grid', placeItems: 'center',
            }}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>
            </div>
            <div>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Channel pulse · last 30 days</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Spend, bookings and CPB per active channel</div>
            </div>
          </div>
          <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive('channels')}>All channels</Btn>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0 }}>
          {[
            {
              id: 'google', label: 'Google Ads', icon: I.google,
              hue: '#4285f4',
              spend: '£1,389', bookings: 49, cpb: '£28.34',
              delta: '+8.2% bookings', tone: 'positive', target: 'google',
              spark: [320, 360, 410, 380, 450, 480, 510, 540, 580, 600, 640, 680],
            },
            {
              id: 'meta', label: 'Meta Ads', icon: I.meta,
              hue: '#0866ff',
              spend: '£842', bookings: 11, cpb: '£76.55',
              delta: '+18.3% spend', tone: 'positive', target: 'meta',
              spark: [120, 150, 180, 210, 230, 260, 280, 310, 320, 340, 360, 380],
            },
            {
              id: 'seo', label: 'SEO', icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>,
              hue: '#16a34a',
              spend: '£900 retainer', bookings: '—', cpb: '37 bookings · organic',
              delta: '+12.1% sessions', tone: 'positive', target: 'seo',
              spark: [200, 215, 230, 245, 250, 268, 272, 290, 300, 315, 330, 345],
            },
            {
              id: 'maint', label: 'Maintenance Pro',
              icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/><path d="m13.4 12.6 4.2-4.2"/><path d="M3.5 18A9 9 0 0 1 12 5a9 9 0 0 1 8.5 13"/></svg>,
              hue: '#7c3aed',
              spend: 'Retainer', bookings: '—', cpb: '99.97% uptime',
              delta: 'all 3 sites green', tone: 'positive', target: 'maintenance',
              spark: [99.85, 99.88, 99.91, 99.94, 99.95, 99.93, 99.96, 99.97, 99.97, 99.97, 99.97, 99.97],
            },
          ].map((c, i) => (
            <button key={c.id}
              onClick={() => setActive(c.target)}
              style={{
                position: 'relative', padding: '16px 18px', textAlign: 'left',
                background: 'var(--surface)', border: 'none',
                borderLeft: i % 2 === 1 ? '1px solid var(--border)' : 'none',
                borderTop: i >= 2 ? '1px solid var(--border)' : 'none',
                cursor: 'pointer', fontFamily: 'inherit',
                display: 'flex', alignItems: 'center', gap: 14, minWidth: 0,
                transition: 'background 0.12s',
                overflow: 'hidden',
              }}
              onMouseEnter={e => e.currentTarget.style.background = 'color-mix(in oklab, ' + c.hue + ' 5%, var(--surface))'}
              onMouseLeave={e => e.currentTarget.style.background = 'var(--surface)'}
            >
              {/* Channel-tinted left rail */}
              <div style={{
                position: 'absolute', top: 0, bottom: 0, left: i % 2 === 1 ? 1 : 0, width: 3,
                background: c.hue, opacity: 0.85,
              }}/>

              <div style={{
                width: 40, height: 40, borderRadius: 10, flexShrink: 0,
                background: 'color-mix(in oklab, ' + c.hue + ' 14%, transparent)',
                border: '1px solid color-mix(in oklab, ' + c.hue + ' 28%, var(--border))',
                color: c.hue, display: 'grid', placeItems: 'center',
              }}>{c.icon}</div>

              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' }}>
                  <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)', letterSpacing: '-0.005em' }}>{c.label}</div>
                  <span style={{
                    fontSize: 10.5, fontWeight: 700,
                    padding: '1px 7px', borderRadius: 99,
                    background: 'color-mix(in oklab, ' + (c.tone === 'positive' ? 'var(--positive)' : c.hue) + ' 12%, transparent)',
                    color: c.tone === 'positive' ? 'var(--positive)' : c.hue,
                    letterSpacing: '0.04em', textTransform: 'uppercase',
                  }}>{c.delta}</span>
                </div>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginTop: 6, flexWrap: 'wrap' }}>
                  <div style={{ fontSize: 18, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{c.spend}</div>
                  <div style={{ fontSize: 11.5, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>
                    {c.bookings === '—' ? c.cpb : `${c.bookings} bookings · ${c.cpb}`}
                  </div>
                </div>
              </div>

              {/* Inline sparkline */}
              <div style={{ width: 92, height: 36, flexShrink: 0 }}>
                <window.Recharts.ResponsiveContainer width="100%" height="100%">
                  <window.Recharts.AreaChart data={c.spark.map((y, x) => ({ x, y }))} margin={{ top: 2, right: 2, left: 2, bottom: 2 }}>
                    <defs>
                      <linearGradient id={`spark-v2-${c.id}`} x1="0" x2="0" y1="0" y2="1">
                        <stop offset="0" stopColor={c.hue} stopOpacity={0.32}/>
                        <stop offset="1" stopColor={c.hue} stopOpacity={0}/>
                      </linearGradient>
                    </defs>
                    <window.Recharts.Area type="monotone" dataKey="y" stroke={c.hue} strokeWidth={1.6} fill={`url(#spark-v2-${c.id})`} dot={false}/>
                  </window.Recharts.AreaChart>
                </window.Recharts.ResponsiveContainer>
              </div>

              <span style={{ color: 'var(--text-faint)', flexShrink: 0 }}>{I.arrowRight}</span>
            </button>
          ))}
        </div>
      </Card>

      {/* Footer row — site preview + team strip */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18 }}>
        <WebsitePreviewCard client={CLIENT} />
        <TeamCard setActive={setActive} />
      </div>
    </div>
  );
};

// ============================================================
// Growth opportunities — full-page sidebar destination
// ============================================================

// Tinted-gradient cover with a service glyph — used in card thumbnails and the
// lightbox hero. Per-category hue keeps related services visually grouped.
const SERVICE_HUE = {
  'Discovery & Strategy':           280,
  'Paid Media':                     220,
  'SEO & Social':                   160,
  'Digital Experiences':            340,
  'Analytics, CRM & AI Automation':  30,
};

const ServiceCover = ({ service, aspect = '16 / 9', glyphSize = 56, showBadges = true }) => {
  const hue = SERVICE_HUE[service.category] ?? 220;
  // Deterministic stock image per service via Picsum's seed API. Each service
  // id maps to a stable photo so the catalogue doesn't reshuffle on reload.
  const imgUrl = service.image || `https://picsum.photos/seed/clicky-${service.id}/640/360`;
  return (
    <div style={{
      position: 'relative', aspectRatio: aspect, overflow: 'hidden',
      background: `linear-gradient(135deg, oklch(0.68 0.15 ${hue}) 0%, oklch(0.42 0.14 ${hue}) 100%)`,
      color: '#fff',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {/* Stock photo */}
      <img src={imgUrl} alt="" loading="lazy"
        onError={e => { e.currentTarget.style.display = 'none'; }}
        style={{
          position: 'absolute', inset: 0,
          width: '100%', height: '100%', objectFit: 'cover', display: 'block',
        }}/>
      {/* Coloured tint overlay so the cover stays on-brand and the glyph reads */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `linear-gradient(135deg, color-mix(in oklab, oklch(0.55 0.16 ${hue}) 55%, transparent) 0%, color-mix(in oklab, oklch(0.30 0.14 ${hue}) 70%, transparent) 100%)`,
      }}/>
      <div style={{
        position: 'absolute', inset: 0,
        background: 'radial-gradient(circle at 25% 20%, rgba(255,255,255,0.18), transparent 55%), radial-gradient(circle at 80% 80%, rgba(0,0,0,0.22), transparent 55%)',
      }}/>
      <div style={{
        color: '#fff', opacity: 0.95, position: 'relative', display: 'inline-flex',
        filter: 'drop-shadow(0 2px 6px rgba(0,0,0,0.35))',
      }}>
        <ServiceIcon kind={service.icon} size={glyphSize} />
      </div>
      {showBadges && (
        <>
          <span style={{
            position: 'absolute', top: 10, left: 10,
            fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
            background: 'rgba(0,0,0,0.55)', color: '#fff',
            backdropFilter: 'blur(4px)', letterSpacing: '0.04em', textTransform: 'uppercase',
          }}>{service.category}</span>
          <div style={{
            position: 'absolute', top: 10, right: 10,
            display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'flex-end',
          }}>
            {service.active && (
              <span style={{
                fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
                background: 'color-mix(in oklab, var(--positive) 75%, #000)', color: '#fff',
                letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>● Active</span>
            )}
            {service.isNew && !service.active && (
              <span style={{
                fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
                background: '#fff', color: 'var(--text)',
                letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>New</span>
            )}
            {service.why && !service.active && (
              <span style={{
                fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
                background: 'color-mix(in oklab, var(--warning) 80%, #000)', color: '#fff',
                letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>Recommended</span>
            )}
          </div>
        </>
      )}
    </div>
  );
};

const ServiceBlogCard = ({ service, onOpen }) => (
  <button onClick={() => onOpen(service)} style={{
    textAlign: 'left', padding: 0,
    background: 'var(--surface)', border: '1px solid var(--border)',
    borderRadius: 'var(--radius)', overflow: 'hidden',
    display: 'flex', flexDirection: 'column',
    cursor: 'pointer',
    transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease',
  }}
    onMouseEnter={e => {
      e.currentTarget.style.borderColor = 'var(--primary)';
      e.currentTarget.style.boxShadow = 'var(--shadow-md)';
      e.currentTarget.style.transform = 'translateY(-1px)';
    }}
    onMouseLeave={e => {
      e.currentTarget.style.borderColor = 'var(--border)';
      e.currentTarget.style.boxShadow = 'none';
      e.currentTarget.style.transform = 'none';
    }}
  >
    <ServiceCover service={service} />
    <div style={{ padding: '14px 16px 16px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
      <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3, textWrap: 'pretty' }}>{service.title}</div>
      <div style={{ fontSize: 12.5, color: 'var(--text-muted)', lineHeight: 1.5, textWrap: 'pretty',
        display: '-webkit-box', WebkitBoxOrient: 'vertical', WebkitLineClamp: 2, overflow: 'hidden' }}>
        {service.blurb}
      </div>
      <div style={{ flex: 1 }}/>
      <div style={{
        marginTop: 6, paddingTop: 10, borderTop: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
        fontSize: 11,
      }}>
        <span style={{
          fontWeight: 600, color: service.active ? 'var(--positive)' : 'var(--text)',
          fontVariantNumeric: 'tabular-nums', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{service.pricing}</span>
        <span style={{ color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', fontSize: 10.5, flexShrink: 0 }}>
          {service.timeline}
        </span>
      </div>
    </div>
  </button>
);

const ServiceLightbox = ({ service, onClose }) => {
  const [form, setForm] = useState({ goal: '', timeline: 'Within a month', budget: '£1k–£5k', notes: '' });
  const [sent, setSent] = useState(false);
  const [showForm, setShowForm] = useState(false);
  if (!service) return null;
  const submit = (e) => { e.preventDefault(); setSent(true); };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)',
      display: 'grid', placeItems: 'center', zIndex: 100, padding: 16,
      backdropFilter: 'blur(2px)',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 760, maxHeight: '92vh',
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)', boxShadow: '0 18px 60px rgba(0,0,0,0.45)',
        overflow: 'auto', position: 'relative',
      }}>
        {/* Hero cover */}
        <div style={{ position: 'relative' }}>
          <ServiceCover service={service} aspect="21 / 9" glyphSize={88} />
          <button onClick={onClose} aria-label="Close" style={{
            position: 'absolute', top: 12, right: 12,
            width: 34, height: 34, border: 'none',
            background: 'rgba(0,0,0,0.5)', color: '#fff', borderRadius: '50%',
            display: 'grid', placeItems: 'center', cursor: 'pointer',
            backdropFilter: 'blur(4px)',
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
          </button>
          <div style={{
            position: 'absolute', bottom: 0, left: 0, right: 0,
            padding: '20px 28px',
            background: 'linear-gradient(180deg, transparent, rgba(0,0,0,0.55) 70%)',
          }}>
            <h2 style={{
              fontSize: 26, fontWeight: 700, color: '#fff',
              margin: 0, letterSpacing: '-0.01em', lineHeight: 1.2,
              textShadow: '0 2px 8px rgba(0,0,0,0.4)',
            }}>{service.title}</h2>
          </div>
        </div>

        {sent ? (
          <div style={{ padding: 36, textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%', margin: '0 auto 16px',
              background: 'color-mix(in oklab, var(--positive) 18%, transparent)',
              color: 'var(--positive)', display: 'grid', placeItems: 'center',
            }}>{I.check}</div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>Enquiry sent</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 20, maxWidth: 380, margin: '0 auto 20px' }}>
              Joe will be in touch within 1 working day with next steps and a quote.
            </div>
            <Btn variant="primary" onClick={onClose} style={{ margin: '0 auto' }}>Done</Btn>
          </div>
        ) : (
          <div style={{ padding: '24px 28px 28px', display: 'flex', flexDirection: 'column', gap: 20 }}>
            {/* Lead summary */}
            <p style={{
              margin: 0, fontSize: 16, lineHeight: 1.55,
              color: 'var(--text)', fontWeight: 500, textWrap: 'pretty',
            }}>{service.blurb}</p>

            {/* Active state — show how it's running */}
            {service.active && (
              <div style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: '14px 16px',
                background: 'color-mix(in oklab, var(--positive) 8%, var(--surface))',
                border: '1px solid color-mix(in oklab, var(--positive) 25%, var(--border))',
                borderRadius: 8,
              }}>
                <div style={{
                  width: 32, height: 32, borderRadius: '50%',
                  background: 'color-mix(in oklab, var(--positive) 16%, transparent)',
                  color: 'var(--positive)',
                  display: 'grid', placeItems: 'center', flexShrink: 0,
                }}>{I.check}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--positive)' }}>This service is already active</div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
                    Live{service.since ? ` since ${service.since}` : ''}{service.activity ? ` · ${service.activity}` : ''}
                  </div>
                </div>
              </div>
            )}

            {/* Why this fits — only when 'why' exists and not active */}
            {service.why && !service.active && (
              <div style={{
                padding: '14px 16px',
                background: 'color-mix(in oklab, var(--warning) 7%, var(--surface))',
                border: '1px solid color-mix(in oklab, var(--warning) 25%, var(--border))',
                borderRadius: 8,
                display: 'flex', gap: 12, alignItems: 'flex-start',
              }}>
                <div style={{
                  width: 32, height: 32, borderRadius: 8, flexShrink: 0,
                  background: 'color-mix(in oklab, var(--warning) 16%, transparent)',
                  color: 'var(--warning)',
                  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"><path d="M12 3v3M12 18v3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M3 12h3M18 12h3M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/><circle cx="12" cy="12" r="3.5"/></svg>
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--warning)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>
                    Recommended for {CLIENT.shortName}
                  </div>
                  <div style={{ fontSize: 13, color: 'var(--text)', marginTop: 4, lineHeight: 1.5 }}>
                    {service.why}
                  </div>
                </div>
              </div>
            )}

            {/* Detail strip — pricing, timeline, category */}
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
              border: '1px solid var(--border)', borderRadius: 8,
              overflow: 'hidden',
            }}>
              {[
                { label: 'Pricing',  value: service.pricing },
                { label: 'Timeline', value: service.timeline },
                { label: 'Category', value: service.category },
              ].map((d, i) => (
                <div key={d.label} style={{
                  padding: '14px 16px',
                  borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                }}>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{d.label}</div>
                  <div style={{ fontSize: 13, fontWeight: 600, marginTop: 4, lineHeight: 1.3 }}>{d.value}</div>
                </div>
              ))}
            </div>

            {/* What's included — illustrative bullets so the lightbox feels substantial */}
            <div>
              <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>What's included</div>
              <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px 16px' }}>
                {[
                  'Onboarding call with Joe + the relevant specialist',
                  'Account setup and tracking review',
                  'Monthly reporting in Looker Studio',
                  'Quarterly strategy review with your AM',
                ].map(x => (
                  <li key={x} style={{ display: 'flex', gap: 8, fontSize: 12.5, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                    <span style={{ color: 'var(--positive)', flexShrink: 0, marginTop: 2 }}>
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
                    </span>
                    {x}
                  </li>
                ))}
              </ul>
            </div>

            {/* Inline enquiry form (toggleable to keep the default state quieter) */}
            {showForm && !service.active ? (
              <form onSubmit={submit} style={{
                display: 'flex', flexDirection: 'column', gap: 14,
                padding: 18, background: 'var(--surface-2)',
                border: '1px solid var(--border)', borderRadius: 8,
              }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>Tell us a bit more</div>
                <FormField label="What are you trying to achieve?" required>
                  <textarea required value={form.goal} onChange={e => setForm(f => ({...f, goal: e.target.value}))}
                    rows={3} placeholder="Outline what success looks like for you" style={inputStyle} />
                </FormField>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                  <FormField label="Timeline">
                    <select value={form.timeline} onChange={e => setForm(f => ({...f, timeline: e.target.value}))} style={inputStyle}>
                      {['Urgent (this week)', 'Within a month', '1–3 months', 'Just exploring'].map(o => <option key={o}>{o}</option>)}
                    </select>
                  </FormField>
                  <FormField label="Budget">
                    <select value={form.budget} onChange={e => setForm(f => ({...f, budget: e.target.value}))} style={inputStyle}>
                      {['Under £1k', '£1k–£5k', '£5k–£15k', '£15k+', 'Need guidance'].map(o => <option key={o}>{o}</option>)}
                    </select>
                  </FormField>
                </div>
                <FormField label="Anything else? (optional)">
                  <textarea value={form.notes} onChange={e => setForm(f => ({...f, notes: e.target.value}))}
                    rows={2} placeholder="Links, references, audience notes…" style={inputStyle} />
                </FormField>
                <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
                  <Btn variant="secondary" type="button" onClick={() => setShowForm(false)}>Cancel</Btn>
                  <Btn variant="primary" iconRight={I.send}>Send enquiry</Btn>
                </div>
              </form>
            ) : (
              <div style={{
                display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 8,
                paddingTop: 8, borderTop: '1px solid var(--border)',
              }}>
                <Btn variant="ghost" icon={I.calendar}>Book 15-min chat</Btn>
                {service.active ? (
                  <Btn variant="primary" icon={I.external} onClick={onClose}>Open service</Btn>
                ) : (
                  <Btn variant="primary" iconRight={I.send} onClick={() => setShowForm(true)}>
                    Enquire about this
                  </Btn>
                )}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
};

const GROWTH_PAGE_SIZE = 12;

// ============================================================
// Add Paid Media Channels — focused catalogue page for the
// paid-channel sub-suite. Frames Paid Media Management as the
// master service, with each advertiser as an incremental add-on
// to the retainer rather than a standalone purchase.
// ============================================================
const PAID_CHANNEL_UPLIFTS = {
  google:    { uplift: 450, eta: 'Live now',    audience: 'Search · Performance Max · Shopping' },
  meta:      { uplift: 450, eta: '1 week',     audience: 'Facebook + Instagram audiences' },
  microsoft: { uplift: 200, eta: '1 week',     audience: 'Bing search — typically older, higher-income' },
  tiktok:    { uplift: 400, eta: '2 weeks',    audience: 'In-feed video, mobile-first audiences' },
  linkedin:  { uplift: 550, eta: '2 weeks',    audience: 'B2B by job title, company, seniority' },
  youtube:   { uplift: 350, eta: '2–3 weeks',  audience: 'Pre-roll, in-stream, Connected-TV' },
  reddit:    { uplift: 200, eta: '1 week',     audience: 'Sub-reddit communities & interest targeting' },
  pinterest: { uplift: 250, eta: '1–2 weeks',  audience: 'Inspiration & save-intent searches' },
  chatgpt:   { uplift: 300, eta: '1 week',     audience: 'Sponsored placements inside ChatGPT' },
  spotify:   { uplift: 200, eta: '1 week',     audience: 'Audio + display between tracks' },
  aishop:    { uplift: 400, eta: '2 weeks',    audience: 'AI-curated Shopping placements' },
};

// Channel brand colours — used for the tinted icon tiles.
const PAID_CHANNEL_HUES = {
  google: '#4285f4', meta: '#0866ff', microsoft: '#00a4ef', tiktok: '#000000',
  linkedin: '#0a66c2', youtube: '#ff0000', reddit: '#ff4500', pinterest: '#e60023',
  chatgpt: '#10a37f', spotify: '#1db954', aishop: '#fbbc04',
};

// Real brand-mark image overrides for the tile (when an SVG file exists).
const PAID_CHANNEL_IMG = {
  google:     'assets/google.svg',
  meta:       'assets/meta.svg',
  microsoft:  'assets/microsoft.svg',
  linkedin:   'assets/linkedin.svg',
  reddit:     'assets/reddit.svg',
  tiktok:     'assets/tiktok.svg',
};

const AddPaidMediaChannelsScreen = ({ setActive }) => {
  const paidServices = SERVICES.filter(s => s.category === 'Paid Media');
  const active = paidServices.filter(s => s.active);
  const available = paidServices.filter(s => !s.active);

  const masterFee = 950; // Paid Media Management retainer
  const totalUplift = active.reduce((n, s) => n + (PAID_CHANNEL_UPLIFTS[s.id]?.uplift || 0), 0);
  const totalRetainer = masterFee + totalUplift;

  const [enquireService, setEnquireService] = useState(null);

  return (
    <div>
      <PageHeader
        title="Add paid media channels"
        subtitle="Paid Media Management is one master service — adding a channel adjusts the retainer rather than starting a new contract."
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.calendar} onClick={() => setActive('events')}>Book 15-min</Btn>
          <Btn variant="primary" size="sm" icon={I.send} onClick={() => setActive('ask')}>Talk to Joe</Btn>
        </>}
      />

      {/* Pricing model explainer */}
      <Card padding={0} style={{ marginBottom: 16, overflow: 'hidden' }}>
        <div style={{
          padding: '14px 18px', borderBottom: '1px solid var(--border)',
          background: 'color-mix(in oklab, var(--primary) 4%, var(--surface))',
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <div style={{
            width: 28, height: 28, borderRadius: 6, flexShrink: 0,
            background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center',
          }}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 16v-4M12 8h.01"/></svg>
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>How paid media pricing works</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>One master retainer for strategy, reporting + your account team. Each live channel adds a small management uplift on top.</div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr', alignItems: 'stretch' }}>
          <div style={{ padding: '16px 22px', borderRight: '1px solid var(--border)' }}>
            <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Master service</div>
            <div style={{ fontSize: 14, fontWeight: 700, marginTop: 6 }}>Paid Media Management</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.5 }}>
              Strategy, channel mix, reporting, weekly optimisation calls, your account pod. Required to run any paid channel.
            </div>
            <div style={{ fontSize: 16, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 8 }}>£{masterFee.toLocaleString('en-GB')}<span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}> / month</span></div>
          </div>
          <Mini label="Active channels"     value={active.length}                                                  sub={`of ${paidServices.length} available`} />
          <Mini label="Channel uplifts"     value={'£' + totalUplift.toLocaleString('en-GB')}                      sub="added to your retainer" />
          <Mini label="Total retainer"      value={'£' + totalRetainer.toLocaleString('en-GB')}                    sub="master + active channels" tone="positive" />
        </div>
      </Card>

      {/* Currently active strip — quick reassurance of what's live */}
      {active.length > 0 && (
        <div style={{
          marginBottom: 16, padding: '12px 16px',
          background: 'color-mix(in oklab, var(--positive) 5%, var(--surface))',
          border: '1px solid color-mix(in oklab, var(--positive) 26%, var(--border))',
          borderRadius: 'var(--radius)',
          display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
        }}>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            padding: '2px 8px', borderRadius: 99,
            background: 'var(--positive)', color: '#fff',
            fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
          }}>
            <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
            Live now
          </span>
          <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>You're running</span>
          <span style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {active.map(s => (
              <span key={s.id} style={{
                display: 'inline-flex', alignItems: 'center', gap: 5,
                padding: '3px 8px 3px 5px', borderRadius: 99,
                background: 'var(--surface)', border: '1px solid var(--border)',
                fontSize: 11.5, fontWeight: 500,
              }}>
                <span style={{
                  width: 18, height: 18, borderRadius: 4,
                  background: 'color-mix(in oklab, ' + (PAID_CHANNEL_HUES[s.id] || '#52525b') + ' 14%, transparent)',
                  display: 'grid', placeItems: 'center',
                }}>
                  {PAID_CHANNEL_IMG[s.id] ? (
                    <img src={PAID_CHANNEL_IMG[s.id]} alt="" width="12" height="12" style={{ display: 'block' }} />
                  ) : (
                    <ServiceIcon kind={s.icon} size={12} />
                  )}
                </span>
                {s.title}
              </span>
            ))}
          </span>
        </div>
      )}

      {/* Channel grid */}
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 14,
      }}>
        {[...active, ...available].map(s => {
          const meta = PAID_CHANNEL_UPLIFTS[s.id] || { uplift: 0, eta: '—', audience: s.blurb };
          const hue = PAID_CHANNEL_HUES[s.id] || '#52525b';
          const recommended = !!s.why && !s.active;
          return (
            <button
              key={s.id}
              onClick={() => setEnquireService(s)}
              style={{
                position: 'relative', textAlign: 'left', padding: 0, fontFamily: 'inherit',
                background: 'var(--surface)',
                border: '1px solid ' + (recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'),
                borderRadius: 'var(--radius)',
                cursor: 'pointer', overflow: 'hidden',
                display: 'flex', flexDirection: 'column', gap: 0,
                transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
              }}
              onMouseEnter={e => { e.currentTarget.style.borderColor = hue; e.currentTarget.style.boxShadow = '0 6px 18px ' + hue + '20'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
              onMouseLeave={e => { e.currentTarget.style.borderColor = recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
            >
              {/* Tinted top header */}
              <div style={{
                position: 'relative',
                padding: '14px 16px',
                background: `linear-gradient(180deg, color-mix(in oklab, ${hue} 12%, var(--surface)) 0%, color-mix(in oklab, ${hue} 4%, var(--surface)) 100%)`,
                borderBottom: '1px solid var(--border)',
                display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <div style={{
                  width: 40, height: 40, borderRadius: 10, flexShrink: 0,
                  background: 'var(--surface)',
                  border: '1px solid color-mix(in oklab, ' + hue + ' 32%, var(--border))',
                  color: hue, display: 'grid', placeItems: 'center',
                  boxShadow: '0 2px 6px rgba(15,23,42,0.04)',
                }}>
                  {PAID_CHANNEL_IMG[s.id] ? (
                    <img src={PAID_CHANNEL_IMG[s.id]} alt="" width="22" height="22" style={{ display: 'block' }} />
                  ) : (
                    <ServiceIcon kind={s.icon} size={22} />
                  )}
                </div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                    <div style={{ fontSize: 14.5, fontWeight: 700, color: 'var(--text)', letterSpacing: '-0.005em' }}>{s.title}</div>
                    {s.isNew && (
                      <span style={{
                        padding: '0 6px', borderRadius: 4, fontSize: 9, fontWeight: 700,
                        background: 'color-mix(in oklab, var(--primary) 14%, transparent)', color: 'var(--primary)',
                        letterSpacing: '0.04em',
                      }}>NEW</span>
                    )}
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{meta.audience}</div>
                </div>
                {/* Status pill */}
                {s.active ? (
                  <span style={{
                    display: 'inline-flex', alignItems: 'center', gap: 4,
                    padding: '2px 8px', borderRadius: 99,
                    background: 'color-mix(in oklab, var(--positive) 14%, transparent)', color: 'var(--positive)',
                    fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                  }}>
                    <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)' }}/>
                    Active
                  </span>
                ) : recommended ? (
                  <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',
                  }}>Recommended</span>
                ) : null}
              </div>

              {/* Body */}
              <div style={{ padding: '14px 16px 12px', display: 'flex', flexDirection: 'column', gap: 8, flex: 1 }}>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                  {s.blurb}
                </div>
                {recommended && s.why && (
                  <div style={{
                    padding: '8px 10px', borderRadius: 6,
                    background: 'color-mix(in oklab, var(--warning) 8%, transparent)',
                    border: '1px solid color-mix(in oklab, var(--warning) 22%, var(--border))',
                    fontSize: 11, color: 'var(--text)', lineHeight: 1.5,
                  }}>
                    <strong style={{ color: 'var(--warning)' }}>Why it's a fit:</strong> {s.why}
                  </div>
                )}
              </div>

              {/* Footer — pricing + CTA */}
              <div style={{
                padding: '10px 16px',
                borderTop: '1px solid var(--border)',
                background: 'var(--surface-2)',
                display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
              }}>
                <div>
                  {s.active ? (
                    <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                      <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>+£{meta.uplift}</span> / month
                      <span style={{ color: 'var(--text-faint)' }}> · already in retainer</span>
                    </div>
                  ) : (
                    <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                      Adds <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>+£{meta.uplift}</span> / month · {meta.eta}
                    </div>
                  )}
                </div>
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 4,
                  fontSize: 11.5, fontWeight: 600,
                  color: s.active ? 'var(--text-muted)' : 'var(--primary)',
                }}>
                  {s.active ? 'Manage' : 'Add channel'}
                  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                </span>
              </div>
            </button>
          );
        })}
      </div>

      {enquireService && <EnquireModal service={enquireService} onClose={() => setEnquireService(null)} />}
    </div>
  );
};

const Mini = ({ label, value, sub, tone }) => (
  <div style={{ padding: '16px 22px', borderRight: '1px solid var(--border)' }}>
    <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{label}</div>
    <div style={{
      fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em',
      color: tone === 'positive' ? 'var(--positive)' : 'var(--text)',
    }}>{value}</div>
    {sub && <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{sub}</div>}
  </div>
);

// =============================================================
// Add SEO — focused catalogue page for the SEO retainer.
// Master service + per-site uplift + add-on packages (Local SEO,
// E-commerce, International, audits, content sprints).
// =============================================================
const AddSeoScreen = ({ setActive }) => {
  const [enquireService, setEnquireService] = useState(null);
  const masterFee = 900; // current SEO retainer

  // Sites — only the ones marked as live get an "active SEO" badge in
  // this prototype (one site is the SEO subject today). Anything not
  // currently in SEO appears as "Add this site".
  const sites = (window.CLIENT?.sites || []).map(s => ({
    ...s,
    seoActive: s.id === 'lodge', // Evergreen Escapes is the live SEO site
  }));
  const activeSeoSites = sites.filter(s => s.seoActive);

  // Add-on packages — one-off and ongoing options that sit on top of
  // the master retainer.
  const packages = [
    {
      id: 'local',  title: 'Local SEO push',                 hue: '#16a34a',
      uplift: 250,  cadence: 'mo', timeline: '2 weeks setup', recommended: true,
      blurb: 'GBP optimisation, local citations, review acquisition. Strong fit for the lodge sites.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s-8-4.5-8-11.5a8 8 0 0 1 16 0c0 7-8 11.5-8 11.5z"/><circle cx="12" cy="10" r="3"/></svg>,
    },
    {
      id: 'audit',  title: 'Technical SEO audit',            hue: '#2563eb',
      uplift: 1800, cadence: 'one-off', timeline: '3 weeks',
      blurb: 'Full crawl, indexability, core web vitals, schema, internal linking — signed deliverable.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>,
    },
    {
      id: 'content', title: 'Content SEO sprint',            hue: '#db2777',
      uplift: 350,  cadence: 'mo', timeline: '1 week setup',
      blurb: '3 long-form articles per month + on-page optimisation against your priority keyword cluster.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M9 13h6M9 17h6M9 9h2"/></svg>,
    },
    {
      id: 'links',  title: 'Link building campaign',         hue: '#7c3aed',
      uplift: 600,  cadence: 'mo', timeline: '2 weeks setup',
      blurb: 'Outreach-led placements (4 per month) with editorial standards. UK travel & lifestyle press.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.7 1.7"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7"/></svg>,
    },
    {
      id: 'ecom',   title: 'E-commerce SEO',                 hue: '#d97706',
      uplift: 450,  cadence: 'mo', timeline: '2 weeks setup',
      blurb: 'Product/category page optimisation, schema, faceted nav. For when you launch direct booking with cart.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.7 13.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/></svg>,
    },
    {
      id: 'intl',   title: 'International SEO',              hue: '#0866ff',
      uplift: 550,  cadence: 'mo', timeline: '3 weeks setup',
      blurb: 'Hreflang, local domains/folders, country-targeted content. For when you expand outside the UK.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>,
    },
    {
      id: 'schema', title: 'Schema markup audit',            hue: '#059669',
      uplift: 750,  cadence: 'one-off', timeline: '1 week',
      blurb: 'Full structured-data review — site, organisation, FAQ, product, review markup with sign-off.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>,
    },
    {
      id: 'gsc',    title: 'GSC + GA4 alignment',            hue: '#52525b',
      uplift: 450,  cadence: 'one-off', timeline: '1 week',
      blurb: 'Reconcile Search Console and GA4 organic numbers, set up the right reporting view.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>,
    },
  ];

  const totalSites = activeSeoSites.length;
  const totalRetainer = masterFee + (totalSites - 1) * 350; // first site included, +£350 per extra

  return (
    <div>
      <PageHeader
        title="Add SEO"
        subtitle="One SEO retainer covers the suite — adding a site or a focused package adjusts the retainer rather than starting a new contract."
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.calendar}>Book 15-min</Btn>
          <Btn variant="primary" size="sm" icon={I.send} onClick={() => setActive && setActive('ask')}>Talk to your SEO lead</Btn>
        </>}
      />

      {/* Pricing model */}
      <Card padding={0} style={{ marginBottom: 16, overflow: 'hidden' }}>
        <div style={{
          padding: '14px 18px', borderBottom: '1px solid var(--border)',
          background: 'color-mix(in oklab, #16a34a 4%, var(--surface))',
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <div style={{
            width: 28, height: 28, borderRadius: 6, flexShrink: 0,
            background: 'color-mix(in oklab, #16a34a 14%, transparent)',
            color: '#16a34a', display: 'grid', placeItems: 'center',
          }}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>How SEO pricing works</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
              Master retainer + £350/mo per additional domain. Packages are billed as monthly uplifts or one-offs on top.
            </div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr' }}>
          <div style={{ padding: '16px 22px', borderRight: '1px solid var(--border)' }}>
            <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Master service</div>
            <div style={{ fontSize: 14, fontWeight: 700, marginTop: 6 }}>SEO Retainer</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.5 }}>
              Quarterly audit, on-page optimisation, 4 outreach links/mo, monthly ranking + traffic report. First domain included.
            </div>
            <div style={{ fontSize: 16, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 8 }}>£{masterFee.toLocaleString('en-GB')}<span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}> / month</span></div>
          </div>
          <Mini label="Sites covered"   value={totalSites} sub={`of ${sites.length} sites you own`} />
          <Mini label="Per-site uplift" value="£350" sub="for each extra domain" />
          <Mini label="Total retainer"  value={'£' + totalRetainer.toLocaleString('en-GB')} sub="master + active sites" tone="positive" />
        </div>
      </Card>

      {/* Sites: live + available to add */}
      <div style={{ marginBottom: 18 }}>
        <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 8 }}>Your sites</div>
        <Card padding={0}>
          {sites.map((s, i) => (
            <div key={s.id} style={{
              display: 'flex', alignItems: 'center', gap: 14,
              padding: '12px 18px',
              borderTop: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{
                width: 36, height: 36, borderRadius: 8, flexShrink: 0,
                background: 'color-mix(in oklab, #16a34a 12%, transparent)',
                color: '#16a34a', display: 'grid', placeItems: 'center',
              }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
              </div>
              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600 }}>{s.name}</div>
                  {s.status === 'planned' && (
                    <span style={{
                      padding: '1px 7px', borderRadius: 99,
                      background: 'var(--surface-2)', color: 'var(--text-muted)',
                      fontSize: 10, fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase',
                    }}>Planned</span>
                  )}
                </div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, fontFamily: 'JetBrains Mono' }}>{s.url}</div>
              </div>
              {s.seoActive ? (
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 5,
                  padding: '3px 10px', borderRadius: 99,
                  background: 'color-mix(in oklab, var(--positive) 12%, transparent)', color: 'var(--positive)',
                  fontSize: 11, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>
                  <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)' }}/>
                  SEO live
                </span>
              ) : (
                <Btn variant="primary" size="sm" icon={I.plus} onClick={() => setEnquireService({ id: 'add-seo-' + s.id, title: `Add SEO for ${s.name}`, blurb: `Adds £350/mo to your SEO retainer for ${s.name}. Includes the same on-page, outreach and monthly reporting as your existing site.`, pricing: '+£350 / month', timeline: '2 weeks setup' })}>
                  Add SEO · +£350/mo
                </Btn>
              )}
            </div>
          ))}
        </Card>
      </div>

      {/* Packages */}
      <div>
        <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 8 }}>SEO packages</div>
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 14,
        }}>
          {packages.map(p => (
            <button key={p.id}
              onClick={() => setEnquireService({ id: p.id, title: p.title, blurb: p.blurb, pricing: '+£' + p.uplift + ' / ' + p.cadence, timeline: p.timeline })}
              style={{
                position: 'relative', textAlign: 'left', padding: 0, fontFamily: 'inherit',
                background: 'var(--surface)',
                border: '1px solid ' + (p.recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'),
                borderRadius: 'var(--radius)', overflow: 'hidden',
                cursor: 'pointer',
                display: 'flex', flexDirection: 'column',
                transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
              }}
              onMouseEnter={e => { e.currentTarget.style.borderColor = p.hue; e.currentTarget.style.boxShadow = '0 6px 18px ' + p.hue + '20'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
              onMouseLeave={e => { e.currentTarget.style.borderColor = p.recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
            >
              <div style={{
                padding: '14px 16px',
                background: `linear-gradient(180deg, color-mix(in oklab, ${p.hue} 12%, var(--surface)) 0%, color-mix(in oklab, ${p.hue} 4%, var(--surface)) 100%)`,
                borderBottom: '1px solid var(--border)',
                display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <div style={{
                  width: 40, height: 40, borderRadius: 10, flexShrink: 0,
                  background: 'var(--surface)',
                  border: '1px solid color-mix(in oklab, ' + p.hue + ' 32%, var(--border))',
                  color: p.hue, display: 'grid', placeItems: 'center',
                  boxShadow: '0 2px 6px rgba(15,23,42,0.04)',
                }}>{p.glyph}</div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                    <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)', letterSpacing: '-0.005em' }}>{p.title}</div>
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{p.timeline}</div>
                </div>
                {p.recommended && (
                  <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',
                  }}>Recommended</span>
                )}
              </div>
              <div style={{ padding: '14px 16px 12px', flex: 1, fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                {p.blurb}
              </div>
              <div style={{
                padding: '10px 16px', borderTop: '1px solid var(--border)',
                background: 'var(--surface-2)',
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              }}>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                  Adds <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>+£{p.uplift}</span> / {p.cadence}
                </div>
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 4,
                  fontSize: 11.5, fontWeight: 600, color: 'var(--primary)',
                }}>
                  Add package
                  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                </span>
              </div>
            </button>
          ))}
        </div>
      </div>

      {enquireService && <EnquireModal service={enquireService} onClose={() => setEnquireService(null)} />}
    </div>
  );
};

// =============================================================
// Add Website Maintenance — focused catalogue page for the
// Maintenance Pro retainer. Master fee + per-site uplift + tier
// upgrades + add-ons (security, accessibility, performance audits).
// =============================================================
const AddMaintenanceScreen = ({ setActive }) => {
  const [enquireService, setEnquireService] = useState(null);
  const masterFee = 450;

  const sites = (window.CLIENT?.sites || []).map(s => ({
    ...s,
    maintActive: s.status === 'active',
  }));
  const activeSites = sites.filter(s => s.maintActive);
  const plannedSites = sites.filter(s => !s.maintActive);

  // Per-site uplift varies by tier; default Standard = £150/mo.
  const totalRetainer = masterFee + activeSites.length * 150;

  const tiers = [
    {
      id: 'standard', name: 'Standard',     hue: '#52525b', uplift: 150,
      features: ['Daily backups', 'Weekly security scans', 'Plugin & CMS updates', 'Monthly health report'],
      blurb: 'The baseline — what every site needs to stay up.',
    },
    {
      id: 'pro', name: 'Pro',                hue: '#7c3aed', uplift: 250, recommended: true,
      features: ['Everything in Standard', 'Hourly backups + 30-day retention', 'CDN + image optimisation', 'Uptime monitoring (1-min)', 'Quarterly performance audit'],
      blurb: 'For revenue-driving sites — your current tier on Evergreen.',
    },
    {
      id: 'premium', name: 'Premium',        hue: '#0866ff', uplift: 450,
      features: ['Everything in Pro', '24/7 incident response', 'Dedicated technical lead', 'Quarterly security pen-test', 'Accessibility audit + remediation'],
      blurb: 'When downtime costs more than the upgrade.',
    },
  ];

  const addons = [
    { id: 'sec',   title: 'Security audit',          hue: '#dc2626', uplift: 1200, cadence: 'one-off', timeline: '2 weeks',
      blurb: 'OWASP top-10 review, penetration test, hardening recommendations with priority backlog.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg> },
    { id: 'a11y',  title: 'Accessibility audit',     hue: '#0866ff', uplift: 950, cadence: 'one-off', timeline: '2 weeks',
      blurb: 'WCAG 2.2 AA compliance check, manual + automated testing, prioritised remediation plan.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="8" r="1.5"/><path d="M9 12h6M12 12v8M9 17l3 4 3-4"/></svg> },
    { id: 'perf',  title: 'Performance audit',       hue: '#16a34a', uplift: 850, cadence: 'one-off', timeline: '1 week', recommended: true,
      blurb: 'Core Web Vitals deep-dive, caching review, image/script audit. Targeted improvements with before/after benchmarks.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg> },
    { id: 'staging', title: 'Staging environment',    hue: '#d97706', uplift: 120, cadence: 'mo', timeline: '3 days',
      blurb: 'Always-on staging copy of your production site for safe testing of plugin/CMS updates and content changes.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg> },
    { id: 'cdn',   title: 'Premium CDN tier',         hue: '#0866ff', uplift: 95, cadence: 'mo', timeline: '1 day',
      blurb: 'Cloudflare Pro / Fastly bandwidth, image resizing, DDoS protection, edge cache rules.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M17 18a5 5 0 0 0-5-5H8a4 4 0 0 1 0-8 5 5 0 0 1 9.5 2A4 4 0 0 1 17 18z"/></svg> },
    { id: 'malware', title: 'Malware removal SLA',    hue: '#dc2626', uplift: 175, cadence: 'mo', timeline: '1 day',
      blurb: 'Guaranteed 4-hour response and clean-up if anything ever gets through. Includes restore from clean backup.',
      glyph: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9 9l6 6M15 9l-6 6"/></svg> },
  ];

  return (
    <div>
      <PageHeader
        title="Add Website Maintenance"
        subtitle="One Maintenance Pro retainer covers the whole portfolio — adding a site or upgrading a tier adjusts the retainer."
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.calendar}>Book 15-min</Btn>
          <Btn variant="primary" size="sm" icon={I.send} onClick={() => setActive && setActive('ask')}>Talk to Nathan</Btn>
        </>}
      />

      {/* Pricing model */}
      <Card padding={0} style={{ marginBottom: 16, overflow: 'hidden' }}>
        <div style={{
          padding: '14px 18px', borderBottom: '1px solid var(--border)',
          background: 'color-mix(in oklab, #7c3aed 4%, var(--surface))',
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <div style={{
            width: 28, height: 28, borderRadius: 6, flexShrink: 0,
            background: 'color-mix(in oklab, #7c3aed 14%, transparent)',
            color: '#7c3aed', display: 'grid', placeItems: 'center',
          }}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/></svg>
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>How Maintenance pricing works</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
              Master fee covers the platform. Each site adds a per-site uplift based on tier (Standard +£150, Pro +£250, Premium +£450).
            </div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr' }}>
          <div style={{ padding: '16px 22px', borderRight: '1px solid var(--border)' }}>
            <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Master service</div>
            <div style={{ fontSize: 14, fontWeight: 700, marginTop: 6 }}>Maintenance Pro</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.5 }}>
              Platform + 24/7 monitoring + dedicated tech team. Required to run any site under maintenance.
            </div>
            <div style={{ fontSize: 16, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 8 }}>£{masterFee.toLocaleString('en-GB')}<span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}> / month</span></div>
          </div>
          <Mini label="Sites maintained" value={activeSites.length} sub={`of ${sites.length} sites`} />
          <Mini label="Per-site uplift" value="£150–450" sub="depending on tier" />
          <Mini label="Total retainer" value={'£' + totalRetainer.toLocaleString('en-GB')} sub="master + active sites" tone="positive" />
        </div>
      </Card>

      {/* Sites: live + sites you can add */}
      <div style={{ marginBottom: 18 }}>
        <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 8 }}>Your sites</div>
        <Card padding={0}>
          {sites.map((s, i) => (
            <div key={s.id} style={{
              display: 'flex', alignItems: 'center', gap: 14,
              padding: '12px 18px',
              borderTop: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{
                width: 36, height: 36, borderRadius: 8, flexShrink: 0,
                background: 'color-mix(in oklab, #7c3aed 12%, transparent)',
                color: '#7c3aed', display: 'grid', placeItems: 'center',
              }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/></svg>
              </div>
              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  <div style={{ fontSize: 13.5, fontWeight: 600 }}>{s.name}</div>
                  {s.status === 'planned' && (
                    <span style={{
                      padding: '1px 7px', borderRadius: 99,
                      background: 'var(--surface-2)', color: 'var(--text-muted)',
                      fontSize: 10, fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase',
                    }}>Planned</span>
                  )}
                </div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, fontFamily: 'JetBrains Mono' }}>{s.url}</div>
              </div>
              {s.maintActive ? (
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 5,
                  padding: '3px 10px', borderRadius: 99,
                  background: 'color-mix(in oklab, var(--positive) 12%, transparent)', color: 'var(--positive)',
                  fontSize: 11, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>
                  <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)' }}/>
                  Pro tier
                </span>
              ) : (
                <Btn variant="primary" size="sm" icon={I.plus} onClick={() => setEnquireService({ id: 'add-maint-' + s.id, title: `Add Maintenance for ${s.name}`, blurb: `Adds Standard tier maintenance (£150/mo) for ${s.name}. Upgrade to Pro or Premium any time.`, pricing: '+£150 / month', timeline: '1 week onboarding' })}>
                  Add site · +£150/mo
                </Btn>
              )}
            </div>
          ))}
        </Card>
      </div>

      {/* Tier upgrades */}
      <div style={{ marginBottom: 18 }}>
        <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 8 }}>Tier comparison</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, alignItems: 'stretch' }}>
          {tiers.map(t => (
            <button key={t.id}
              onClick={() => setEnquireService({ id: 'tier-' + t.id, title: `${t.name} tier`, blurb: t.blurb + ' Includes: ' + t.features.join(' · '), pricing: '+£' + t.uplift + ' / month per site', timeline: 'Switch any time' })}
              style={{
                position: 'relative', padding: 0, textAlign: 'left', fontFamily: 'inherit',
                background: 'var(--surface)',
                border: '1px solid ' + (t.recommended ? 'color-mix(in oklab, ' + t.hue + ' 36%, var(--border))' : 'var(--border)'),
                borderRadius: 'var(--radius)', overflow: 'hidden',
                cursor: 'pointer',
                display: 'flex', flexDirection: 'column',
                transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
              }}
              onMouseEnter={e => { e.currentTarget.style.borderColor = t.hue; e.currentTarget.style.boxShadow = '0 6px 18px ' + t.hue + '20'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
              onMouseLeave={e => { e.currentTarget.style.borderColor = t.recommended ? 'color-mix(in oklab, ' + t.hue + ' 36%, var(--border))' : 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
            >
              {/* "Current" pill — pulled out of flow so a longer blurb on
                  one tier doesn't push that card's header taller than the
                  others. Sits absolute in the top-right of the card. */}
              {t.recommended && (
                <span style={{
                  position: 'absolute', top: 12, right: 12, zIndex: 1,
                  padding: '2px 8px', borderRadius: 99,
                  background: 'color-mix(in oklab, ' + t.hue + ' 14%, transparent)', color: t.hue,
                  fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>Current</span>
              )}

              <div style={{
                padding: '14px 16px',
                paddingRight: t.recommended ? 80 : 16, // leave room for absolute pill
                minHeight: 78, // pin header height so dividers align across all 3 cards
                background: `linear-gradient(180deg, color-mix(in oklab, ${t.hue} 12%, var(--surface)) 0%, color-mix(in oklab, ${t.hue} 4%, var(--surface)) 100%)`,
                borderBottom: '1px solid var(--border)',
                display: 'flex', flexDirection: 'column', justifyContent: 'center',
              }}>
                <div style={{ fontSize: 14, fontWeight: 700 }}>{t.name}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.45 }}>{t.blurb}</div>
              </div>
              <div style={{ padding: '12px 16px', display: 'flex', flexDirection: 'column', gap: 8, flex: 1 }}>
                {t.features.map((f, i) => (
                  <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 8, fontSize: 12, color: 'var(--text)' }}>
                    <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" style={{ color: t.hue, flexShrink: 0, marginTop: 2 }}><path d="M20 6 9 17l-5-5"/></svg>
                    {f}
                  </div>
                ))}
              </div>
              <div style={{
                padding: '10px 16px', borderTop: '1px solid var(--border)',
                background: 'var(--surface-2)',
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                marginTop: 'auto',
              }}>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                  <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>+£{t.uplift}</span> / month per site
                </div>
                <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--primary)' }}>
                  {t.recommended ? 'Manage' : 'Switch tier →'}
                </span>
              </div>
            </button>
          ))}
        </div>
      </div>

      {/* Add-ons */}
      <div>
        <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 8 }}>Add-ons</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 14 }}>
          {addons.map(p => (
            <button key={p.id}
              onClick={() => setEnquireService({ id: p.id, title: p.title, blurb: p.blurb, pricing: '+£' + p.uplift + ' / ' + p.cadence, timeline: p.timeline })}
              style={{
                position: 'relative', textAlign: 'left', padding: 0, fontFamily: 'inherit',
                background: 'var(--surface)',
                border: '1px solid ' + (p.recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'),
                borderRadius: 'var(--radius)', overflow: 'hidden', cursor: 'pointer',
                display: 'flex', flexDirection: 'column',
                transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
              }}
              onMouseEnter={e => { e.currentTarget.style.borderColor = p.hue; e.currentTarget.style.boxShadow = '0 6px 18px ' + p.hue + '20'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
              onMouseLeave={e => { e.currentTarget.style.borderColor = p.recommended ? 'color-mix(in oklab, var(--warning) 36%, var(--border))' : 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }}
            >
              <div style={{
                padding: '14px 16px',
                background: `linear-gradient(180deg, color-mix(in oklab, ${p.hue} 12%, var(--surface)) 0%, color-mix(in oklab, ${p.hue} 4%, var(--surface)) 100%)`,
                borderBottom: '1px solid var(--border)',
                display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <div style={{
                  width: 40, height: 40, borderRadius: 10, flexShrink: 0,
                  background: 'var(--surface)',
                  border: '1px solid color-mix(in oklab, ' + p.hue + ' 32%, var(--border))',
                  color: p.hue, display: 'grid', placeItems: 'center',
                  boxShadow: '0 2px 6px rgba(15,23,42,0.04)',
                }}>{p.glyph}</div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)', letterSpacing: '-0.005em' }}>{p.title}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{p.timeline}</div>
                </div>
                {p.recommended && (
                  <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',
                  }}>Recommended</span>
                )}
              </div>
              <div style={{ padding: '14px 16px 12px', flex: 1, fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>
                {p.blurb}
              </div>
              <div style={{
                padding: '10px 16px', borderTop: '1px solid var(--border)',
                background: 'var(--surface-2)',
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              }}>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                  Adds <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>+£{p.uplift}</span> / {p.cadence}
                </div>
                <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--primary)' }}>
                  Add →
                </span>
              </div>
            </button>
          ))}
        </div>
      </div>

      {enquireService && <EnquireModal service={enquireService} onClose={() => setEnquireService(null)} />}
    </div>
  );
};

const GrowthScreen = ({ setActive }) => {
  const [category, setCategory] = useState('All');
  const [query, setQuery] = useState('');
  const [page, setPage] = useState(1);
  const [showActive, setShowActive] = useState(true);
  const [openService, setOpenService] = useState(null);

  const totalActive = SERVICES.filter(s => s.active).length;
  const recommendedCount = SERVICES.filter(s => s.why && !s.active).length;

  const filtered = SERVICES
    .filter(s => showActive || !s.active)
    .filter(s => {
      if (category === 'All') return true;
      if (category === 'Recommended') return s.why && !s.active;
      return s.category === category;
    })
    .filter(s => !query.trim() || (s.title + ' ' + s.blurb + ' ' + (s.why || '')).toLowerCase().includes(query.trim().toLowerCase()))
    // sort: recommended first, then active, then alphabetical
    .sort((a, b) => {
      const ra = a.why && !a.active ? 0 : 1;
      const rb = b.why && !b.active ? 0 : 1;
      if (ra !== rb) return ra - rb;
      if (a.active !== b.active) return a.active ? 1 : -1;
      return a.title.localeCompare(b.title);
    });

  const visible = filtered.slice(0, page * GROWTH_PAGE_SIZE);
  const moreLeft = filtered.length - visible.length;

  const tabs = [
    { id: 'All',         count: SERVICES.length },
    { id: 'Recommended', count: recommendedCount, accent: true },
    ...SERVICE_CATEGORIES.map(c => ({ id: c, count: SERVICES.filter(s => s.category === c).length })),
  ];

  return (
    <div>
      <PageHeader
        title="Add Services"
        subtitle={`Everything Clicky offers ${CLIENT.shortName} — recommended additions surface first.`}
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.calendar}>Book 30-min review</Btn>
          <Btn variant="primary" size="sm" icon={I.send}>Talk to Joe</Btn>
        </>}
      />

      {/* Master service categories — every Clicky retainer/category as
          a hero tile so the user understands the full structure of what
          we offer before they hit the flat catalogue below. Three of
          them (Paid Media, SEO, Maintenance) deep-link to dedicated
          pages with retainer-uplift detail; the others scroll-and-filter
          the catalogue below to that category. */}
      {(() => {
        // Synthetic master record for Maintenance (not in SERVICES because
        // it's modelled as sites + tiers, not catalogue entries).
        const counts = (cat) => {
          const items = SERVICES.filter(s => s.category === cat);
          return {
            total:   items.length,
            active:  items.filter(s => s.active).length,
            why:     items.filter(s => s.why && !s.active).length,
            sample:  items.filter(s => s.active).slice(0, 3),
            recItems: items.filter(s => s.why && !s.active).slice(0, 2),
          };
        };

        const masters = [
          {
            id: 'paid-media', label: 'Paid Media Management', hue: '#2563eb',
            description: 'One retainer for strategy, reporting and your account team. Channels (Google, Meta, Microsoft, TikTok, Reddit, LinkedIn) add a small uplift.',
            pricing: '£950 / mo + per-channel uplift',
            ...counts('Paid Media'),
            cta: 'Manage paid channels',
            route: 'add-paid-media',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11v2a2 2 0 0 0 2 2h2l5 4V5L7 9H5a2 2 0 0 0-2 2zM15 8a4 4 0 0 1 0 8M19 5a8 8 0 0 1 0 14"/></svg>,
          },
          {
            id: 'seo', label: 'SEO', hue: '#16a34a',
            description: 'Quarterly audits, on-page optimisation, links and reporting across your sites and packages.',
            pricing: '£900 / mo + per-site uplift',
            ...counts('SEO & Social'),
            cta: 'Manage SEO',
            route: 'add-seo',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>,
          },
          {
            id: 'maintenance', label: 'Website Maintenance Pro', hue: '#7c3aed',
            description: 'Backups, security, uptime monitoring, plus optional performance, accessibility and security audits.',
            pricing: '£450 / mo + £150–450 per site',
            // Maintenance is its own thing — show synthetic counts based on CLIENT.sites
            total: 6, active: ((window.CLIENT?.sites) || []).filter(s => s.status === 'active').length, why: 1,
            sample: [{ id: 'maint-base', title: 'Pro tier · 3 sites' }],
            recItems: [{ id: 'rec-perf', title: 'Performance audit' }],
            cta: 'Manage maintenance',
            route: 'add-maintenance',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/></svg>,
          },
          {
            id: 'experiences', label: 'Digital Experiences', hue: '#db2777',
            description: 'Landing pages, creative production, brand and web design — billed per project or sprint.',
            pricing: 'Project-based',
            ...counts('Digital Experiences'),
            cta: 'Browse experiences',
            categoryFilter: 'Digital Experiences',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M2 8l10 5 10-5L12 3z"/><path d="M2 12l10 5 10-5M2 16l10 5 10-5"/></svg>,
          },
          {
            id: 'analytics', label: 'Analytics, CRM & AI Automation', hue: '#0866ff',
            description: 'GA4, Looker, conversion tracking, CRM integrations, AI-driven workflows and reporting automation.',
            pricing: 'One-off + retainer mix',
            ...counts('Analytics, CRM & AI Automation'),
            cta: 'Browse analytics',
            categoryFilter: 'Analytics, CRM & AI Automation',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>,
          },
          {
            id: 'discovery', label: 'Discovery & Strategy', hue: '#52525b',
            description: 'Strategic consultancy, audits, market research and channel strategy — usually one-offs.',
            pricing: 'One-off',
            ...counts('Discovery & Strategy'),
            cta: 'Browse strategy',
            categoryFilter: 'Discovery & Strategy',
            icon: <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M16.24 7.76l-2.12 6.36-6.36 2.12 2.12-6.36z"/></svg>,
          },
        ];

        return (
          <div style={{ marginBottom: 18 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10, gap: 8, flexWrap: 'wrap' }}>
              <div>
                <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-0.005em' }}>Service categories</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>The full picture of what Clicky offers — pick a category to manage what's running or add something new.</div>
              </div>
            </div>
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(360px, 1fr))', gap: 14,
            }}>
              {masters.map(m => {
                const hasDeepPage = !!m.route;
                return (
                  <button
                    key={m.id}
                    onClick={() => {
                      if (m.route) { setActive && setActive(m.route); return; }
                      if (m.categoryFilter) { setCategory(m.categoryFilter); setPage(1); /* scroll the catalogue into view */
                        setTimeout(() => {
                          const el = document.getElementById('clicky-services-catalogue');
                          if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
                        }, 50);
                      }
                    }}
                    style={{
                      position: 'relative', textAlign: 'left', padding: 0, fontFamily: 'inherit',
                      background: 'var(--surface)',
                      border: '1px solid var(--border)',
                      borderRadius: 'var(--radius)', boxShadow: 'var(--shadow-sm)',
                      cursor: 'pointer', overflow: 'hidden',
                      display: 'flex', flexDirection: 'column',
                      transition: 'border-color 120ms ease, box-shadow 120ms ease, transform 80ms ease',
                    }}
                    onMouseEnter={e => { e.currentTarget.style.borderColor = m.hue; e.currentTarget.style.boxShadow = '0 6px 18px ' + m.hue + '20'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
                    onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'var(--shadow-sm)'; e.currentTarget.style.transform = 'translateY(0)'; }}
                  >
                    {/* Header */}
                    <div style={{
                      padding: '16px 18px',
                      background: `linear-gradient(180deg, color-mix(in oklab, ${m.hue} 10%, var(--surface)) 0%, color-mix(in oklab, ${m.hue} 3%, var(--surface)) 100%)`,
                      borderBottom: '1px solid var(--border)',
                      display: 'flex', alignItems: 'flex-start', gap: 14,
                    }}>
                      <div style={{
                        width: 42, height: 42, borderRadius: 10, flexShrink: 0,
                        background: 'var(--surface)',
                        border: '1px solid color-mix(in oklab, ' + m.hue + ' 30%, var(--border))',
                        color: m.hue, display: 'grid', placeItems: 'center',
                        boxShadow: '0 2px 6px rgba(15,23,42,0.04)',
                      }}>{m.icon}</div>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                          <div style={{ fontSize: 14.5, fontWeight: 700, color: 'var(--text)', letterSpacing: '-0.005em' }}>{m.label}</div>
                          {hasDeepPage && (
                            <span style={{
                              padding: '1px 7px', borderRadius: 99,
                              background: 'color-mix(in oklab, ' + m.hue + ' 14%, transparent)', color: m.hue,
                              fontSize: 9.5, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                            }}>Master service</span>
                          )}
                        </div>
                        <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.5 }}>{m.description}</div>
                      </div>
                    </div>

                    {/* Body */}
                    <div style={{ padding: '12px 18px 14px', display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
                      {/* Active */}
                      {m.active > 0 && m.sample.length > 0 ? (
                        <div>
                          <div style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6 }}>Currently active</div>
                          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
                            {m.sample.map(s => (
                              <span key={s.id} style={{
                                display: 'inline-flex', alignItems: 'center', gap: 5,
                                padding: '3px 9px 3px 5px', borderRadius: 99,
                                background: 'color-mix(in oklab, var(--positive) 10%, transparent)',
                                border: '1px solid color-mix(in oklab, var(--positive) 22%, var(--border))',
                                color: 'var(--text)', fontSize: 11, fontWeight: 500,
                              }}>
                                <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)' }}/>
                                {s.title}
                              </span>
                            ))}
                            {m.active > m.sample.length && (
                              <span style={{ fontSize: 11, color: 'var(--text-muted)', alignSelf: 'center' }}>+{m.active - m.sample.length} more</span>
                            )}
                          </div>
                        </div>
                      ) : (
                        <div style={{ fontSize: 11, color: 'var(--text-faint)', fontStyle: 'italic' }}>Nothing in this category active yet.</div>
                      )}

                      {/* Recommended */}
                      {m.recItems && m.recItems.length > 0 && (
                        <div>
                          <div style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--warning)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6 }}>Recommended for you</div>
                          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
                            {m.recItems.map(s => (
                              <span key={s.id} style={{
                                display: 'inline-flex', alignItems: 'center', gap: 5,
                                padding: '3px 9px', borderRadius: 99,
                                background: 'color-mix(in oklab, var(--warning) 10%, transparent)',
                                border: '1px solid color-mix(in oklab, var(--warning) 28%, var(--border))',
                                color: 'var(--text)', fontSize: 11, fontWeight: 500,
                              }}>
                                {s.title}
                              </span>
                            ))}
                          </div>
                        </div>
                      )}
                    </div>

                    {/* Footer */}
                    <div style={{
                      padding: '10px 18px', borderTop: '1px solid var(--border)',
                      background: 'var(--surface-2)',
                      display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
                    }}>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Pricing</div>
                        <div style={{ fontSize: 12, color: 'var(--text)', fontWeight: 500, marginTop: 2 }}>{m.pricing}</div>
                      </div>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexShrink: 0 }}>
                        <div style={{ fontSize: 11, color: 'var(--text-muted)', textAlign: 'right' }}>
                          <span style={{ color: 'var(--positive)', fontWeight: 700 }}>{m.active}</span> active
                          {m.total > m.active && (
                            <> · <span style={{ color: 'var(--text)', fontWeight: 600 }}>{m.total - m.active}</span> available</>
                          )}
                        </div>
                        <span style={{
                          display: 'inline-flex', alignItems: 'center', gap: 4,
                          color: m.hue, fontSize: 12, fontWeight: 600,
                        }}>
                          {m.cta}
                          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                        </span>
                      </div>
                    </div>
                  </button>
                );
              })}
            </div>
          </div>
        );
      })()}

      {/* Stats strip */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', alignItems: 'center' }}>
          {[
            { label: 'Total services',    value: SERVICES.length, sub: 'in the Clicky catalogue' },
            { label: 'Active for you',    value: totalActive, sub: 'live with Clicky', tone: 'positive' },
            { label: 'Recommended',       value: recommendedCount, sub: 'picked by your team', tone: 'warning' },
            { label: 'Available to add',  value: SERVICES.length - totalActive, sub: 'click any tile to learn more' },
          ].map((s, i) => (
            <div key={s.label} style={{
              padding: '16px 20px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
              <div style={{
                fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em',
                color: s.tone === 'positive' ? 'var(--positive)'
                     : s.tone === 'warning'  ? 'var(--warning)'
                     : 'var(--text)',
              }}>{s.value}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      {/* Browse-all anchor — used by the master tile "Browse X" CTAs */}
      <div id="clicky-services-catalogue" style={{ scrollMarginTop: 12, marginBottom: 10 }}>
        <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-0.005em' }}>Browse the full catalogue</div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Every service Clicky offers — filter by category or search by name.</div>
      </div>

      {/* Filter bar */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16,
        flexWrap: 'wrap',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
          {tabs.map(t => {
            if (t.count === 0 && t.id !== 'All') return null;
            return (
              <button key={t.id} onClick={() => { setCategory(t.id); setPage(1); }} style={{
                padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
                background: category === t.id ? (t.accent ? 'var(--warning)' : 'var(--text)') : 'var(--surface)',
                color:      category === t.id ? '#fff' : (t.accent ? 'var(--warning)' : 'var(--text-muted)'),
                border: '1px solid ' + (category === t.id ? (t.accent ? 'var(--warning)' : 'var(--text)') : 'var(--border)'),
                cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 5,
              }}>
                {t.accent && <span style={{ width: 6, height: 6, borderRadius: '50%', background: category === t.id ? '#fff' : 'var(--warning)' }}/>}
                {t.id}
                <span style={{
                  fontSize: 10, fontWeight: 600,
                  fontVariantNumeric: 'tabular-nums', opacity: 0.7,
                }}>{t.count}</span>
              </button>
            );
          })}
        </div>

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

        <label style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          fontSize: 12, color: 'var(--text-muted)', cursor: 'pointer',
          padding: '6px 10px',
        }}>
          <input type="checkbox" checked={showActive} onChange={e => setShowActive(e.target.checked)}
            style={{ accentColor: 'var(--primary)' }}/>
          Show active services
        </label>

        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '6px 10px', borderRadius: 8,
          background: 'var(--surface)', border: '1px solid var(--border)',
          minWidth: 220,
        }}>
          <span style={{ color: 'var(--text-faint)', display: 'inline-flex' }}>{I.search}</span>
          <input value={query} onChange={e => { setQuery(e.target.value); setPage(1); }} placeholder="Search services"
            style={{
              border: 'none', outline: 'none', background: 'transparent',
              color: 'var(--text)', fontSize: 12, flex: 1, fontFamily: 'inherit',
            }}/>
          {query && (
            <button onClick={() => { setQuery(''); setPage(1); }} style={{
              border: 'none', background: 'transparent', color: 'var(--text-faint)',
              cursor: 'pointer', padding: 0, fontSize: 14, lineHeight: 1,
            }}>×</button>
          )}
        </div>
      </div>

      {/* Result count */}
      <div style={{
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
        marginBottom: 12,
      }}>
        <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
          Showing <strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{visible.length}</strong> of {filtered.length}
        </span>
        <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>Click any tile to see more</span>
      </div>

      {/* Grid */}
      {visible.length === 0 ? (
        <Card>
          <div style={{ padding: '32px 16px', textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>
            No services match these filters.
            <div style={{ marginTop: 12 }}>
              <Btn variant="ghost" size="sm" onClick={() => { setCategory('All'); setQuery(''); setPage(1); }}>Reset filters</Btn>
            </div>
          </div>
        </Card>
      ) : (
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 16,
        }}>
          {visible.map(s => (
            <ServiceBlogCard key={s.id} service={s} onOpen={setOpenService} />
          ))}
        </div>
      )}

      {moreLeft > 0 && (
        <div style={{ marginTop: 20, display: 'flex', justifyContent: 'center' }}>
          <Btn variant="secondary" onClick={() => setPage(p => p + 1)}>
            Load {Math.min(moreLeft, GROWTH_PAGE_SIZE)} more
          </Btn>
        </div>
      )}

      {/* Lightbox */}
      {openService && <ServiceLightbox service={openService} onClose={() => setOpenService(null)} />}
    </div>
  );
};

window.GrowthScreen = GrowthScreen;

// ============================================================
// Files & External Tools — full-page sidebar destination
// ============================================================

const FilesScreen = () => {
  return (
    <div>
      <PageHeader
        title="Files & external tools"
        subtitle={`Shared Drive folder for ${CLIENT.shortName} and the analytics tools, project workspaces and vertical reports your account team uses.`}
      />
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 2fr) minmax(0, 1fr)', gap: 16, alignItems: 'start' }}>
        <FilesCard />
        <ExternalToolsCard />
      </div>
    </div>
  );
};

window.FilesScreen = FilesScreen;

// ============================================================
// Google Ads (KPIs + dual chart + top campaigns table)
// ============================================================

const GoogleAdsScreen = ({ sparkStyle }) => {
  const [range, setRange] = useState('Last 30 Days');
  const [openRange, setOpenRange] = useState(false);
  const ranges = ['Last 7 Days', 'Last 30 Days', 'Last 90 Days', 'Year to date'];

  return (
    <div>
      {/* Channel header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)', background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center',
          }}>{I.google}</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Google Ads</h1>
              <Badge tone="positive">● Linked</Badge>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Aggregated across 2 linked accounts</div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, position: 'relative' }}>
          <Btn variant="secondary" size="sm" icon={I.plus}>Add Account</Btn>
          <div style={{ position: 'relative' }}>
            <Btn variant="secondary" size="sm" iconRight={I.chevDown} onClick={() => setOpenRange(o => !o)}>{range}</Btn>
            {openRange && (
              <div style={{
                position: 'absolute', right: 0, top: '110%', zIndex: 10,
                background: 'var(--surface)', border: '1px solid var(--border)',
                borderRadius: 'var(--radius)', boxShadow: 'var(--shadow-md)',
                minWidth: 160, padding: 4,
              }}>
                {ranges.map(r => (
                  <button key={r} onClick={() => { setRange(r); setOpenRange(false); }} style={{
                    display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 10px',
                    background: r === range ? 'var(--hover)' : 'transparent', border: 'none',
                    borderRadius: 4, cursor: 'pointer', fontSize: 13, color: 'var(--text)', textAlign: 'left',
                  }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = r === range ? 'var(--hover)' : 'transparent'}
                  >
                    <span style={{ width: 14, color: 'var(--primary)' }}>{r === range && I.check}</span>{r}
                  </button>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Section heading */}
      <div style={{ marginBottom: 14 }}>
        <h2 style={{ fontSize: 15, fontWeight: 600, margin: 0 }}>Overall Performance Overview</h2>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Aggregated data across 2 linked accounts</div>
      </div>

      {/* KPI grid */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 12, marginBottom: 20 }}>
        {KPIS.map(k => <KpiCard key={k.key} kpi={k} sparkStyle={sparkStyle} />)}
      </div>

      {/* Charts */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 20 }}>
        <SpendTrendCard />
        <ConvTrendCard />
      </div>

      {/* Linked accounts + top campaigns */}
      <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 12 }}>
        <LinkedAccountsCard />
        <TopCampaignsCard />
      </div>
    </div>
  );
};

const SpendTrendCard = () => {
  const { LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer, Legend, Area, AreaChart } = window.Recharts;
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Spend Trend</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Avg. weekly spend</div>
        </div>
        <Btn variant="ghost" size="sm" icon={I.download}>Export</Btn>
      </div>
      <div style={{ padding: '12px 8px 12px' }}>
        <ResponsiveContainer width="100%" height={240}>
          <AreaChart data={SPEND_TREND} margin={{ top: 10, right: 16, left: 0, bottom: 0 }}>
            <defs>
              <linearGradient id="spend-fill" x1="0" x2="0" y1="0" y2="1">
                <stop offset="0" stopColor="var(--primary)" stopOpacity={0.25}/>
                <stop offset="1" stopColor="var(--primary)" stopOpacity={0}/>
              </linearGradient>
            </defs>
            <CartesianGrid strokeDasharray="2 4" vertical={false} />
            <XAxis dataKey="d" tickLine={false} axisLine={false} dy={6} />
            <YAxis tickLine={false} axisLine={false} dx={-4} domain={[35, 65]} />
            <Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 6, fontSize: 12 }} />
            <Area type="monotone" dataKey="v" stroke="var(--primary)" strokeWidth={2} fill="url(#spend-fill)" dot={{ r: 3, fill: 'var(--primary)' }} activeDot={{ r: 5 }} />
          </AreaChart>
        </ResponsiveContainer>
      </div>
      <div style={{ padding: '8px 18px 14px', display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-muted)' }}>
        <span style={{ width: 10, height: 2, background: 'var(--primary)', borderRadius: 2 }}/> Avg. Weekly Spend
      </div>
    </Card>
  );
};

const ConvTrendCard = () => {
  const { LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer, Legend } = window.Recharts;
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Conversions Trend</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Conversions vs. Cost per conversion</div>
        </div>
        <Btn variant="ghost" size="sm" icon={I.download}>Export</Btn>
      </div>
      <div style={{ padding: '12px 8px 12px' }}>
        <ResponsiveContainer width="100%" height={240}>
          <LineChart data={CONV_TREND} margin={{ top: 10, right: 16, left: 0, bottom: 0 }}>
            <CartesianGrid strokeDasharray="2 4" vertical={false} />
            <XAxis dataKey="d" tickLine={false} axisLine={false} dy={6} />
            <YAxis yAxisId="l" tickLine={false} axisLine={false} dx={-4} />
            <YAxis yAxisId="r" orientation="right" tickLine={false} axisLine={false} dx={4} />
            <Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 6, fontSize: 12 }} />
            <Line yAxisId="l" type="monotone" dataKey="conv" stroke="oklch(0.65 0.16 160)" strokeWidth={2} dot={{ r: 3 }} />
            <Line yAxisId="r" type="monotone" dataKey="cpc" stroke="oklch(0.78 0.15 80)" strokeWidth={2} dot={{ r: 3 }} />
          </LineChart>
        </ResponsiveContainer>
      </div>
      <div style={{ padding: '8px 18px 14px', display: 'flex', alignItems: 'center', gap: 14, fontSize: 11, color: 'var(--text-muted)' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 2, background: 'oklch(0.65 0.16 160)', borderRadius: 2 }}/>Avg. Weekly Conversions</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}><span style={{ width: 10, height: 2, background: 'oklch(0.78 0.15 80)', borderRadius: 2 }}/>Avg. Cost Per Conversion</span>
      </div>
    </Card>
  );
};

const LinkedAccountsCard = () => (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div style={{ fontWeight: 600, fontSize: 14 }}>Linked Accounts</div>
      <Badge tone="neutral">2</Badge>
    </div>
    <div style={{ padding: 8 }}>
      {ACCOUNTS.map((a, i) => (
        <div key={i} style={{
          padding: 12, display: 'flex', flexDirection: 'column', gap: 8,
          borderRadius: 6, cursor: 'pointer',
        }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
        >
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--positive)' }}/>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</div>
              <div style={{ fontSize: 11, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono' }}>{a.id}</div>
            </div>
            <span style={{ color: 'var(--text-faint)' }}>{I.external}</span>
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>30-day spend</span>
            <span style={{ fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{a.spend}</span>
          </div>
        </div>
      ))}
      <button style={{
        width: '100%', padding: 10, marginTop: 4,
        background: 'transparent', border: '1px dashed var(--border-strong)',
        borderRadius: 6, color: 'var(--text-muted)', cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, fontSize: 12,
      }}>{I.plus} Connect another account</button>
    </div>
  </Card>
);

const TOP_CAMPAIGNS = [
  { name: 'Evergreen — Branded',              spend: 412.40, clicks: 188, conv: 6, cpc: 2.19, ctr: 11.2 },
  { name: 'Cornwall Lodge Holidays — Search',spend: 318.20, clicks: 142, conv: 3, cpc: 2.24, ctr: 8.4 },
  { name: 'Spring Breaks — Local',           spend: 286.00, clicks: 124, conv: 4, cpc: 2.31, ctr: 10.1 },
  { name: 'Cornwall Lodges — Performance Max',  spend: 274.18, clicks:  91, conv: 1, cpc: 3.01, ctr: 6.7 },
  { name: 'Remarketing — Site Visitors',    spend: 152.20, clicks:  42, conv: 0, cpc: 3.62, ctr: 4.1 },
];

const TopCampaignsCard = () => {
  const s = useTableSort(TOP_CAMPAIGNS, 'spend', 'desc');
  const cols = [
    { key: 'name',   label: 'Campaign', align: 'left' },
    { key: 'spend',  label: 'Spend',    align: 'right' },
    { key: 'clicks', label: 'Clicks',   align: 'right' },
    { key: 'conv',   label: 'Conv.',    align: 'right' },
    { key: 'cpc',    label: 'CPC',      align: 'right' },
    { key: 'ctr',    label: 'CTR',      align: 'right' },
  ];
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Top Campaigns</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>By spend, last 30 days</div>
        </div>
        <Btn variant="ghost" size="sm" iconRight={I.arrowRight}>View all</Btn>
      </div>
      <div style={{ overflow: 'hidden' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)' }}>
              {cols.map(c => (
                <SortableTh key={c.key} sortKey={c.key} align={c.align} currentKey={s.sortKey} dir={s.sortDir} onSort={s.onSort}>{c.label}</SortableTh>
              ))}
            </tr>
          </thead>
          <tbody>
            {s.sorted.map((c, i) => (
              <tr key={i} style={{ borderBottom: i < s.sorted.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <td style={{ padding: '12px 14px', fontWeight: 500 }}>{c.name}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>£{c.spend.toFixed(2)}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{c.clicks}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>{c.conv}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>£{c.cpc.toFixed(2)}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{c.ctr.toFixed(1)}%</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
};

// ============================================================
// My Reports
// ============================================================

// Modal — client requests a new report; account team builds & uploads
const RequestReportModal = ({ onClose, onSubmit, sent }) => {
  const [type, setType]       = useState('performance');
  const [channel, setChannel] = useState('google');
  const [period, setPeriod]   = useState('Last month');
  const [format, setFormat]   = useState('PDF');
  const [priority, setPriority] = useState('Normal');
  const [notes, setNotes]     = useState('');

  const types = [
    { id: 'performance', label: 'Performance review',  desc: 'Spend, conversions, ROAS — month or quarter snapshot.' },
    { id: 'audit',       label: 'Audit / deep-dive',   desc: 'Search terms, geo, device — investigative drill-down.' },
    { id: 'creative',    label: 'Creative readout',    desc: 'Top performing ads, themes, messages, recommendations.' },
    { id: 'custom',      label: 'Something else',      desc: "We'll build it from your brief in the notes below." },
  ];

  const channels = [
    { id: 'google', label: 'Google Ads' },
    { id: 'seo',    label: 'SEO' },
    { id: 'all',    label: 'All channels' },
  ];

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 50,
      background: 'rgba(8, 12, 22, 0.45)',
      backdropFilter: 'blur(2px)',
      display: 'grid', placeItems: 'center',
      padding: 24,
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 'min(620px, 100%)', maxHeight: '90vh', overflowY: 'auto',
        background: 'var(--surface)', borderRadius: 'var(--radius)',
        border: '1px solid var(--border)', boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
      }}>
        {sent ? (
          <div style={{ padding: '36px 32px', textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%',
              background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
              color: 'var(--positive)', margin: '0 auto 14px',
              display: 'grid', placeItems: 'center',
            }}>
              <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
            </div>
            <div style={{ fontSize: 18, fontWeight: 700, marginBottom: 6 }}>Request sent</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', maxWidth: 420, margin: '0 auto 6px', lineHeight: 1.5 }}>
              Joe Marshall has been notified and will pick this up. You'll get an email when it's uploaded — typically within 2 working days.
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', marginBottom: 22 }}>
              REQ-{Math.floor(Math.random() * 900 + 100)}
            </div>
            <Btn variant="primary" onClick={onClose}>Done</Btn>
          </div>
        ) : (
          <>
            <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div>
                <div style={{ fontSize: 16, fontWeight: 700 }}>Request a report</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Your account team will build and upload — usually within 2 working days.</div>
              </div>
              <button onClick={onClose} style={{
                width: 32, height: 32, borderRadius: 6, border: '1px solid var(--border)',
                background: 'var(--surface)', color: 'var(--text-muted)', cursor: 'pointer',
                display: 'grid', placeItems: 'center',
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
              </button>
            </div>

            <div style={{ padding: 22, display: 'flex', flexDirection: 'column', gap: 18 }}>
              {/* Type */}
              <div>
                <Label>Report type</Label>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8, marginTop: 8 }}>
                  {types.map(t => {
                    const active = type === t.id;
                    return (
                      <button key={t.id} onClick={() => setType(t.id)} style={{
                        textAlign: 'left', padding: '10px 12px',
                        border: '1px solid ' + (active ? 'var(--primary)' : 'var(--border)'),
                        background: active ? 'color-mix(in oklab, var(--primary) 6%, var(--surface))' : 'var(--surface)',
                        boxShadow: active ? '0 0 0 3px color-mix(in oklab, var(--primary) 14%, transparent)' : 'none',
                        borderRadius: 8, cursor: 'pointer',
                      }}>
                        <div style={{ fontSize: 13, fontWeight: 600 }}>{t.label}</div>
                        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.4 }}>{t.desc}</div>
                      </button>
                    );
                  })}
                </div>
              </div>

              {/* Channel + period + format + priority */}
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 14 }}>
                <div>
                  <Label>Channel</Label>
                  <Select value={channel} onChange={setChannel} options={channels} />
                </div>
                <div>
                  <Label>Period</Label>
                  <Select value={period} onChange={setPeriod} options={[
                    { id: 'Last 7 days',  label: 'Last 7 days' },
                    { id: 'Last 30 days', label: 'Last 30 days' },
                    { id: 'Last month',   label: 'Last month' },
                    { id: 'This quarter', label: 'This quarter' },
                    { id: 'YTD',          label: 'Year to date' },
                    { id: 'Custom',       label: 'Custom range…' },
                  ]} />
                </div>
                <div>
                  <Label>Format</Label>
                  <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
                    {['PDF', 'XLS', 'Slides'].map(f => (
                      <button key={f} onClick={() => setFormat(f)} style={{
                        flex: 1, padding: '7px 0', fontSize: 12, fontWeight: 500,
                        border: '1px solid ' + (format === f ? 'var(--primary)' : 'var(--border)'),
                        background: format === f ? 'color-mix(in oklab, var(--primary) 8%, var(--surface))' : 'var(--surface)',
                        color: format === f ? 'var(--primary)' : 'var(--text)',
                        borderRadius: 6, cursor: 'pointer',
                      }}>{f}</button>
                    ))}
                  </div>
                </div>
                <div>
                  <Label>Priority</Label>
                  <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
                    {['Normal', 'Urgent'].map(p => (
                      <button key={p} onClick={() => setPriority(p)} style={{
                        flex: 1, padding: '7px 0', fontSize: 12, fontWeight: 500,
                        border: '1px solid ' + (priority === p ? 'var(--primary)' : 'var(--border)'),
                        background: priority === p ? 'color-mix(in oklab, var(--primary) 8%, var(--surface))' : 'var(--surface)',
                        color: priority === p ? 'var(--primary)' : 'var(--text)',
                        borderRadius: 6, cursor: 'pointer',
                      }}>{p}</button>
                    ))}
                  </div>
                </div>
              </div>

              {/* Notes */}
              <div>
                <Label>Brief / notes <span style={{ color: 'var(--text-faint)', fontWeight: 400 }}>(optional)</span></Label>
                <textarea
                  value={notes}
                  onChange={e => setNotes(e.target.value)}
                  placeholder="Anything specific you want included? Comparisons, segments, themes…"
                  rows={4}
                  style={{
                    width: '100%', marginTop: 6, padding: '10px 12px',
                    fontSize: 13, fontFamily: 'inherit',
                    border: '1px solid var(--border)', borderRadius: 6,
                    background: 'var(--surface)', color: 'var(--text)', resize: 'vertical',
                  }}
                />
              </div>

              {/* Footer */}
              <div style={{
                display: 'flex', alignItems: 'center', gap: 12, paddingTop: 6,
                borderTop: '1px solid var(--border)', marginTop: 4, paddingTop: 16,
              }}>
                <PersonAvatar name="Joe Marshall" size={26} src="assets/team/joe.png" />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12, color: 'var(--text)', fontWeight: 500 }}>Joe Marshall will pick this up</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>You'll get an email when it's uploaded.</div>
                </div>
                <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
                <Btn variant="primary" icon={I.send || I.arrowRight} onClick={onSubmit}>Send request</Btn>
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );
};

// Tiny labelled-form helpers used by the modal
const Label = ({ children }) => (
  <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>{children}</div>
);
const Select = ({ value, onChange, options }) => (
  <select value={value} onChange={e => onChange(e.target.value)} style={{
    width: '100%', marginTop: 6, padding: '7px 10px',
    fontSize: 13, fontFamily: 'inherit',
    border: '1px solid var(--border)', borderRadius: 6,
    background: 'var(--surface)', color: 'var(--text)', cursor: 'pointer',
  }}>
    {options.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
  </select>
);

// Lightweight in-app preview of a Ready report — mocks a 4-page PDF so the
// client can browse the document without leaving the dashboard.
const ReportPreviewModal = ({ report, onClose }) => {
  const [page, setPage] = useState(1);
  const total = 4;
  if (!report) return null;
  const isXls = report.format === 'XLS';

  // Mock per-page content. Real implementation would render the file.
  const Page = ({ idx }) => {
    if (idx === 1) {
      // Cover
      return (
        <div style={{
          padding: '48px 56px',
          height: '100%',
          background: 'linear-gradient(135deg, #18181b 0%, #2a2a30 100%)',
          color: '#fff',
          display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
        }}>
          <div>
            <img src="assets/clicky-logo-vert-white.png" alt="" style={{ height: 56, opacity: 0.95 }} />
            <div style={{ fontSize: 11, color: 'rgba(255,255,255,0.55)', textTransform: 'uppercase', letterSpacing: '0.1em', marginTop: 28, fontWeight: 600 }}>
              {report.channel} · {report.period}
            </div>
            <h1 style={{ fontSize: 32, fontWeight: 700, margin: '6px 0 0', lineHeight: 1.15, letterSpacing: '-0.01em', maxWidth: 520 }}>{report.name}</h1>
            <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.7)', marginTop: 14 }}>
              Prepared for <strong style={{ color: '#fff' }}>{(window.CLIENT?.name) || 'Evergreen Escapes'}</strong>
            </div>
          </div>
          <div style={{ fontSize: 11, color: 'rgba(255,255,255,0.55)', display: 'flex', justifyContent: 'space-between' }}>
            <span>Built by {report.uploadedBy} · {report.uploadedOn}</span>
            <span>Confidential · Clicky × {(window.CLIENT?.shortName) || 'Evergreen'}</span>
          </div>
        </div>
      );
    }
    if (idx === 2) {
      // Executive summary
      return (
        <div style={{ padding: '40px 56px', height: '100%', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>Page 2 · Executive summary</div>
          <h2 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.01em' }}>The headline</h2>
          <p style={{ margin: 0, fontSize: 14, lineHeight: 1.65, color: 'var(--text)' }}>
            <strong style={{ color: 'var(--positive)' }}>Strong April.</strong> Bookings closed at <strong>49</strong> — up <strong>+22.5%</strong> month-on-month — at an all-in cost-per-booking of <strong>£31.65</strong>. Branded search continues to do the heavy lifting; Performance Max picked up share through the second half of the month after a structure refresh.
          </p>
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12,
            marginTop: 6,
          }}>
            {[
              { label: 'Spend',    value: '£1,550.98', delta: '+12.4%' },
              { label: 'Bookings', value: '49',        delta: '+22.5%' },
              { label: 'Cost / book', value: '£31.65', delta: '−8.4%' },
            ].map(s => (
              <div key={s.label} style={{
                padding: 14, border: '1px solid var(--border)', borderRadius: 8,
              }}>
                <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
                <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4 }}>{s.value}</div>
                <div style={{ fontSize: 11, color: 'var(--positive)', marginTop: 2, fontWeight: 600 }}>{s.delta} vs prev 30d</div>
              </div>
            ))}
          </div>
          <h3 style={{ fontSize: 14, fontWeight: 600, margin: '6px 0 0' }}>What changed this month</h3>
          <ul style={{ margin: 0, paddingLeft: 20, fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.7 }}>
            <li>PMax restructured into theme-led asset groups · CPC down 11%</li>
            <li>Negative-keyword sweep on Branded search — wasted spend down £180</li>
            <li>Date-picker fix on /availability lifted CVR by 0.4pp</li>
          </ul>
        </div>
      );
    }
    if (idx === 3) {
      // Charts page (mock visual)
      return (
        <div style={{ padding: '40px 56px', height: '100%', display: 'flex', flexDirection: 'column', gap: 18 }}>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>Page 3 · Performance trend</div>
          <h2 style={{ fontSize: 20, fontWeight: 700, margin: 0, letterSpacing: '-0.01em' }}>Spend vs bookings · last 30 days</h2>
          {/* Mock chart — bars + area */}
          <div style={{
            position: 'relative', flex: 1, minHeight: 220,
            border: '1px solid var(--border)', borderRadius: 8,
            background: 'var(--surface-2)',
            padding: 18,
            display: 'flex', alignItems: 'flex-end', gap: 4,
          }}>
            {[42, 48, 55, 50, 58, 62, 55, 60, 68, 72, 65, 70, 78, 82, 75, 80, 88, 92, 85, 90, 95, 88, 92, 100, 96, 102, 108, 112, 105, 110].map((v, i) => (
              <div key={i} style={{
                flex: 1, height: v + '%',
                background: `linear-gradient(180deg, color-mix(in oklab, var(--primary) 75%, transparent) 0%, color-mix(in oklab, var(--primary) 35%, transparent) 100%)`,
                borderRadius: '2px 2px 0 0',
              }}/>
            ))}
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--text-faint)' }}>
            <span>1 Apr</span><span>15 Apr</span><span>30 Apr</span>
          </div>
        </div>
      );
    }
    // Page 4 — recommendations
    return (
      <div style={{ padding: '40px 56px', height: '100%', display: 'flex', flexDirection: 'column', gap: 18 }}>
        <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>Page 4 · Recommendations</div>
        <h2 style={{ fontSize: 20, fontWeight: 700, margin: 0, letterSpacing: '-0.01em' }}>What we'd do next</h2>
        {[
          { title: 'Test Microsoft Ads in May', body: 'Branded share on Bing is ~18% of search demand and untapped. Estimated +£800–£1,400/mo bookings at low risk.' },
          { title: 'Reactivate past-guest email series', body: '12,400 contacts not currently nurtured. Industry benchmark: 6–9% repeat-bookings lift from a 4-touch series.' },
          { title: 'Speed up Park Experience', body: 'Page weight is 3.4MB and LCP 3.1s. Fixing this is worth 5–9% CVR uplift on those flows.' },
        ].map((r, i) => (
          <div key={i} style={{ padding: 14, border: '1px solid var(--border)', borderRadius: 8 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{
                width: 24, height: 24, borderRadius: '50%',
                background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
                color: 'var(--primary)', display: 'grid', placeItems: 'center',
                fontSize: 11, fontWeight: 700, fontVariantNumeric: 'tabular-nums',
              }}>{i + 1}</span>
              <div style={{ fontSize: 14, fontWeight: 600 }}>{r.title}</div>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 6, lineHeight: 1.5 }}>{r.body}</div>
          </div>
        ))}
      </div>
    );
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.65)',
      display: 'flex', flexDirection: 'column', zIndex: 100,
      backdropFilter: 'blur(2px)',
    }}>
      {/* Toolbar */}
      <div onClick={e => e.stopPropagation()} style={{
        height: 56, background: '#1f1f23', color: '#fff',
        display: 'flex', alignItems: 'center', padding: '0 16px', gap: 14, flexShrink: 0,
      }}>
        <div style={{
          width: 32, height: 36, borderRadius: 4,
          background: isXls ? '#0f9d58' : '#dc2626',
          display: 'grid', placeItems: 'center',
          fontSize: 9, fontWeight: 800, color: '#fff', letterSpacing: '0.04em',
        }}>{report.format}</div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{report.name}</div>
          <div style={{ fontSize: 11, color: 'rgba(255,255,255,0.55)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {report.id} · {report.size} · uploaded {report.uploadedOn} by {report.uploadedBy}
          </div>
        </div>
        {/* Page nav */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
          <button onClick={() => setPage(p => Math.max(1, p - 1))} disabled={page === 1}
            style={{
              width: 28, height: 28, borderRadius: 4, border: 'none',
              background: 'rgba(255,255,255,0.08)', color: '#fff',
              cursor: page === 1 ? 'not-allowed' : 'pointer', opacity: page === 1 ? 0.4 : 1,
              display: 'grid', placeItems: 'center',
            }}>{I.chevLeft}</button>
          <span style={{ color: 'rgba(255,255,255,0.85)', fontVariantNumeric: 'tabular-nums', minWidth: 60, textAlign: 'center' }}>
            {page} of {total}
          </span>
          <button onClick={() => setPage(p => Math.min(total, p + 1))} disabled={page === total}
            style={{
              width: 28, height: 28, borderRadius: 4, border: 'none',
              background: 'rgba(255,255,255,0.08)', color: '#fff',
              cursor: page === total ? 'not-allowed' : 'pointer', opacity: page === total ? 0.4 : 1,
              display: 'grid', placeItems: 'center',
            }}>{I.chevRight}</button>
        </div>
        <div style={{ width: 1, height: 24, background: 'rgba(255,255,255,0.15)' }}/>
        <button title="Download" style={{
          height: 32, padding: '0 12px', borderRadius: 4, border: 'none',
          background: 'rgba(255,255,255,0.08)', color: '#fff',
          cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: 500,
          display: 'inline-flex', alignItems: 'center', gap: 6,
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v12M6 11l6 6 6-6M5 21h14"/></svg>
          Download
        </button>
        <button title="Print" style={{
          height: 32, width: 32, borderRadius: 4, border: 'none',
          background: 'rgba(255,255,255,0.08)', color: '#fff',
          cursor: 'pointer', display: 'grid', placeItems: 'center',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9V2h12v7M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>
        </button>
        <button onClick={onClose} aria-label="Close" style={{
          height: 32, width: 32, borderRadius: 4, border: 'none',
          background: 'rgba(255,255,255,0.08)', color: '#fff',
          cursor: 'pointer', display: 'grid', placeItems: 'center',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
        </button>
      </div>

      {/* Page area */}
      <div onClick={e => e.stopPropagation()} style={{
        flex: 1, padding: 24, overflowY: 'auto',
        display: 'flex', justifyContent: 'center', alignItems: 'flex-start',
        background: 'rgba(0,0,0,0.3)',
      }}>
        <div style={{
          width: '100%', maxWidth: 760, aspectRatio: '210 / 297',
          background: '#fff', color: '#18181b',
          boxShadow: '0 12px 40px rgba(0,0,0,0.4)',
          borderRadius: 4, overflow: 'hidden',
          position: 'relative',
        }}>
          <Page idx={page} />
          {/* Page number footer */}
          <div style={{
            position: 'absolute', bottom: 18, left: 0, right: 0, textAlign: 'center',
            fontSize: 10, color: page === 1 ? 'rgba(255,255,255,0.5)' : 'var(--text-faint)',
            letterSpacing: '0.04em',
          }}>
            {page} / {total}
          </div>
        </div>
      </div>

      {/* Bottom thumbnail strip */}
      <div onClick={e => e.stopPropagation()} style={{
        padding: 12, background: '#1a1a1e',
        display: 'flex', justifyContent: 'center', gap: 8, flexShrink: 0,
        borderTop: '1px solid rgba(255,255,255,0.08)',
      }}>
        {[1, 2, 3, 4].map(p => (
          <button key={p} onClick={() => setPage(p)} style={{
            width: 56, height: 80, borderRadius: 3, padding: 0,
            border: page === p ? '2px solid var(--primary)' : '1px solid rgba(255,255,255,0.15)',
            background: '#fff', cursor: 'pointer', overflow: 'hidden',
            display: 'grid', placeItems: 'center', position: 'relative',
          }}>
            <span style={{ fontSize: 9, color: '#999', fontWeight: 500 }}>Page {p}</span>
          </button>
        ))}
      </div>
    </div>
  );
};

const ReportsScreen = () => {
  const [selected, setSelected] = useState([]);
  const [filter, setFilter] = useState('all');
  const [requestOpen, setRequestOpen] = useState(false);
  const [requestSent, setRequestSent] = useState(false);
  const [previewReport, setPreviewReport] = useState(null);

  const filters = [
    { id: 'all',   label: 'All',         count: REPORTS.length },
    { id: 'ready', label: 'Ready',       count: REPORTS.filter(r => r.status === 'Ready').length },
    { id: 'prog',  label: 'In progress', count: REPORTS.filter(r => r.status === 'In progress').length },
  ];
  const filtered = filter === 'all'   ? REPORTS
                 : filter === 'ready' ? REPORTS.filter(r => r.status === 'Ready')
                 : REPORTS.filter(r => r.status === 'In progress');
  const reportSort = useTableSort(filtered, 'requestedOn', 'desc');
  const visible = reportSort.sorted;

  return (
    <div>
      <PageHeader
        title="My Reports"
        subtitle="Custom reports your account team builds and uploads on request."
        actions={<Btn variant="primary" size="sm" icon={I.plus} onClick={() => { setRequestSent(false); setRequestOpen(true); }}>Request a report</Btn>}
      />

      {/* Helper banner */}
      <div style={{
        marginBottom: 16, padding: '12px 16px',
        display: 'flex', alignItems: 'center', gap: 12,
        background: 'color-mix(in oklab, var(--primary) 5%, var(--surface))',
        border: '1px solid color-mix(in oklab, var(--primary) 18%, var(--border))',
        borderRadius: 'var(--radius)',
      }}>
        <PersonAvatar name="Joe Marshall" size={36} hue={200} src="assets/team/joe.png" />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>Reports are bespoke — built and uploaded by your account team</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
            Tell us what you need; we'll have it back to you typically within 2 working days. I'm your usual lead — Joe.
          </div>
        </div>
      </div>

      <Card padding={0}>
        {/* Toolbar */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: 12, borderBottom: '1px solid var(--border)' }}>
          <div style={{ display: 'flex', gap: 4, padding: 3, background: 'var(--surface-2)', borderRadius: 6, border: '1px solid var(--border)' }}>
            {filters.map(f => (
              <button key={f.id} onClick={() => setFilter(f.id)} style={{
                padding: '4px 10px', fontSize: 12, fontWeight: 500, border: 'none',
                background: filter === f.id ? 'var(--surface)' : 'transparent',
                color: filter === f.id ? 'var(--text)' : 'var(--text-muted)',
                borderRadius: 4, cursor: 'pointer',
                boxShadow: filter === f.id ? 'var(--shadow-sm)' : 'none',
              }}>{f.label} <span style={{ color: 'var(--text-faint)', marginLeft: 2 }}>{f.count}</span></button>
            ))}
          </div>
          <Btn variant="ghost" size="sm" icon={I.filter}>Filter</Btn>
          <div style={{ flex: 1 }} />
          {selected.length > 0 && (
            <>
              <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{selected.length} selected</span>
              <Btn variant="secondary" size="sm">Archive</Btn>
            </>
          )}
        </div>

        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)' }}>
              <th style={{ padding: '12px 14px', width: 40 }}>
                <input type="checkbox" onChange={e => setSelected(e.target.checked ? visible.map(r => r.id) : [])}/>
              </th>
              {[
                { key: 'name',        label: 'Report' },
                { key: 'channel',     label: 'Channel' },
                { key: 'period',      label: 'Period' },
                { key: 'status',      label: 'Status' },
                { key: 'uploadedBy',  label: 'Built by' },
              ].map(c => (
                <SortableTh key={c.key} sortKey={c.key} currentKey={reportSort.sortKey} dir={reportSort.sortDir} onSort={reportSort.onSort}>{c.label}</SortableTh>
              ))}
              <th style={{ padding: '12px 14px', borderBottom: '1px solid var(--border)' }}/>
            </tr>
          </thead>
          <tbody>
            {visible.map((r, i) => {
              const checked = selected.includes(r.id);
              const isReady = r.status === 'Ready';
              return (
                <tr key={r.id} style={{
                    borderBottom: i < visible.length - 1 ? '1px solid var(--border)' : 'none',
                    cursor: isReady ? 'pointer' : 'default',
                  }}
                  onClick={() => isReady && setPreviewReport(r)}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  <td style={{ padding: '12px 14px' }} onClick={e => e.stopPropagation()}>
                    <input type="checkbox" checked={checked} onChange={() => setSelected(s => checked ? s.filter(x => x !== r.id) : [...s, r.id])}/>
                  </td>
                  <td style={{ padding: '12px 14px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                      {isReady ? <FileIcon kind={r.format === 'XLS' ? 'sheet' : 'pdf'} /> : (
                        <div style={{
                          width: 30, height: 36, borderRadius: 4,
                          background: 'color-mix(in oklab, var(--warning) 10%, var(--surface-2))',
                          border: '1px dashed color-mix(in oklab, var(--warning) 40%, var(--border))',
                          display: 'grid', placeItems: 'center', flexShrink: 0,
                          color: 'var(--warning)',
                        }}>
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
                        </div>
                      )}
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontWeight: 600 }}>{r.name}</div>
                        <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 6 }}>
                          <span style={{ fontFamily: 'JetBrains Mono' }}>{r.id}</span>
                          {isReady && r.format && (
                            <>
                              <span style={{ color: 'var(--border)' }}>·</span>
                              <span>{r.format} · {r.size}</span>
                            </>
                          )}
                          {!isReady && (
                            <>
                              <span style={{ color: 'var(--border)' }}>·</span>
                              <span>Requested {r.requestedOn}</span>
                            </>
                          )}
                        </div>
                      </div>
                    </div>
                  </td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>{I.google}{r.channel}</span>
                  </td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>{r.period}</td>
                  <td style={{ padding: '12px 14px' }}>
                    {isReady
                      ? <Badge tone="positive">Ready</Badge>
                      : <Badge tone="warning">In progress</Badge>}
                  </td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>
                    {isReady ? (
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <PersonAvatar
                          name={r.uploadedBy}
                          size={22}
                          src={
                            r.uploadedBy?.startsWith('Joe')    ? 'assets/team/joe.png' :
                            r.uploadedBy?.startsWith('Matt')   ? 'assets/team/matt.png' :
                            r.uploadedBy?.startsWith('Nathan') ? 'assets/team/nathan.png' :
                            undefined
                          }
                        />
                        <div style={{ minWidth: 0 }}>
                          <div style={{ fontSize: 12, color: 'var(--text)', fontWeight: 500, lineHeight: 1.2 }}>{r.uploadedBy}</div>
                          <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 1 }}>Uploaded {r.uploadedOn}</div>
                        </div>
                      </div>
                    ) : (
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, fontStyle: 'italic' }}>
                        <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--warning)', animation: 'pulse 1.4s ease-in-out infinite' }}/>
                        Report processing
                      </span>
                    )}
                  </td>
                  <td style={{ padding: '12px 14px', textAlign: 'right' }} onClick={e => e.stopPropagation()}>
                    {isReady ? (
                      <div style={{ display: 'inline-flex', gap: 6 }}>
                        <Btn variant="secondary" size="sm" icon={<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>}
                          onClick={() => setPreviewReport(r)}>
                          Open
                        </Btn>
                        <Btn variant="ghost" size="sm" icon={I.download}>Download</Btn>
                      </div>
                    ) : (
                      <Btn variant="ghost" size="sm">View request</Btn>
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </Card>

      {requestOpen && (
        <RequestReportModal
          onClose={() => setRequestOpen(false)}
          sent={requestSent}
          onSubmit={() => setRequestSent(true)}
        />
      )}
      {previewReport && (
        <ReportPreviewModal
          report={previewReport}
          onClose={() => setPreviewReport(null)}
        />
      )}
    </div>
  );
};

// ============================================================
// Contracts & Billing
// ============================================================

// =============================================================
// ContractDetailScreen — full-page detail view for a single
// contract. Reached via "View detail" on a ContractCard or by
// clicking a contract row anywhere else in the portal.
// =============================================================
const ContractDetailScreen = ({ contractId, onBack, setActive }) => {
  const c = CONTRACTS.find(x => x.id === contractId);
  if (!c) {
    return (
      <div>
        <PageHeader title="Contract not found" subtitle="The contract you tried to open could not be located." />
        <Btn variant="primary" size="sm" onClick={onBack}>Back to billing</Btn>
      </div>
    );
  }

  const monthlyNum = (() => {
    const n = Number(String(c.monthly || '').replace(/[£,]/g, ''));
    return isFinite(n) ? n : 0;
  })();
  const isOneOff = /one-off|weeks|ad-hoc/i.test(c.term || '');

  // Invoices for this contract + per-line amounts
  const lineFor = (inv) => (inv.lines || []).find(l => l.contractId === c.id) || { amount: 0 };
  const invoices = INVOICES
    .filter(inv => (inv.lines || []).some(l => l.contractId === c.id))
    .sort((a, b) => new Date(b.date) - new Date(a.date));
  const totalPaid = invoices
    .filter(i => /Paid/i.test(i.status))
    .reduce((s, i) => s + lineFor(i).amount, 0);
  const totalOutstanding = invoices
    .filter(i => /Due|Overdue/i.test(i.status))
    .reduce((s, i) => s + lineFor(i).amount, 0);
  const totalBilled = totalPaid + totalOutstanding;

  // Status tone
  const statusTone = {
    'Active':       { color: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 12%, transparent)' },
    'Renewing':     { color: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 14%, transparent)' },
    'In progress':  { color: 'var(--primary)',  bg: 'color-mix(in oklab, var(--primary) 12%, transparent)' },
    'Completed':    { color: 'var(--text-muted)', bg: 'var(--surface-2)' },
  }[c.status] || { color: 'var(--text-muted)', bg: 'var(--surface-2)' };

  // Synthesise scope of work from the contract name. In a real product
  // this would live on the contract record.
  const scope = (() => {
    if (/google ads/i.test(c.name)) return [
      'Search, Performance Max & Shopping campaign management',
      'Weekly bid + structure optimisation',
      'Monthly performance reporting and review call',
      'Conversion tracking + audience refinement',
      'Account team: Joe Marshall (lead), Matt Jones (PPC), Shannon May (specialist)',
    ];
    if (/seo/i.test(c.name)) return [
      'Technical audit & quarterly health check',
      'On-page optimisation across priority pages',
      '4 outreach-led link placements per month',
      'Monthly ranking + traffic report',
      'Account team: Joe Marshall (lead), Alex Beecham (Head of SEO)',
    ];
    if (/ga4|tracking/i.test(c.name)) return [
      'Full GA4 implementation + audit',
      'Tag Manager build covering all primary conversions',
      'Looker Studio dashboard build',
      'Conversion-tracking validation + sign-off',
      'Account team: Nathan Smith (Agency Systems)',
    ];
    if (/landing page/i.test(c.name)) return [
      'Discovery + creative direction (1 week)',
      'Wireframes + design (2 weeks)',
      'Build + integration (2 weeks)',
      'QA + launch (1 week)',
      'Account team: Hayley Roberts (Design lead), Nathan Smith (Build)',
    ];
    if (/events|training/i.test(c.name)) return [
      'Tickets to Clicky-hosted events at member rates',
      'Access to private Slack channel for event attendees',
      'Recordings + slide decks shared post-event',
      'Discretionary training sessions billed per booking',
    ];
    return ['Scope of work as agreed in the signed contract.'];
  })();

  return (
    <div>
      {/* Back link */}
      <button
        onClick={onBack}
        style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '4px 8px 4px 4px', borderRadius: 6, marginBottom: 12,
          background: 'transparent', border: 'none', color: 'var(--text-muted)',
          fontSize: 12, fontWeight: 500, cursor: 'pointer', fontFamily: 'inherit',
        }}
        onMouseEnter={e => { e.currentTarget.style.background = 'var(--hover)'; e.currentTarget.style.color = 'var(--text)'; }}
        onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-muted)'; }}
      >
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M11 18l-6-6 6-6"/></svg>
        Back to Contracts &amp; Billing
      </button>

      {/* Hero header */}
      <Card padding={0} style={{ marginBottom: 16, overflow: 'hidden' }}>
        <div style={{
          padding: '22px 26px',
          background: c.renewing
            ? 'color-mix(in oklab, var(--warning) 5%, var(--surface))'
            : 'color-mix(in oklab, var(--primary) 4%, var(--surface))',
          borderBottom: '1px solid var(--border)',
        }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                <span style={{ fontFamily: 'JetBrains Mono', fontSize: 11.5, color: 'var(--text-muted)' }}>{c.id}</span>
                <span style={{
                  padding: '2px 8px', borderRadius: 99,
                  background: statusTone.bg, color: statusTone.color,
                  fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                }}>{c.status}</span>
                {c.renewing && (
                  <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',
                  }}>{c.daysToRenew} days to renew</span>
                )}
                {totalOutstanding > 0 && (
                  <span style={{
                    padding: '2px 8px', borderRadius: 99,
                    background: 'color-mix(in oklab, var(--negative) 12%, transparent)', color: 'var(--negative)',
                    fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                  }}>£{totalOutstanding.toLocaleString('en-GB', { minimumFractionDigits: 2 })} outstanding</span>
                )}
              </div>
              <h1 style={{ fontSize: 24, fontWeight: 700, margin: '8px 0 0', letterSpacing: '-0.015em' }}>{c.name}</h1>
            </div>
            <div style={{ display: 'flex', gap: 8, flexShrink: 0 }}>
              {c.renewing && (
                <Btn variant="primary" size="sm" icon={<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>}>
                  Renew now
                </Btn>
              )}
              {totalOutstanding > 0 && (
                <Btn variant="primary" size="sm">Pay outstanding</Btn>
              )}
              <Btn variant="secondary" size="sm" icon={I.download}>Download PDF</Btn>
              <Btn variant="ghost" size="sm" icon={I.send}>Talk to Joe</Btn>
            </div>
          </div>
        </div>

        {/* Stat strip */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }}>
          {[
            { label: isOneOff ? 'Project value' : 'Monthly fee', value: c.monthly,                                                          sub: c.term },
            { label: 'Total billed',                              value: '£' + totalBilled.toLocaleString('en-GB', { minimumFractionDigits: 2 }), sub: `${invoices.length} invoice${invoices.length === 1 ? '' : 's'}` },
            { label: 'Total paid',                                value: '£' + totalPaid.toLocaleString('en-GB', { minimumFractionDigits: 2 }),   sub: `${invoices.filter(i => /Paid/i.test(i.status)).length} paid`, tone: 'positive' },
            { label: 'Outstanding',                               value: '£' + totalOutstanding.toLocaleString('en-GB', { minimumFractionDigits: 2 }), sub: totalOutstanding > 0 ? `${invoices.filter(i => /Due|Overdue/i.test(i.status)).length} unpaid` : 'all paid', tone: totalOutstanding > 0 ? 'negative' : 'positive' },
          ].map((s, i) => (
            <div key={s.label} style={{
              padding: '16px 22px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{s.label}</div>
              <div style={{
                fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em',
                color: s.tone === 'positive' ? 'var(--positive)' : s.tone === 'negative' ? 'var(--negative)' : 'var(--text)',
              }}>{s.value}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 16, alignItems: 'flex-start' }}>
        {/* Left column */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {/* Scope & services */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{
                width: 28, height: 28, borderRadius: 6, flexShrink: 0,
                background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                color: 'var(--primary)', display: 'grid', placeItems: 'center',
              }}>
                <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/></svg>
              </div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>Scope of work</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>What this contract covers month-to-month.</div>
              </div>
            </div>
            <div style={{ padding: '12px 18px 16px' }}>
              <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 8 }}>
                {scope.map((line, i) => (
                  <li key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, fontSize: 13, color: 'var(--text)', lineHeight: 1.5 }}>
                    <span style={{
                      width: 16, height: 16, borderRadius: 4, flexShrink: 0,
                      background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
                      color: 'var(--positive)', display: 'grid', placeItems: 'center', marginTop: 2,
                    }}>
                      <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
                    </span>
                    {line}
                  </li>
                ))}
              </ul>
            </div>
          </Card>

          {/* Invoices */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <div style={{
                  width: 28, height: 28, borderRadius: 6, flexShrink: 0,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center',
                }}>
                  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
                </div>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 600 }}>Invoices · {invoices.length}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>
                    £{totalPaid.toLocaleString('en-GB', { minimumFractionDigits: 2 })} paid
                    {totalOutstanding > 0 && <> · <span style={{ color: 'var(--negative)' }}>£{totalOutstanding.toLocaleString('en-GB', { minimumFractionDigits: 2 })} outstanding</span></>}
                  </div>
                </div>
              </div>
              <Btn variant="ghost" size="sm" icon={I.download}>Statement</Btn>
            </div>
            {invoices.length === 0 ? (
              <div style={{ padding: 24, textAlign: 'center', fontSize: 13, color: 'var(--text-muted)', fontStyle: 'italic' }}>
                No invoices billed against this contract yet.
              </div>
            ) : (
              <>
                <div style={{
                  display: 'grid', gridTemplateColumns: '110px 1fr 110px 110px 100px 110px',
                  padding: '10px 18px', background: 'var(--surface-2)',
                  fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
                  textTransform: 'uppercase', letterSpacing: '0.06em',
                  borderBottom: '1px solid var(--border)', gap: 12,
                }}>
                  <div>Invoice</div>
                  <div>Description</div>
                  <div style={{ textAlign: 'right' }}>This contract</div>
                  <div style={{ textAlign: 'right' }}>Invoice total</div>
                  <div>Due</div>
                  <div style={{ textAlign: 'right' }}>Status</div>
                </div>
                {invoices.map(inv => {
                  const line = lineFor(inv);
                  const isOverdue = /Overdue/i.test(inv.status);
                  const isOutstanding = /Due|Overdue/i.test(inv.status);
                  const tone = isOverdue ? { color: 'var(--negative)', bg: 'color-mix(in oklab, var(--negative) 12%, transparent)' }
                              : isOutstanding ? { color: 'var(--warning)', bg: 'color-mix(in oklab, var(--warning) 12%, transparent)' }
                              : { color: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 10%, transparent)' };
                  return (
                    <div key={inv.id} style={{
                      display: 'grid', gridTemplateColumns: '110px 1fr 110px 110px 100px 110px',
                      padding: '12px 18px', alignItems: 'center', gap: 12,
                      borderBottom: '1px solid var(--border)',
                      background: isOutstanding ? 'color-mix(in oklab, ' + tone.color + ' 4%, transparent)' : 'transparent',
                      fontSize: 12.5,
                    }}>
                      <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11.5 }}>{inv.id}</div>
                      <div>
                        <div style={{ fontWeight: 600 }}>{line.description || inv.period}</div>
                        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 1 }}>Issued {inv.date}</div>
                      </div>
                      <div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 700 }}>£{line.amount.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
                      <div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>
                        {inv.amount}
                        {(inv.lines || []).length > 1 && <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>{(inv.lines || []).length} line items</div>}
                      </div>
                      <div style={{ color: 'var(--text-muted)', fontSize: 11.5 }}>{inv.due}</div>
                      <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
                        <span style={{
                          padding: '2px 8px', borderRadius: 99,
                          background: tone.bg, color: tone.color,
                          fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                        }}>{inv.status}</span>
                      </div>
                    </div>
                  );
                })}
              </>
            )}
          </Card>

          {/* Activity log */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>Activity</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>Recent changes and events on this contract.</div>
            </div>
            <div style={{ padding: '4px 0' }}>
              {[
                { when: '12 Apr 2026', who: 'Joe Marshall', action: 'Approved', detail: 'Q2 strategy adjustments — added Performance Max test budget.' },
                { when: '01 Apr 2026', who: 'System',       action: 'Invoiced', detail: 'Auto-charge attempt for April retainer — successful.' },
                { when: '05 Mar 2026', who: 'Daniel Trevethan', action: 'Signed', detail: 'E-signed amendment increasing monthly retainer scope.' },
                { when: c.start,        who: 'Daniel Trevethan', action: 'Signed', detail: `Original contract signed and activated.` },
              ].map((a, i) => (
                <div key={i} style={{
                  display: 'flex', alignItems: 'flex-start', gap: 12,
                  padding: '12px 18px',
                  borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                }}>
                  <div style={{
                    width: 8, height: 8, borderRadius: '50%', marginTop: 6, flexShrink: 0,
                    background: a.action === 'Signed' ? 'var(--primary)' : a.action === 'Invoiced' ? 'var(--text-muted)' : 'var(--positive)',
                  }}/>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' }}>
                      <span style={{ fontSize: 13, fontWeight: 600 }}>{a.action}</span>
                      <span style={{ fontSize: 11.5, color: 'var(--text-muted)' }}>by {a.who}</span>
                      <span style={{ fontSize: 10.5, color: 'var(--text-faint)', marginLeft: 'auto' }}>{a.when}</span>
                    </div>
                    <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.5 }}>{a.detail}</div>
                  </div>
                </div>
              ))}
            </div>
          </Card>
        </div>

        {/* Right column */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {/* Key dates */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>Key dates</div>
            </div>
            <div style={{ padding: '12px 18px 14px', display: 'flex', flexDirection: 'column', gap: 12 }}>
              {[
                { label: 'Started',     value: c.start },
                { label: 'Term length', value: c.term },
                { label: c.term && c.term.includes('One-off') ? 'Completed' : 'Renews',    value: c.renews, tone: c.renewing ? 'warning' : 'muted' },
                ...(c.daysToRenew ? [{ label: 'Days to renew', value: c.daysToRenew + ' days', tone: 'warning' }] : []),
              ].map(row => (
                <div key={row.label} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
                  <span style={{ fontSize: 11.5, color: 'var(--text-muted)' }}>{row.label}</span>
                  <span style={{
                    fontSize: 12.5, fontWeight: 600, fontVariantNumeric: 'tabular-nums',
                    color: row.tone === 'warning' ? 'var(--warning)' : 'var(--text)',
                  }}>{row.value}</span>
                </div>
              ))}
            </div>
          </Card>

          {/* Documents */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>Documents</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>The signed contract and any amendments.</div>
            </div>
            <div>
              {[
                { name: c.id + ' · Signed contract.pdf', size: '184 KB', kind: 'pdf', date: c.start },
                { name: 'Schedule of services.pdf',      size: '92 KB',  kind: 'pdf', date: c.start },
                ...(c.renewing ? [{ name: 'Renewal proposal · Q2 2026.pdf', size: '256 KB', kind: 'pdf', date: '01 May 2026' }] : []),
              ].map((d, i) => (
                <button key={d.name} style={{
                  display: 'flex', alignItems: 'center', gap: 10,
                  width: '100%', padding: '11px 18px',
                  background: 'transparent', border: 'none',
                  borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                  cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left',
                }}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  <span style={{
                    width: 28, height: 28, borderRadius: 6, flexShrink: 0,
                    background: 'color-mix(in oklab, var(--negative) 10%, transparent)', color: 'var(--negative)',
                    display: 'grid', placeItems: 'center', fontSize: 9, fontWeight: 700,
                  }}>PDF</span>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.name}</div>
                    <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 2 }}>{d.size} · uploaded {d.date}</div>
                  </div>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-faint)', flexShrink: 0 }}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
                </button>
              ))}
            </div>
          </Card>

          {/* Account team */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ fontSize: 13, fontWeight: 600 }}>Your account team</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>Day-to-day on this contract.</div>
            </div>
            <div style={{ padding: '4px 0' }}>
              {TEAM.slice(0, 3).map((p, i) => (
                <button key={p.name} onClick={() => setActive && setActive('team')} style={{
                  display: 'flex', alignItems: 'center', gap: 10,
                  width: '100%', padding: '10px 18px',
                  background: 'transparent', border: 'none',
                  borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                  cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left',
                }}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  <PersonAvatar name={p.name} size={28} hue={p.hue} src={p.src} />
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600 }}>{p.name}</div>
                    <div style={{ fontSize: 10.5, color: 'var(--text-muted)', marginTop: 1 }}>{p.role}</div>
                  </div>
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-faint)', flexShrink: 0 }}><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                </button>
              ))}
            </div>
          </Card>

          {/* Danger zone */}
          <Card>
            <div style={{ fontSize: 12.5, fontWeight: 600, marginBottom: 10 }}>Need to make a change?</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              <Btn variant="ghost" size="sm">Request amendment</Btn>
              <Btn variant="ghost" size="sm" icon={I.send} onClick={() => setActive && setActive('ask')}>Talk to {TEAM.find(p => p.primary)?.name?.split(' ')[0] || 'Joe'}</Btn>
              <button style={{
                padding: '7px 12px', borderRadius: 6,
                background: 'transparent', color: 'var(--negative)',
                border: '1px solid color-mix(in oklab, var(--negative) 30%, var(--border))',
                fontSize: 11.5, fontWeight: 500, fontFamily: 'inherit', cursor: 'pointer',
              }}>Cancel contract</button>
            </div>
          </Card>
        </div>
      </div>
    </div>
  );
};

// =============================================================
// ContractCard — one contract with its linked invoices nested
// underneath. Header shows status, monthly value, term and dates;
// footer shows total billed + outstanding; body is a collapsible
// invoice table scoped to this contract.
// =============================================================
const ContractCard = ({ contract: c, invoices, onViewDetail }) => {
  // Auto-expand contracts that need attention (renewing soon, outstanding).
  const hasOutstanding = invoices.some(i => i.status === 'Due' || i.status === 'Overdue');
  const [open, setOpen] = useState(c.renewing || hasOutstanding || c.status === 'In progress');

  const lineFor = (inv) => (inv.lines || []).find(l => l.contractId === c.id) || { amount: 0 };
  const totalBilled = invoices
    .filter(i => i.status === 'Paid')
    .reduce((s, i) => s + lineFor(i).amount, 0);
  const outstandingTotal = invoices
    .filter(i => i.status === 'Due' || i.status === 'Overdue')
    .reduce((s, i) => s + lineFor(i).amount, 0);

  const statusTone = {
    'Active':       { color: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 12%, transparent)' },
    'Renewing':     { color: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 14%, transparent)' },
    'In progress':  { color: 'var(--primary)',  bg: 'color-mix(in oklab, var(--primary) 12%, transparent)' },
    'Completed':    { color: 'var(--text-muted)', bg: 'var(--surface-2)' },
  }[c.status] || { color: 'var(--text-muted)', bg: 'var(--surface-2)' };

  const invStatusTone = (s) =>
    /Overdue/i.test(s) ? { color: 'var(--negative)', bg: 'color-mix(in oklab, var(--negative) 12%, transparent)' }
    : /Due/i.test(s)   ? { color: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 12%, transparent)' }
    : /Paid/i.test(s)  ? { color: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 10%, transparent)' }
    : { color: 'var(--text-muted)', bg: 'var(--surface-2)' };

  return (
    <Card padding={0} style={{
      overflow: 'hidden',
      borderColor: c.renewing ? 'color-mix(in oklab, var(--warning) 30%, var(--border))'
                  : hasOutstanding ? 'color-mix(in oklab, var(--negative) 24%, var(--border))'
                  : 'var(--border)',
    }}>
      {/* Header */}
      <div style={{
        padding: '16px 20px',
        background: c.renewing ? 'color-mix(in oklab, var(--warning) 5%, var(--surface))'
                  : 'color-mix(in oklab, var(--primary) 3%, var(--surface))',
        borderBottom: open ? '1px solid var(--border)' : 'none',
        display: 'flex', alignItems: 'flex-start', gap: 14,
      }}>
        <button
          onClick={() => setOpen(v => !v)}
          aria-label={open ? 'Collapse contract' : 'Expand contract'}
          style={{
            width: 28, height: 28, borderRadius: 6, flexShrink: 0,
            background: 'var(--surface)', border: '1px solid var(--border)',
            color: 'var(--text-muted)', cursor: 'pointer',
            display: 'grid', placeItems: 'center',
            transform: open ? 'rotate(0)' : 'rotate(-90deg)',
            transition: 'transform 150ms ease, background 120ms ease',
          }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'var(--surface)'}
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
        </button>

        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: 'var(--text-muted)' }}>{c.id}</span>
            <span style={{
              padding: '2px 8px', borderRadius: 99,
              background: statusTone.bg, color: statusTone.color,
              fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
            }}>{c.status}</span>
            {c.renewing && (
              <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',
              }}>{c.daysToRenew}d to renew</span>
            )}
            {hasOutstanding && (
              <span style={{
                padding: '2px 8px', borderRadius: 99,
                background: 'color-mix(in oklab, var(--negative) 12%, transparent)', color: 'var(--negative)',
                fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
              }}>£{outstandingTotal.toLocaleString('en-GB', { minimumFractionDigits: 2 })} outstanding</span>
            )}
          </div>
          <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)', marginTop: 6, letterSpacing: '-0.005em' }}>
            {c.name}
          </div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 18, marginTop: 8, fontSize: 11.5, color: 'var(--text-muted)' }}>
            <span><span style={{ color: 'var(--text-faint)' }}>Term:</span> <span style={{ color: 'var(--text)', fontWeight: 500 }}>{c.term}</span></span>
            <span><span style={{ color: 'var(--text-faint)' }}>Started:</span> <span style={{ color: 'var(--text)', fontWeight: 500 }}>{c.start}</span></span>
            <span><span style={{ color: 'var(--text-faint)' }}>{c.monthly && c.term && c.term.includes('One-off') ? 'Total:' : c.term && c.term !== 'One-off' ? 'Renews:' : 'Status:'}</span> <span style={{ color: c.renewing ? 'var(--warning)' : 'var(--text)', fontWeight: 500 }}>{c.renews}</span></span>
            <span style={{ marginLeft: 'auto' }}>
              <span style={{ color: 'var(--text-faint)' }}>{c.term && c.term.includes('One-off') ? 'Project value' : 'Monthly'}:</span>{' '}
              <span style={{ color: 'var(--text)', fontWeight: 700, fontSize: 14, fontVariantNumeric: 'tabular-nums' }}>{c.monthly}</span>
            </span>
          </div>
        </div>

        <div style={{ display: 'flex', gap: 6, flexShrink: 0, alignItems: 'flex-start' }}>
          {c.renewing && (
            <Btn variant="primary" size="sm" icon={<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>}>
              Renew
            </Btn>
          )}
          {onViewDetail && (
            <Btn variant="secondary" size="sm" iconRight={I.arrowRight} onClick={() => onViewDetail(c.id)}>
              View detail
            </Btn>
          )}
          <Btn variant="ghost" size="sm" icon={I.download}>PDF</Btn>
        </div>
      </div>

      {/* Invoice body */}
      {open && (
        <div>
          {invoices.length === 0 ? (
            <div style={{
              padding: '20px 24px', fontSize: 12.5, color: 'var(--text-muted)',
              fontStyle: 'italic',
            }}>
              No invoices yet for this contract.
            </div>
          ) : (
            <>
              <div style={{
                display: 'grid',
                gridTemplateColumns: '110px 1fr 110px 110px 100px 110px',
                padding: '10px 20px', background: 'var(--surface-2)',
                fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
                textTransform: 'uppercase', letterSpacing: '0.06em',
                borderBottom: '1px solid var(--border)', gap: 12,
              }}>
                <div>Invoice</div>
                <div>Period · line item</div>
                <div style={{ textAlign: 'right' }}>This contract</div>
                <div style={{ textAlign: 'right' }}>Invoice total</div>
                <div>Due</div>
                <div style={{ textAlign: 'right' }}>Status</div>
              </div>
              {invoices
                .slice()
                .sort((a, b) => new Date(b.date) - new Date(a.date))
                .map((inv, i) => {
                  const line = lineFor(inv);
                  const tone = invStatusTone(inv.status);
                  const isOutstanding = /Due|Overdue/i.test(inv.status);
                  return (
                    <div key={inv.id} style={{
                      display: 'grid',
                      gridTemplateColumns: '110px 1fr 110px 110px 100px 110px',
                      padding: '12px 20px', alignItems: 'center', gap: 12,
                      borderBottom: '1px solid var(--border)',
                      background: isOutstanding ? 'color-mix(in oklab, ' + tone.color + ' 4%, transparent)' : 'transparent',
                      fontSize: 12.5,
                    }}>
                      <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11.5, color: 'var(--text)' }}>{inv.id}</div>
                      <div>
                        <div style={{ fontWeight: 600, color: 'var(--text)' }}>{line.description || inv.period}</div>
                        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 1 }}>Issued {inv.date}</div>
                      </div>
                      <div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 700 }}>£{line.amount.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
                      <div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>
                        {inv.amount}
                        {(inv.lines || []).length > 1 && <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>{(inv.lines || []).length} line items</div>}
                      </div>
                      <div style={{ color: 'var(--text-muted)', fontSize: 11.5, fontVariantNumeric: 'tabular-nums' }}>{inv.due}</div>
                      <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6 }}>
                        <span style={{
                          padding: '2px 8px', borderRadius: 99,
                          background: tone.bg, color: tone.color,
                          fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                        }}>{inv.status}</span>
                      </div>
                    </div>
                  );
                })}

              {/* Footer totals */}
              <div style={{
                display: 'grid', gridTemplateColumns: '1fr auto auto auto',
                padding: '12px 20px', alignItems: 'center', gap: 22,
                background: 'var(--surface-2)',
                fontSize: 11.5,
              }}>
                <div style={{ color: 'var(--text-muted)' }}>{invoices.length} invoice{invoices.length === 1 ? '' : 's'} for {c.name}</div>
                <div>
                  <span style={{ color: 'var(--text-faint)', fontSize: 10.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginRight: 6 }}>Paid</span>
                  <span style={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'var(--positive)' }}>£{totalBilled.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</span>
                </div>
                {outstandingTotal > 0 && (
                  <div>
                    <span style={{ color: 'var(--text-faint)', fontSize: 10.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginRight: 6 }}>Outstanding</span>
                    <span style={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'var(--negative)' }}>£{outstandingTotal.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</span>
                  </div>
                )}
                {outstandingTotal > 0 && (
                  <Btn variant="primary" size="sm">Pay outstanding</Btn>
                )}
              </div>
            </>
          )}
        </div>
      )}
    </Card>
  );
};

const StandaloneInvoicesCard = ({ invoices }) => {
  const [open, setOpen] = useState(true);
  const total = invoices.reduce((s, i) => s + Number(String(i.amount).replace(/[£,]/g, '')), 0);
  const invStatusTone = (s) =>
    /Overdue/i.test(s) ? { color: 'var(--negative)', bg: 'color-mix(in oklab, var(--negative) 12%, transparent)' }
    : /Due/i.test(s)   ? { color: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 12%, transparent)' }
    : /Paid/i.test(s)  ? { color: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 10%, transparent)' }
    : { color: 'var(--text-muted)', bg: 'var(--surface-2)' };

  return (
    <Card padding={0} style={{ overflow: 'hidden' }}>
      <div style={{
        padding: '14px 20px', borderBottom: open ? '1px solid var(--border)' : 'none',
        background: 'var(--surface-2)',
        display: 'flex', alignItems: 'center', gap: 14,
      }}>
        <button onClick={() => setOpen(v => !v)} aria-label={open ? 'Collapse' : 'Expand'} style={{
          width: 28, height: 28, borderRadius: 6, flexShrink: 0,
          background: 'var(--surface)', border: '1px solid var(--border)',
          color: 'var(--text-muted)', cursor: 'pointer',
          display: 'grid', placeItems: 'center',
          transform: open ? 'rotate(0)' : 'rotate(-90deg)',
          transition: 'transform 150ms ease',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
        </button>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>Other invoices</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>One-offs that aren't tied to a contract — events, ad-hoc items.</div>
        </div>
        <div style={{ fontSize: 11.5, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>
          {invoices.length} invoice{invoices.length === 1 ? '' : 's'} · £{total.toLocaleString('en-GB', { minimumFractionDigits: 2 })}
        </div>
      </div>
      {open && (
        <>
          <div style={{
            display: 'grid', gridTemplateColumns: '110px 1fr 110px 100px 110px',
            padding: '10px 20px', background: 'var(--surface-2)',
            fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
            textTransform: 'uppercase', letterSpacing: '0.06em',
            borderBottom: '1px solid var(--border)', gap: 12,
          }}>
            <div>Invoice</div>
            <div>Description</div>
            <div style={{ textAlign: 'right' }}>Amount</div>
            <div>Due</div>
            <div style={{ textAlign: 'right' }}>Status</div>
          </div>
          {invoices.map(inv => {
            const tone = invStatusTone(inv.status);
            const isOutstanding = /Due|Overdue/i.test(inv.status);
            return (
              <div key={inv.id} style={{
                display: 'grid', gridTemplateColumns: '110px 1fr 110px 100px 110px',
                padding: '12px 20px', alignItems: 'center', gap: 12,
                borderBottom: '1px solid var(--border)',
                background: isOutstanding ? 'color-mix(in oklab, ' + tone.color + ' 4%, transparent)' : 'transparent',
                fontSize: 12.5,
              }}>
                <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11.5 }}>{inv.id}</div>
                <div>
                  <div style={{ fontWeight: 600 }}>{inv.period}</div>
                  <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 1 }}>Issued {inv.date}</div>
                </div>
                <div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 700 }}>{inv.amount}</div>
                <div style={{ color: 'var(--text-muted)', fontSize: 11.5 }}>{inv.due}</div>
                <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                  <span style={{
                    padding: '2px 8px', borderRadius: 99,
                    background: tone.bg, color: tone.color,
                    fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
                  }}>{inv.status}</span>
                </div>
              </div>
            );
          })}
        </>
      )}
    </Card>
  );
};

const BillingScreen = ({ initialTab, openContractDetail, setActive }) => {
  const [tab, setTab] = useState(initialTab || 'contracts');
  // Sync the active tab when the parent passes a new initialTab (sidebar
  // sub-row click while we're already on the billing route).
  useEffect(() => {
    if (initialTab && initialTab !== tab) setTab(initialTab);
  }, [initialTab]); // eslint-disable-line
  const monthlyNum = (c) => {
    const n = Number(String(c.monthly || '').replace(/[£,]/g, ''));
    return isFinite(n) ? n : 0;
  };
  const totalMRR = CONTRACTS.filter(c => c.status === 'Active').reduce((s, c) => s + monthlyNum(c), 0);
  const nextDue = INVOICES.find(i => i.status === 'Due');
  const ytdSpend = INVOICES.filter(i => i.status === 'Paid').reduce((s, i) => s + Number(i.amount.replace(/[£,]/g, '')), 0);
  const contractSort = useTableSort(CONTRACTS, 'start', 'desc');
  const invoiceSort  = useTableSort(INVOICES, 'date', 'desc');

  const renewingCount = CONTRACTS.filter(c => c.renewing).length;
  const activeCount = CONTRACTS.filter(c => c.status === 'Active').length;

  // Invoice metrics
  const overdueInvoices = INVOICES.filter(i => i.status === 'Overdue');
  const dueInvoices     = INVOICES.filter(i => i.status === 'Due');
  const outstandingInvoices = [...overdueInvoices, ...dueInvoices];
  const outstandingTotal = outstandingInvoices.reduce((s, i) => s + Number(i.amount.replace(/[£,]/g, '')), 0);
  const paidThisYear = INVOICES.filter(i => i.status === 'Paid');
  const avgInvoice = paidThisYear.length
    ? paidThisYear.reduce((s, i) => s + Number(i.amount.replace(/[£,]/g, '')), 0) / paidThisYear.length
    : 0;

  // Per-tab summary stats — contracts and invoices each show metrics that
  // matter for that view. Payment tab keeps a slim contract-leaning summary.
  const contractsStats = [
    {
      label: 'Active contracts',
      value: String(activeCount),
      sub: `${activeCount} services running`,
      tone: 'neutral',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8zM14 3v5h5M9 13h6M9 17h4"/></svg>,
    },
    {
      label: 'Monthly retainer',
      value: '£' + totalMRR.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
      sub: 'across all active services',
      tone: 'neutral',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 1v22M17 5H9.5a3.5 3.5 0 1 0 0 7h5a3.5 3.5 0 1 1 0 7H6"/></svg>,
    },
    {
      label: 'Up for renewal',
      value: renewingCount ? String(renewingCount) : '0',
      sub: renewingCount ? 'Action required this month' : 'all secure for now',
      tone: renewingCount ? 'warning' : 'positive',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>,
    },
    {
      label: 'Annual contract value',
      value: '£' + (totalMRR * 12).toLocaleString('en-GB', { minimumFractionDigits: 0 }),
      sub: 'across active retainers',
      tone: 'neutral',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>,
    },
  ];

  const invoicesStats = [
    {
      label: 'Outstanding',
      value: '£' + outstandingTotal.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
      sub: `${outstandingInvoices.length} invoice${outstandingInvoices.length === 1 ? '' : 's'} unpaid`,
      tone: outstandingInvoices.length ? (overdueInvoices.length ? 'negative' : 'warning') : 'positive',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>,
    },
    {
      label: 'Next invoice due',
      value: nextDue ? nextDue.amount : '—',
      sub: nextDue ? `Due ${nextDue.due}` : 'No upcoming',
      tone: nextDue ? 'warning' : 'positive',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18"/><path d="M7 15h2M12 15h5"/></svg>,
    },
    {
      label: 'YTD paid',
      value: '£' + ytdSpend.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
      sub: `${paidThisYear.length} invoices · 2026 to date`,
      tone: 'positive',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>,
    },
    {
      label: 'Average invoice',
      value: '£' + avgInvoice.toLocaleString('en-GB', { minimumFractionDigits: 2 }),
      sub: 'across paid invoices',
      tone: 'neutral',
      icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>,
    },
  ];

  const stats = tab === 'invoices' ? invoicesStats : contractsStats;

  return (
    <div>
      <PageHeader
        title="Contracts & Billing"
        subtitle="Your active services, invoices and payment details"
        actions={<>
          <Btn variant="secondary" size="sm" icon={I.download}>Statement</Btn>
          <AddServicesChannelsButton setActive={setActive} />
        </>}
      />

      {/* Summary stats — per-tab numbers; hidden on the dedicated summary tab */}
      {(tab === 'contracts' || tab === 'invoices') && (
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', alignItems: 'center' }}>
          {stats.map((s, i) => {
            const accent = s.tone === 'positive' ? 'var(--positive)'
                         : s.tone === 'warning'  ? 'var(--warning)'
                         : s.tone === 'negative' ? 'var(--negative)'
                         : 'var(--text-muted)';
            return (
              <div key={s.label} style={{
                padding: '16px 20px',
                borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                display: 'flex', alignItems: 'flex-start', gap: 12, minWidth: 0,
              }}>
                <div style={{
                  width: 36, height: 36, borderRadius: 8, flexShrink: 0,
                  background: `color-mix(in oklab, ${accent} 14%, transparent)`,
                  color: accent,
                  display: 'grid', placeItems: 'center',
                }}>{s.icon}</div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
                  <div style={{
                    fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2, letterSpacing: '-0.02em',
                    color: s.tone === 'warning' ? 'var(--warning)' : s.tone === 'positive' ? 'var(--positive)' : 'var(--text)',
                  }}>{s.value}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1 }}>{s.sub}</div>
                </div>
              </div>
            );
          })}
        </div>
      </Card>
      )}

      {/* Tabs */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 4, padding: 4, borderRadius: 8, background: 'var(--surface-2)', border: '1px solid var(--border)', width: 'fit-content', marginBottom: 14 }}>
        {[
          { id: 'summary',   label: 'Summary' },
          { id: 'contracts', label: 'By contract',   count: CONTRACTS.length },
          { id: 'invoices',  label: 'All invoices',  count: INVOICES.length },
          { id: 'payment',   label: 'Payment method' },
        ].map(t => (
          <button key={t.id} onClick={() => setTab(t.id)} style={{
            padding: '6px 12px', borderRadius: 6, fontSize: 13, fontWeight: 500,
            background: tab === t.id ? 'var(--surface)' : 'transparent',
            color: tab === t.id ? 'var(--text)' : 'var(--text-muted)',
            border: tab === t.id ? '1px solid var(--border)' : '1px solid transparent',
            cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
            boxShadow: tab === t.id ? 'var(--shadow-sm)' : 'none',
          }}>
            {t.label}
            {t.count !== undefined && <Badge tone="neutral">{t.count}</Badge>}
          </button>
        ))}
      </div>

      {tab === 'summary' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
          {/* Contracts overview card */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{
                  width: 28, height: 28, borderRadius: 6,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center',
                }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8zM14 3v5h5M9 13h6M9 17h4"/></svg>
                </span>
                <div style={{ fontWeight: 600, fontSize: 14 }}>Contracts</div>
              </div>
              <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setTab('contracts')}>Open contracts</Btn>
            </div>
            <div style={{ padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 }}>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>Active</div>
                  <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{activeCount}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>Monthly retainer</div>
                  <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>£{totalMRR.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
                </div>
              </div>
              {renewingCount > 0 && (
                <div style={{
                  padding: '10px 14px', borderRadius: 8,
                  background: 'color-mix(in oklab, var(--warning) 7%, var(--surface))',
                  border: '1px solid color-mix(in oklab, var(--warning) 25%, var(--border))',
                  display: 'flex', alignItems: 'center', gap: 10,
                }}>
                  <span style={{
                    width: 28, height: 28, borderRadius: '50%',
                    background: 'color-mix(in oklab, var(--warning) 14%, transparent)',
                    color: 'var(--warning)', display: 'grid', placeItems: 'center', flexShrink: 0,
                  }}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>
                  </span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--warning)' }}>{renewingCount} contract{renewingCount === 1 ? '' : 's'} up for renewal</div>
                    <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Action required this month</div>
                  </div>
                  <Btn variant="primary" size="sm" onClick={() => setTab('contracts')}>Review</Btn>
                </div>
              )}
              <div>
                <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Latest contracts</div>
                <div style={{ display: 'flex', flexDirection: 'column' }}>
                  {CONTRACTS.slice(0, 4).map((c, i) => (
                    <div key={c.id} style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: '8px 0',
                      borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                    }}>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{
                          fontSize: 12.5, fontWeight: 500, color: 'var(--text)',
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{c.name}</div>
                        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', marginTop: 1 }}>{c.id} · {c.term}</div>
                      </div>
                      <span style={{ fontSize: 12, fontWeight: 600, fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>{c.monthly}</span>
                      <Badge tone={
                        c.status === 'Renewing' ? 'warning'
                        : c.status === 'Active' ? 'positive'
                        : c.status === 'In progress' ? 'primary' : 'neutral'
                      }>{c.status}</Badge>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </Card>

          {/* Invoices overview card */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{
                  width: 28, height: 28, borderRadius: 6,
                  background: outstandingInvoices.length
                    ? `color-mix(in oklab, ${overdueInvoices.length ? 'var(--negative)' : 'var(--warning)'} 14%, transparent)`
                    : 'color-mix(in oklab, var(--positive) 12%, transparent)',
                  color: outstandingInvoices.length ? (overdueInvoices.length ? 'var(--negative)' : 'var(--warning)') : 'var(--positive)',
                  display: 'grid', placeItems: 'center',
                }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18"/><path d="M7 15h2M12 15h5"/></svg>
                </span>
                <div style={{ fontWeight: 600, fontSize: 14 }}>Invoices</div>
              </div>
              <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setTab('invoices')}>Open invoices</Btn>
            </div>
            <div style={{ padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 }}>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>Outstanding</div>
                  <div style={{
                    fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2,
                    color: outstandingInvoices.length ? (overdueInvoices.length ? 'var(--negative)' : 'var(--warning)') : 'var(--positive)',
                  }}>£{outstandingTotal.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>YTD paid</div>
                  <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2, color: 'var(--positive)' }}>£{ytdSpend.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</div>
                </div>
              </div>
              {overdueInvoices.length > 0 && (
                <div style={{
                  padding: '10px 14px', borderRadius: 8,
                  background: 'color-mix(in oklab, var(--negative) 7%, var(--surface))',
                  border: '1px solid color-mix(in oklab, var(--negative) 30%, var(--border))',
                  display: 'flex', alignItems: 'center', gap: 10,
                }}>
                  <span style={{
                    width: 28, height: 28, borderRadius: '50%',
                    background: 'color-mix(in oklab, var(--negative) 14%, transparent)',
                    color: 'var(--negative)', display: 'grid', placeItems: 'center', flexShrink: 0,
                  }}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                  </span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--negative)' }}>{overdueInvoices.length} invoice{overdueInvoices.length === 1 ? '' : 's'} overdue</div>
                    <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{overdueInvoices[0].id} · {overdueInvoices[0].amount}</div>
                  </div>
                  <Btn variant="primary" size="sm" onClick={() => setTab('invoices')}>Pay now</Btn>
                </div>
              )}
              <div>
                <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Recent invoices</div>
                <div style={{ display: 'flex', flexDirection: 'column' }}>
                  {INVOICES.slice(0, 4).map((inv, i) => (
                    <div key={inv.id} style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: '8px 0',
                      borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                    }}>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{
                          fontSize: 12.5, fontWeight: 500, color: 'var(--text)',
                          fontFamily: 'JetBrains Mono',
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{inv.id}</div>
                        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 1 }}>{inv.period} · due {inv.due}</div>
                      </div>
                      <span style={{ fontSize: 12, fontWeight: 600, fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>{inv.amount}</span>
                      <Badge tone={inv.status === 'Paid' ? 'positive' : inv.status === 'Overdue' ? 'negative' : 'warning'}>{inv.status}</Badge>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </Card>
        </div>
      )}

      {tab === 'contracts' && (() => {
        // Group invoices under the contracts they belong to. An invoice with
        // multi-contract line items appears under each contract it touches,
        // showing only the relevant line items + amount.
        const invoicesByContract = {};
        const standaloneInvoices = [];
        for (const inv of INVOICES) {
          const cids = new Set((inv.lines || []).map(l => l.contractId).filter(Boolean));
          if (cids.size === 0) standaloneInvoices.push(inv);
          else for (const cid of cids) {
            if (!invoicesByContract[cid]) invoicesByContract[cid] = [];
            invoicesByContract[cid].push(inv);
          }
        }
        // Sort: Active → Renewing → In progress → Completed
        const order = { 'Active': 0, 'Renewing': 1, 'In progress': 2, 'Completed': 3 };
        const orderedContracts = [...CONTRACTS].sort((a, b) =>
          ((order[a.status] ?? 99) - (order[b.status] ?? 99)) ||
          (new Date(b.start) - new Date(a.start))
        );

        return (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {orderedContracts.map(c => (
              <ContractCard key={c.id} contract={c} invoices={invoicesByContract[c.id] || []} onViewDetail={openContractDetail} />
            ))}

            {standaloneInvoices.length > 0 && (
              <StandaloneInvoicesCard invoices={standaloneInvoices} />
            )}
          </div>
        );
      })()}

      {tab === 'invoices' && (
        <Card padding={0}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead>
              <tr style={{ background: 'var(--surface-2)' }}>
                {[
                  { key: 'id',     label: 'Invoice' },
                  { key: 'date',   label: 'Issued' },
                  { key: 'period', label: 'Period' },
                  { key: 'due',    label: 'Due' },
                  { key: 'amount', label: 'Amount', align: 'right' },
                  { key: 'status', label: 'Status' },
                ].map(c => (
                  <SortableTh key={c.key} sortKey={c.key} align={c.align} currentKey={invoiceSort.sortKey} dir={invoiceSort.sortDir} onSort={invoiceSort.onSort}>{c.label}</SortableTh>
                ))}
                <th style={{ padding: '12px 14px', borderBottom: '1px solid var(--border)' }}/>
              </tr>
            </thead>
            <tbody>
              {invoiceSort.sorted.map((inv, i) => (
                <tr key={inv.id} style={{ borderTop: i === 0 ? 'none' : '1px solid var(--border)' }}>
                  <td style={{ padding: '12px 14px', fontFamily: 'JetBrains Mono', fontSize: 12, color: 'var(--text)' }}>{inv.id}</td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{inv.date}</td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>{inv.period}</td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{inv.due}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>{inv.amount}</td>
                  <td style={{ padding: '12px 14px' }}>
                    <Badge tone={inv.status === 'Paid' ? 'positive' : inv.status === 'Due' ? 'warning' : 'neutral'}>{inv.status}</Badge>
                  </td>
                  <td style={{ padding: '12px 14px', textAlign: 'right' }}>
                    <Btn variant="ghost" size="sm" icon={I.download}>PDF</Btn>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
      )}

      {tab === 'payment' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {/* Primary: Invoicing terms (the default for most clients) */}
          <Card padding={0}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{
                  width: 28, height: 28, borderRadius: 8,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center',
                }}>{I.doc || I.receipt}</span>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>Invoicing terms</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>How most Clicky clients pay — invoiced on the 1st, settled by the due date</div>
                </div>
              </div>
              <span style={{
                fontSize: 10, fontWeight: 700, padding: '4px 10px', borderRadius: 99,
                background: 'color-mix(in oklab, var(--positive) 15%, transparent)',
                color: 'var(--positive)', textTransform: 'uppercase', letterSpacing: '0.06em',
              }}>Primary</span>
            </div>

            <div style={{ padding: 20, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
              {/* Terms summary */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                {[
                  { k: 'Payment terms',  v: 'Net 14 from invoice date' },
                  { k: 'Billing cycle',  v: 'Monthly — issued 1st of month' },
                  { k: 'Currency',       v: 'GBP (£)' },
                  { k: 'Settlement',     v: 'BACS / Faster Payments' },
                ].map(row => (
                  <div key={row.k} style={{ display: 'grid', gridTemplateColumns: '130px 1fr', gap: 12, fontSize: 13 }}>
                    <span style={{ color: 'var(--text-muted)' }}>{row.k}</span>
                    <span style={{ color: 'var(--text)', fontWeight: 500 }}>{row.v}</span>
                  </div>
                ))}
              </div>

              {/* Bank remittance card */}
              <div style={{
                background: 'var(--surface-2)', border: '1px solid var(--border)',
                borderRadius: 'var(--radius)', padding: 16,
              }}>
                <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>Remit to</div>
                <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>Clicky Media Ltd</div>
                {[
                  { k: 'Bank',         v: 'NatWest, Manchester' },
                  { k: 'Sort code',    v: '60-15-22' },
                  { k: 'Account no.',  v: '4419 0028' },
                  { k: 'Reference',    v: 'STMA-2026' },
                ].map(row => (
                  <div key={row.k} style={{ display: 'grid', gridTemplateColumns: '90px 1fr', gap: 10, fontSize: 12, marginTop: 4, fontFamily: 'JetBrains Mono' }}>
                    <span style={{ color: 'var(--text-muted)', fontFamily: 'Inter' }}>{row.k}</span>
                    <span style={{ color: 'var(--text)' }}>{row.v}</span>
                  </div>
                ))}
              </div>
            </div>

            <div style={{ padding: '14px 20px', borderTop: '1px solid var(--border)', display: 'flex', gap: 8 }}>
              <Btn variant="secondary" size="sm">Update terms</Btn>
              <Btn variant="ghost" size="sm">Download W-9 / VAT details</Btn>
            </div>
          </Card>

          {/* Two-column: Backup card + Billing contact */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
            <Card padding={0}>
              <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>Backup payment method</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Charged automatically if an invoice is more than 7 days overdue</div>
                </div>
                <span style={{
                  fontSize: 10, fontWeight: 600, padding: '3px 8px', borderRadius: 99,
                  background: 'var(--surface-2)', color: 'var(--text-muted)',
                  textTransform: 'uppercase', letterSpacing: '0.06em',
                }}>Optional</span>
              </div>
              <div style={{ padding: 20 }}>
                <div style={{
                  background: 'linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%)',
                  color: '#fff', borderRadius: 'var(--radius)', padding: 18, marginBottom: 14,
                  fontFamily: 'JetBrains Mono', position: 'relative', overflow: 'hidden',
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 18 }}>
                    <div style={{ fontSize: 11, opacity: 0.7, fontFamily: 'Inter' }}>Card on file</div>
                    <div style={{ fontSize: 14, fontWeight: 700, fontFamily: 'Inter', letterSpacing: '0.02em' }}>VISA</div>
                  </div>
                  <div style={{ fontSize: 16, letterSpacing: '0.15em', marginBottom: 12 }}>•••• •••• •••• 4421</div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11 }}>
                    <div>
                      <div style={{ opacity: 0.6, fontFamily: 'Inter' }}>Cardholder</div>
                      <div style={{ marginTop: 2, fontFamily: 'Inter' }}>L. Stevens</div>
                    </div>
                    <div>
                      <div style={{ opacity: 0.6, fontFamily: 'Inter' }}>Expires</div>
                      <div style={{ marginTop: 2 }}>09 / 28</div>
                    </div>
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 8 }}>
                  <Btn variant="secondary" size="sm">Update card</Btn>
                  <Btn variant="ghost" size="sm">Remove</Btn>
                </div>
                <div style={{ marginTop: 12, fontSize: 11, color: 'var(--text-faint)', lineHeight: 1.5 }}>
                  We'll only charge this card automatically as a fallback. You can also use it to pay an individual invoice from the Invoices tab.
                </div>
              </div>
            </Card>

            <Card padding={0}>
              <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', fontWeight: 600, fontSize: 14 }}>Billing contact</div>
              <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 14 }}>
                {[
                  { k: 'Company',       v: 'Evergreen Escapes Ltd' },
                  { k: 'Billing email', v: 'accounts@st-mabyn-escape.co.uk' },
                  { k: 'PO required',   v: 'No' },
                  { k: 'VAT number',    v: 'GB 482 2097 71' },
                  { k: 'Address',       v: '14 Mill Lane, Henley-on-Thames, RG9 2BA, UK' },
                ].map(row => (
                  <div key={row.k} style={{ display: 'grid', gridTemplateColumns: '110px 1fr', gap: 12, fontSize: 13 }}>
                    <span style={{ color: 'var(--text-muted)' }}>{row.k}</span>
                    <span style={{ color: 'var(--text)', fontWeight: 500 }}>{row.v}</span>
                  </div>
                ))}
                <div style={{ paddingTop: 6 }}>
                  <Btn variant="ghost" size="sm">Edit details</Btn>
                </div>
              </div>
            </Card>
          </div>
        </div>
      )}
    </div>
  );
};

window.BillingScreen = BillingScreen;

// ============================================================
// Support Tickets
// ============================================================

// Tone helpers used by the tickets strip and table — kept as a small map
// so the tile colour, status badge and table icon stay in lockstep.
const TICKET_STATUS_META = {
  'Open':           { tone: 'var(--primary)',  badge: 'primary',  icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg> },
  'In progress':    { tone: 'var(--primary)',  badge: 'primary',  icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 7v5l3 2"/></svg> },
  'Awaiting reply': { tone: 'var(--warning)',  badge: 'warning',  icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg> },
  'Resolved':       { tone: 'var(--positive)', badge: 'positive', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg> },
};

const TICKET_PRIORITY_META = {
  'High':   { fg: 'var(--negative)', bg: 'color-mix(in oklab, var(--negative) 14%, transparent)', badge: 'negative',
              icon: <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m18 15-6-6-6 6"/><path d="m18 9-6-6-6 6" opacity=".5"/></svg> },
  'Normal': { fg: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 16%, transparent)', badge: 'warning',
              icon: <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14"/></svg> },
  'Low':    { fg: 'var(--text-muted)', bg: 'var(--surface-2)', badge: 'neutral',
              icon: <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/><path d="m6 15 6 6 6-6" opacity=".5"/></svg> },
};

// Tiny inline bar chart that doesn't depend on Recharts — keeps the tickets
// strip light. Bars sit on a baseline; tallest is clamped to height.
const MiniBars = ({ data, color, height = 28 }) => {
  const max = Math.max(...data, 1);
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 2, height, width: '100%' }}>
      {data.map((v, i) => (
        <div key={i} title={`Wk ${i + 1}: ${v}`}
          style={{
            flex: 1,
            height: `${Math.max(8, (v / max) * 100)}%`,
            background: color,
            borderRadius: 1,
            opacity: i === data.length - 1 ? 1 : 0.55,
          }}/>
      ))}
    </div>
  );
};

// Tiny inline line sparkline (no Recharts) — for the response-time trend.
const MiniLine = ({ data, color, height = 28 }) => {
  const max = Math.max(...data, 1);
  const min = Math.min(...data, 0);
  const range = Math.max(1, max - min);
  const w = 100, h = 100;
  const points = data.map((v, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - ((v - min) / range) * (h - 8) - 4;
    return `${x.toFixed(2)},${y.toFixed(2)}`;
  }).join(' ');
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" width="100%" height={height}>
      <polyline points={points} fill="none" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
      {/* End-point dot to anchor the eye */}
      {data.length > 0 && (() => {
        const x = w;
        const v = data[data.length - 1];
        const y = h - ((v - min) / range) * (h - 8) - 4;
        return <circle cx={x} cy={y} r="3" fill={color} />;
      })()}
    </svg>
  );
};

const TicketsScreen = () => {
  // Mock weekly trend data for the strip charts and the trend block.
  const weeklyOpened   = [3, 4, 2, 5, 4, 3, 6, 4];   // tickets opened per week (last 8 wks)
  const weeklyResolved = [2, 4, 3, 4, 5, 3, 5, 5];   // tickets resolved per week
  const weeklyResponse = [78, 64, 72, 58, 51, 46, 49, 46]; // avg first-response (mins) — trending down
  const weeklyOpen     = [4, 4, 3, 4, 3, 3, 2, 2];   // open backlog over time
  const totalOpen      = TICKETS.filter(t => t.status === 'Open' || t.status === 'In progress').length;
  const totalAwaiting  = TICKETS.filter(t => t.status === 'Awaiting reply').length;

  // Status breakdown (donut). Counts pulled from the live TICKETS list,
  // padded with mocked historical resolutions for visual mass.
  const statusCounts = [
    { key: 'In progress',     count: TICKETS.filter(t => t.status === 'In progress').length,     color: 'var(--primary)' },
    { key: 'Awaiting reply',  count: TICKETS.filter(t => t.status === 'Awaiting reply').length,  color: 'var(--warning)' },
    { key: 'Resolved',        count: TICKETS.filter(t => t.status === 'Resolved').length + 5,    color: 'var(--positive)' },
  ];
  const statusTotal = statusCounts.reduce((a, b) => a + b.count, 0) || 1;

  const ticketSort = useTableSort(TICKETS, 'opened', 'desc');

  return (
    <div>
      <PageHeader title="Support Tickets" subtitle="Conversations with your account team" actions={<>
        <Btn variant="secondary" size="sm" icon={I.filter}>Filter</Btn>
        <Btn variant="primary" size="sm" icon={I.plus}>New Ticket</Btn>
      </>} />

      {/* Stat strip — each tile gets a tinted icon tile + an inline graph */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 16 }}>
        {[
          {
            label: 'Open',
            value: totalOpen,
            sub: 'across this client',
            icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>,
            color: 'var(--primary)',
            graph: <MiniBars data={weeklyOpen} color="var(--primary)" />,
            graphLabel: 'Open backlog · 8 wk',
          },
          {
            label: 'Awaiting reply',
            value: totalAwaiting,
            sub: 'on you · oldest 2 days',
            icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 7v5l3 2"/></svg>,
            color: 'var(--warning)',
            graph: (
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--text-muted)' }}>
                <span style={{
                  width: 8, height: 8, borderRadius: '50%', background: 'var(--warning)',
                  animation: 'kpiPulse 2s ease-in-out infinite', color: 'var(--warning)',
                }}/>
                Reply needed
              </div>
            ),
            graphLabel: '',
          },
          {
            label: 'Resolved this month',
            value: 7,
            sub: '+2 vs last month',
            icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>,
            color: 'var(--positive)',
            graph: <MiniBars data={weeklyResolved} color="var(--positive)" />,
            graphLabel: 'Resolved · 8 wk',
          },
          {
            label: 'Avg first response',
            value: '46m',
            sub: '−13m vs last month',
            icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="13" r="8"/><path d="M12 9v4l2 2"/><path d="M9 2h6"/><path d="M12 7V5"/></svg>,
            color: 'var(--positive)',
            graph: <MiniLine data={weeklyResponse} color="var(--positive)" />,
            graphLabel: 'Response time · 8 wk',
          },
        ].map(s => (
          <Card key={s.label}>
            <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
              <div style={{
                width: 36, height: 36, borderRadius: 8, flexShrink: 0,
                background: `color-mix(in oklab, ${s.color} 14%, transparent)`,
                color: s.color,
                display: 'grid', placeItems: 'center',
              }}>{s.icon}</div>
              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ fontSize: 11, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
                <div style={{ fontSize: 24, fontWeight: 700, marginTop: 2, letterSpacing: '-0.02em', fontVariantNumeric: 'tabular-nums' }}>{s.value}</div>
                <div style={{
                  fontSize: 11, marginTop: 1,
                  color: s.sub.startsWith('+') ? 'var(--positive)'
                       : s.sub.startsWith('−') ? 'var(--positive)'
                       : 'var(--text-muted)',
                }}>{s.sub}</div>
              </div>
            </div>
            {s.graph && (
              <div style={{ marginTop: 10 }}>
                {s.graph}
                {s.graphLabel && (
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 4, display: 'flex', justifyContent: 'space-between' }}>
                    <span>{s.graphLabel}</span>
                    <span style={{ fontFamily: 'JetBrains Mono' }}>now</span>
                  </div>
                )}
              </div>
            )}
          </Card>
        ))}
      </div>

      <Card padding={0}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)' }}>
              {[
                { key: 'id',       label: 'ID' },
                { key: 'subject',  label: 'Subject' },
                { key: 'priority', label: 'Priority' },
                { key: 'status',   label: 'Status' },
                { key: 'assignee', label: 'Assignee' },
                { key: 'opened',   label: 'Opened' },
              ].map(c => (
                <SortableTh key={c.key} sortKey={c.key} currentKey={ticketSort.sortKey} dir={ticketSort.sortDir} onSort={ticketSort.onSort}>{c.label}</SortableTh>
              ))}
            </tr>
          </thead>
          <tbody>
            {ticketSort.sorted.map((t, i) => {
              const sm = TICKET_STATUS_META[t.status] || TICKET_STATUS_META['Open'];
              const pm = TICKET_PRIORITY_META[t.priority] || TICKET_PRIORITY_META['Normal'];
              return (
                <tr key={t.id} style={{ borderBottom: i < ticketSort.sorted.length - 1 ? '1px solid var(--border)' : 'none', cursor: 'pointer' }}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  <td style={{ padding: '12px 14px', fontFamily: 'JetBrains Mono', fontSize: 12, color: 'var(--text-muted)' }}>{t.id}</td>
                  <td style={{ padding: '12px 14px', fontWeight: 500 }}>{t.subject}</td>
                  <td style={{ padding: '12px 14px' }}>
                    <span style={{
                      display: 'inline-flex', alignItems: 'center', gap: 6,
                      padding: '3px 9px 3px 7px', borderRadius: 99,
                      background: pm.bg, color: pm.fg,
                      fontSize: 11, fontWeight: 600,
                    }}>
                      <span style={{ display: 'inline-grid', placeItems: 'center' }}>{pm.icon}</span>
                      {t.priority}
                    </span>
                  </td>
                  <td style={{ padding: '12px 14px' }}>
                    <span style={{
                      display: 'inline-flex', alignItems: 'center', gap: 6,
                      padding: '3px 9px 3px 7px', borderRadius: 99,
                      background: `color-mix(in oklab, ${sm.tone} 14%, transparent)`,
                      color: sm.tone,
                      fontSize: 11, fontWeight: 600,
                    }}>
                      <span style={{ display: 'inline-grid', placeItems: 'center' }}>{sm.icon}</span>
                      {t.status}
                    </span>
                  </td>
                  <td style={{ padding: '12px 14px' }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                      <PersonAvatar name={t.assignee} size={20} hue={200} src={
                        t.assignee === 'Joe Marshall'  ? 'assets/team/joe.png'  :
                        t.assignee === 'Matt Jones'    ? 'assets/team/matt.png' :
                        t.assignee === 'Nathan Smith'  ? 'assets/team/nathan.png' :
                        undefined
                      } />
                      <span style={{ color: 'var(--text-muted)' }}>{t.assignee}</span>
                    </span>
                  </td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>{t.opened}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </Card>
    </div>
  );
};

// ============================================================
// Ask Clicky (AI chat)
// ============================================================

// =============================================================
// AskAnythingLightbox — modal launcher for ClickyAI shown when
// the user clicks any "Ask ClickyAI" rainbow button. Surfaces
// the composer + suggestion chips inline so the question can be
// asked without leaving the current screen. On submit, the
// lightbox closes and routes to the full Ask page with the
// query pre-staged so the response renders there.
// =============================================================
const AskAnythingLightbox = ({ onClose, onSubmit }) => {
  const [input, setInput] = useState('');

  const send = (text) => {
    const t = (text || '').trim();
    if (!t) return;
    onSubmit(t);
  };

  return (
    <div
      onClick={onClose}
      style={{
        position: 'fixed', inset: 0, zIndex: 200,
        background: 'rgba(15,23,42,0.45)',
        backdropFilter: 'blur(6px)',
        display: 'grid', placeItems: 'center',
        padding: 24,
        animation: 'searchFade 180ms ease-out',
      }}
    >
      <div
        onClick={e => e.stopPropagation()}
        className="clicky-ai-border"
        style={{
          position: 'relative',
          width: '100%', maxWidth: 660,
          borderRadius: 'var(--radius)',
          boxShadow: '0 24px 60px rgba(15,23,42,0.30)',
          overflow: 'hidden',
        }}
      >
        <div style={{
          background: 'var(--surface)',
          padding: '28px 28px 24px',
          display: 'flex', flexDirection: 'column', gap: 18,
        }}>
          {/* Close */}
          <button
            onClick={onClose}
            aria-label="Close"
            style={{
              position: 'absolute', top: 12, right: 12,
              width: 30, height: 30, borderRadius: 8,
              background: 'var(--surface-2)', color: 'var(--text-muted)',
              border: '1px solid var(--border)', cursor: 'pointer',
              display: 'grid', placeItems: 'center', fontSize: 18, lineHeight: 1,
              fontFamily: 'inherit',
            }}
          >×</button>

          {/* Hero */}
          <div style={{ textAlign: 'center', maxWidth: 480, margin: '4px auto 0' }}>
            <div style={{
              width: 52, height: 52, borderRadius: '50%', margin: '0 auto 12px',
              background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
            }}>
              <img src="assets/ai-ask.svg" alt="" width="30" height="30" style={{ display: 'block' }} />
            </div>
            <h2 style={{ fontSize: 20, fontWeight: 700, margin: '0 0 4px', letterSpacing: '-0.02em' }}>Ask ClickyAI anything</h2>
            <p style={{ fontSize: 12.5, color: 'var(--text-muted)', margin: 0, lineHeight: 1.55 }}>
              Type a question or pick a starter — your answer will appear in the full Ask page.
            </p>
          </div>

          {/* Composer */}
          <div className="clicky-ai-box is-collapsed" style={{
            display: 'flex', alignItems: 'center', gap: 8,
            borderRadius: 'var(--radius)', padding: 4,
          }}>
            <button style={{ width: 32, height: 32, border: 'none', background: 'transparent', color: 'var(--text-muted)', borderRadius: 6, display: 'grid', placeItems: 'center', cursor: 'pointer' }}>{I.paperclip}</button>
            <input
              autoFocus
              value={input}
              onChange={e => setInput(e.target.value)}
              onKeyDown={e => {
                if (e.key === 'Enter') { e.preventDefault(); send(input); }
                if (e.key === 'Escape') { e.preventDefault(); onClose(); }
              }}
              placeholder="Ask about performance, suggest optimisations…"
              style={{ flex: 1, height: 36, border: 'none', background: 'transparent', outline: 'none', fontSize: 13.5, color: 'var(--text)' }}
            />
            <Btn variant="primary" size="sm" icon={I.send} onClick={() => send(input)} disabled={!input.trim()}>Send</Btn>
          </div>

          {/* Suggestions */}
          <div>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Try one of these</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
              {ASK_AMPLIFY_SUGGESTIONS.slice(0, 4).map(s => (
                <button key={s} onClick={() => send(s)} style={{
                  padding: '10px 12px', background: 'var(--surface-2)',
                  border: '1px solid var(--border)', borderRadius: 'var(--radius)',
                  color: 'var(--text)', fontSize: 12.5, cursor: 'pointer', textAlign: 'left',
                  display: 'flex', alignItems: 'center', gap: 8, fontFamily: 'inherit',
                }}
                  onMouseEnter={e => e.currentTarget.style.borderColor = 'var(--primary)'}
                  onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--border)'}
                >
                  <img src="assets/ai-ask.svg" alt="" width="14" height="14" style={{ display: 'block', flexShrink: 0 }} />
                  <span style={{ flex: 1 }}>{s}</span>
                  <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
                </button>
              ))}
            </div>
          </div>

          <div style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
            paddingTop: 4, borderTop: '1px dashed var(--border)',
          }}>
            <span style={{ fontSize: 11, color: 'var(--text-faint)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
              <GeminiMark size={11} /> Powered by Gemini · responses in the full Ask page
            </span>
            <button
              onClick={() => { onClose(); window.dispatchEvent(new CustomEvent('clicky:openAskFull')); }}
              style={{
                background: 'none', border: 'none', color: 'var(--primary)',
                fontSize: 11.5, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit',
              }}
            >
              Open full Ask page →
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

const AskScreen = ({ initialQuery, onQueryConsumed } = {}) => {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState('');
  const [thinking, setThinking] = useState(false);
  const scrollRef = useRef(null);

  useEffect(() => {
    scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });
  }, [messages, thinking]);

  const send = async (text) => {
    if (!text.trim()) return;
    const userMsg = { role: 'user', content: text };
    setMessages(m => [...m, userMsg]);
    setInput('');
    setThinking(true);
    try {
      const reply = await window.claude.complete({
        messages: [
          { role: 'user', content: `You are Clicky, a friendly UK-based digital advertising assistant for a Google Ads dashboard. The user is Daniel at Evergreen Escapes, a self-catering lodge holiday park in Cornwall. Keep replies under 120 words, use British English. Be professional and action-oriented. User question: ${text}` },
        ],
      });
      setMessages(m => [...m, { role: 'assistant', content: reply }]);
    } catch (e) {
      setMessages(m => [...m, { role: 'assistant', content: 'Sorry — I had trouble reaching the model. Try again in a moment.' }]);
    }
    setThinking(false);
  };

  // If the parent passes in an initialQuery (e.g. from the Ask lightbox),
  // auto-send it once and tell the parent to clear it so we don't loop.
  useEffect(() => {
    if (initialQuery && messages.length === 0 && !thinking) {
      send(initialQuery);
      if (onQueryConsumed) onQueryConsumed();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [initialQuery]);

  const isEmpty = messages.length === 0 && !thinking;

  const Composer = (
    <div>
      <div className="clicky-ai-box is-collapsed" style={{ maxWidth: 760, margin: '0 auto', display: 'flex', alignItems: 'center', gap: 8,
        borderRadius: 'var(--radius)', padding: 4,
      }}>
        <button style={{ width: 32, height: 32, border: 'none', background: 'transparent', color: 'var(--text-muted)', borderRadius: 6, display: 'grid', placeItems: 'center', cursor: 'pointer' }}>{I.paperclip}</button>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter') send(input); }}
          placeholder="Ask about performance, suggest optimisations…"
          style={{ flex: 1, height: 32, border: 'none', background: 'transparent', outline: 'none', fontSize: 13, color: 'var(--text)' }}
        />
        <Btn variant="primary" size="sm" icon={I.send} onClick={() => send(input)} disabled={!input.trim()}>Send</Btn>
      </div>
      <div style={{ maxWidth: 760, margin: '8px auto 0', fontSize: 11, color: 'var(--text-faint)', textAlign: 'center' }}>
        Clicky can make mistakes. Verify critical numbers in your reports.
      </div>
    </div>
  );

  return (
    <div>
      {/* Channel-style header — matches Growth Opportunities + Account Insights */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)',
            background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center',
            flexShrink: 0,
          }}>
            <img src="assets/ai-ask.svg" alt="" width="22" height="22" style={{ display: 'block' }} />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Ask Anything</h1>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 5,
                fontSize: 11, fontWeight: 500, color: 'var(--text-muted)',
                padding: '3px 8px', borderRadius: 99,
                background: 'var(--surface-2)', border: '1px solid var(--border)',
              }}>
                <GeminiMark size={16} /> Powered by Gemini
              </span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
              Your AI assistant for performance, optimisations and reporting
            </div>
          </div>
        </div>
      </div>

      {isEmpty ? (
        // Empty state: hero + composer + suggestions stacked together near the top,
        // followed by a "Joe explainer" speech bubble below.
        <>
        <Card padding={24} style={{ maxWidth: 820, margin: '0 auto' }}>
          <div style={{ maxWidth: 640, margin: '8px auto 20px', textAlign: 'center' }}>
            <div style={{
              width: 48, height: 48, borderRadius: '50%', margin: '0 auto 12px',
              background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
            }}>
              <img src="assets/ai-ask.svg" alt="" width="28" height="28" style={{ display: 'block' }} />
            </div>
            <h2 style={{ fontSize: 18, fontWeight: 700, margin: '0 0 4px', letterSpacing: '-0.02em' }}>How can I help today?</h2>
            <p style={{ fontSize: 12.5, color: 'var(--text-muted)', margin: 0 }}>Ask anything about your accounts. I have context on the last 30 days of performance.</p>
          </div>

          {Composer}

          <div style={{ maxWidth: 760, margin: '20px auto 0' }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Try one of these</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, textAlign: 'left' }}>
              {ASK_AMPLIFY_SUGGESTIONS.map(s => (
                <button key={s} onClick={() => send(s)} style={{
                  padding: '10px 12px', background: 'var(--surface-2)',
                  border: '1px solid var(--border)', borderRadius: 'var(--radius)',
                  color: 'var(--text)', fontSize: 12.5, cursor: 'pointer', textAlign: 'left',
                  display: 'flex', alignItems: 'center', gap: 8,
                }}
                  onMouseEnter={e => e.currentTarget.style.borderColor = 'var(--primary)'}
                  onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--border)'}
                >
                  <img src="assets/ai-ask.svg" alt="" width="16" height="16" style={{ display: 'block', flexShrink: 0 }} />
                  <span style={{ flex: 1 }}>{s}</span>
                  <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
                </button>
              ))}
            </div>
          </div>
        </Card>

        {/* Joe explainer — sets expectations for what Ask Anything is good at,
            framed as a personal note. Same speech-bubble pattern as Account
            Insights so the AM presence feels consistent across AI surfaces. */}
        {(() => {
          const am = TEAM.find(p => p.primary) || TEAM.find(p => p.name === 'Joe Marshall');
          const firstName = am?.name?.split(' ')[0] || 'your AM';
          return (
            <div style={{ maxWidth: 820, margin: '24px auto 0', padding: '0 8px', display: 'flex', flexDirection: 'column', gap: 10 }}>
              {/* AM byline */}
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                {am && <PersonAvatar name={am.name} size={40} hue={am.hue} src={am.src} />}
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontSize: 10.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                    A note from {firstName}
                  </div>
                  <div style={{ fontSize: 13, color: 'var(--text)', fontWeight: 600, marginTop: 1 }}>{am?.name || 'Your account manager'}</div>
                </div>
              </div>

              {/* Speech bubble */}
              <div style={{ position: 'relative', marginLeft: 24, paddingTop: 8 }}>
                <div style={{
                  position: 'absolute', top: 0, left: 16,
                  width: 0, height: 0,
                  borderLeft: '9px solid transparent',
                  borderRight: '9px solid transparent',
                  borderBottom: '9px solid color-mix(in oklab, var(--primary) 22%, var(--border))',
                }}/>
                <div style={{
                  position: 'absolute', top: 1, left: 17,
                  width: 0, height: 0,
                  borderLeft: '8px solid transparent',
                  borderRight: '8px solid transparent',
                  borderBottom: '8px solid color-mix(in oklab, var(--primary) 5%, var(--surface))',
                  zIndex: 2,
                }}/>

                <div style={{
                  position: 'relative',
                  padding: '14px 16px 12px',
                  background: 'color-mix(in oklab, var(--primary) 5%, var(--surface))',
                  border: '1px solid color-mix(in oklab, var(--primary) 22%, var(--border))',
                  borderRadius: 14,
                  display: 'flex', flexDirection: 'column', gap: 12,
                }}>
                  <p style={{ margin: 0, fontSize: 12.5, lineHeight: 1.6, color: 'var(--text)' }}>
                    Hi {CLIENT.contact?.split(' ')[0] || 'there'} — quick rundown on what ClickyAI™ is good at, and when you should just ping me instead.
                  </p>

                  <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                    {[
                      {
                        title: "What it's great at",
                        desc: 'Explaining numbers, summarising 30 days of performance, suggesting optimisations, drafting client-side updates, comparing channels.',
                      },
                      {
                        title: "What it has access to",
                        desc: "Your live performance data across every channel we manage, your Performance Targets, recent reports and tickets — all the same data I see.",
                      },
                      {
                        title: "When to ping me instead",
                        desc: "Anything strategic, contractual, or where you want a judgement call — those land better with a human. I'm an email away.",
                      },
                    ].map((s, i) => (
                      <div key={i} style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
                        <div style={{
                          width: 4, height: 4, borderRadius: '50%',
                          background: 'var(--primary)', flexShrink: 0, marginTop: 7, opacity: 0.7,
                        }}/>
                        <div style={{ minWidth: 0, flex: 1 }}>
                          <div style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--text)' }}>{s.title}</div>
                          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1, lineHeight: 1.5 }}>{s.desc}</div>
                        </div>
                      </div>
                    ))}
                  </div>

                  <p style={{ margin: 0, fontSize: 12, lineHeight: 1.55, color: 'var(--text)' }}>
                    Verify any critical numbers in your reports — and if a reply doesn't sit right, tell me. ClickyAI gets sharper the more we correct it.
                  </p>

                  <div style={{
                    fontSize: 12, color: 'var(--text-muted)', fontStyle: 'italic',
                    marginTop: -2,
                  }}>
                    — {firstName}
                  </div>
                </div>
              </div>

              <div style={{
                marginLeft: 24,
                fontSize: 10.5, color: 'var(--text-faint)',
                display: 'flex', alignItems: 'center', gap: 6,
                paddingTop: 4,
              }}>
                <GeminiMark size={11} />
                <span>Powered by Gemini · context refreshed live</span>
              </div>
            </div>
          );
        })()}
        </>
      ) : (
        // Active state: chat history grows up to a max-height, composer below.
        <Card padding={0} style={{ display: 'flex', flexDirection: 'column' }}>
          <div ref={scrollRef} style={{
            maxHeight: 'calc(100vh - 320px)', minHeight: 240,
            overflowY: 'auto', padding: 24,
          }}>
            <div style={{ maxWidth: 760, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 16 }}>
              {messages.map((m, i) => (
                <div key={i} style={{ display: 'flex', gap: 12, alignItems: 'flex-start', flexDirection: m.role === 'user' ? 'row-reverse' : 'row' }}>
                  {m.role === 'user'
                    ? <Avatar name="LS" size={28} />
                    : <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'color-mix(in oklab, var(--primary) 12%, transparent)', color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>{I.sparkles}</div>}
                  <div style={{
                    maxWidth: '80%',
                    background: m.role === 'user' ? 'var(--primary)' : 'var(--surface-2)',
                    color: m.role === 'user' ? '#fff' : 'var(--text)',
                    border: m.role === 'user' ? 'none' : '1px solid var(--border)',
                    padding: '12px 14px', borderRadius: 12,
                    fontSize: 13, lineHeight: 1.55, whiteSpace: 'pre-wrap',
                  }}>{m.content}</div>
                </div>
              ))}
              {thinking && (
                <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
                  <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'color-mix(in oklab, var(--primary) 12%, transparent)', color: 'var(--primary)', display: 'grid', placeItems: 'center' }}>{I.sparkles}</div>
                  <div style={{ display: 'flex', gap: 4 }}>
                    {[0,1,2].map(i => <span key={i} style={{
                      width: 6, height: 6, borderRadius: '50%', background: 'var(--text-faint)',
                      animation: `pulse 1.2s ease-in-out ${i*0.15}s infinite`,
                    }}/>)}
                  </div>
                  <style>{`@keyframes pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }`}</style>
                </div>
              )}
            </div>
          </div>

          <div style={{ padding: 16, borderTop: '1px solid var(--border)', background: 'var(--surface)' }}>
            {Composer}
          </div>
        </Card>
      )}
    </div>
  );
};

// ============================================================
// My Ad Channels — master/landing page. Tiles for each ACTIVE
// channel (linked accounts shown), plus a tile for adding more.
// Acts as a hub before drilling into a specific channel screen.
// ============================================================

const buildSpark = (seed, n = 14, base = 50, amp = 30) => {
  // Deterministic-ish noise from seed string
  let s = 0;
  for (let i = 0; i < seed.length; i++) s = (s * 31 + seed.charCodeAt(i)) >>> 0;
  const out = [];
  for (let i = 0; i < n; i++) {
    s = (s * 1664525 + 1013904223) >>> 0;
    const r = (s % 1000) / 1000;
    out.push({ x: i, y: base + Math.sin(i / 2.2 + (s % 7)) * amp * 0.5 + r * amp });
  }
  return out;
};

const ChannelTile = ({ channel, onOpen }) => {
  const { AreaChart, Area, ResponsiveContainer } = window.Recharts;
  const sparkData = buildSpark(channel.id);
  const trendUp = channel.delta && channel.delta.startsWith('+');

  return (
    <button
      onClick={() => onOpen(channel.target || 'google')}
      style={{
        textAlign: 'left', padding: 0,
        background: 'var(--surface)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--radius)',
        cursor: 'pointer',
        transition: 'border-color 0.12s, box-shadow 0.12s, transform 0.05s',
        display: 'flex', flexDirection: 'column',
        overflow: 'hidden',
      }}
      onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; }}
      onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; }}
    >
      {/* Header */}
      <div style={{ padding: '14px 16px', display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
          <div style={{
            width: 36, height: 36, borderRadius: 8,
            background: 'var(--surface-2)',
            border: '1px solid var(--border)',
            display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>{channel.icon}</div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{channel.label}</div>
            <div style={{ fontSize: 11, color: 'var(--positive)', fontWeight: 500, display: 'flex', alignItems: 'center', gap: 4 }}>
              <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--positive)' }}/>
              Active · {channel.accountCount} {channel.accountCount === 1 ? 'account' : 'accounts'}
            </div>
          </div>
        </div>
        <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
      </div>

      {/* Linked accounts list */}
      <div style={{ padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 4 }}>
        {channel.accounts.map(a => (
          <div key={a.name} style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            padding: '6px 0', fontSize: 11.5,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
              <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--positive)', flexShrink: 0 }}/>
              <span style={{ color: 'var(--text)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</span>
            </div>
            <span style={{ color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', fontSize: 10.5, flexShrink: 0, marginLeft: 8 }}>{a.id}</span>
          </div>
        ))}
      </div>

      {/* Spark + KPIs */}
      <div style={{ padding: '12px 16px 0' }}>
        <div style={{ height: 44, marginLeft: -4, marginRight: -4 }}>
          <ResponsiveContainer width="100%" height="100%">
            <AreaChart data={sparkData} margin={{ top: 4, right: 4, bottom: 0, left: 4 }}>
              <defs>
                <linearGradient id={`spark-${channel.id}`} x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor="var(--primary)" stopOpacity={0.32}/>
                  <stop offset="100%" stopColor="var(--primary)" stopOpacity={0}/>
                </linearGradient>
              </defs>
              <Area type="monotone" dataKey="y" stroke="var(--primary)" strokeWidth={1.6} fill={`url(#spark-${channel.id})`} />
            </AreaChart>
          </ResponsiveContainer>
        </div>
      </div>

      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
        padding: '10px 16px 14px', gap: 8,
      }}>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>{channel.organic ? 'Organic · 30d' : 'Spend · 30d'}</div>
          <div style={{ fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{channel.organic ? '4.2k' : channel.spend}</div>
        </div>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Bookings</div>
          <div style={{ fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{channel.bookings}</div>
        </div>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>vs prev</div>
          <div style={{
            fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2,
            color: trendUp ? 'var(--positive)' : 'var(--negative)',
          }}>{channel.delta}</div>
        </div>
      </div>
    </button>
  );
};

// Tile for the Website Maintenance Pro service — same outer dimensions as
// ChannelTile but the inner content reflects per-site health + open requests
// rather than ad spend.
const MaintenanceTile = ({ onOpen }) => {
  const allSites = window.CLIENT?.sites || [];
  const activeSites = allSites.filter(s => s.status === 'active');
  const healthMap = SITE_HEALTH;
  const reqs = CHANGE_REQUESTS.filter(r => activeSites.some(s => s.id === r.site));

  const uptimeAvg = activeSites.length
    ? activeSites.reduce((sum, s) => sum + (healthMap[s.id]?.uptime30 || 0), 0) / activeSites.length
    : 0;
  const speedAvg = activeSites.length
    ? Math.round(activeSites.reduce((sum, s) => sum + (healthMap[s.id]?.perf?.score || 0), 0) / activeSites.length)
    : 0;
  const openCount   = reqs.filter(r => r.status !== 'done').length;
  const urgentCount = reqs.filter(r => r.status !== 'done' && (r.priority === 'urgent' || r.priority === 'high')).length;

  // For the mini bar — recent uptime samples from the first active site
  const uptimeBars = healthMap[activeSites[0]?.id]?.uptimeDaily?.slice(-30) || [];

  return (
    <button
      onClick={() => onOpen('maintenance')}
      style={{
        textAlign: 'left', padding: 0,
        background: 'var(--surface)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--radius)',
        cursor: 'pointer',
        transition: 'border-color 0.12s, box-shadow 0.12s',
        display: 'flex', flexDirection: 'column',
        overflow: 'hidden',
      }}
      onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; }}
      onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'none'; }}
    >
      {/* Header */}
      <div style={{ padding: '14px 16px', display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
          <div style={{
            width: 36, height: 36, borderRadius: 8,
            background: 'var(--surface-2)',
            border: '1px solid var(--border)',
            display: 'grid', placeItems: 'center', flexShrink: 0,
            color: 'var(--primary)',
          }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
              <path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/>
            </svg>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>Website Maintenance Pro</div>
            <div style={{ fontSize: 11, color: 'var(--positive)', fontWeight: 500, display: 'flex', alignItems: 'center', gap: 4 }}>
              <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--positive)' }}/>
              Active · {activeSites.length} {activeSites.length === 1 ? 'site' : 'sites'}
            </div>
          </div>
        </div>
        <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
      </div>

      {/* Sites list (mirrors the accounts list on ChannelTile) */}
      <div style={{ padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 4 }}>
        {activeSites.slice(0, 3).map(s => {
          const h = healthMap[s.id];
          const ok = h && h.uptime30 >= 99.9 && h.perf?.score >= 80;
          const dot = !h ? 'var(--text-faint)'
                    : h.uptime30 < 99 ? 'var(--negative)'
                    : (h.uptime30 < 99.9 || h.perf?.score < 80) ? 'var(--warning)'
                    : 'var(--positive)';
          return (
            <div key={s.id} style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              padding: '6px 0', fontSize: 11.5,
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
                <span style={{ width: 5, height: 5, borderRadius: '50%', background: dot, flexShrink: 0 }}/>
                <span style={{ color: 'var(--text)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{s.name}</span>
              </div>
              <span style={{ color: 'var(--text-faint)', fontFamily: 'JetBrains Mono', fontSize: 10.5, flexShrink: 0, marginLeft: 8 }}>
                {h ? h.uptime30.toFixed(2) + '%' : '—'}
              </span>
            </div>
          );
        })}
      </div>

      {/* Mini uptime strip (in place of the ad-spend sparkline) */}
      <div style={{ padding: '12px 16px 0' }}>
        <div style={{ display: 'flex', gap: 1.5, alignItems: 'flex-end', height: 32 }}>
          {uptimeBars.map((u, i) => {
            const tone = u >= 99.9 ? 'var(--positive)'
                       : u >= 99   ? 'var(--warning)'
                       : 'var(--negative)';
            return (
              <div key={i}
                title={`Day ${i + 1}: ${u.toFixed(2)}% uptime`}
                style={{ flex: 1, height: '100%', background: tone, borderRadius: 1, opacity: u >= 99.9 ? 0.85 : 1 }}/>
            );
          })}
        </div>
      </div>

      {/* Metrics row — uptime / page speed / open requests */}
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
        padding: '10px 16px 14px', gap: 8,
      }}>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Uptime · 30d</div>
          <div style={{
            fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2,
            color: uptimeAvg >= 99.9 ? 'var(--positive)' : uptimeAvg >= 99 ? 'var(--warning)' : 'var(--negative)',
          }}>{uptimeAvg ? uptimeAvg.toFixed(2) + '%' : '—'}</div>
        </div>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Page speed</div>
          <div style={{
            fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2,
            color: speedAvg >= 90 ? 'var(--positive)' : speedAvg >= 70 ? 'var(--warning)' : 'var(--negative)',
          }}>{speedAvg || '—'}</div>
        </div>
        <div>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Open req.</div>
          <div style={{
            fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2,
            color: urgentCount ? 'var(--warning)' : 'var(--text)',
          }}>{openCount}{urgentCount ? <span style={{ fontSize: 10, marginLeft: 4, color: 'var(--negative)' }}>● {urgentCount}</span> : null}</div>
        </div>
      </div>
    </button>
  );
};

const AddChannelTile = ({ channel, onPick }) => (
  <button
    onClick={() => onPick && onPick(channel)}
    style={{
      textAlign: 'left', padding: 0,
      background: 'var(--surface)',
      border: '1px dashed var(--border-strong)',
      borderRadius: 'var(--radius)',
      cursor: 'pointer',
      transition: 'border-color 0.12s, box-shadow 0.12s, background 0.12s',
      display: 'flex', flexDirection: 'column',
      overflow: 'hidden',
    }}
    onMouseEnter={e => {
      e.currentTarget.style.borderColor = 'var(--primary)';
      e.currentTarget.style.background = 'color-mix(in oklab, var(--primary) 4%, var(--surface))';
      e.currentTarget.style.boxShadow = 'var(--shadow-md)';
    }}
    onMouseLeave={e => {
      e.currentTarget.style.borderColor = 'var(--border-strong)';
      e.currentTarget.style.background = 'var(--surface)';
      e.currentTarget.style.boxShadow = 'none';
    }}
  >
    {/* Header — mirrors ChannelTile header */}
    <div style={{ padding: '14px 16px', display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
        <div style={{
          width: 36, height: 36, borderRadius: 8,
          background: 'var(--surface-2)',
          border: '1px solid var(--border)',
          display: 'grid', placeItems: 'center', flexShrink: 0,
          filter: 'grayscale(1)', opacity: 0.7,
        }}>{channel.icon}</div>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{channel.label}</div>
          <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 500, display: 'flex', alignItems: 'center', gap: 4 }}>
            <span style={{
              width: 6, height: 6, borderRadius: '50%',
              background: 'transparent', border: '1.5px dashed var(--text-faint)',
            }}/>
            Available to connect
          </div>
        </div>
      </div>
      <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
    </div>

    {/* Blurb — equivalent visual weight to ChannelTile's accounts list + sparkline */}
    <div style={{ padding: '0 16px', flex: 1 }}>
      <div style={{ fontSize: 12.5, color: 'var(--text-muted)', lineHeight: 1.5 }}>
        {channel.blurb || channel.hint}
      </div>
    </div>

    {/* Stats row — matches ChannelTile's 3-cell metric row */}
    <div style={{
      display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
      padding: '14px 16px 0', gap: 8,
    }}>
      {(channel.stats || []).map((s, i) => (
        <div key={i}>
          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>{s.label}</div>
          <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2, color: 'var(--text-muted)' }}>{s.value}</div>
        </div>
      ))}
    </div>

    {/* CTA footer — full-width Add button */}
    <div style={{ padding: '12px 16px 14px' }}>
      <span style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
        width: '100%', padding: '8px 12px',
        borderRadius: 6,
        background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
        color: 'var(--primary)',
        fontSize: 12, fontWeight: 600,
      }}>
        {I.plus} Add channel
      </span>
    </div>
  </button>
);

// ============================================================
// SEO Channel Screen — organic search visibility for st-mabyn-escape.co.uk
// Shows GSC-style KPIs, top queries/pages, ranking distribution,
// backlinks profile, and a list of in-flight content/technical tasks.
// ============================================================

const SEO_KPIS = [
  { key: 'clicks',      label: 'Organic clicks',    value: '4,219',  delta: '+18.6%', deltaTone: 'positive', spark: [62, 70, 64, 78, 82, 88, 94, 91, 102, 108, 115, 122] },
  { key: 'impressions', label: 'Impressions',       value: '128.4k', delta: '+9.2%',  deltaTone: 'positive', spark: [80, 78, 84, 82, 88, 86, 92, 96, 98, 104, 110, 118] },
  { key: 'ctr',         label: 'Average CTR',       value: '3.29%',  delta: '+0.4pp', deltaTone: 'positive', spark: [50, 48, 52, 54, 56, 58, 56, 60, 62, 60, 64, 66] },
  { key: 'pos',         label: 'Average position',  value: '12.4',   delta: '−1.8',   deltaTone: 'positive', spark: [80, 78, 75, 72, 70, 68, 65, 62, 60, 58, 55, 52] },
];

const SEO_TOP_QUERIES = [
  { q: 'cornwall lodge holidays',           clicks: 412, imp: 8420,  ctr: '4.9%',  pos: 5.2,  delta: '+12%' },
  { q: 'st mabyn lodge escape',             clicks: 318, imp: 1240,  ctr: '25.6%', pos: 1.4,  delta: '+8%'  },
  { q: 'lodges with hot tubs cornwall',     clicks: 286, imp: 6890,  ctr: '4.2%',  pos: 6.8,  delta: '+22%' },
  { q: 'self catering cornwall coast',      clicks: 214, imp: 9320,  ctr: '2.3%',  pos: 11.4, delta: '+4%'  },
  { q: 'dog friendly lodges cornwall',      clicks: 198, imp: 5470,  ctr: '3.6%',  pos: 8.2,  delta: '+18%' },
  { q: 'cornwall lodges for families',      clicks: 162, imp: 7240,  ctr: '2.2%',  pos: 12.6, delta: '−3%'  },
  { q: 'lodge ownership cornwall',          clicks: 128, imp: 2180,  ctr: '5.9%',  pos: 4.8,  delta: '+44%' },
  { q: 'st mabyn cornwall',                 clicks: 104, imp: 720,   ctr: '14.4%', pos: 2.1,  delta: '+2%'  },
];

const SEO_TOP_PAGES = [
  { url: '/',                            clicks: 968, imp: 18420, ctr: '5.3%' },
  { url: '/lodges/orchard-meadow',       clicks: 412, imp:  6240, ctr: '6.6%' },
  { url: '/ownership',                   clicks: 318, imp:  4180, ctr: '7.6%' },
  { url: '/things-to-do/north-cornwall', clicks: 286, imp:  9420, ctr: '3.0%' },
  { url: '/blog/lodge-with-hot-tub',     clicks: 198, imp:  5870, ctr: '3.4%' },
  { url: '/availability',                clicks: 164, imp:  2940, ctr: '5.6%' },
];

const SEO_RANK_BUCKETS = [
  { label: 'Pos 1–3',   count: 38,  pct: 0.18, tone: 'positive' },
  { label: 'Pos 4–10',  count: 86,  pct: 0.40, tone: 'primary'  },
  { label: 'Pos 11–20', count: 64,  pct: 0.30, tone: 'warning'  },
  { label: 'Pos 21–50', count: 18,  pct: 0.08, tone: 'neutral'  },
  { label: 'Pos 51+',   count:  8,  pct: 0.04, tone: 'neutral'  },
];

const SEO_TASKS = [
  { type: 'Content', title: 'Hot tub lodges hub page',           owner: 'Hayley Roberts', status: 'In review',  due: 'May 14' },
  { type: 'Tech',    title: 'Fix CWV — LCP on /lodges templates', owner: 'Nathan Smith',  status: 'In progress', due: 'May 9'  },
  { type: 'Content', title: 'Refresh ownership FAQ schema',      owner: 'Joe Marshall',   status: 'Drafting',   due: 'May 21' },
  { type: 'Links',   title: 'Outreach: Cornwall travel blogs',   owner: 'Shannon May',    status: 'Live',       due: '—'      },
  { type: 'Tech',    title: 'Internal linking audit (top 50)',   owner: 'Nathan Smith',   status: 'Scheduled',  due: 'Jun 2'  },
];

const SeoSparkline = ({ data, tone = 'primary' }) => {
  const { AreaChart, Area, ResponsiveContainer } = window.Recharts;
  const series = data.map((y, i) => ({ x: i, y }));
  const color = tone === 'positive' ? 'var(--positive)' : tone === 'warning' ? 'var(--warning)' : 'var(--primary)';
  return (
    <div style={{ height: 36, marginLeft: -4, marginRight: -4 }}>
      <ResponsiveContainer width="100%" height="100%">
        <AreaChart data={series} margin={{ top: 4, right: 4, bottom: 0, left: 4 }}>
          <defs>
            <linearGradient id={`seo-spark-${tone}`} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity={0.32}/>
              <stop offset="100%" stopColor={color} stopOpacity={0}/>
            </linearGradient>
          </defs>
          <Area type="monotone" dataKey="y" stroke={color} strokeWidth={1.6} fill={`url(#seo-spark-${tone})`} />
        </AreaChart>
      </ResponsiveContainer>
    </div>
  );
};

const SeoKpiCard = ({ kpi }) => (
  <Card>
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6 }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{kpi.label}</div>
      <div style={{ fontSize: 11, color: kpi.deltaTone === 'positive' ? 'var(--positive)' : 'var(--negative)', fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{kpi.delta}</div>
    </div>
    <div style={{ fontSize: 26, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em', marginBottom: 6 }}>{kpi.value}</div>
    <SeoSparkline data={kpi.spark} tone={kpi.deltaTone} />
  </Card>
);

const SeoScreen = ({ sparkStyle }) => {
  const [range, setRange] = useState('Last 30 Days');
  const [openRange, setOpenRange] = useState(false);
  const [tab, setTab] = useState('queries'); // queries | pages
  const ranges = ['Last 7 Days', 'Last 30 Days', 'Last 90 Days', 'Year to date'];

  const totalKw = SEO_RANK_BUCKETS.reduce((n, b) => n + b.count, 0);
  const top10  = SEO_RANK_BUCKETS.slice(0, 2).reduce((n, b) => n + b.count, 0);
  const querySort = useTableSort(SEO_TOP_QUERIES, 'clicks', 'desc');
  const pageSort  = useTableSort(SEO_TOP_PAGES,   'clicks', 'desc');

  return (
    <div>
      {/* Channel header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)', background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center', color: 'var(--primary)',
          }}>{I.seo}</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>SEO</h1>
              <Badge tone="positive">● Linked</Badge>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 6 }}>
              <span>st-mabyn-escape.co.uk</span>
              <span style={{ color: 'var(--text-faint)' }}>·</span>
              <span>Search Console + GA4</span>
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, position: 'relative' }}>
          <Btn variant="secondary" size="sm" icon={I.external}>Open in GSC</Btn>
          <div style={{ position: 'relative' }}>
            <Btn variant="secondary" size="sm" iconRight={I.chevDown} onClick={() => setOpenRange(o => !o)}>{range}</Btn>
            {openRange && (
              <div style={{
                position: 'absolute', right: 0, top: '110%', zIndex: 10,
                background: 'var(--surface)', border: '1px solid var(--border)',
                borderRadius: 'var(--radius)', boxShadow: 'var(--shadow-md)',
                minWidth: 160, padding: 4,
              }}>
                {ranges.map(r => (
                  <button key={r} onClick={() => { setRange(r); setOpenRange(false); }} style={{
                    display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 10px',
                    background: r === range ? 'var(--hover)' : 'transparent', border: 'none',
                    borderRadius: 4, cursor: 'pointer', fontSize: 13, color: 'var(--text)', textAlign: 'left',
                  }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = r === range ? 'var(--hover)' : 'transparent'}
                  >
                    <span style={{ width: 14, color: 'var(--primary)' }}>{r === range && I.check}</span>{r}
                  </button>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Section heading */}
      <div style={{ marginBottom: 14 }}>
        <h2 style={{ fontSize: 15, fontWeight: 600, margin: 0 }}>Organic Performance Overview</h2>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>From Google Search Console — last sync 2 hours ago</div>
      </div>

      {/* KPI grid */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 12, marginBottom: 20 }}>
        {SEO_KPIS.map(k => <SeoKpiCard key={k.key} kpi={k} />)}
      </div>

      {/* Top queries / pages with tabs */}
      <Card padding={0} style={{ marginBottom: 20 }}>
        <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', gap: 4 }}>
            {[
              { id: 'queries', label: 'Top queries' },
              { id: 'pages',   label: 'Top pages' },
            ].map(t => (
              <button key={t.id} onClick={() => setTab(t.id)} style={{
                padding: '6px 12px', fontSize: 13, fontWeight: 600,
                background: tab === t.id ? 'var(--surface-2)' : 'transparent',
                color: tab === t.id ? 'var(--text)' : 'var(--text-muted)',
                border: 'none', borderRadius: 6, cursor: 'pointer',
              }}>{t.label}</button>
            ))}
          </div>
          <Btn variant="ghost" size="sm" icon={I.download}>Export</Btn>
        </div>

        {tab === 'queries' ? (
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead>
              <tr style={{ background: 'var(--surface-2)' }}>
                <SortableTh sortKey="q"      currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>Query</SortableTh>
                <SortableTh sortKey="clicks" align="right" width={90}  currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>Clicks</SortableTh>
                <SortableTh sortKey="imp"    align="right" width={110} currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>Impressions</SortableTh>
                <SortableTh sortKey="ctr"    align="right" width={80}  currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>CTR</SortableTh>
                <SortableTh sortKey="pos"    align="right" width={90}  currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>Avg. pos</SortableTh>
                <SortableTh sortKey="delta"  align="right" width={80}  currentKey={querySort.sortKey} dir={querySort.sortDir} onSort={querySort.onSort}>Δ</SortableTh>
              </tr>
            </thead>
            <tbody>
              {querySort.sorted.map((q, i) => (
                <tr key={q.q} style={{ borderTop: '1px solid var(--border)' }}>
                  <td style={{ padding: '12px 14px', color: 'var(--text)', fontWeight: 500 }}>{q.q}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>{q.clicks}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{q.imp.toLocaleString()}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{q.ctr}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>{q.pos.toFixed(1)}</td>
                  <td style={{
                    padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 600,
                    color: q.delta.startsWith('+') ? 'var(--positive)' : 'var(--negative)',
                  }}>{q.delta}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : (
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead>
              <tr style={{ background: 'var(--surface-2)' }}>
                <SortableTh sortKey="url"    currentKey={pageSort.sortKey} dir={pageSort.sortDir} onSort={pageSort.onSort}>Page</SortableTh>
                <SortableTh sortKey="clicks" align="right" width={90}  currentKey={pageSort.sortKey} dir={pageSort.sortDir} onSort={pageSort.onSort}>Clicks</SortableTh>
                <SortableTh sortKey="imp"    align="right" width={110} currentKey={pageSort.sortKey} dir={pageSort.sortDir} onSort={pageSort.onSort}>Impressions</SortableTh>
                <SortableTh sortKey="ctr"    align="right" width={80}  currentKey={pageSort.sortKey} dir={pageSort.sortDir} onSort={pageSort.onSort}>CTR</SortableTh>
              </tr>
            </thead>
            <tbody>
              {pageSort.sorted.map(p => (
                <tr key={p.url} style={{ borderTop: '1px solid var(--border)' }}>
                  <td style={{ padding: '12px 14px', color: 'var(--text)', fontWeight: 500, fontFamily: 'JetBrains Mono', fontSize: 12 }}>{p.url}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>{p.clicks}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{p.imp.toLocaleString()}</td>
                  <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{p.ctr}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </Card>

      {/* Three-up: Rankings · Backlinks · CWV */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12, marginBottom: 20 }}>
        {/* Rankings distribution */}
        <Card padding={0}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Keyword rankings</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{totalKw} tracked</div>
          </div>
          <div style={{ padding: 16 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginBottom: 14 }}>
              <span style={{ fontSize: 26, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{top10}</span>
              <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>keywords in top 10</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {SEO_RANK_BUCKETS.map(b => (
                <div key={b.label} style={{ display: 'grid', gridTemplateColumns: '78px 1fr 36px', alignItems: 'center', gap: 10, fontSize: 12 }}>
                  <span style={{ color: 'var(--text-muted)' }}>{b.label}</span>
                  <div style={{ height: 6, background: 'var(--surface-2)', borderRadius: 3, overflow: 'hidden' }}>
                    <div style={{
                      width: `${b.pct * 100}%`, height: '100%',
                      background: b.tone === 'positive' ? 'var(--positive)' : b.tone === 'warning' ? 'var(--warning)' : b.tone === 'primary' ? 'var(--primary)' : 'var(--text-faint)',
                    }}/>
                  </div>
                  <span style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>{b.count}</span>
                </div>
              ))}
            </div>
          </div>
        </Card>

        {/* Backlinks */}
        <Card padding={0}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Backlinks</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>via Ahrefs</div>
          </div>
          <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div>
              <div style={{ fontSize: 11, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>Domain Rating</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 4 }}>
                <span style={{ fontSize: 26, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>34</span>
                <span style={{ fontSize: 11, color: 'var(--positive)', fontWeight: 600 }}>+2 this month</span>
              </div>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Referring domains</div>
                <div style={{ fontSize: 18, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>184</div>
                <div style={{ fontSize: 10, color: 'var(--positive)', fontWeight: 600 }}>+12 (30d)</div>
              </div>
              <div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Total backlinks</div>
                <div style={{ fontSize: 18, fontWeight: 600, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>2,840</div>
                <div style={{ fontSize: 10, color: 'var(--positive)', fontWeight: 600 }}>+86 (30d)</div>
              </div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 6 }}>Recent links</div>
              {[
                { d: 'visitcornwall.com',  dr: 76 },
                { d: 'coolplaces.co.uk',   dr: 58 },
                { d: 'cornwalllive.com',   dr: 81 },
              ].map(l => (
                <div key={l.d} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, padding: '4px 0', fontFamily: 'JetBrains Mono' }}>
                  <span style={{ color: 'var(--text)' }}>{l.d}</span>
                  <span style={{ color: 'var(--text-muted)' }}>DR {l.dr}</span>
                </div>
              ))}
            </div>
          </div>
        </Card>

        {/* Core Web Vitals */}
        <Card padding={0}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Core Web Vitals</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Mobile · 28d</div>
          </div>
          <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
            {[
              { k: 'LCP',  v: '2.1s',  status: 'Good',           tone: 'positive', sub: 'Largest Contentful Paint' },
              { k: 'INP',  v: '184ms', status: 'Good',           tone: 'positive', sub: 'Interaction to Next Paint' },
              { k: 'CLS',  v: '0.08',  status: 'Needs work',     tone: 'warning',  sub: 'Cumulative Layout Shift' },
            ].map(m => (
              <div key={m.k} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10 }}>
                <div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', fontWeight: 600 }}>{m.k}</div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>{m.sub}</div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <div style={{ fontSize: 18, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{m.v}</div>
                  <div style={{
                    fontSize: 10, fontWeight: 600,
                    color: m.tone === 'positive' ? 'var(--positive)' : m.tone === 'warning' ? 'var(--warning)' : 'var(--negative)',
                  }}>{m.status}</div>
                </div>
              </div>
            ))}
            <div style={{ marginTop: 4, fontSize: 11, color: 'var(--text-muted)', borderTop: '1px solid var(--border)', paddingTop: 10 }}>
              CLS regression on /lodges templates — fix in flight, see tasks below.
            </div>
          </div>
        </Card>
      </div>

      {/* In-flight SEO tasks */}
      <Card padding={0}>
        <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 14 }}>In-flight SEO work</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Content, technical, and outreach tasks owned by your Clicky team</div>
          </div>
          <Btn variant="ghost" size="sm" iconRight={I.arrowRight}>View roadmap</Btn>
        </div>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)', color: 'var(--text-muted)', fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.04em' }}>
              <th style={{ textAlign: 'left', padding: '12px 14px', fontWeight: 600, width: 90 }}>Type</th>
              <th style={{ textAlign: 'left', padding: '12px 14px', fontWeight: 600 }}>Task</th>
              <th style={{ textAlign: 'left', padding: '12px 14px', fontWeight: 600, width: 160 }}>Owner</th>
              <th style={{ textAlign: 'left', padding: '12px 14px', fontWeight: 600, width: 130 }}>Status</th>
              <th style={{ textAlign: 'left', padding: '12px 14px', fontWeight: 600, width: 90 }}>Due</th>
            </tr>
          </thead>
          <tbody>
            {SEO_TASKS.map(t => {
              const tone = t.status === 'Live' ? 'positive' : t.status === 'In review' || t.status === 'In progress' ? 'primary' : 'neutral';
              const typeTone = t.type === 'Tech' ? 'warning' : t.type === 'Links' ? 'primary' : 'neutral';
              return (
                <tr key={t.title} style={{ borderTop: '1px solid var(--border)' }}>
                  <td style={{ padding: '12px 14px' }}><Badge tone={typeTone}>{t.type}</Badge></td>
                  <td style={{ padding: '12px 14px', color: 'var(--text)', fontWeight: 500 }}>{t.title}</td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)' }}>{t.owner}</td>
                  <td style={{ padding: '12px 14px' }}><Badge tone={tone}>{t.status}</Badge></td>
                  <td style={{ padding: '12px 14px', color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{t.due}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </Card>
    </div>
  );
};

window.SeoScreen = SeoScreen;

// ============================================================
// Paid Media (all) — summary across every active paid channel.
// Surfaces total spend, blended CPB, channel mix, per-channel
// breakdown with sparklines, and top campaigns.
// ============================================================
const PaidMediaScreen = ({ setActive, openAskLightbox }) => {
  const { AreaChart, Area, BarChart, Bar, ResponsiveContainer, Tooltip, XAxis, YAxis, Legend, CartesianGrid } = window.Recharts;

  // Channels — only paid media. Mirrors the numbers used elsewhere
  // (Dashboard ad-channel pane, ClickyAI dashboard pulse) so the data
  // reconciles top-down.
  const channels = [
    {
      id: 'google', label: 'Google Ads', icon: I.google,
      hue: '#4285f4', target: 'google',
      status: 'Active', accountCount: 2,
      spend: 1389.22, bookings: 49, cpb: 28.34, roas: 5.8, deltaSpend: 0.082, deltaBookings: 0.114,
      sub: 'Search · Performance Max · Display',
      spark: [310, 340, 380, 360, 410, 440, 480, 520, 540, 560, 590, 620, 640, 680],
      campaigns: [
        { name: 'Branded — Lodge Search',     spend: 412.40, bookings: 18, cpb: 22.91, top: true },
        { name: 'Performance Max — Family',   spend: 384.10, bookings: 14, cpb: 27.44 },
        { name: 'Non-Brand — Cornwall Stays', spend: 348.72, bookings: 11, cpb: 31.70 },
      ],
    },
    {
      id: 'meta', label: 'Meta Ads', icon: I.meta,
      hue: '#0866ff', target: 'meta',
      status: 'Active', accountCount: 1,
      spend: 842.06, bookings: 11, cpb: 76.55, roas: 3.2, deltaSpend: 0.183, deltaBookings: 0.092,
      sub: 'Facebook + Instagram · Advantage+',
      spark: [110, 130, 160, 180, 210, 240, 260, 290, 310, 330, 360, 380, 410, 442],
      campaigns: [
        { name: 'Advantage+ Shopping · Lodges', spend: 528.40, bookings: 7, cpb: 75.49, top: true },
        { name: 'Retargeting · Past visitors',   spend: 178.20, bookings: 3, cpb: 59.40 },
        { name: 'Awareness · Cornwall families', spend: 135.46, bookings: 1, cpb: 135.46 },
      ],
    },
    // Microsoft Ads is currently a recommended-but-not-active channel; we
    // surface it greyed-out so the gap is visible without polluting totals.
    {
      id: 'microsoft', label: 'Microsoft Ads', icon: I.microsoft,
      hue: '#00a4ef', target: 'channels',
      status: 'Not connected', accountCount: 0,
      sub: 'Bing Search · 18% of branded UK demand',
      isInactive: true,
      campaigns: [],
    },
  ];

  const active = channels.filter(c => !c.isInactive);
  const inactive = channels.filter(c => c.isInactive);

  // Aggregates
  const totalSpend    = active.reduce((n, c) => n + c.spend, 0);
  const totalBookings = active.reduce((n, c) => n + c.bookings, 0);
  const blendedCpb    = totalSpend / Math.max(1, totalBookings);
  const blendedRoas   = active.reduce((n, c) => n + c.roas * c.spend, 0) / Math.max(1, totalSpend);

  // 30-day combined trend (sum of channel sparks)
  const len = active[0]?.spark.length || 14;
  const combined = Array.from({ length: len }, (_, i) => ({
    x: i,
    google: active.find(c => c.id === 'google')?.spark[i] || 0,
    meta:   active.find(c => c.id === 'meta')?.spark[i] || 0,
  }));

  // Top campaigns flattened
  const allCampaigns = active.flatMap(c => c.campaigns.map(camp => ({
    ...camp, channel: c.label, channelHue: c.hue, channelIcon: c.icon, target: c.target,
  })));
  const topCampaigns = [...allCampaigns].sort((a, b) => b.spend - a.spend).slice(0, 5);

  return (
    <div>
      <PageHeader
        title="Paid Media"
        subtitle={`Aggregated performance across ${active.length} active paid channels · last 30 days`}
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.download}>Export</Btn>
          <Btn variant="primary" size="sm" icon={I.plus} onClick={() => setActive('growth')}>Add channel</Btn>
        </>}
      />

      {/* Summary strip */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }}>
          {[
            { label: 'Total spend · 30d', value: '£' + totalSpend.toLocaleString('en-GB', { minimumFractionDigits: 2 }), sub: '+13.4% vs prev', tone: 'muted' },
            { label: 'Bookings',          value: totalBookings,                                                          sub: '+10.7% vs prev', tone: 'positive' },
            { label: 'Blended CPB',       value: '£' + blendedCpb.toFixed(2),                                            sub: '−6.8% vs prev',  tone: 'positive' },
            { label: 'Blended ROAS',      value: blendedRoas.toFixed(2) + '×',                                           sub: 'across paid mix', tone: 'muted' },
          ].map((s, i) => (
            <div key={s.label} style={{
              padding: '18px 22px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
              <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em' }}>{s.value}</div>
              <div style={{ fontSize: 11, marginTop: 2,
                color: s.tone === 'positive' ? 'var(--positive)' : 'var(--text-muted)',
                fontWeight: s.tone === 'positive' ? 600 : 400,
              }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 16, marginBottom: 16 }}>
        {/* Combined spend trend */}
        <Card padding={0}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Combined paid spend · last 14 days</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Stacked by channel · Google + Meta</div>
            </div>
            <div style={{ display: 'flex', gap: 12, fontSize: 11, color: 'var(--text-muted)' }}>
              {active.map(c => (
                <span key={c.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 2, background: c.hue }}/>
                  {c.label}
                </span>
              ))}
            </div>
          </div>
          <div style={{ padding: 16, height: 240 }}>
            <ResponsiveContainer width="100%" height="100%">
              <AreaChart data={combined} margin={{ top: 10, right: 12, left: 0, bottom: 0 }}>
                <defs>
                  <linearGradient id="pm-google" x1="0" x2="0" y1="0" y2="1"><stop offset="0" stopColor="#4285f4" stopOpacity={0.45}/><stop offset="1" stopColor="#4285f4" stopOpacity={0.05}/></linearGradient>
                  <linearGradient id="pm-meta"   x1="0" x2="0" y1="0" y2="1"><stop offset="0" stopColor="#0866ff" stopOpacity={0.45}/><stop offset="1" stopColor="#0866ff" stopOpacity={0.05}/></linearGradient>
                </defs>
                <CartesianGrid stroke="var(--border)" strokeDasharray="2 4" vertical={false}/>
                <XAxis dataKey="x" hide />
                <YAxis tick={{ fontSize: 10, fill: 'var(--text-faint)' }} axisLine={false} tickLine={false} width={36}/>
                <Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 6, fontSize: 11 }} />
                <Area type="monotone" dataKey="google" stackId="1" stroke="#4285f4" strokeWidth={1.6} fill="url(#pm-google)" name="Google Ads" />
                <Area type="monotone" dataKey="meta"   stackId="1" stroke="#0866ff" strokeWidth={1.6} fill="url(#pm-meta)"   name="Meta Ads" />
              </AreaChart>
            </ResponsiveContainer>
          </div>
        </Card>

        {/* Channel mix */}
        <Card padding={0}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Channel mix</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>How spend splits across channels</div>
          </div>
          <div style={{ padding: 18, display: 'flex', flexDirection: 'column', gap: 14 }}>
            {/* Stacked bar */}
            <div style={{
              display: 'flex', height: 14, borderRadius: 99, overflow: 'hidden',
              background: 'var(--surface-2)',
            }}>
              {active.map(c => (
                <div key={c.id} style={{
                  flex: c.spend, background: c.hue,
                }} title={`${c.label} · £${c.spend.toFixed(2)} (${Math.round(100 * c.spend / totalSpend)}%)`}/>
              ))}
            </div>
            {active.map(c => {
              const pct = Math.round(100 * c.spend / totalSpend);
              return (
                <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ width: 8, height: 8, borderRadius: 2, background: c.hue, flexShrink: 0 }}/>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
                      <span style={{ fontSize: 12.5, fontWeight: 600 }}>{c.label}</span>
                      <span style={{ fontSize: 12.5, fontWeight: 600, color: c.hue, fontVariantNumeric: 'tabular-nums' }}>{pct}%</span>
                    </div>
                    <div style={{ fontSize: 11, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums', marginTop: 1 }}>
                      £{c.spend.toLocaleString('en-GB', { minimumFractionDigits: 2 })} · {c.bookings} bookings
                    </div>
                  </div>
                </div>
              );
            })}
            {inactive.length > 0 && (
              <div style={{
                marginTop: 6, paddingTop: 12, borderTop: '1px dashed var(--border)',
                fontSize: 11, color: 'var(--text-muted)',
              }}>
                <span style={{ color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', fontSize: 10 }}>Not yet running</span>
                {inactive.map(c => (
                  <button key={c.id} onClick={() => setActive('opportunities')} style={{
                    display: 'flex', alignItems: 'center', gap: 8, marginTop: 8,
                    padding: '6px 8px', borderRadius: 6,
                    background: 'transparent', border: '1px dashed var(--border)',
                    cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left', width: '100%',
                  }}>
                    <span style={{
                      width: 22, height: 22, borderRadius: 5,
                      background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
                      color: 'var(--text-muted)', flexShrink: 0,
                    }}>{c.icon}</span>
                    <div style={{ minWidth: 0, flex: 1 }}>
                      <div style={{ fontSize: 12, fontWeight: 600 }}>{c.label}</div>
                      <div style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{c.sub}</div>
                    </div>
                    <span style={{ color: 'var(--primary)', fontSize: 11, fontWeight: 600 }}>Explore →</span>
                  </button>
                ))}
              </div>
            )}
          </div>
        </Card>
      </div>

      {/* Per-channel breakdown */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ fontWeight: 600, fontSize: 14 }}>By channel</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Click any channel to drill in</div>
        </div>
        <div>
          {active.map((c, i) => (
            <button key={c.id}
              onClick={() => setActive(c.target)}
              style={{
                width: '100%', textAlign: 'left',
                padding: '16px 22px',
                background: 'transparent', border: 'none',
                borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                cursor: 'pointer', fontFamily: 'inherit',
                display: 'grid', gridTemplateColumns: '40px 1.2fr 0.8fr 0.8fr 0.8fr 0.6fr 110px 24px', gap: 16, alignItems: 'center',
                position: 'relative', transition: 'background 120ms ease',
              }}
              onMouseEnter={e => e.currentTarget.style.background = 'color-mix(in oklab, ' + c.hue + ' 4%, var(--surface))'}
              onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
            >
              <div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, width: 3, background: c.hue, opacity: 0.85 }}/>
              <div style={{
                width: 36, height: 36, borderRadius: 8,
                background: 'color-mix(in oklab, ' + c.hue + ' 14%, transparent)',
                border: '1px solid color-mix(in oklab, ' + c.hue + ' 28%, var(--border))',
                color: c.hue, display: 'grid', placeItems: 'center',
              }}>{c.icon}</div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)' }}>{c.label}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{c.sub}</div>
              </div>
              <Stat label="Spend"    value={'£' + c.spend.toLocaleString('en-GB', { minimumFractionDigits: 2 })} delta={`${c.deltaSpend > 0 ? '+' : ''}${(c.deltaSpend * 100).toFixed(1)}%`} tone="muted"/>
              <Stat label="Bookings" value={c.bookings} delta={`${c.deltaBookings > 0 ? '+' : ''}${(c.deltaBookings * 100).toFixed(1)}%`} tone="positive"/>
              <Stat label="CPB"      value={'£' + c.cpb.toFixed(2)}/>
              <Stat label="ROAS"     value={c.roas.toFixed(1) + '×'}/>
              <div style={{ width: 110, height: 38 }}>
                <ResponsiveContainer width="100%" height="100%">
                  <AreaChart data={c.spark.map((y, x) => ({ x, y }))} margin={{ top: 2, right: 2, left: 2, bottom: 2 }}>
                    <defs>
                      <linearGradient id={`pm-row-${c.id}`} x1="0" x2="0" y1="0" y2="1"><stop offset="0" stopColor={c.hue} stopOpacity={0.32}/><stop offset="1" stopColor={c.hue} stopOpacity={0}/></linearGradient>
                    </defs>
                    <Area type="monotone" dataKey="y" stroke={c.hue} strokeWidth={1.6} fill={`url(#pm-row-${c.id})`} dot={false}/>
                  </AreaChart>
                </ResponsiveContainer>
              </div>
              <span style={{ color: 'var(--text-faint)' }}>{I.arrowRight}</span>
            </button>
          ))}
        </div>
      </Card>

      {/* Top campaigns across channels */}
      <Card padding={0}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Top campaigns · all paid</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Highest spend in the last 30 days, across every channel</div>
          </div>
        </div>
        <div style={{
          display: 'grid', gridTemplateColumns: '60px 1.4fr 1fr 0.8fr 0.8fr 0.8fr',
          padding: '10px 22px', background: 'var(--surface-2)',
          fontSize: 10.5, fontWeight: 700, color: 'var(--text-faint)',
          textTransform: 'uppercase', letterSpacing: '0.06em',
          borderBottom: '1px solid var(--border)', gap: 16,
        }}>
          <div>#</div><div>Campaign</div><div>Channel</div><div>Spend</div><div>Bookings</div><div>CPB</div>
        </div>
        {topCampaigns.map((c, i) => (
          <div key={i} style={{
            display: 'grid', gridTemplateColumns: '60px 1.4fr 1fr 0.8fr 0.8fr 0.8fr',
            padding: '12px 22px', alignItems: 'center', gap: 16,
            borderBottom: '1px solid var(--border)', fontSize: 12.5,
          }}>
            <div style={{
              fontFamily: 'JetBrains Mono', fontSize: 11.5, color: 'var(--text-faint)', fontWeight: 600,
              fontVariantNumeric: 'tabular-nums',
            }}>{String(i + 1).padStart(2, '0')}</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 13, fontWeight: 600 }}>{c.name}</span>
              {c.top && (
                <span style={{
                  fontSize: 9.5, fontWeight: 700, padding: '1px 6px', borderRadius: 99,
                  background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
                  color: 'var(--positive)', textTransform: 'uppercase', letterSpacing: '0.04em',
                }}>Top</span>
              )}
            </div>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--text-muted)' }}>
              <span style={{
                width: 18, height: 18, borderRadius: 4,
                background: 'color-mix(in oklab, ' + c.channelHue + ' 14%, transparent)',
                color: c.channelHue, display: 'grid', placeItems: 'center',
              }}>{c.channelIcon}</span>
              {c.channel}
            </div>
            <div style={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>£{c.spend.toFixed(2)}</div>
            <div style={{ color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{c.bookings}</div>
            <div style={{ color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>£{c.cpb.toFixed(2)}</div>
          </div>
        ))}
      </Card>
    </div>
  );
};

const Stat = ({ label, value, delta, tone }) => (
  <div>
    <div style={{ fontSize: 9.5, fontWeight: 700, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{label}</div>
    <div style={{ fontSize: 14, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{value}</div>
    {delta && <div style={{
      fontSize: 10.5, marginTop: 1,
      color: tone === 'positive' ? 'var(--positive)' : 'var(--text-muted)',
      fontWeight: tone === 'positive' ? 600 : 500,
    }}>{delta}</div>}
  </div>
);

const ChannelsScreen = ({ setActive }) => {
  const activeChannels = [
    {
      id: 'google',
      label: 'Google Ads',
      icon: I.google,
      target: 'google',
      accountCount: 2,
      accounts: [
        { name: 'Evergreen Escapes', id: '482-209-7716' },
        { name: 'Evergreen Ownership',   id: '931-554-2280' },
      ],
      spend: '£1,550.98',
      bookings: '49',
      delta: '+12.4%',
    },
    {
      id: 'meta',
      label: 'Meta Ads',
      icon: I.meta,
      target: 'meta',
      accountCount: 2,
      accounts: [
        { name: 'Evergreen Escapes', id: 'act_8472940' },
        { name: 'Evergreen Ownership',   id: 'act_9013182' },
      ],
      spend: '£842.16',
      bookings: '11',
      delta: '+18.3%',
    },
    {
      id: 'seo',
      label: 'SEO',
      icon: I.seo,
      target: 'seo',
      accountCount: 1,
      accounts: [
        { name: 'st-mabyn-escape.co.uk', id: 'GSC · GA4' },
      ],
      // SEO doesn't have ad spend — show organic-equivalent metrics
      spend: '£0',
      bookings: '37',
      delta: '+18.6%',
      organic: true,
    },
  ];

  const inactiveChannels = [
    {
      id: 'microsoft', label: 'Microsoft Ads', icon: I.microsoft,
      blurb: '8–12% of UK search demand happens on Bing — your branded query share there is untapped, and the audience skews older and higher-income (matching your ownership profile).',
      stats: [
        { label: 'Audience',  value: 'Older HHI £40k+' },
        { label: 'Setup',     value: '2 wks' },
        { label: 'Est. CPC',  value: '£2.10' },
      ],
    },
    {
      id: 'linkedin',  label: 'LinkedIn Ads',  icon: I.linkedin,
      blurb: 'Targeted lead-gen audience — second-home buyers, holiday-let investors, professional services. Best fit for the Ownership funnel.',
      stats: [
        { label: 'Audience',  value: 'HNW buyers' },
        { label: 'Setup',     value: '3 wks' },
        { label: 'Est. CPL',  value: '£25' },
      ],
    },
    {
      id: 'tiktok',    label: 'TikTok Ads',    icon: I.tiktok,
      blurb: 'Mobile-first inspiration audience 25–34 — UGC-style lodge content performs strongly. Low CPM, high reach, great fit for top-of-funnel.',
      stats: [
        { label: 'Audience',  value: 'Mobile · 25–34' },
        { label: 'Setup',     value: '3 wks' },
        { label: 'Est. CPM',  value: '£3.20' },
      ],
    },
    {
      id: 'youtube',   label: 'YouTube Ads',   icon: I.youtube,
      blurb: 'Connected-TV inventory for travel research. Skippable in-stream + bumper formats let you build awareness against active holiday-planners.',
      stats: [
        { label: 'Audience',  value: 'CTV · researchers' },
        { label: 'Setup',     value: '2 wks' },
        { label: 'Est. CPV',  value: '£0.04' },
      ],
    },
    {
      id: 'reddit',    label: 'Reddit Ads',    icon: I.reddit,
      blurb: 'Niche communities like r/cornwall (94k) and r/uktravel (412k) actively discuss self-catering breaks. Hospitality CPMs dropped 22% YoY here.',
      stats: [
        { label: 'Audience',  value: 'r/cornwall, r/uktravel' },
        { label: 'Setup',     value: '1 wk' },
        { label: 'Est. CPM',  value: '£2.40' },
      ],
    },
  ];

  // Aggregate stats across active services — Google + Meta combined ad spend
  const totalSpend = '£2,393.14';

  // Maintenance summary — pulled from the same SITE_HEALTH + CHANGE_REQUESTS
  // sources used by the Website Maintenance Pro screen, so values stay in sync.
  const wmActiveSites = (window.CLIENT?.sites || []).filter(s => s.status === 'active');
  const wmReqs        = CHANGE_REQUESTS.filter(r => wmActiveSites.some(s => s.id === r.site));
  const wmOpen        = wmReqs.filter(r => r.status !== 'done').length;
  const wmUptimeAvg   = wmActiveSites.length
    ? wmActiveSites.reduce((sum, s) => sum + (SITE_HEALTH[s.id]?.uptime30 || 0), 0) / wmActiveSites.length
    : 0;

  // "Active services" includes the maintenance product alongside paid channels
  const activeServiceCount = activeChannels.length + 1; // +1 for Website Maintenance Pro
  const totalAccountsAndSites = activeChannels.reduce((n, c) => n + c.accountCount, 0) + wmActiveSites.length;

  return (
    <div>
      <PageHeader
        title="All Services"
        subtitle={`Every active service for ${CLIENT.shortName} — paid media, organic and managed maintenance`}
        actions={<Btn variant="primary" size="sm" icon={I.plus} onClick={() => setActive('growth')}>Add new service</Btn>}
      />

      {/* Aggregate strip */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', alignItems: 'center' }}>
          {[
            {
              label: 'Active services',
              value: activeServiceCount,
              sub: `${inactiveChannels.length} available to add`,
            },
            {
              label: 'Linked accounts & sites',
              value: totalAccountsAndSites,
              sub: `${activeChannels.reduce((n, c) => n + c.accountCount, 0)} ad accounts · ${wmActiveSites.length} sites`,
            },
            {
              label: 'Ad spend · 30d',
              value: totalSpend,
              sub: '+15.6% vs prev 30d',
              tone: 'positive',
            },
            {
              label: 'Maintenance · 30d',
              value: wmUptimeAvg ? wmUptimeAvg.toFixed(2) + '%' : '—',
              sub: wmOpen ? `${wmOpen} open request${wmOpen === 1 ? '' : 's'}` : 'all triaged',
              tone: wmUptimeAvg >= 99.9 ? 'positive' : wmUptimeAvg >= 99 ? 'warning' : 'negative',
            },
          ].map((s, i) => (
            <div key={s.label} style={{
              padding: '16px 20px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
              <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em' }}>{s.value}</div>
              <div style={{
                fontSize: 11, marginTop: 2,
                color: s.tone === 'positive' ? 'var(--positive)'
                     : s.tone === 'warning'  ? 'var(--warning)'
                     : s.tone === 'negative' ? 'var(--negative)'
                     : 'var(--text-muted)',
              }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      {/* Master chart — service performance · last 30 days */}
      {(() => {
        // Augment with average page-speed for the maintenance product so it
        // sits next to the channels with comparable data.
        const wmSpeedAvg = wmActiveSites.length
          ? Math.round(wmActiveSites.reduce((sum, s) => sum + (SITE_HEALTH[s.id]?.perf?.score || 0), 0) / wmActiveSites.length)
          : 0;

        const services = [
          {
            id: 'google', label: 'Google Ads', icon: I.google, target: 'google',
            spendNum: 1550.98, bookings: 49, delta: '+12.4%', deltaTone: 'positive',
            color: 'var(--primary)',
            sub: '2 ad accounts',
          },
          {
            id: 'meta', label: 'Meta Ads', icon: I.meta, target: 'meta',
            spendNum: 842.16, bookings: 11, delta: '+18.3%', deltaTone: 'positive',
            color: '#1877f2',
            sub: '2 ad accounts · Feed + Reels',
          },
          {
            id: 'seo', label: 'SEO', icon: I.seo, target: 'seo',
            spendNum: 0, bookings: 37, delta: '+18.6%', deltaTone: 'positive',
            color: 'var(--positive)',
            sub: 'Organic · 4,219 clicks · 30d',
            organic: true,
          },
          {
            id: 'maintenance', label: 'Website Maintenance Pro', target: 'maintenance',
            iconNode: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/></svg>,
            spendNum: null, bookings: null,
            metric: { label: 'Uptime', value: wmUptimeAvg ? wmUptimeAvg.toFixed(2) + '%' : '—' },
            second: { label: 'Page speed', value: wmSpeedAvg || '—' },
            delta: wmOpen ? `${wmOpen} open requests` : 'all triaged',
            deltaTone: wmOpen ? 'warning' : 'positive',
            color: '#ef4444',
            sub: `${wmActiveSites.length} live sites`,
          },
        ];

        const totalSpendNum = services.reduce((s, x) => s + (x.spendNum || 0), 0) || 1;
        const totalBookings = services.reduce((s, x) => s + (x.bookings || 0), 0) || 1;

        return (
          <Card padding={0} style={{ marginBottom: 16 }}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
                <div style={{
                  width: 32, height: 32, borderRadius: 8,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
                }}>
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>
                </div>
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>Service performance · last 30 days</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                    Bookings + spend split across paid, organic and managed services
                  </div>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 14, fontSize: 11, color: 'var(--text-muted)' }}>
                <span><strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{totalBookings}</strong> total bookings</span>
                <span style={{ color: 'var(--text-faint)' }}>·</span>
                <span><strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{totalSpend}</strong> spend</span>
              </div>
            </div>

            <div style={{ padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 12 }}>
              {services.map(s => {
                const isMaintenance = s.id === 'maintenance';
                const sharePct = isMaintenance ? 100
                              : s.organic ? (s.bookings / totalBookings) * 100
                              : (s.spendNum / totalSpendNum) * 100;
                return (
                  <div key={s.id}
                    onClick={() => setActive(s.target)}
                    style={{
                      display: 'grid', gridTemplateColumns: '220px 1fr 200px', alignItems: 'center', gap: 14,
                      padding: '6px 8px', borderRadius: 8, cursor: 'pointer',
                      transition: 'background 0.12s',
                    }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                  >
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
                      <span style={{
                        width: 28, height: 28, borderRadius: 6, flexShrink: 0,
                        background: 'var(--surface-2)', border: '1px solid var(--border)',
                        display: 'grid', placeItems: 'center',
                        color: s.color,
                      }}>{s.icon || s.iconNode}</span>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{s.label}</div>
                        <div style={{
                          fontSize: 10.5, color: 'var(--text-faint)',
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{s.sub}</div>
                      </div>
                    </div>

                    {/* Bar — proportion of total (spend for paid, bookings for organic, full for maintenance) */}
                    <div style={{ position: 'relative', height: 16 }}>
                      <div style={{
                        position: 'absolute', inset: 0,
                        background: 'var(--surface-2)', borderRadius: 4, overflow: 'hidden',
                      }}>
                        <div style={{
                          width: sharePct + '%', height: '100%', background: s.color,
                          opacity: isMaintenance ? 0.45 : 0.85,
                          transition: 'width 0.3s ease',
                        }}/>
                      </div>
                      <div style={{
                        position: 'absolute', top: '50%', transform: 'translateY(-50%)',
                        left: `min(calc(${sharePct}% + 8px), calc(100% - 38px))`,
                        fontSize: 10.5, fontWeight: 700, color: 'var(--text-muted)',
                        fontVariantNumeric: 'tabular-nums',
                      }}>{isMaintenance ? '—' : sharePct.toFixed(0) + '%'}</div>
                    </div>

                    {/* Right metrics */}
                    <div style={{ textAlign: 'right' }}>
                      {isMaintenance ? (
                        <>
                          <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>
                            {s.metric.value}
                            <span style={{ fontSize: 11, fontWeight: 400, color: 'var(--text-faint)' }}> · {s.second.value} speed</span>
                          </div>
                          <div style={{
                            fontSize: 11, fontWeight: 600, marginTop: 1,
                            color: s.deltaTone === 'warning' ? 'var(--warning)' : 'var(--positive)',
                          }}>{s.delta}</div>
                        </>
                      ) : (
                        <>
                          <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>
                            {s.organic ? s.bookings + ' bookings' : '£' + s.spendNum.toFixed(2)}
                            <span style={{ fontSize: 11, fontWeight: 400, color: 'var(--text-faint)' }}>
                              {s.organic ? ' · organic' : ' · ' + s.bookings + ' bookings'}
                            </span>
                          </div>
                          <div style={{ fontSize: 11, fontWeight: 600, marginTop: 1, color: 'var(--positive)' }}>
                            {s.delta} vs prev 30d
                          </div>
                        </>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>

            <div style={{
              padding: '10px 18px', borderTop: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', gap: 18, flexWrap: 'wrap',
              fontSize: 11, color: 'var(--text-muted)',
            }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <span style={{ width: 12, height: 8, borderRadius: 2, background: 'var(--primary)' }}/>
                Paid bar = % of paid spend
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <span style={{ width: 12, height: 8, borderRadius: 2, background: 'var(--positive)' }}/>
                Organic bar = % of all bookings
              </span>
              <span style={{ marginLeft: 'auto', color: 'var(--text-faint)' }}>Click any row to drill in</span>
            </div>
          </Card>
        );
      })()}

      {/* Secondary chart row — bookings donut + spend split + maintenance health */}
      {(() => {
        const bookingGroups = [
          { key: 'google', label: 'Google Ads', count: 49, color: 'var(--primary)' },
          { key: 'seo',    label: 'SEO',        count: 37, color: 'var(--positive)' },
          { key: 'meta',   label: 'Meta Ads',   count: 11, color: '#1877f2' },
        ];
        const bookingsTotal = bookingGroups.reduce((a, b) => a + b.count, 0) || 1;

        const spendGroups = [
          { key: 'google', label: 'Google Ads', amount: 1550.98, color: 'var(--primary)' },
          { key: 'meta',   label: 'Meta Ads',   amount: 842.16,  color: '#1877f2' },
        ];
        const spendTotal = spendGroups.reduce((a, b) => a + b.amount, 0) || 1;

        const wmSpeedAvg = wmActiveSites.length
          ? Math.round(wmActiveSites.reduce((sum, s) => sum + (SITE_HEALTH[s.id]?.perf?.score || 0), 0) / wmActiveSites.length)
          : 0;
        const wmTotalReqs = wmReqs.length;
        const wmDoneReqs  = wmReqs.filter(r => r.status === 'done').length;

        return (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 24 }}>
            {/* Bookings donut */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>Bookings by service</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>last 30 days</span>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                {(() => {
                  const size = 100, stroke = 14;
                  const r = (size - stroke) / 2;
                  const c = 2 * Math.PI * r;
                  let acc = 0;
                  return (
                    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ flexShrink: 0 }}>
                      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--border)" strokeWidth={stroke}/>
                      {bookingGroups.map(s => {
                        const len = (s.count / bookingsTotal) * c;
                        const dasharray = `${len} ${c}`;
                        const offset = -acc;
                        acc += len;
                        return (
                          <circle key={s.key}
                            cx={size / 2} cy={size / 2} r={r}
                            fill="none" stroke={s.color} strokeWidth={stroke}
                            strokeDasharray={dasharray}
                            strokeDashoffset={offset}
                            transform={`rotate(-90 ${size / 2} ${size / 2})`}/>
                        );
                      })}
                      <text x={size / 2} y={size / 2 - 2} textAnchor="middle" dominantBaseline="central"
                        fontSize="22" fontWeight="700" fill="currentColor"
                        style={{ fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>
                        {bookingsTotal}
                      </text>
                      <text x={size / 2} y={size / 2 + 14} textAnchor="middle" dominantBaseline="central"
                        fontSize="9" fontWeight="500" fill="var(--text-faint)"
                        style={{ textTransform: 'uppercase', letterSpacing: '0.04em' }}>
                        bookings
                      </text>
                    </svg>
                  );
                })()}
                <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 6 }}>
                  {bookingGroups.map(s => (
                    <div key={s.key} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
                      <span style={{ width: 8, height: 8, borderRadius: 2, background: s.color, flexShrink: 0 }}/>
                      <span style={{ color: 'var(--text)', flex: 1, minWidth: 0 }}>{s.label}</span>
                      <span style={{ color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums', fontFamily: 'JetBrains Mono', fontSize: 11 }}>
                        {Math.round((s.count / bookingsTotal) * 100)}%
                      </span>
                    </div>
                  ))}
                </div>
              </div>
            </Card>

            {/* Spend split — stacked horizontal bar */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>Paid spend split</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>£{spendTotal.toLocaleString('en-GB', { minimumFractionDigits: 2 })}</span>
              </div>
              <div style={{
                display: 'flex', height: 14, borderRadius: 99,
                overflow: 'hidden', background: 'var(--surface-2)',
                marginBottom: 14,
              }}>
                {spendGroups.map(s => (
                  <div key={s.key}
                    title={`${s.label}: £${s.amount.toFixed(2)}`}
                    style={{
                      width: `${(s.amount / spendTotal) * 100}%`,
                      background: s.color,
                    }}/>
                ))}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {spendGroups.map(s => (
                  <div key={s.key} style={{ display: 'grid', gridTemplateColumns: '12px 1fr auto auto', alignItems: 'center', gap: 8 }}>
                    <span style={{ width: 10, height: 10, borderRadius: 2, background: s.color }}/>
                    <span style={{ fontSize: 12, color: 'var(--text)' }}>{s.label}</span>
                    <span style={{ fontSize: 11, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono' }}>
                      {Math.round((s.amount / spendTotal) * 100)}%
                    </span>
                    <span style={{ fontSize: 12, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums', fontFamily: 'JetBrains Mono', fontWeight: 600 }}>
                      £{s.amount.toFixed(0)}
                    </span>
                  </div>
                ))}
              </div>
            </Card>

            {/* Maintenance health — uptime + speed + requests */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>Maintenance health</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{wmActiveSites.length} sites</span>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {/* Uptime row */}
                <div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <span style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500 }}>Avg uptime · 30d</span>
                    <span style={{
                      fontSize: 13, fontWeight: 700, fontVariantNumeric: 'tabular-nums',
                      color: wmUptimeAvg >= 99.9 ? 'var(--positive)' : wmUptimeAvg >= 99 ? 'var(--warning)' : 'var(--negative)',
                    }}>{wmUptimeAvg ? wmUptimeAvg.toFixed(2) + '%' : '—'}</span>
                  </div>
                  <div style={{ height: 6, borderRadius: 3, background: 'var(--surface-2)', overflow: 'hidden' }}>
                    <div style={{
                      width: Math.max(0, Math.min(100, (wmUptimeAvg - 99) * 100)) + '%',
                      height: '100%',
                      background: wmUptimeAvg >= 99.9 ? 'var(--positive)' : wmUptimeAvg >= 99 ? 'var(--warning)' : 'var(--negative)',
                    }}/>
                  </div>
                </div>

                {/* Page speed row */}
                <div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <span style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500 }}>Avg page speed</span>
                    <span style={{
                      fontSize: 13, fontWeight: 700, fontVariantNumeric: 'tabular-nums',
                      color: wmSpeedAvg >= 90 ? 'var(--positive)' : wmSpeedAvg >= 70 ? 'var(--warning)' : 'var(--negative)',
                    }}>{wmSpeedAvg || '—'}<span style={{ fontSize: 10, fontWeight: 500, color: 'var(--text-faint)' }}>/100</span></span>
                  </div>
                  <div style={{ height: 6, borderRadius: 3, background: 'var(--surface-2)', overflow: 'hidden' }}>
                    <div style={{
                      width: wmSpeedAvg + '%', height: '100%',
                      background: wmSpeedAvg >= 90 ? 'var(--positive)' : wmSpeedAvg >= 70 ? 'var(--warning)' : 'var(--negative)',
                    }}/>
                  </div>
                </div>

                {/* Open requests row */}
                <div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <span style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500 }}>Change requests</span>
                    <span style={{ fontSize: 13, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>
                      <span style={{ color: wmOpen ? 'var(--warning)' : 'var(--text)' }}>{wmOpen}</span>
                      <span style={{ fontSize: 10, fontWeight: 500, color: 'var(--text-faint)' }}> open / {wmTotalReqs}</span>
                    </span>
                  </div>
                  <div style={{ display: 'flex', height: 6, borderRadius: 3, overflow: 'hidden', background: 'var(--surface-2)' }}>
                    <div style={{ width: `${(wmDoneReqs / Math.max(1, wmTotalReqs)) * 100}%`, height: '100%', background: 'var(--positive)' }}/>
                    <div style={{ width: `${(wmOpen / Math.max(1, wmTotalReqs)) * 100}%`, height: '100%', background: 'var(--warning)' }}/>
                  </div>
                </div>

                <div style={{
                  marginTop: 4, paddingTop: 8, borderTop: '1px solid var(--border)',
                  fontSize: 11, color: 'var(--text-muted)',
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                }}>
                  <span>{wmDoneReqs} done · {wmOpen} open</span>
                  <button onClick={() => setActive('maintenance')} style={{
                    background: 'none', border: 'none', color: 'var(--primary)',
                    fontSize: 11, fontWeight: 600, cursor: 'pointer', padding: 0,
                  }}>Open Maintenance →</button>
                </div>
              </div>
            </Card>
          </div>
        );
      })()}

      {/* Active services grid */}
      <div style={{ marginBottom: 8, display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <h2 style={{ fontSize: 14, fontWeight: 600, margin: 0, color: 'var(--text)' }}>Active services</h2>
        <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{activeServiceCount} of {activeServiceCount + inactiveChannels.length}</span>
      </div>
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 12,
        marginBottom: 24,
      }}>
        {activeChannels.map(c => (
          <ChannelTile key={c.id} channel={c} onOpen={(target) => setActive(target)} />
        ))}
        <MaintenanceTile onOpen={(target) => setActive(target)} />
      </div>

      {/* Available services */}
      <div style={{ marginBottom: 8, display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <h2 style={{ fontSize: 14, fontWeight: 600, margin: 0, color: 'var(--text)' }}>Available services</h2>
        <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>Talk to Joe for setup — typically 1–2 weeks</span>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 12 }}>
        {inactiveChannels.map(c => (
          <AddChannelTile key={c.id} channel={c} onPick={() => setActive('growth')} />
        ))}
      </div>
    </div>
  );
};

// ============================================================
// All CPTs index — full grid of every Client Performance Target
// with status / source filters and search.
// ============================================================
const CptsIndexScreen = ({ setActive, openKpiDetail, openRequestKpi }) => {
  const all = window.AGREED_KPIS || [];
  const [statusFilter, setStatusFilter] = useState('all');
  const [sourceFilter, setSourceFilter] = useState('all');
  const [query, setQuery] = useState('');

  const counts = useMemo(() => {
    const byStatus = { 'on-track': 0, ahead: 0, watch: 0, off: 0, pending: 0 };
    const bySource = { 'google-ads': 0, manual: 0, pending: 0 };
    all.forEach(k => {
      if (byStatus[k.status] != null) byStatus[k.status]++;
      if (bySource[k.source] != null) bySource[k.source]++;
    });
    return { byStatus, bySource };
  }, [all]);

  const visible = all.filter(k => {
    if (statusFilter !== 'all') {
      if (statusFilter === 'on-track' && !(k.status === 'on-track' || k.status === 'ahead')) return false;
      if (statusFilter !== 'on-track' && k.status !== statusFilter) return false;
    }
    if (sourceFilter !== 'all' && k.source !== sourceFilter) return false;
    if (query.trim()) {
      const q = query.trim().toLowerCase();
      if (!(k.label + ' ' + (k.sub || '') + ' ' + (k.owner || '')).toLowerCase().includes(q)) return false;
    }
    return true;
  });

  const liveCount    = counts.bySource['google-ads'];
  const manualCount  = counts.bySource['manual'];
  const pendingCount = counts.bySource['pending'];

  const statusTabs = [
    { id: 'all',      label: 'All',          n: all.length },
    { id: 'on-track', label: 'On track',     n: counts.byStatus['on-track'] + counts.byStatus['ahead'] },
    { id: 'watch',    label: 'Watch',        n: counts.byStatus['watch'] },
    { id: 'off',      label: 'Off track',    n: counts.byStatus['off'] },
    { id: 'pending',  label: 'Pending',      n: counts.byStatus['pending'] },
  ];

  const sourceTabs = [
    { id: 'all',         label: 'Any source' },
    { id: 'google-ads',  label: 'Live · Google Ads', n: liveCount },
    { id: 'manual',      label: 'Manual', n: manualCount },
    { id: 'pending',     label: 'Pending setup', n: pendingCount },
  ];

  const summary = [
    { label: 'Total CPTs',     value: all.length,          sub: 'across this client' },
    { label: 'Live · Google',  value: liveCount,           sub: 'auto-pulled', tone: 'positive' },
    { label: 'Manual',         value: manualCount,         sub: 'logged by AM' },
    { label: 'Pending setup',  value: pendingCount,        sub: pendingCount ? 'needs config' : 'all configured', tone: pendingCount ? 'warning' : 'muted' },
  ];

  return (
    <div>
      <PageHeader
        title="All Performance Targets"
        subtitle={`Every business KPI we report against for ${CLIENT.shortName} — live, manual and pending`}
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.chevLeft} onClick={() => setActive && setActive('dashboard')}>Back to dashboard</Btn>
          <Btn variant="primary" size="sm" icon={I.plus} onClick={() => openRequestKpi && openRequestKpi()}>Request a new Performance Target</Btn>
        </>}
      />

      {/* Summary strip */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', alignItems: 'center' }}>
          {summary.map((s, i) => (
            <div key={s.label} style={{
              padding: '16px 20px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
              <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em' }}>{s.value}</div>
              <div style={{
                fontSize: 11, marginTop: 2,
                color: s.tone === 'positive' ? 'var(--positive)'
                     : s.tone === 'warning'  ? 'var(--warning)'
                     : 'var(--text-muted)',
              }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      {/* Master chart — quarter progress per Performance Target */}
      {(() => {
        const trackable = all.filter(k => k.source !== 'pending' && k.actual != null);
        const avgProgress = trackable.length
          ? trackable.reduce((sum, k) => sum + Math.min(100, k.progress), 0) / trackable.length
          : 0;
        const timeProgress = trackable[0]?.timeProgress ?? 67;
        const onPace = trackable.filter(k => k.progress >= timeProgress).length;
        return (
          <Card padding={0} style={{ marginBottom: 16 }}>
            <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
                <div style={{
                  width: 32, height: 32, borderRadius: 8,
                  background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
                  color: 'var(--primary)', display: 'grid', placeItems: 'center', flexShrink: 0,
                }}>
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18"/><path d="M7 16V11M11 16V8M15 16v-3M19 16V6"/></svg>
                </div>
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>Quarter progress · Q2 2026</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                    Each target's actual vs target — dashed line shows quarter pace ({timeProgress}%)
                  </div>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 14, fontSize: 11, color: 'var(--text-muted)' }}>
                <span><strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{avgProgress.toFixed(0)}%</strong> avg progress</span>
                <span style={{ color: 'var(--text-faint)' }}>·</span>
                <span><strong style={{ color: 'var(--positive)', fontVariantNumeric: 'tabular-nums' }}>{onPace}</strong> of {trackable.length} on pace</span>
              </div>
            </div>

            <div style={{ padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 12 }}>
              {all.map(k => {
                const isPending = k.source === 'pending' || k.actual == null;
                const progress = isPending ? 0 : Math.min(100, k.progress);
                const tone = STATUS_TONES[k.status] || STATUS_TONES['on-track'];
                const barColor = isPending ? 'var(--text-faint)'
                              : k.status === 'off' || k.status === 'behind' ? 'var(--negative)'
                              : k.status === 'watch' || k.status === 'at-risk' ? 'var(--warning)'
                              : 'var(--positive)';
                return (
                  <div key={k.key}
                    onClick={() => openKpiDetail && openKpiDetail(k.key)}
                    style={{
                      display: 'grid', gridTemplateColumns: '220px 1fr 160px', alignItems: 'center', gap: 14,
                      padding: '6px 8px', borderRadius: 8, cursor: 'pointer',
                      transition: 'background 0.12s',
                    }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                  >
                    {/* Label + status pill */}
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
                      <span style={{
                        width: 24, height: 24, borderRadius: 6, flexShrink: 0,
                        background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
                        color: 'var(--primary)',
                        display: 'grid', placeItems: 'center',
                      }}>{KPI_ICONS[k.key] || I.target}</span>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{
                          fontSize: 12.5, fontWeight: 600, color: 'var(--text)',
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{k.label}</div>
                        <div style={{
                          fontSize: 10, color: tone.fg, fontWeight: 600,
                          textTransform: 'uppercase', letterSpacing: '0.04em',
                        }}>{tone.label}</div>
                      </div>
                    </div>

                    {/* Progress bar with quarter-pace marker */}
                    <div style={{ position: 'relative', height: 18 }}>
                      <div style={{
                        position: 'absolute', inset: 0,
                        background: 'var(--surface-2)',
                        borderRadius: 4, overflow: 'hidden',
                      }}>
                        <div style={{
                          width: progress + '%', height: '100%',
                          background: isPending
                            ? 'repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 4px, var(--border) 4px, var(--border) 8px)'
                            : barColor,
                          opacity: isPending ? 1 : 0.85,
                          transition: 'width 0.3s ease',
                        }}/>
                      </div>
                      {/* Quarter-pace marker — only relevant for trackable rows */}
                      {!isPending && (
                        <div style={{
                          position: 'absolute', top: -2, bottom: -2,
                          left: timeProgress + '%',
                          width: 2, background: 'var(--text)',
                          opacity: 0.55,
                          borderRadius: 1,
                        }} title={`Quarter pace · ${timeProgress}%`}/>
                      )}
                    </div>

                    {/* Right value */}
                    <div style={{ textAlign: 'right' }}>
                      {isPending ? (
                        <div style={{ fontSize: 11, color: 'var(--text-muted)', fontStyle: 'italic' }}>Pending setup</div>
                      ) : (
                        <>
                          <div style={{ fontSize: 13, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>
                            {formatKpi(k.actual, k.unit)}
                            <span style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 400 }}> / {formatKpi(k.target, k.unit)}</span>
                          </div>
                          <div style={{
                            fontSize: 11, fontWeight: 600, marginTop: 1,
                            color: k.deltaTone === 'warning' ? 'var(--warning)'
                                 : k.deltaTone === 'negative' ? 'var(--negative)'
                                 : 'var(--positive)',
                          }}>{k.delta}</div>
                        </>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>

            {/* Legend */}
            <div style={{
              padding: '10px 18px', borderTop: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', gap: 18, flexWrap: 'wrap',
              fontSize: 11, color: 'var(--text-muted)',
            }}>
              {[
                { label: 'Ahead / on track', color: 'var(--positive)' },
                { label: 'Watch',             color: 'var(--warning)' },
                { label: 'Off track',         color: 'var(--negative)' },
                { label: 'Pending setup',     color: 'var(--text-faint)' },
              ].map(s => (
                <span key={s.label} style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ width: 12, height: 8, borderRadius: 2, background: s.color }}/>
                  {s.label}
                </span>
              ))}
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginLeft: 'auto' }}>
                <span style={{ width: 2, height: 14, background: 'var(--text)', opacity: 0.55 }}/>
                Quarter pace ({timeProgress}%)
              </span>
            </div>
          </Card>
        );
      })()}

      {/* Secondary chart row — status donut + portfolio trend + source breakdown */}
      {(() => {
        const statusGroups = [
          { key: 'on-track', label: 'On track', count: counts.byStatus['on-track'] + counts.byStatus['ahead'], color: 'var(--positive)' },
          { key: 'watch',    label: 'Watch',    count: counts.byStatus['watch'],   color: 'var(--warning)' },
          { key: 'off',      label: 'Off track',count: counts.byStatus['off'],     color: 'var(--negative)' },
          { key: 'pending',  label: 'Pending',  count: counts.byStatus['pending'], color: 'var(--text-faint)' },
        ].filter(s => s.count > 0);
        const donutTotal = statusGroups.reduce((a, b) => a + b.count, 0) || 1;

        const sourceGroups = [
          { key: 'google-ads', label: 'Live · Google Ads', count: liveCount,    color: 'var(--positive)' },
          { key: 'manual',     label: 'Manual logging',    count: manualCount,  color: 'var(--primary)' },
          { key: 'pending',    label: 'Pending setup',     count: pendingCount, color: 'var(--warning)' },
        ].filter(s => s.count > 0);
        const sourceTotal = sourceGroups.reduce((a, b) => a + b.count, 0) || 1;

        return (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 16 }}>
            {/* Status donut */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>By status</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>portfolio</span>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                {(() => {
                  const size = 100, stroke = 14;
                  const r = (size - stroke) / 2;
                  const c = 2 * Math.PI * r;
                  let acc = 0;
                  return (
                    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ flexShrink: 0 }}>
                      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--border)" strokeWidth={stroke}/>
                      {statusGroups.map(s => {
                        const len = (s.count / donutTotal) * c;
                        const dasharray = `${len} ${c}`;
                        const offset = -acc;
                        acc += len;
                        return (
                          <circle key={s.key}
                            cx={size / 2} cy={size / 2} r={r}
                            fill="none" stroke={s.color} strokeWidth={stroke}
                            strokeDasharray={dasharray}
                            strokeDashoffset={offset}
                            transform={`rotate(-90 ${size / 2} ${size / 2})`}/>
                        );
                      })}
                      <text x={size / 2} y={size / 2 - 2} textAnchor="middle" dominantBaseline="central"
                        fontSize="22" fontWeight="700" fill="currentColor"
                        style={{ fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>
                        {donutTotal}
                      </text>
                      <text x={size / 2} y={size / 2 + 14} textAnchor="middle" dominantBaseline="central"
                        fontSize="9" fontWeight="500" fill="var(--text-faint)"
                        style={{ textTransform: 'uppercase', letterSpacing: '0.04em' }}>
                        targets
                      </text>
                    </svg>
                  );
                })()}
                <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 6 }}>
                  {statusGroups.map(s => (
                    <div key={s.key} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
                      <span style={{ width: 8, height: 8, borderRadius: 2, background: s.color, flexShrink: 0 }}/>
                      <span style={{ color: 'var(--text)', flex: 1, minWidth: 0 }}>{s.label}</span>
                      <span style={{ color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums', fontFamily: 'JetBrains Mono', fontSize: 11 }}>{s.count}</span>
                    </div>
                  ))}
                </div>
              </div>
            </Card>

            {/* Portfolio trend — overlay sparklines */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>Trend overlay</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>last 24 weeks</span>
              </div>
              {(() => {
                const trended = all.filter(k => Array.isArray(k.trend) && k.trend.length);
                // Normalise each series to its own min-max so they overlay readably
                const w = 100, h = 100;
                return (
                  <>
                    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" width="100%" height={120} style={{ display: 'block' }}>
                      {/* Faint baseline grid */}
                      {[25, 50, 75].map(y => (
                        <line key={y} x1="0" x2={w} y1={y} y2={y} stroke="var(--border)" strokeWidth="0.5" strokeDasharray="2 3"/>
                      ))}
                      {trended.map(k => {
                        const series = k.trend.map(p => p.v ?? p.y ?? 0);
                        const max = Math.max(...series), min = Math.min(...series);
                        const range = Math.max(1, max - min);
                        const pts = series.map((v, i) => {
                          const x = (i / (series.length - 1)) * w;
                          const y = h - ((v - min) / range) * (h - 8) - 4;
                          return `${x.toFixed(2)},${y.toFixed(2)}`;
                        }).join(' ');
                        const color = k.status === 'off' || k.status === 'behind' ? 'var(--negative)'
                                    : k.status === 'watch' || k.status === 'at-risk' ? 'var(--warning)'
                                    : 'var(--positive)';
                        return (
                          <polyline key={k.key} points={pts} fill="none" stroke={color}
                            strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"
                            opacity="0.75" vectorEffect="non-scaling-stroke"/>
                        );
                      })}
                    </svg>
                    <div style={{
                      marginTop: 10, display: 'flex', flexDirection: 'column', gap: 4,
                      fontSize: 11, color: 'var(--text-muted)',
                    }}>
                      {trended.slice(0, 3).map(k => (
                        <div key={k.key} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                          <span style={{
                            width: 12, height: 2,
                            background: k.status === 'watch' ? 'var(--warning)' : k.status === 'off' ? 'var(--negative)' : 'var(--positive)',
                          }}/>
                          <span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{k.label}</span>
                        </div>
                      ))}
                      {trended.length > 3 && (
                        <span style={{ fontSize: 10.5, color: 'var(--text-faint)' }}>+ {trended.length - 3} more</span>
                      )}
                    </div>
                  </>
                );
              })()}
            </Card>

            {/* Source breakdown — stacked horizontal bar */}
            <Card>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                <h3 style={{ fontSize: 13, fontWeight: 600, margin: 0 }}>By data source</h3>
                <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>how each target updates</span>
              </div>
              <div style={{
                display: 'flex', height: 14, borderRadius: 99,
                overflow: 'hidden', background: 'var(--surface-2)',
                marginBottom: 14,
              }}>
                {sourceGroups.map(s => (
                  <div key={s.key}
                    title={`${s.label}: ${s.count} of ${sourceTotal}`}
                    style={{
                      width: `${(s.count / sourceTotal) * 100}%`,
                      background: s.color,
                    }}/>
                ))}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {sourceGroups.map(s => (
                  <div key={s.key} style={{ display: 'grid', gridTemplateColumns: '12px 1fr auto', alignItems: 'center', gap: 8 }}>
                    <span style={{ width: 10, height: 10, borderRadius: 2, background: s.color }}/>
                    <span style={{ fontSize: 12, color: 'var(--text)' }}>{s.label}</span>
                    <span style={{ fontSize: 12, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums', fontFamily: 'JetBrains Mono' }}>{s.count}</span>
                  </div>
                ))}
              </div>
            </Card>
          </div>
        );
      })()}

      {/* Filter bar */}
      <div style={{
        display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8,
        marginBottom: 16,
      }}>
        {statusTabs.map(t => (
          <button key={t.id} onClick={() => setStatusFilter(t.id)} style={{
            padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
            background: statusFilter === t.id ? 'var(--text)' : 'var(--surface)',
            color:      statusFilter === t.id ? 'var(--surface)' : 'var(--text-muted)',
            border: '1px solid ' + (statusFilter === t.id ? 'var(--text)' : 'var(--border)'),
            cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            {t.label}
            <span style={{
              fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 99,
              background: statusFilter === t.id ? 'color-mix(in oklab, var(--surface) 25%, transparent)' : 'var(--surface-2)',
              color:      statusFilter === t.id ? 'var(--surface)' : 'var(--text-muted)',
              fontVariantNumeric: 'tabular-nums',
            }}>{t.n}</span>
          </button>
        ))}

        <div style={{ width: 1, height: 22, background: 'var(--border)', margin: '0 4px' }} />

        {sourceTabs.map(t => (
          <button key={t.id} onClick={() => setSourceFilter(t.id)} style={{
            padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
            background: sourceFilter === t.id ? 'var(--primary)' : 'var(--surface)',
            color:      sourceFilter === t.id ? '#fff' : 'var(--text-muted)',
            border: '1px solid ' + (sourceFilter === t.id ? 'var(--primary)' : 'var(--border)'),
            cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            {t.label}
            {t.n != null && (
              <span style={{
                fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 99,
                background: sourceFilter === t.id ? 'rgba(255,255,255,0.22)' : 'var(--surface-2)',
                color:      sourceFilter === t.id ? '#fff' : 'var(--text-muted)',
                fontVariantNumeric: 'tabular-nums',
              }}>{t.n}</span>
            )}
          </button>
        ))}

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

        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '6px 10px', borderRadius: 8,
          background: 'var(--surface)', border: '1px solid var(--border)',
          minWidth: 220,
        }}>
          <span style={{ color: 'var(--text-faint)', display: 'inline-flex' }}>{I.search}</span>
          <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Search CPTs"
            style={{
              border: 'none', outline: 'none', background: 'transparent',
              color: 'var(--text)', fontSize: 12, flex: 1, fontFamily: 'inherit',
            }}/>
          {query && (
            <button onClick={() => setQuery('')} style={{
              border: 'none', background: 'transparent', color: 'var(--text-faint)',
              cursor: 'pointer', padding: 0, fontSize: 14, lineHeight: 1,
            }}>×</button>
          )}
        </div>
      </div>

      {/* Result count */}
      <div style={{
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
        marginBottom: 10,
      }}>
        <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
          Showing <strong style={{ color: 'var(--text)', fontVariantNumeric: 'tabular-nums' }}>{visible.length}</strong> of {all.length}
        </span>
        <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>Click a card to open its detail view</span>
      </div>

      {/* Cards grid */}
      {visible.length === 0 ? (
        <Card>
          <div style={{
            padding: '48px 16px', textAlign: 'center',
            color: 'var(--text-muted)', fontSize: 13,
          }}>
            No CPTs match these filters.
            <div style={{ marginTop: 12 }}>
              <Btn variant="ghost" size="sm" onClick={() => { setStatusFilter('all'); setSourceFilter('all'); setQuery(''); }}>Reset filters</Btn>
            </div>
          </div>
        </Card>
      ) : (
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 12,
        }}>
          {visible.map(k => (
            <AgreedKpiCard key={k.key} kpi={k} onClick={() => openKpiDetail && openKpiDetail(k.key)} />
          ))}
        </div>
      )}
    </div>
  );
};

// ============================================================
// Website Maintenance — per-site health, performance and change requests
// ============================================================

// Mock per-site health snapshot. Keyed by CLIENT.sites[].id.
// For 'planned-1' we omit health and surface a launch-prep state instead.
const SITE_HEALTH = {
  'lodge': {
    uptime30: 99.98,
    incidents30: 1,
    lastCheck: '2 min ago',
    monitorRegion: 'London (eu-west-2)',
    ssl: { status: 'valid', issuer: "Let's Encrypt R3", daysToExpiry: 56 },
    perf: {
      score: 92, lcp: 1.9, inp: 142, cls: 0.04, ttfb: 320, pageWeight: 1.4, requests: 47,
      // last-30 perf scores for the sparkline trend
      trend: spark(20, 30, 'up'),
    },
    // 30 daily uptime samples (each 0–100). Empty / outage days = lower.
    uptimeDaily: [
      100,100,100,100,100, 100,100, 99.7, 100,100,
      100,100, 99.4, 100,100, 100,100,100,100,100,
      100,100,100, 99.9, 100,100,100,100,100,100,
    ],
    checks: [
      { name: 'SSL certificate',          status: 'pass', detail: "Valid · expires in 56 days" },
      { name: 'robots.txt',               status: 'pass', detail: 'Reachable · indexable' },
      { name: 'XML sitemap',              status: 'pass', detail: '124 URLs · last fetched 2h ago' },
      { name: 'Security headers',         status: 'warn', detail: 'CSP missing · HSTS, X-Content-Type-Options OK' },
      { name: 'Broken links (24h crawl)', status: 'pass', detail: '0 broken · 412 internal links' },
      { name: '404 monitoring',           status: 'pass', detail: '3 soft 404s redirected this week' },
      { name: 'DNS resolution',           status: 'pass', detail: 'A + CNAME OK · TTL 3600' },
      { name: 'WordPress core',           status: 'pass', detail: '6.7.1 · up to date' },
      { name: 'Plugin updates',           status: 'warn', detail: '2 minor updates pending review' },
      { name: 'Database backups',         status: 'pass', detail: 'Last backup 4h ago · 30-day retention' },
    ],
    platform: { name: 'WordPress', version: '6.7.1', latest: '6.7.1' },
    php:      { version: '8.2.15',  latest: '8.3.10' },
    hosting:  { provider: 'Kinsta', region: 'London (eu-west-2)', plan: 'Business 2', stack: 'Nginx · PHP-FPM · MySQL 8.0' },
  },
  'ownership': {
    uptime30: 99.92,
    incidents30: 2,
    lastCheck: '4 min ago',
    monitorRegion: 'London (eu-west-2)',
    ssl: { status: 'valid', issuer: "Let's Encrypt R3", daysToExpiry: 56 },
    perf: {
      score: 84, lcp: 2.6, inp: 198, cls: 0.07, ttfb: 410, pageWeight: 2.1, requests: 62,
      trend: spark(21, 30, 'flat'),
    },
    uptimeDaily: [
      100,100,100, 99.4, 100, 100,100, 99.1, 100,100,
      100, 98.7, 100,100,100, 100,100,100,100,100,
      100,100,100,100, 99.5, 100,100,100,100,100,
    ],
    checks: [
      { name: 'SSL certificate',          status: 'pass', detail: "Valid · expires in 56 days" },
      { name: 'robots.txt',               status: 'pass', detail: 'Reachable · indexable' },
      { name: 'XML sitemap',              status: 'pass', detail: '38 URLs · last fetched 6h ago' },
      { name: 'Security headers',         status: 'fail', detail: 'CSP + Referrer-Policy missing' },
      { name: 'Broken links (24h crawl)', status: 'warn', detail: '2 broken outbound links found' },
      { name: '404 monitoring',           status: 'pass', detail: 'No 404s in last 24h' },
      { name: 'DNS resolution',           status: 'pass', detail: 'A + CNAME OK · TTL 3600' },
      { name: 'WordPress core',           status: 'warn', detail: '6.6.2 · 1 minor behind' },
      { name: 'Plugin updates',           status: 'pass', detail: 'All up to date' },
      { name: 'Database backups',         status: 'pass', detail: 'Last backup 6h ago · 30-day retention' },
    ],
    platform: { name: 'WordPress', version: '6.6.2', latest: '6.7.1' },
    php:      { version: '8.1.27',  latest: '8.3.10' },
    hosting:  { provider: 'Kinsta', region: 'London (eu-west-2)', plan: 'Business 2', stack: 'Nginx · PHP-FPM · MySQL 8.0' },
  },
  'parkex': {
    uptime30: 99.85,
    incidents30: 3,
    lastCheck: '6 min ago',
    monitorRegion: 'London (eu-west-2)',
    ssl: { status: 'expiring', issuer: "Let's Encrypt R3", daysToExpiry: 12 },
    perf: {
      score: 71, lcp: 3.1, inp: 244, cls: 0.12, ttfb: 520, pageWeight: 3.4, requests: 88,
      trend: spark(22, 30, 'down'),
    },
    uptimeDaily: [
      100,100, 98.2, 100,100, 100,100,100,100,100,
      100, 97.4, 100,100,100, 99.3, 100,100,100,100,
      100,100,100,100,100, 100,100,100,100,100,
    ],
    checks: [
      { name: 'SSL certificate',          status: 'warn', detail: 'Renews in 12 days · auto-renew configured' },
      { name: 'robots.txt',               status: 'pass', detail: 'Reachable · indexable' },
      { name: 'XML sitemap',              status: 'warn', detail: 'Stale · last fetched 3d ago' },
      { name: 'Security headers',         status: 'fail', detail: 'CSP, HSTS, Referrer-Policy missing' },
      { name: 'Broken links (24h crawl)', status: 'fail', detail: '7 broken links · 4 in nav' },
      { name: '404 monitoring',           status: 'warn', detail: '11 soft 404s in last 24h' },
      { name: 'DNS resolution',           status: 'pass', detail: 'A + CNAME OK · TTL 3600' },
      { name: 'WordPress core',           status: 'pass', detail: '6.7.1 · up to date' },
      { name: 'Plugin updates',           status: 'fail', detail: '5 updates pending · 2 with security advisories' },
      { name: 'Database backups',         status: 'pass', detail: 'Last backup 12h ago · 30-day retention' },
    ],
    platform: { name: 'WordPress', version: '6.7.1', latest: '6.7.1' },
    php:      { version: '8.0.30',  latest: '8.3.10' },
    hosting:  { provider: 'Kinsta', region: 'London (eu-west-2)', plan: 'Business 2', stack: 'Nginx · PHP-FPM · MySQL 8.0' },
  },
  // 'planned-1' has no health — render launch-prep state
};

const CHANGE_REQUESTS = [
  { id: 'WM-208', site: 'lodge',     title: 'Update homepage hero copy + image for Easter', category: 'Content',  status: 'in-progress', requested: '28 Apr 2026', owner: 'Hayley',  priority: 'normal' },
  { id: 'WM-205', site: 'lodge',     title: 'Add new 3-bed lodge to availability grid',     category: 'Content',  status: 'queued',      requested: '24 Apr 2026', owner: 'Hayley',  priority: 'normal' },
  { id: 'WM-204', site: 'ownership', title: 'Wire HubSpot form for ownership enquiries',    category: 'Dev',      status: 'review',      requested: '21 Apr 2026', owner: 'Nathan',  priority: 'high'   },
  { id: 'WM-201', site: 'parkex',    title: 'Fix broken links in main nav',                 category: 'Bug fix',  status: 'queued',      requested: '20 Apr 2026', owner: 'Nathan',  priority: 'high'   },
  { id: 'WM-198', site: 'parkex',    title: 'Update plugin: WPForms (security release)',    category: 'Maintenance', status: 'scheduled', requested: '19 Apr 2026', owner: 'Nathan', priority: 'urgent' },
  { id: 'WM-194', site: 'lodge',     title: 'Add EV charging info to amenities page',       category: 'Content',  status: 'done',        requested: '14 Apr 2026', owner: 'Hayley',  priority: 'normal' },
  { id: 'WM-187', site: 'ownership', title: 'Compress hero images (3.4MB → target 600KB)',  category: 'Performance', status: 'done',     requested: '08 Apr 2026', owner: 'Nathan',  priority: 'normal' },
];

const REQUEST_STATUS_TONE = {
  'queued':      { label: 'Queued',      bg: 'var(--surface-2)', fg: 'var(--text-muted)' },
  'in-progress': { label: 'In progress', bg: 'color-mix(in oklab, var(--primary) 14%, transparent)', fg: 'var(--primary)' },
  'review':      { label: 'In review',   bg: 'color-mix(in oklab, var(--primary) 14%, transparent)', fg: 'var(--primary)' },
  'scheduled':   { label: 'Scheduled',   bg: 'color-mix(in oklab, var(--warning) 16%, transparent)', fg: 'var(--warning)' },
  'done':        { label: 'Done',        bg: 'color-mix(in oklab, var(--positive) 14%, transparent)', fg: 'var(--positive)' },
};

const PRIORITY_TONE = {
  'urgent': { label: 'Urgent', fg: 'var(--negative)' },
  'high':   { label: 'High',   fg: 'var(--warning)' },
  'normal': { label: 'Normal', fg: 'var(--text-muted)' },
  'low':    { label: 'Low',    fg: 'var(--text-faint)' },
};

const CHECK_TONE = {
  pass: { fg: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 14%, transparent)', label: 'Pass' },
  warn: { fg: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 16%, transparent)',  label: 'Warning' },
  fail: { fg: 'var(--negative)', bg: 'color-mix(in oklab, var(--negative) 14%, transparent)', label: 'Fail' },
};

// Web vital scoring thresholds (Google CrUX bands)
const VITAL_THRESHOLDS = {
  lcp:  { good: 2.5,  poor: 4.0,  unit: 's',  label: 'LCP',  desc: 'Largest Contentful Paint' },
  inp:  { good: 200,  poor: 500,  unit: 'ms', label: 'INP',  desc: 'Interaction to Next Paint' },
  cls:  { good: 0.1,  poor: 0.25, unit: '',   label: 'CLS',  desc: 'Cumulative Layout Shift' },
  ttfb: { good: 800,  poor: 1800, unit: 'ms', label: 'TTFB', desc: 'Time to First Byte' },
};

const vitalBand = (key, val) => {
  const t = VITAL_THRESHOLDS[key]; if (!t) return 'pass';
  if (val <= t.good) return 'pass';
  if (val <= t.poor) return 'warn';
  return 'fail';
};

// Tiny inline brand marks for the Stack & environment strip. Kept simple
// (single-color glyph tokens) so they tint via parent colour rather than
// trying to be pixel-perfect logo recreations.
const WordPressMark = () => (
  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" aria-hidden="true">
    <circle cx="12" cy="12" r="10.5" />
    <path d="M3 9l3.4 8 1.6-4.4-1.1-2.7H3zm6 9l3-8 3 8h-2.6l-.5-1.6h-1.7L9.5 18H9zm6.5-9 .9 2.5L18.7 18l3-9h-2.6l-1.1 3.6L17 9h-1.5z" fill="currentColor" stroke="none" />
  </svg>
);

const PhpMark = () => (
  // Stylised "php" wordmark inside an ellipse — recognisable without nailing the exact PHP logo
  <svg width="26" height="22" viewBox="0 0 32 20" fill="none" stroke="currentColor" strokeWidth="1.2" aria-hidden="true">
    <ellipse cx="16" cy="10" rx="14.5" ry="8.5" />
    <text x="16" y="14" textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize="9" fontWeight="700" fill="currentColor" stroke="none" letterSpacing="-0.5">php</text>
  </svg>
);

const HostMark = () => (
  // Generic "stacked servers" cloud-host glyph
  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <rect x="3" y="4"  width="18" height="6" rx="1.5" />
    <rect x="3" y="14" width="18" height="6" rx="1.5" />
    <circle cx="7" cy="7" r="0.8" fill="currentColor" />
    <circle cx="7" cy="17" r="0.8" fill="currentColor" />
    <path d="M11 7h7M11 17h7" />
  </svg>
);

// Tiny ring chart used in stat tiles. Shows a 0–1 ratio as a stroke arc,
// with an optional centered numeric label.
const MiniRing = ({ value, max = 100, color, size = 40, stroke = 4, label }) => {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(1, max === 0 ? 0 : value / max));
  const filled = c * pct;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} aria-hidden="true">
      <circle cx={size / 2} cy={size / 2} r={r}
        fill="none" stroke="var(--border)" strokeWidth={stroke} />
      <circle cx={size / 2} cy={size / 2} r={r}
        fill="none" stroke={color} strokeWidth={stroke}
        strokeDasharray={`${filled} ${c}`}
        strokeLinecap="round"
        transform={`rotate(-90 ${size / 2} ${size / 2})`}
        style={{ transition: 'stroke-dasharray 0.3s ease' }} />
      {label != null && (
        <text x={size / 2} y={size / 2 + 0.5}
          textAnchor="middle" dominantBaseline="central"
          fontSize={size * 0.32} fontWeight="700"
          fill="currentColor"
          style={{ fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>
          {label}
        </text>
      )}
    </svg>
  );
};

const SiteHealthDot = ({ status }) => {
  const tone = CHECK_TONE[status] || CHECK_TONE.pass;
  return (
    <span style={{
      width: 8, height: 8, borderRadius: '50%', background: tone.fg, display: 'inline-block', flexShrink: 0,
    }}/>
  );
};

const NewRequestModal = ({ site, onClose }) => {
  const [form, setForm] = useState({
    category: 'Content',
    priority: 'normal',
    title: '',
    detail: '',
    when: 'Within a week',
  });
  const [sent, setSent] = useState(false);
  const submit = (e) => { e.preventDefault(); setSent(true); };
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)',
      display: 'grid', placeItems: 'center', zIndex: 100, padding: 16,
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 560,
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)', boxShadow: '0 10px 40px rgba(0,0,0,0.3)',
      }}>
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)',
            background: 'color-mix(in oklab, var(--primary) 10%, transparent)',
            color: 'var(--primary)', display: 'grid', placeItems: 'center',
          }}><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/></svg></div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 15, fontWeight: 600 }}>New maintenance request</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{site.name} · {site.url}</div>
          </div>
          <button onClick={onClose} aria-label="Close" style={{
            width: 32, height: 32, border: 'none', background: 'transparent', color: 'var(--text-muted)',
            borderRadius: 6, cursor: 'pointer', display: 'grid', placeItems: 'center',
          }}><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
        </div>

        {sent ? (
          <div style={{ padding: 32, textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%', margin: '0 auto 16px',
              background: 'color-mix(in oklab, var(--positive) 18%, transparent)',
              color: 'var(--positive)', display: 'grid', placeItems: 'center',
            }}>{I.check}</div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>Request submitted</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 20 }}>
              Nathan will triage this within 1 working day and reply with an ETA in your tickets.
            </div>
            <Btn variant="primary" onClick={onClose} style={{ margin: '0 auto' }}>Done</Btn>
          </div>
        ) : (
          <form onSubmit={submit} style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <FormField label="Category">
                <select value={form.category} onChange={e => setForm(f => ({...f, category: e.target.value}))} style={inputStyle}>
                  {['Content', 'Bug fix', 'New page', 'Performance', 'Dev', 'Maintenance', 'Other'].map(o => <option key={o}>{o}</option>)}
                </select>
              </FormField>
              <FormField label="Priority">
                <select value={form.priority} onChange={e => setForm(f => ({...f, priority: e.target.value}))} style={inputStyle}>
                  {[
                    { v: 'low',    l: 'Low' },
                    { v: 'normal', l: 'Normal' },
                    { v: 'high',   l: 'High' },
                    { v: 'urgent', l: 'Urgent — site impacting' },
                  ].map(o => <option key={o.v} value={o.v}>{o.l}</option>)}
                </select>
              </FormField>
            </div>
            <FormField label="Short title" required>
              <input required value={form.title} onChange={e => setForm(f => ({...f, title: e.target.value}))}
                placeholder="e.g. Update opening hours on contact page" style={inputStyle} />
            </FormField>
            <FormField label="What needs to change?" required>
              <textarea required value={form.detail} onChange={e => setForm(f => ({...f, detail: e.target.value}))}
                rows={4} placeholder="Be as specific as you can — include URLs, copy, links to assets…" style={inputStyle} />
            </FormField>
            <FormField label="When do you need this by?">
              <select value={form.when} onChange={e => setForm(f => ({...f, when: e.target.value}))} style={inputStyle}>
                {['Same day if possible', 'Within a week', 'Within 2 weeks', 'No rush'].map(o => <option key={o}>{o}</option>)}
              </select>
            </FormField>
            <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, paddingTop: 4 }}>
              <Btn variant="secondary" onClick={onClose} type="button">Cancel</Btn>
              <Btn variant="primary" iconRight={I.send}>Submit request</Btn>
            </div>
          </form>
        )}
      </div>
    </div>
  );
};

const VitalCard = ({ vKey, value, perfTrend }) => {
  const t = VITAL_THRESHOLDS[vKey];
  const band = vitalBand(vKey, value);
  const tone = CHECK_TONE[band];
  const display = vKey === 'cls' ? value.toFixed(2)
                : vKey === 'lcp' ? value.toFixed(1) + 's'
                : value + (t.unit ? t.unit : '');
  return (
    <div style={{
      padding: 14, border: '1px solid var(--border)', borderRadius: 'var(--radius)',
      background: 'var(--surface)', display: 'flex', flexDirection: 'column', gap: 6,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 600, letterSpacing: '0.04em' }}>{t.label}</div>
        <span style={{
          fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 99,
          background: tone.bg, color: tone.fg,
        }}>{tone.label}</span>
      </div>
      <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{display}</div>
      <div style={{ fontSize: 11, color: 'var(--text-faint)' }}>{t.desc}</div>
    </div>
  );
};

const UptimeStrip = ({ daily }) => (
  <div style={{ display: 'flex', gap: 2, alignItems: 'flex-end', height: 32 }}>
    {daily.map((u, i) => {
      const tone = u >= 99.9 ? 'var(--positive)'
                 : u >= 99   ? 'var(--warning)'
                 : 'var(--negative)';
      return (
        <div key={i}
          title={`Day ${i + 1}: ${u.toFixed(2)}% uptime`}
          style={{
            flex: 1, height: '100%', background: tone, borderRadius: 1,
            opacity: u >= 99.9 ? 0.85 : 1,
          }}/>
      );
    })}
  </div>
);

const MaintenanceScreen = ({ siteId, setSiteId, setActive }) => {
  const sites = (window.CLIENT?.sites || []);
  // Default to first active site; persist user's selection.
  const initial = siteId || sites.find(s => s.status === 'active')?.id || sites[0]?.id;
  useEffect(() => {
    if (siteId == null && initial) setSiteId(initial);
  }, []); // eslint-disable-line
  const activeId = siteId || initial;
  const site = sites.find(s => s.id === activeId) || sites[0];

  const [requestOpen, setRequestOpen] = useState(false);
  const [statusFilter, setStatusFilter] = useState('open'); // open | done | all

  if (!site) {
    return <div><PageHeader title="Website Maintenance Pro" subtitle="No sites configured for this client" /></div>;
  }

  const isPlanned = site.status === 'planned';
  const health = SITE_HEALTH[site.id];

  const siteRequests = CHANGE_REQUESTS.filter(r => r.site === site.id);
  const visibleRequests = siteRequests.filter(r =>
    statusFilter === 'all'  ? true :
    statusFilter === 'done' ? r.status === 'done' :
    /* open */                r.status !== 'done'
  );

  const openCount = siteRequests.filter(r => r.status !== 'done').length;
  const urgentCount = siteRequests.filter(r => r.status !== 'done' && (r.priority === 'urgent' || r.priority === 'high')).length;

  return (
    <div>
      {/* Channel-style header — matches Google Ads / SEO */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)', background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center', color: 'var(--primary)',
          }}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-7 7L4 21l1.3-1.3 7-7a4 4 0 0 0 5.4-5.4l-2.7 2.7-2-2 2.7-2.7z"/>
            </svg>
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Website Maintenance Pro</h1>
              <Badge tone="positive">● Active</Badge>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
              Live health checks, performance and change requests for every site
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <Btn variant="secondary" size="sm" icon={I.external} onClick={() => window.open('https://' + site.url, '_blank')}>Open site</Btn>
          <Btn variant="primary" size="sm" icon={I.plus} onClick={() => setActive && setActive('growth')}>
            Add Website
          </Btn>
        </div>
      </div>

      {/* Site switcher */}
      <div style={{
        display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16,
        padding: 6, background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)',
      }}>
        {sites.map(s => {
          const on = s.id === site.id;
          const planned = s.status === 'planned';
          return (
            <button key={s.id} onClick={() => setSiteId(s.id)} style={{
              flex: '1 1 200px',
              padding: '12px 14px', textAlign: 'left',
              background: on ? 'color-mix(in oklab, var(--primary) 10%, transparent)' : 'transparent',
              color: on ? 'var(--primary)' : 'var(--text)',
              border: '1px solid ' + (on ? 'color-mix(in oklab, var(--primary) 35%, transparent)' : 'transparent'),
              borderRadius: 'calc(var(--radius) - 4px)',
              cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 10,
            }}>
              <span style={{
                width: 8, height: 8, borderRadius: '50%',
                background: planned ? 'transparent' : 'var(--positive)',
                border: planned ? '1.5px dashed var(--text-faint)' : 'none',
                flexShrink: 0,
              }}/>
              <span style={{ minWidth: 0, flex: 1 }}>
                <span style={{ display: 'block', fontSize: 13, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s.name}</span>
                <span style={{ display: 'block', fontSize: 11, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s.url}</span>
              </span>
              {planned && (
                <span style={{
                  fontSize: 10, fontWeight: 600, padding: '2px 6px', borderRadius: 99,
                  background: 'var(--surface-2)', color: 'var(--text-muted)',
                }}>Planned</span>
              )}
            </button>
          );
        })}
      </div>

      {isPlanned ? (
        // Launch-prep state — no health, just a clear "not yet" panel
        <Card>
          <div style={{ padding: 32, textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%', margin: '0 auto 16px',
              background: 'var(--surface-2)', color: 'var(--text-muted)',
              display: 'grid', placeItems: 'center',
            }}>
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
            </div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>Site not yet launched</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 16, maxWidth: 460, margin: '0 auto 16px' }}>
              {site.role || 'New build'} · health checks and request flow will go live once {site.name} ships. Target launch: <strong>August 2026</strong>.
            </div>
            <div style={{ display: 'inline-flex', gap: 8, justifyContent: 'center' }}>
              <Btn variant="secondary" size="sm" onClick={() => setActive && setActive('tickets')}>Talk to your team</Btn>
              <Btn variant="ghost" size="sm" onClick={() => { const first = sites.find(s => s.status === 'active'); if (first) setSiteId(first.id); }}>Switch to a live site</Btn>
            </div>
          </div>
        </Card>
      ) : (
        <>
          {/* Live status strip (left, 2/3) + screenshot (right, 1/3) — 16:9 capture */}
          <div style={{
            display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 16,
            marginBottom: 16, alignItems: 'stretch',
          }}>
          <Card padding={0} style={{ overflow: 'hidden', order: 2 }}>
            <div style={{ position: 'relative', aspectRatio: '16 / 9', background: 'var(--surface-2)' }}>
              {site.preview ? (
                <img
                  src={site.preview}
                  alt={site.name + ' — homepage screenshot'}
                  style={{
                    width: '100%', height: '100%',
                    objectFit: 'cover', objectPosition: 'top center', display: 'block',
                  }}
                />
              ) : (
                <div style={{
                  width: '100%', height: '100%',
                  display: 'grid', placeItems: 'center',
                  color: 'var(--text-faint)', fontSize: 12,
                }}>
                  Screenshot pending — will capture on next health check
                </div>
              )}
              {/* Soft fade into the card body */}
              <div style={{
                position: 'absolute', inset: 0, pointerEvents: 'none',
                background: 'linear-gradient(to bottom, transparent 60%, color-mix(in oklab, var(--surface) 75%, transparent) 100%)',
              }}/>
              {/* Browser-chrome URL bar in the top-left, like a real screenshot capture */}
              <div style={{
                position: 'absolute', top: 12, left: 12,
                display: 'inline-flex', alignItems: 'center', gap: 8,
                padding: '4px 10px 4px 8px', borderRadius: 99,
                background: 'color-mix(in oklab, #000 55%, transparent)',
                color: '#fff', fontSize: 11, fontWeight: 500,
                backdropFilter: 'blur(6px)',
              }}>
                <span style={{ display: 'inline-flex', gap: 3 }}>
                  <span style={{ width: 7, height: 7, borderRadius: '50%', background: '#ff5f57' }}/>
                  <span style={{ width: 7, height: 7, borderRadius: '50%', background: '#febc2e' }}/>
                  <span style={{ width: 7, height: 7, borderRadius: '50%', background: '#28c840' }}/>
                </span>
                <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10.5, opacity: 0.85 }}>
                  https://{site.url}
                </span>
              </div>
              {/* Visit-site CTA top-right */}
              <a href={'https://' + site.url} target="_blank" rel="noopener noreferrer"
                style={{
                  position: 'absolute', top: 12, right: 12,
                  display: 'inline-flex', alignItems: 'center', gap: 5,
                  padding: '4px 10px', borderRadius: 99,
                  background: 'color-mix(in oklab, #000 55%, transparent)',
                  color: '#fff', fontSize: 11, fontWeight: 500,
                  textDecoration: 'none',
                  backdropFilter: 'blur(6px)',
                }}>
                Visit site
                <span style={{ width: 12, height: 12, display: 'inline-flex' }}>{I.external}</span>
              </a>
              {/* Capture caption bottom-left */}
              <div style={{
                position: 'absolute', left: 16, bottom: 14,
                color: '#fff', textShadow: '0 1px 4px rgba(0,0,0,0.55)',
              }}>
                <div style={{ fontSize: 14, fontWeight: 600, lineHeight: 1.2 }}>{site.name}</div>
                <div style={{ fontSize: 11, opacity: 0.85, marginTop: 2 }}>
                  {site.role}
                  {health?.lastCheck && <> · captured {health.lastCheck}</>}
                </div>
              </div>
            </div>
          </Card>

          {/* Live status strip — sits to the left of the screenshot, 2x2 layout */}
          <Card padding={0} style={{ height: '100%', order: 1 }}>
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gridTemplateRows: '1fr 1fr',
              height: '100%',
            }}>
              {(() => {
                const totalRequests = siteRequests.length;
                const doneCount = siteRequests.filter(r => r.status === 'done').length;
                // Let's Encrypt cert lifetime is 90 days — the ring shows time remaining.
                const sslLifetime = 90;
                return [
                  {
                    label: 'Uptime · 30d',
                    value: health.uptime30.toFixed(2) + '%',
                    sub: `${health.incidents30} incident${health.incidents30 === 1 ? '' : 's'} · last check ${health.lastCheck}`,
                    tone: health.uptime30 >= 99.9 ? 'positive' : health.uptime30 >= 99 ? 'warning' : 'negative',
                    // ring scaled into the 99–100 band so 99.85% reads visibly different from 99.98%
                    ring: { value: Math.max(0, health.uptime30 - 99), max: 1, label: null },
                  },
                  {
                    label: 'Page speed score',
                    value: health.perf.score,
                    sub: `LCP ${health.perf.lcp}s · INP ${health.perf.inp}ms`,
                    tone: health.perf.score >= 90 ? 'positive' : health.perf.score >= 70 ? 'warning' : 'negative',
                    ring: { value: health.perf.score, max: 100, label: health.perf.score },
                  },
                  {
                    label: 'SSL',
                    value: health.ssl.status === 'expiring' ? `Renews in ${health.ssl.daysToExpiry}d` : 'Valid',
                    sub: health.ssl.issuer,
                    tone: health.ssl.status === 'expiring' ? 'warning' : 'positive',
                    ring: { value: health.ssl.daysToExpiry, max: sslLifetime, label: health.ssl.daysToExpiry + 'd' },
                  },
                  {
                    label: 'Open requests',
                    value: openCount,
                    sub: urgentCount ? `${urgentCount} urgent / high` : (totalRequests ? `${doneCount}/${totalRequests} done` : 'no requests yet'),
                    tone: urgentCount ? 'warning' : 'muted',
                    // Fill the ring with the share triaged (done / total). Center label = open count.
                    ring: { value: doneCount, max: Math.max(1, totalRequests), label: openCount },
                  },
                ];
              })().map((s, i) => {
                const accent = s.tone === 'positive' ? 'var(--positive)'
                             : s.tone === 'warning'  ? 'var(--warning)'
                             : s.tone === 'negative' ? 'var(--negative)'
                             : 'var(--text-muted)';
                return (
                  <div key={s.label} style={{
                    padding: '16px 20px',
                    borderLeft: i % 2 === 1 ? '1px solid var(--border)' : 'none',
                    borderTop:  i >= 2      ? '1px solid var(--border)' : 'none',
                    display: 'flex', alignItems: 'center', gap: 14,
                    minWidth: 0,
                  }}>
                    <div style={{ flexShrink: 0, color: accent }}>
                      <MiniRing
                        value={s.ring.value}
                        max={s.ring.max}
                        color={accent}
                        size={44}
                        stroke={4}
                        label={s.ring.label}
                      />
                    </div>
                    <div style={{ minWidth: 0, flex: 1 }}>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
                      <div style={{ fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2, letterSpacing: '-0.01em' }}>{s.value}</div>
                      <div style={{
                        fontSize: 11, marginTop: 2,
                        color: accent,
                        overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                      }}>{s.sub}</div>
                    </div>
                  </div>
                );
              })}
            </div>
          </Card>
          </div>

          {/* Stack & environment — what the site is built on */}
          {(() => {
            const cmp = (a, b) => {
              const pa = a.split('.').map(Number);
              const pb = b.split('.').map(Number);
              for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
                const x = pa[i] || 0, y = pb[i] || 0;
                if (x !== y) return x < y ? -1 : 1;
              }
              return 0;
            };

            // Platform status (e.g. WordPress 6.6.2 vs latest 6.7.1)
            const pl = health.platform;
            const plDiff = cmp(pl.version, pl.latest);
            const plMaj = pl.version.split('.')[0] !== pl.latest.split('.')[0];
            const plStatus = plDiff === 0 ? 'pass' : plMaj ? 'fail' : 'warn';
            const plLabel  = plDiff === 0 ? 'Up to date' : `${pl.latest} available`;

            // PHP status — anything < 8.1 is end-of-life as of mid-2026
            const ph = health.php;
            const phMajMin = ph.version.split('.').slice(0, 2).join('.');
            const phEol = cmp(phMajMin + '.0', '8.1.0') < 0;
            const phBehind = cmp(ph.version, ph.latest) < 0;
            const phStatus = phEol ? 'fail' : phBehind ? 'warn' : 'pass';
            const phLabel  = phEol ? 'End of life · upgrade urgently'
                            : phBehind ? `Supported · ${ph.latest} available`
                            : 'Latest stable';

            const ho = health.hosting;

            const items = [
              {
                label: 'Platform',
                logo: <WordPressMark />,
                tone: { fg: '#21759b', bg: 'color-mix(in oklab, #21759b 14%, transparent)' },
                title: pl.name,
                version: pl.version,
                status: plStatus,
                statusLabel: plLabel,
              },
              {
                label: 'PHP',
                logo: <PhpMark />,
                tone: { fg: '#777bb4', bg: 'color-mix(in oklab, #777bb4 16%, transparent)' },
                title: 'PHP',
                version: ph.version,
                status: phStatus,
                statusLabel: phLabel,
              },
              {
                label: 'Hosting',
                logo: <HostMark />,
                tone: { fg: 'var(--primary)', bg: 'color-mix(in oklab, var(--primary) 12%, transparent)' },
                title: ho.provider,
                version: ho.region.replace(/\s*\(.*\)$/, ''), // 'London (eu-west-2)' → 'London'
                status: 'pass',
                statusLabel: `${ho.plan} · ${ho.stack}`,
              },
            ];

            return (
              <Card padding={0} style={{ marginBottom: 16 }}>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
                  {items.map((it, i) => {
                    const tone = CHECK_TONE[it.status];
                    return (
                      <div key={it.label} style={{
                        padding: '14px 18px',
                        borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                        display: 'flex', alignItems: 'center', gap: 12,
                        minWidth: 0,
                      }}>
                        <div style={{
                          width: 40, height: 40, borderRadius: 8, flexShrink: 0,
                          background: it.tone.bg, color: it.tone.fg,
                          display: 'grid', placeItems: 'center',
                        }}>{it.logo}</div>
                        <div style={{ minWidth: 0, flex: 1 }}>
                          <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{it.label}</div>
                          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 2, minWidth: 0 }}>
                            <span style={{ fontSize: 14, fontWeight: 600, lineHeight: 1.2 }}>{it.title}</span>
                            <span style={{ fontSize: 12, color: 'var(--text-muted)', fontFamily: 'JetBrains Mono', fontVariantNumeric: 'tabular-nums' }}>{it.version}</span>
                          </div>
                          <div style={{
                            display: 'inline-flex', alignItems: 'center', gap: 5,
                            marginTop: 4, fontSize: 11,
                            color: tone.fg, minWidth: 0,
                            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                            maxWidth: '100%',
                          }}>
                            <span style={{
                              width: 6, height: 6, borderRadius: '50%',
                              background: tone.fg, flexShrink: 0,
                            }}/>
                            <span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{it.statusLabel}</span>
                          </div>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </Card>
            );
          })()}

          <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 16, alignItems: 'start' }}>
            {/* LEFT column */}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

              {/* Performance / Core Web Vitals */}
              <Card>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 10 }}>
                  <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Performance & Core Web Vitals</h3>
                  <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>Mobile · synthetic test · {health.monitorRegion}</span>
                </div>

                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 12 }}>
                  <VitalCard vKey="lcp"  value={health.perf.lcp} />
                  <VitalCard vKey="inp"  value={health.perf.inp} />
                  <VitalCard vKey="cls"  value={health.perf.cls} />
                  <VitalCard vKey="ttfb" value={health.perf.ttfb} />
                </div>

                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10, fontSize: 12 }}>
                  <div style={{ padding: '8px 12px', background: 'var(--surface-2)', borderRadius: 8 }}>
                    <div style={{ color: 'var(--text-faint)', fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.04em' }}>Page weight</div>
                    <div style={{ fontWeight: 600, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>{health.perf.pageWeight} MB</div>
                  </div>
                  <div style={{ padding: '8px 12px', background: 'var(--surface-2)', borderRadius: 8 }}>
                    <div style={{ color: 'var(--text-faint)', fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.04em' }}>Requests</div>
                    <div style={{ fontWeight: 600, fontSize: 13, fontVariantNumeric: 'tabular-nums' }}>{health.perf.requests}</div>
                  </div>
                  <div style={{ padding: '8px 12px', background: 'var(--surface-2)', borderRadius: 8 }}>
                    <div style={{ color: 'var(--text-faint)', fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.04em' }}>30d trend</div>
                    <div style={{ height: 22, marginTop: 2 }}>
                      <Sparkline data={health.perf.trend} positive={true} />
                    </div>
                  </div>
                </div>
              </Card>

              {/* Uptime history */}
              <Card>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                  <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Uptime · last 30 days</h3>
                  <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>1-min interval · checked from {health.monitorRegion}</span>
                </div>
                <UptimeStrip daily={health.uptimeDaily} />
                <div style={{
                  display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                  marginTop: 10, fontSize: 11, color: 'var(--text-muted)',
                }}>
                  <span>30 days ago</span>
                  <span style={{ display: 'inline-flex', gap: 12 }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                      <span style={{ width: 8, height: 8, borderRadius: 1, background: 'var(--positive)' }}/> ≥ 99.9%
                    </span>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                      <span style={{ width: 8, height: 8, borderRadius: 1, background: 'var(--warning)' }}/> 99–99.9%
                    </span>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                      <span style={{ width: 8, height: 8, borderRadius: 1, background: 'var(--negative)' }}/> &lt; 99%
                    </span>
                  </span>
                  <span>Today</span>
                </div>
              </Card>

              {/* Automated checks */}
              <Card>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                  <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Automated health checks</h3>
                  <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{health.platform.name} {health.platform.version} · {health.hosting.provider}</span>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column' }}>
                  {health.checks.map((c, i) => {
                    const tone = CHECK_TONE[c.status];
                    return (
                      <div key={c.name} style={{
                        display: 'grid', gridTemplateColumns: '20px 1fr auto', alignItems: 'center', gap: 10,
                        padding: '10px 0',
                        borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                      }}>
                        <SiteHealthDot status={c.status} />
                        <div style={{ minWidth: 0 }}>
                          <div style={{ fontSize: 13, fontWeight: 500 }}>{c.name}</div>
                          <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{c.detail}</div>
                        </div>
                        <span style={{
                          fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
                          background: tone.bg, color: tone.fg, whiteSpace: 'nowrap',
                        }}>{tone.label}</span>
                      </div>
                    );
                  })}
                </div>
              </Card>
            </div>

            {/* RIGHT column — change requests */}
            <div>
              <Card>
                <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
                  <h3 style={{ fontSize: 14, fontWeight: 600, margin: 0 }}>Change requests</h3>
                  <Btn variant="primary" size="sm" icon={I.plus} onClick={() => setRequestOpen(true)}>New request</Btn>
                </div>

                <div style={{ display: 'flex', gap: 6, marginBottom: 12 }}>
                  {[
                    { id: 'open', label: 'Open',  n: openCount },
                    { id: 'done', label: 'Done',  n: siteRequests.filter(r => r.status === 'done').length },
                    { id: 'all',  label: 'All',   n: siteRequests.length },
                  ].map(t => (
                    <button key={t.id} onClick={() => setStatusFilter(t.id)} style={{
                      padding: '4px 10px', borderRadius: 99, fontSize: 11, fontWeight: 500,
                      background: statusFilter === t.id ? 'var(--text)' : 'var(--surface)',
                      color:      statusFilter === t.id ? 'var(--surface)' : 'var(--text-muted)',
                      border: '1px solid ' + (statusFilter === t.id ? 'var(--text)' : 'var(--border)'),
                      cursor: 'pointer',
                      display: 'inline-flex', alignItems: 'center', gap: 5,
                    }}>{t.label} <span style={{
                      fontSize: 10, fontWeight: 600,
                      fontVariantNumeric: 'tabular-nums',
                      opacity: 0.7,
                    }}>{t.n}</span></button>
                  ))}
                </div>

                {visibleRequests.length === 0 ? (
                  <div style={{
                    padding: '32px 12px', textAlign: 'center',
                    color: 'var(--text-muted)', fontSize: 12,
                    border: '1px dashed var(--border)', borderRadius: 8,
                  }}>
                    No {statusFilter === 'done' ? 'completed' : statusFilter === 'open' ? 'open' : ''} requests for this site.
                  </div>
                ) : (
                  <div style={{ display: 'flex', flexDirection: 'column' }}>
                    {visibleRequests.map((r, i) => {
                      const s = REQUEST_STATUS_TONE[r.status];
                      const p = PRIORITY_TONE[r.priority];
                      return (
                        <div key={r.id} style={{
                          padding: '12px 0',
                          borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                          display: 'flex', flexDirection: 'column', gap: 6,
                        }}>
                          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 8 }}>
                            <div style={{ minWidth: 0 }}>
                              <div style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.3 }}>{r.title}</div>
                              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 3, fontFamily: 'JetBrains Mono' }}>
                                {r.id} · {r.category} · {r.requested}
                              </div>
                            </div>
                            <span style={{
                              fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
                              background: s.bg, color: s.fg, whiteSpace: 'nowrap', flexShrink: 0,
                            }}>{s.label}</span>
                          </div>
                          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 11 }}>
                            <span style={{ color: 'var(--text-muted)' }}>Owner · {r.owner}</span>
                            <span style={{ color: p.fg, fontWeight: 600 }}>{p.label}</span>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}

                <div style={{
                  marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--border)',
                  fontSize: 11, color: 'var(--text-muted)',
                }}>
                  Average turnaround for content updates: <strong style={{ color: 'var(--text)' }}>1.2 working days</strong>
                </div>
              </Card>
            </div>
          </div>
        </>
      )}

      {requestOpen && <NewRequestModal site={site} onClose={() => setRequestOpen(false)} />}
    </div>
  );
};

// ============================================================
// My Clicky Team — hierarchical org chart of who's working on the account.
// AM (Joe) sits as the lead, three managers report to him, and Shannon
// reports to Matt as a secondary tier.
// ============================================================

const TeamMemberCard = ({ person, tier, onSelect, onContact, selected }) => {
  const tone = person.status === 'online' ? 'positive'
             : person.status === 'away'   ? 'warning'
             : 'muted';
  const toneColor = tone === 'positive' ? 'var(--positive)'
                  : tone === 'warning'  ? 'var(--warning)'
                  : 'var(--text-faint)';
  const isLead = tier === 'lead';
  const reportsTo = person.reportsTo;
  return (
    <div
      onClick={() => onSelect && onSelect(person)}
      role={onSelect ? 'button' : undefined}
      style={{
        background: 'var(--surface)',
        border: '1px solid ' + (selected ? 'var(--primary)' : 'var(--border)'),
        boxShadow: selected ? '0 0 0 3px color-mix(in oklab, var(--primary) 15%, transparent)' : 'var(--shadow-sm)',
        borderRadius: 'var(--radius)',
        padding: isLead ? 18 : 14,
        display: 'flex', flexDirection: 'column', gap: isLead ? 12 : 10,
        cursor: onSelect ? 'pointer' : 'default',
        transition: 'border-color 0.12s, box-shadow 0.12s',
        position: 'relative',
      }}
      onMouseEnter={onSelect ? e => {
        if (!selected) { e.currentTarget.style.borderColor = 'var(--primary)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; }
      } : undefined}
      onMouseLeave={onSelect ? e => {
        if (!selected) { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.boxShadow = 'var(--shadow-sm)'; }
      } : undefined}
    >
      {isLead && (
        <span style={{
          position: 'absolute', top: 12, right: 12,
          fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
          background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
          color: 'var(--primary)', letterSpacing: '0.04em', textTransform: 'uppercase',
        }}>Account Manager</span>
      )}

      <div style={{ display: 'flex', alignItems: 'center', gap: isLead ? 16 : 12 }}>
        <div style={{ position: 'relative', flexShrink: 0 }}>
          <PersonAvatar name={person.name} size={isLead ? 64 : 48} hue={person.hue} src={person.src} />
          <span style={{
            position: 'absolute', bottom: 0, right: 0,
            width: isLead ? 14 : 12, height: isLead ? 14 : 12, borderRadius: '50%',
            background: toneColor, border: '2px solid var(--surface)',
          }}/>
        </div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: isLead ? 16 : 14, fontWeight: 700, letterSpacing: '-0.01em' }}>{person.name}</div>
          <div style={{ fontSize: isLead ? 12.5 : 11.5, color: 'var(--text-muted)', marginTop: 2 }}>{person.role}</div>
          <div style={{ fontSize: 11, color: toneColor, marginTop: 4, display: 'flex', alignItems: 'center', gap: 5 }}>
            <span style={{ width: 6, height: 6, borderRadius: '50%', background: toneColor }}/>
            {person.status === 'online' ? 'Online now' : person.status === 'away' ? 'Away' : 'Offline'}
            <span style={{ color: 'var(--text-faint)' }}>·</span>
            <span style={{ color: 'var(--text-muted)' }}>{person.meta}</span>
          </div>
        </div>
      </div>

      {/* Bio — shown on lead and selected card */}
      {(isLead || selected) && person.bio && (
        <div style={{
          fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5,
          paddingTop: 4, borderTop: '1px solid var(--border)', marginTop: 2,
        }}>{person.bio}</div>
      )}

      {/* Focus area chips */}
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
        {person.focus.map(f => (
          <span key={f} style={{
            fontSize: 10.5, padding: '3px 8px', borderRadius: 99,
            background: 'var(--surface-2)', color: 'var(--text-muted)',
            fontWeight: 500,
          }}>{f}</span>
        ))}
      </div>

      {/* Reports-to row — shown for non-lead so the secondary hierarchy
          (Shannon → Matt) is visible inline without needing a deeper tree. */}
      {reportsTo && (
        <div style={{
          fontSize: 11, color: 'var(--text-faint)',
          display: 'flex', alignItems: 'center', gap: 4,
        }}>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
          Reports to <span style={{ color: 'var(--text-muted)', fontWeight: 500 }}>{reportsTo}</span>
        </div>
      )}

      {/* Contact actions */}
      <div style={{
        display: 'flex', gap: 6,
        paddingTop: 6, marginTop: 'auto',
        borderTop: '1px solid var(--border)',
      }}>
        <a href={`mailto:${person.email}`} onClick={e => e.stopPropagation()}
          style={{
            flex: 1, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
            padding: '6px 10px', borderRadius: 6,
            background: 'var(--surface)', color: 'var(--text-muted)',
            border: '1px solid var(--border)', fontSize: 11, fontWeight: 500,
            textDecoration: 'none', cursor: 'pointer',
          }}
          onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface-2)'; e.currentTarget.style.color = 'var(--text)'; }}
          onMouseLeave={e => { e.currentTarget.style.background = 'var(--surface)'; e.currentTarget.style.color = 'var(--text-muted)'; }}
        >
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>
          Email
        </a>
        <a href={`tel:${person.phone.replace(/\s/g, '')}`} onClick={e => e.stopPropagation()}
          style={{
            flex: 1, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
            padding: '6px 10px', borderRadius: 6,
            background: 'var(--surface)', color: 'var(--text-muted)',
            border: '1px solid var(--border)', fontSize: 11, fontWeight: 500,
            textDecoration: 'none', cursor: 'pointer',
          }}
          onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface-2)'; e.currentTarget.style.color = 'var(--text)'; }}
          onMouseLeave={e => { e.currentTarget.style.background = 'var(--surface)'; e.currentTarget.style.color = 'var(--text-muted)'; }}
        >
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
          Call
        </a>
      </div>
    </div>
  );
};

// Compact roster row — avatar + name + role + status dot, used in the
// left-hand list to switch the spotlighted person.
const TeamRosterRow = ({ person, isActive, onClick, isLead }) => {
  const tone = person.status === 'online' ? 'var(--positive)'
             : person.status === 'away'   ? 'var(--warning)'
             : 'var(--text-faint)';
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 12,
      width: '100%', padding: '10px 12px',
      background: isActive ? 'color-mix(in oklab, var(--primary) 10%, transparent)' : 'transparent',
      color: 'inherit', border: 'none', borderRadius: 8,
      cursor: 'pointer', textAlign: 'left',
      transition: 'background 120ms ease',
    }}
      onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = 'var(--hover)'; }}
      onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = 'transparent'; }}
    >
      <div style={{ position: 'relative', flexShrink: 0 }}>
        <PersonAvatar name={person.name} size={36} hue={person.hue} src={person.src} />
        <span style={{
          position: 'absolute', bottom: -1, right: -1,
          width: 10, height: 10, borderRadius: '50%',
          background: tone, border: '2px solid var(--surface)',
        }}/>
      </div>
      <div style={{ minWidth: 0, flex: 1 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ fontSize: 13, fontWeight: 600, color: isActive ? 'var(--primary)' : 'var(--text)' }}>{person.name}</span>
          {isLead && (
            <span style={{
              fontSize: 9, fontWeight: 700, padding: '1px 5px', borderRadius: 99,
              background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
              color: 'var(--primary)', letterSpacing: '0.04em', textTransform: 'uppercase',
            }}>AM</span>
          )}
        </div>
        <div style={{
          fontSize: 11, color: 'var(--text-muted)', marginTop: 1,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{person.role}</div>
      </div>
    </button>
  );
};

// Main detail panel — the full "profile" view of the spotlighted person.
const TeamProfilePanel = ({ person }) => {
  if (!person) return null;
  const tone = person.status === 'online' ? 'var(--positive)'
             : person.status === 'away'   ? 'var(--warning)'
             : 'var(--text-faint)';
  const teamMate = (name) => TEAM.find(p => p.name === name);
  const mgr = person.reportsTo ? teamMate(person.reportsTo) : null;
  const reports = TEAM.filter(p => p.reportsTo === person.name);

  return (
    <div style={{
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--radius)', overflow: 'hidden',
      display: 'flex', flexDirection: 'column',
    }}>
      {/* Hero band */}
      <div style={{
        position: 'relative', padding: '24px 28px 22px',
        background: `linear-gradient(135deg, color-mix(in oklab, oklch(0.92 0.04 ${person.hue}) 40%, var(--surface)) 0%, var(--surface) 60%)`,
      }}>
        {person.primary && (
          <span style={{
            position: 'absolute', top: 16, right: 16,
            fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99,
            background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
            color: 'var(--primary)', letterSpacing: '0.04em', textTransform: 'uppercase',
          }}>Account Manager</span>
        )}
        <div style={{ display: 'flex', alignItems: 'center', gap: 18 }}>
          <div style={{ position: 'relative', flexShrink: 0 }}>
            <PersonAvatar name={person.name} size={84} hue={person.hue} src={person.src} />
            <span style={{
              position: 'absolute', bottom: 2, right: 2,
              width: 18, height: 18, borderRadius: '50%',
              background: tone, border: '3px solid var(--surface)',
            }}/>
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <h1 style={{ fontSize: 24, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>{person.name}</h1>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 4 }}>{person.role}</div>
            <div style={{
              fontSize: 11.5, color: tone, marginTop: 8,
              display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap',
            }}>
              <span style={{ width: 7, height: 7, borderRadius: '50%', background: tone }}/>
              {person.status === 'online' ? 'Online now' : person.status === 'away' ? 'Away' : 'Offline'}
              <span style={{ color: 'var(--text-faint)' }}>·</span>
              <span style={{ color: 'var(--text-muted)' }}>{person.meta}</span>
              {person.joined && (<>
                <span style={{ color: 'var(--text-faint)' }}>·</span>
                <span style={{ color: 'var(--text-muted)' }}>At Clicky since {person.joined}</span>
              </>)}
            </div>
          </div>
        </div>
      </div>

      {/* Body */}
      <div style={{ padding: '20px 28px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
        {person.bio && (
          <p style={{ margin: 0, fontSize: 14, color: 'var(--text)', lineHeight: 1.55 }}>{person.bio}</p>
        )}

        {/* Focus areas */}
        {person.focus && person.focus.length > 0 && (
          <div>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>
              Focus areas for {CLIENT.shortName}
            </div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {person.focus.map(f => (
                <span key={f} style={{
                  fontSize: 11, padding: '4px 10px', borderRadius: 99,
                  background: 'var(--surface-2)', color: 'var(--text)',
                  border: '1px solid var(--border)', fontWeight: 500,
                }}>{f}</span>
              ))}
            </div>
          </div>
        )}

        {/* Qualifications & certifications */}
        {(() => {
          const quals = getTeamQualifications(person.name);
          if (!quals.length) return null;
          const verifiedCount = quals.filter(q => q.verified).length;
          return (
            <div>
              <div style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                marginBottom: 8, gap: 8,
              }}>
                <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                  Certifications & qualifications
                </div>
                <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                  {quals.length} {quals.length === 1 ? 'cert' : 'certs'}
                  {verifiedCount > 0 && (
                    <> · <span style={{ color: 'var(--positive)', fontWeight: 600 }}>{verifiedCount} verified</span></>
                  )}
                </span>
              </div>
              <QualificationsList qualifications={quals} />
            </div>
          );
        })()}

        {/* Contact + relationships row */}
        <div style={{
          display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16,
        }}>
          {/* Contact */}
          <div style={{
            padding: 14, borderRadius: 8,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
          }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Get in touch</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              <a href={`mailto:${person.email}`} style={{
                display: 'inline-flex', alignItems: 'center', gap: 8,
                fontSize: 13, color: 'var(--text)', textDecoration: 'none', fontWeight: 500,
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-muted)' }}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>
                {person.email}
              </a>
              <a href={`tel:${(person.phone || '').replace(/\s/g, '')}`} style={{
                display: 'inline-flex', alignItems: 'center', gap: 8,
                fontSize: 13, color: 'var(--text)', textDecoration: 'none', fontWeight: 500,
                fontVariantNumeric: 'tabular-nums',
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-muted)' }}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
                {person.phone}
              </a>
            </div>
            <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
              <Btn variant="primary" size="sm" icon={I.send}>Message</Btn>
              <Btn variant="secondary" size="sm" icon={I.calendar}>Book 15-min</Btn>
            </div>
          </div>

          {/* Relationships */}
          <div style={{
            padding: 14, borderRadius: 8,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
          }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>Where they fit</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {mgr ? (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)', minWidth: 80 }}>Reports to</span>
                  <PersonAvatar name={mgr.name} size={22} hue={mgr.hue} src={mgr.src} />
                  <span style={{ fontSize: 12, color: 'var(--text)', fontWeight: 500 }}>{mgr.name}</span>
                </div>
              ) : person.primary && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)', minWidth: 80 }}>Role</span>
                  <span style={{
                    fontSize: 11, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
                    background: 'color-mix(in oklab, var(--primary) 14%, transparent)',
                    color: 'var(--primary)',
                  }}>Account lead</span>
                </div>
              )}
              {reports.length > 0 && (
                <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)', minWidth: 80, paddingTop: 3 }}>Direct reports</span>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                    {reports.map(r => (
                      <div key={r.name} style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                        <PersonAvatar name={r.name} size={20} hue={r.hue} src={r.src} />
                        <span style={{ fontSize: 11.5, color: 'var(--text)', fontWeight: 500 }}>{r.name.split(' ')[0]}</span>
                      </div>
                    ))}
                  </div>
                </div>
              )}
              {person.joined && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)', minWidth: 80 }}>Tenure</span>
                  <span style={{ fontSize: 12, color: 'var(--text)' }}>At Clicky since {person.joined}</span>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

const TeamScreen = () => {
  const lead = TEAM.find(p => p.primary);
  const directs    = TEAM.filter(p => p.reportsTo === lead?.name);
  const secondTier = TEAM.filter(p => directs.some(d => d.name === p.reportsTo));
  const [selectedName, setSelectedName] = useState(lead?.name || TEAM[0]?.name);
  const selected = TEAM.find(p => p.name === selectedName) || lead;

  return (
    <div>
      <PageHeader
        title="Your Team"
        subtitle={`${TEAM.length} people on the ${CLIENT.shortName} account · led by ${lead?.name || 'your AM'}`}
        actions={<>
          <Btn variant="ghost" size="sm" icon={I.calendar}>Book a team call</Btn>
          <Btn variant="primary" size="sm" icon={I.send}>Message the team</Btn>
        </>}
      />

      {/* Two-column layout: roster (left) + spotlight profile (right) */}
      <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: 16, alignItems: 'flex-start' }}>
        {/* Roster */}
        <Card padding={0}>
          <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--border)' }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              Account Manager
            </div>
          </div>
          <div style={{ padding: 6 }}>
            {lead && (
              <TeamRosterRow person={lead} isActive={selectedName === lead.name} isLead
                onClick={() => setSelectedName(lead.name)} />
            )}
          </div>

          <div style={{ padding: '12px 16px 6px', borderTop: '1px solid var(--border)' }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              The Team
            </div>
          </div>
          <div style={{ padding: 6 }}>
            {[...directs, ...secondTier].map(p => (
              <TeamRosterRow key={p.name} person={p} isActive={selectedName === p.name}
                onClick={() => setSelectedName(p.name)} />
            ))}
          </div>

          {/* Client-side team — the people from {CLIENT.name} with portal
              access. Shown alongside Clicky so it reads as one shared
              team. Pulls from the same store as the Manage Users modal
              in the topbar (clicky_client_users); falls back to defaults. */}
          {(() => {
            let clientUsers = [];
            try {
              const saved = JSON.parse(localStorage.getItem('clicky_client_users') || 'null');
              if (Array.isArray(saved) && saved.length) clientUsers = saved;
            } catch (e) {}
            if (!clientUsers.length) {
              const C = window.CLIENT || {};
              const domain = (C.url || 'client.co.uk').replace(/\/.*$/, '');
              const slug = (n) => (n || '').toLowerCase().replace(/[^a-z]/g, '.').replace(/\.+/g, '.').replace(/^\.|\.$/g, '');
              clientUsers = [
                { id: 'cu-1', name: C.contact || 'Daniel Trevethan', email: `${slug(C.contact || 'daniel.trevethan')}@${domain}`, role: C.contactRole || 'Owner',  status: 'active', primary: true },
                { id: 'cu-2', name: 'Emma Holloway',                 email: `emma@${domain}`, role: 'Marketing lead', status: 'active' },
                { id: 'cu-3', name: 'Tom Brennan',                   email: `tom@${domain}`,  role: 'Viewer',         status: 'invited' },
              ];
            }
            const C = window.CLIENT || {};
            return (
              <>
                <div style={{ padding: '12px 16px 6px', borderTop: '1px solid var(--border)' }}>
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
                    <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      At {C.shortName || C.name || 'your company'}
                    </div>
                    <span style={{
                      fontSize: 9.5, fontWeight: 700, padding: '1px 6px', borderRadius: 99,
                      background: 'color-mix(in oklab, var(--primary) 12%, transparent)', color: 'var(--primary)',
                      letterSpacing: '0.04em', textTransform: 'uppercase',
                    }}>Client</span>
                  </div>
                  <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 2, lineHeight: 1.4 }}>
                    Your team in this portal — we work with all of you.
                  </div>
                </div>
                <div style={{ padding: '4px 6px 6px', display: 'flex', flexDirection: 'column', gap: 1 }}>
                  {clientUsers.map(u => (
                    <div key={u.id || u.name} style={{
                      display: 'flex', alignItems: 'center', gap: 8,
                      padding: '6px 8px', borderRadius: 6,
                      transition: 'background 120ms ease',
                    }}
                      onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
                      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                    >
                      <PersonAvatar name={u.name} size={26} hue={(u.name?.charCodeAt(0) * 11) % 360} />
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                          <span style={{
                            fontSize: 12, fontWeight: 600, color: 'var(--text)',
                            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                          }}>{u.name || <em style={{ color: 'var(--text-faint)' }}>Pending invite</em>}</span>
                          {u.primary && (
                            <span style={{
                              fontSize: 9, fontWeight: 700, padding: '0 5px', borderRadius: 99,
                              background: 'color-mix(in oklab, var(--primary) 14%, transparent)', color: 'var(--primary)',
                              letterSpacing: '0.04em',
                            }}>YOU</span>
                          )}
                        </div>
                        <div style={{
                          fontSize: 10.5, color: 'var(--text-muted)', marginTop: 1,
                          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        }}>{u.role}</div>
                      </div>
                      {u.status === 'invited' && (
                        <span style={{
                          fontSize: 9, fontWeight: 700, padding: '1px 6px', borderRadius: 99,
                          background: 'color-mix(in oklab, var(--warning) 14%, transparent)', color: 'var(--warning)',
                          letterSpacing: '0.04em', textTransform: 'uppercase', flexShrink: 0,
                        }}>Invited</span>
                      )}
                    </div>
                  ))}
                </div>
              </>
            );
          })()}

          {/* Wider Clicky team — specialists not on this account, surfaced
              greyed-out so the client knows the wider bench is there if
              they ever need it. */}
          <div style={{ padding: '12px 16px 6px', borderTop: '1px solid var(--border)' }}>
            <div style={{ fontSize: 11, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              Wider Clicky team
            </div>
            <div style={{ fontSize: 10.5, color: 'var(--text-faint)', marginTop: 2, lineHeight: 1.4 }}>
              30+ specialists across the agency — here if you ever need them.
            </div>
          </div>
          <div style={{ padding: '4px 6px 6px', display: 'flex', flexDirection: 'column', gap: 1 }}>
            {[
              { name: 'Alex Beecham',     role: 'Head of SEO' },
              { name: 'Priya Anand',      role: 'Senior Strategist' },
              { name: 'Lucy Crane',       role: 'Creative Director' },
              { name: 'Ravi Mehta',       role: 'Senior PPC Specialist' },
              { name: 'Beth Lawson',      role: 'Email & Lifecycle Lead' },
              { name: 'Owen Hartley',     role: 'Conversion Analyst' },
              { name: 'Tom Ainsworth',    role: 'Head of Paid Social' },
              { name: 'Sarah Yelland',    role: 'Head of Operations' },
              { name: 'Marcus Chen',      role: 'Tech & Tag Lead' },
              { name: 'Hannah Rourke',    role: 'Junior Designer' },
              { name: 'Niamh O’Connor', role: 'Junior PPC Analyst' },
              { name: 'James Kerr',       role: 'Account Director' },
            ].map(p => (
              <div key={p.name}
                title={`${p.name} — not on this account, ask Joe to bring them in if needed`}
                style={{
                  display: 'flex', alignItems: 'center', gap: 8,
                  padding: '5px 8px', borderRadius: 6,
                  opacity: 0.55,
                  cursor: 'help',
                  transition: 'opacity 120ms ease, background 120ms ease',
                }}
                onMouseEnter={e => { e.currentTarget.style.opacity = '0.85'; e.currentTarget.style.background = 'var(--surface-2)'; }}
                onMouseLeave={e => { e.currentTarget.style.opacity = '0.55'; e.currentTarget.style.background = 'transparent'; }}
              >
                <PersonAvatar name={p.name} size={20} hue={(p.name.charCodeAt(0) * 11) % 360} />
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontSize: 11.5, color: 'var(--text-muted)', fontWeight: 500, lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                    {p.name}
                  </div>
                  <div style={{ fontSize: 10, color: 'var(--text-faint)', lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                    {p.role}
                  </div>
                </div>
              </div>
            ))}
          </div>

          <div style={{
            padding: '12px 16px 14px', borderTop: '1px solid var(--border)',
            fontSize: 11, color: 'var(--text-muted)',
            display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
          }}>
            <span>Need more help?</span>
            <Btn variant="ghost" size="sm" icon={I.send}>Talk to Joe</Btn>
          </div>
        </Card>

        {/* Spotlight profile */}
        <TeamProfilePanel person={selected} />
      </div>
    </div>
  );
};

// ============================================================
// Growth Opportunities — AI-driven recommendations specific to St Mabyn,
// derived (in the prototype, mocked) from current channel data, search
// query reports, conversion gaps and existing service coverage.
// ============================================================

// Each opportunity is "intelligently worked out" — in the prototype each one
// has a `signals` array showing what data points informed it, mimicking the
// way an LLM would surface its reasoning.
const GROWTH_OPPORTUNITIES = [
  {
    id: 'op-bing',
    title: 'Tap untapped UK search demand on Microsoft Ads',
    rationale: 'Your Google Ads search query report shows 18% of branded searches happening on Bing — but you have no Microsoft Ads presence. Microsoft also skews older + higher-income, which matches your ownership audience.',
    impact: { range: '+£800–£1,400', cadence: 'mo', note: 'incremental bookings' },
    confidence: 0.84,
    category: 'Channel',
    service: 'Microsoft Ads onboarding',
    serviceTarget: 'growth',
    serviceIcon: I.microsoft,
    signals: [
      'Branded search share on Bing: ~18% (last 30d)',
      'Demographic match: 55+ household income £40k+',
      'Competitive auction insights show 2 lodge competitors active',
    ],
    tone: 'primary',
    isNew: true,
  },
  {
    id: 'op-email',
    title: 'Re-engage 12,400 lapsed past-guest contacts',
    rationale: 'You have a database of 12,400+ past guests but no automated re-engagement series. A 4-touch email flow could lift repeat-booking rate by an estimated 6–9%.',
    impact: { range: '+£1,800–£2,600', cadence: 'mo', note: 'repeat bookings' },
    confidence: 0.78,
    category: 'Email',
    service: 'Email automation series',
    serviceTarget: 'growth',
    serviceIcon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>,
    signals: [
      '12,400 past-guest contacts in your CRM',
      'Industry benchmark: 6–9% lift in repeat from 4-touch reactivation',
      'No active email series detected against this audience',
    ],
    tone: 'positive',
    isNew: true,
  },
  {
    id: 'op-cro',
    title: 'CRO audit on Park Experience — 3.4MB page weight is hurting bookings',
    rationale: 'Park Experience scores 71/100 on page speed (LCP 3.1s, page weight 3.4MB). Sites in your sector that improve to 90+ see 8–12% lift in booking conversion rate.',
    impact: { range: '+5–9%', cadence: 'CVR', note: 'on Park Experience flows' },
    confidence: 0.71,
    category: 'CRO',
    service: 'CRO + Performance audit',
    serviceTarget: 'maintenance',
    serviceIcon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/><path d="m13.4 12.6 4.2-4.2"/><path d="M3.5 18A9 9 0 0 1 12 5a9 9 0 0 1 8.5 13"/></svg>,
    signals: [
      'Park Experience speed score: 71/100',
      'LCP 3.1s · CLS 0.12 · page weight 3.4MB',
      'Sector median for high-converting holiday-park sites: 88+',
    ],
    tone: 'warning',
    isNew: true,
  },
  {
    id: 'op-ownership-lp',
    title: 'Dedicated landing page test for ownership enquiries',
    rationale: 'Ownership traffic currently lands on a generic page. AI analysis of top-performing competitor pages shows 3 patterns yours is missing: financing-calculator, owner-testimonials, lifestyle gallery.',
    impact: { range: '+30–55%', cadence: 'CVR', note: 'on ownership leads' },
    confidence: 0.69,
    category: 'Landing pages',
    service: 'Landing page build',
    serviceTarget: 'growth',
    serviceIcon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 10h18M9 21V10"/></svg>,
    signals: [
      'Ownership lands on generic /ownership page (basic copy)',
      '3 missing patterns vs top competitors (analysed via AI)',
      'CPT marked as Pending setup → high upside if conversion improves',
    ],
    tone: 'primary',
    isNew: false,
  },
  {
    id: 'op-reddit-intent',
    title: 'Capture high-intent UK travel-planning conversations on Reddit',
    rationale: 'Daily threads on r/cornwall (94k), r/uktravel (412k) and r/UKFamilyHolidays (38k) ask "best self-catering near the coast" — high-intent, mid-funnel queries with no paid competitors in your audit. Reddit Ads can target those threads directly at hospitality CPMs that dropped 22% YoY.',
    impact: { range: '+£600–£1,100', cadence: 'mo', note: 'incremental bookings · low CPM' },
    confidence: 0.91,
    category: 'Channel',
    service: 'Reddit Ads — intent-led pilot',
    serviceTarget: 'growth',
    serviceIcon: I.reddit,
    signals: [
      '60+ travel-planning posts/day across target subs',
      'Reddit Ads hospitality CPM: −22% YoY · still unsaturated',
      'Zero direct competitors running paid against these threads',
    ],
    tone: 'primary',
    isNew: true,
  },
  {
    id: 'op-reddit',
    title: 'Test Reddit Ads in Cornwall + UK travel niches',
    rationale: 'r/cornwall (94k) and r/uktravel (412k) actively discuss self-catering breaks. Reddit Ads CPMs for hospitality have dropped 22% YoY and remain unsaturated.',
    impact: { range: '+£300–£700', cadence: 'mo', note: 'incremental top-of-funnel' },
    confidence: 0.58,
    category: 'Channel',
    service: 'Reddit Ads pilot',
    serviceTarget: 'growth',
    serviceIcon: I.reddit,
    signals: [
      'r/cornwall 94k subs · r/uktravel 412k subs',
      'Hospitality CPM down 22% YoY on Reddit',
      'Audience overlap with your direct-booking customer profile',
    ],
    tone: 'muted',
    isNew: false,
  },
];

const GROWTH_CATEGORIES = ['All', 'Channel', 'Email', 'CRO', 'Landing pages', 'Tracking'];

// Small helper — confidence ring chart, reuses MiniRing pattern
const ConfidenceRing = ({ value, color, size = 36 }) => {
  const r = (size - 4) / 2;
  const c = 2 * Math.PI * r;
  const filled = c * Math.max(0, Math.min(1, value));
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <circle cx={size / 2} cy={size / 2} r={r}
        fill="none" stroke="var(--border)" strokeWidth="3" />
      <circle cx={size / 2} cy={size / 2} r={r}
        fill="none" stroke={color} strokeWidth="3"
        strokeDasharray={`${filled} ${c}`}
        strokeLinecap="round"
        transform={`rotate(-90 ${size / 2} ${size / 2})`} />
      <text x={size / 2} y={size / 2 + 0.5}
        textAnchor="middle" dominantBaseline="central"
        fontSize="10" fontWeight="700"
        fill="currentColor" style={{ fontVariantNumeric: 'tabular-nums' }}>
        {Math.round(value * 100)}
      </text>
    </svg>
  );
};

const GrowthOpportunitiesScreen = ({ setActive, openAskLightbox }) => {
  const [category, setCategory] = useState('All');
  const [dismissed, setDismissed] = useState({});

  const visible = GROWTH_OPPORTUNITIES
    .filter(o => !dismissed[o.id])
    .filter(o => category === 'All' || o.category === category);

  const newCount = GROWTH_OPPORTUNITIES.filter(o => o.isNew && !dismissed[o.id]).length;
  const highImpact = GROWTH_OPPORTUNITIES.filter(o => o.confidence >= 0.75 && !dismissed[o.id]).length;

  const accentFor = (tone) => tone === 'positive' ? 'var(--positive)'
                            : tone === 'warning'  ? 'var(--warning)'
                            : tone === 'negative' ? 'var(--negative)'
                            : tone === 'primary'  ? 'var(--primary)'
                            : 'var(--text-muted)';

  return (
    <div>
      {/* AI-themed channel-style header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)',
            background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center',
            flexShrink: 0,
          }}>
            <img src="assets/ai-opps.svg" alt="" width="22" height="22" style={{ display: 'block' }} />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Growth Opportunities</h1>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 5,
                fontSize: 11, fontWeight: 500, color: 'var(--text-muted)',
                padding: '3px 8px', borderRadius: 99,
                background: 'var(--surface-2)', border: '1px solid var(--border)',
              }}>
                <GeminiMark size={16} /> Powered by Gemini
              </span>
              {newCount > 0 && (
                <span style={{
                  fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
                  background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
                  color: 'var(--positive)', textTransform: 'uppercase', letterSpacing: '0.04em',
                }}>{newCount} new</span>
              )}
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 6 }}>
              <span>AI + expert team recommendations · refreshed 2 hours ago</span>
              <span style={{ color: 'var(--text-faint)' }}>·</span>
              <span>Based on your Google Ads, GA4 and CPT data</span>
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <Btn variant="secondary" size="sm" icon={<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>}>Refresh</Btn>
        </div>
      </div>

      {/* Stat strip — counts + AI-flavoured value */}
      <Card padding={0} style={{ marginBottom: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', alignItems: 'center' }}>
          {[
            { label: 'Total opportunities', value: GROWTH_OPPORTUNITIES.length, sub: 'surfaced this month' },
            { label: 'New since last visit', value: newCount, sub: 'tagged for review', tone: 'primary' },
            { label: 'High confidence',     value: highImpact, sub: 'AI confidence ≥ 75%', tone: 'positive' },
            { label: 'Combined upside',     value: '£3.2k–5k', sub: 'estimated /mo · all channels', tone: 'positive' },
          ].map((s, i) => (
            <div key={s.label} style={{
              padding: '16px 20px',
              borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
            }}>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>{s.label}</div>
              <div style={{
                fontSize: 22, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 4, letterSpacing: '-0.01em',
                color: s.tone === 'primary' ? 'var(--primary)' : s.tone === 'positive' ? 'var(--positive)' : 'var(--text)',
              }}>{s.value}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{s.sub}</div>
            </div>
          ))}
        </div>
      </Card>

      {/* Category filter */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16, flexWrap: 'wrap' }}>
        {GROWTH_CATEGORIES.map(t => {
          const count = t === 'All'
            ? GROWTH_OPPORTUNITIES.filter(o => !dismissed[o.id]).length
            : GROWTH_OPPORTUNITIES.filter(o => o.category === t && !dismissed[o.id]).length;
          if (t !== 'All' && count === 0) return null;
          return (
            <button key={t} onClick={() => setCategory(t)} style={{
              padding: '6px 12px', borderRadius: 99, fontSize: 12, fontWeight: 500,
              background: category === t ? 'var(--text)' : 'var(--surface)',
              color:      category === t ? 'var(--surface)' : 'var(--text-muted)',
              border: '1px solid ' + (category === t ? 'var(--text)' : 'var(--border)'),
              cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
            }}>
              {t}
              <span style={{
                fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 99,
                background: category === t ? 'color-mix(in oklab, var(--surface) 25%, transparent)' : 'var(--surface-2)',
                color:      category === t ? 'var(--surface)' : 'var(--text-muted)',
                fontVariantNumeric: 'tabular-nums',
              }}>{count}</span>
            </button>
          );
        })}
      </div>

      {/* Opportunity cards */}
      {visible.length === 0 ? (
        <Card>
          <div style={{ padding: '32px 16px', textAlign: 'center', color: 'var(--text-muted)' }}>
            No opportunities for this filter. Hit Refresh to ask ClickyAI™ for the next batch.
          </div>
        </Card>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 16 }}>
          {visible.map(o => {
            const accent = accentFor(o.tone);
            // Account-manager comments per opportunity — Joe's review
            const amComments = {
              'op-bing':         "Solid hypothesis — the audience match is right. I'd start at £600/mo for 6 weeks before we commit further.",
              'op-email':        "12k contacts is gold. We'll need to validate consent first, but if it lands this should run evergreen, not as a one-off.",
              'op-cro':          "Agreed. Nathan to lead with Hayley — quick win, low cost, hurts revenue every day we don't fix it.",
              'op-ownership-lp': "Hayley's already prototyping this. Worth the £6–8k build cost given the lifetime value of an ownership lead.",
              'op-tracking':     "T-2098 is on Nathan's queue this week. AI's right that bid signal is at risk until then — fix is in flight.",
              'op-reddit':       "Interesting but lower priority right now. Let's revisit once Microsoft Ads is bedded in.",
            };
            const amComment = amComments[o.id];
            return (
              <div key={o.id} className="clicky-ai-border" style={{
                position: 'relative',
                padding: 18,
                borderRadius: 'var(--radius)',
                display: 'flex', flexDirection: 'column', gap: 12,
                overflow: 'hidden',
              }}>
                {/* Top row: title + isNew + dismiss */}
                <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
                  <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, minWidth: 0, flex: 1 }}>
                    <div style={{
                      width: 36, height: 36, borderRadius: 8, flexShrink: 0,
                      background: `color-mix(in oklab, ${accent} 12%, transparent)`,
                      color: accent, display: 'grid', placeItems: 'center',
                    }}>{o.serviceIcon}</div>
                    <div style={{ minWidth: 0 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                        <span style={{ fontSize: 15, fontWeight: 600, lineHeight: 1.3 }}>{o.title}</span>
                        {o.isNew && (
                          <span style={{
                            fontSize: 9, fontWeight: 700, padding: '2px 6px', borderRadius: 99,
                            background: 'color-mix(in oklab, var(--positive) 16%, transparent)',
                            color: 'var(--positive)', textTransform: 'uppercase', letterSpacing: '0.04em',
                          }}>New</span>
                        )}
                      </div>
                      <div style={{
                        fontSize: 11, color: 'var(--text-faint)', marginTop: 4,
                        display: 'inline-flex', alignItems: 'center', gap: 5,
                      }}>
                        <img src="assets/ai-opps.svg" alt="" width="11" height="11" style={{ display: 'block' }} />
                        {o.category} · Generated by ClickyAI™
                      </div>
                    </div>
                  </div>
                  <button onClick={() => setDismissed(d => ({ ...d, [o.id]: true }))}
                    title="Dismiss this opportunity"
                    style={{
                      width: 26, height: 26, border: 'none', background: 'transparent',
                      color: 'var(--text-faint)', borderRadius: 6, cursor: 'pointer',
                      display: 'grid', placeItems: 'center',
                    }}
                    onMouseEnter={e => { e.currentTarget.style.background = 'var(--hover)'; e.currentTarget.style.color = 'var(--text-muted)'; }}
                    onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-faint)'; }}
                  >
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
                  </button>
                </div>

                {/* Rationale */}
                <p style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.55, margin: 0 }}>
                  {o.rationale}
                </p>

                {/* Impact + confidence row */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '10px 12px',
                  background: 'var(--surface-2)', borderRadius: 'calc(var(--radius) - 8px)' }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Estimated impact</div>
                    <div style={{ fontSize: 16, fontWeight: 700, color: accent, marginTop: 1, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>
                      {o.impact.range} <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}>/{o.impact.cadence}</span>
                    </div>
                    <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>{o.impact.note}</div>
                  </div>
                  <div style={{ flexShrink: 0, color: accent }}>
                    <ConfidenceRing value={o.confidence} color={accent} />
                  </div>
                  <div style={{ flexShrink: 0, minWidth: 80 }}>
                    <div style={{ fontSize: 10, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Confidence</div>
                    <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>{o.confidence >= 0.8 ? 'High' : o.confidence >= 0.65 ? 'Medium' : 'Exploratory'}</div>
                  </div>
                </div>

                {/* Signals — "why we're suggesting this" */}
                <div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 600, marginBottom: 6, display: 'flex', alignItems: 'center', gap: 5 }}>
                    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
                    Why we're suggesting this
                  </div>
                  <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 4 }}>
                    {o.signals.map((s, i) => (
                      <li key={i} style={{ fontSize: 11.5, color: 'var(--text-muted)', display: 'flex', gap: 8, lineHeight: 1.45 }}>
                        <span style={{ color: 'var(--text-faint)', flexShrink: 0, fontFamily: 'JetBrains Mono', fontSize: 10, marginTop: 2 }}>{(i + 1).toString().padStart(2, '0')}</span>
                        <span>{s}</span>
                      </li>
                    ))}
                  </ul>
                </div>

                {/* Account manager approval — Joe's review of this AI suggestion */}
                {amComment && (() => {
                  const joe = (window.TEAM || []).find(p => p.name === 'Joe Marshall');
                  return (
                    <div style={{
                      padding: '10px 12px', borderRadius: 8,
                      background: 'color-mix(in oklab, var(--positive) 6%, var(--surface))',
                      border: '1px solid color-mix(in oklab, var(--positive) 25%, var(--border))',
                      borderLeft: '3px solid var(--positive)',
                      display: 'flex', gap: 10, alignItems: 'flex-start',
                    }}>
                      <PersonAvatar name="Joe Marshall" size={26} hue={joe?.hue || 200} src={joe?.src || 'assets/team/joe.png'} />
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--text-muted)', marginBottom: 4 }}>
                          <span style={{
                            width: 14, height: 14, borderRadius: '50%',
                            background: 'color-mix(in oklab, var(--positive) 16%, transparent)',
                            color: 'var(--positive)',
                            display: 'inline-grid', placeItems: 'center', flexShrink: 0,
                          }}>
                            <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
                          </span>
                          Approved by <strong style={{ color: 'var(--text)', fontWeight: 600 }}>Joe Marshall</strong>
                          <span style={{ color: 'var(--text-faint)' }}>·</span>
                          <span>Account Manager</span>
                        </div>
                        <div style={{ fontSize: 12.5, color: 'var(--text)', lineHeight: 1.5, fontStyle: 'italic' }}>
                          "{amComment}"
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* CTAs */}
                <div style={{
                  display: 'flex', gap: 8, paddingTop: 10, marginTop: 'auto',
                  borderTop: '1px solid var(--border)',
                }}>
                  <Btn variant="primary" size="sm" icon={I.plus}
                    onClick={() => setActive && setActive(o.serviceTarget || 'growth')}>
                    {o.service}
                  </Btn>
                  <Btn variant="ghost" size="sm" icon={I.send}
                    onClick={() => setActive && setActive('ask')}>
                    Ask follow-up
                  </Btn>
                  <div style={{ flex: 1 }}/>
                  <Btn variant="ghost" size="sm" onClick={() => setDismissed(d => ({ ...d, [o.id]: true }))}>Dismiss</Btn>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* Methodology footer */}
      <div style={{
        marginTop: 20, padding: '14px 18px',
        borderRadius: 'var(--radius)', border: '1px dashed var(--border)',
        fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5,
        display: 'flex', alignItems: 'flex-start', gap: 12,
      }}>
        <div style={{
          width: 28, height: 28, borderRadius: 6, flexShrink: 0,
          background: 'var(--surface-2)',
          display: 'grid', placeItems: 'center',
        }}><img src="assets/ai-opps.svg" alt="" width="18" height="18" style={{ display: 'block' }} /></div>
        <div>
          <div style={{ color: 'var(--text)', fontWeight: 600, marginBottom: 2 }}>How ClickyAI™ + your account team build these</div>
          ClickyAI™ continuously scans your Google Ads search query reports, GA4 funnels, CPT progress, open tickets and the audited service mix — cross-referencing industry benchmarks for hospitality / holiday-park brands. Our expert team then reviews every suggestion, adds context only humans spot, and ships the ones worth your time. New opportunities surface daily; dismissed ones won't reappear unless the underlying signal changes.
        </div>
      </div>
    </div>
  );
};

// ============================================================
// Meta Ads — performance overview for the Meta channel.
// Mirrors the Google Ads screen layout but with Meta-specific data:
// objectives, placements, and audience-led campaigns.
// ============================================================

const META_KPIS = [
  { key: 'spend',    label: 'Spend',          value: '£842.16',  delta: +18.3, dir: 'up',   trend: spark(31, 24, 'up'),   tone: 'positive' },
  { key: 'bookings', label: 'Bookings',       value: '11',       delta: +37.5, dir: 'up',   trend: spark(32, 24, 'up'),   tone: 'positive' },
  { key: 'roas',     label: 'ROAS',           value: '4.8x',     delta: +0.4,  dir: 'up',   trend: spark(33, 24, 'up'),   tone: 'positive' },
  { key: 'reach',    label: 'Reach',          value: '184.2k',   delta: +12.1, dir: 'up',   trend: spark(34, 24, 'up'),   tone: 'positive' },
  { key: 'ctr',      label: 'CTR',            value: '1.84%',    delta: -0.3,  dir: 'down', trend: spark(35, 24, 'down'), tone: 'negative' },
  { key: 'cpm',      label: 'CPM',            value: '£4.57',    delta: -8.2,  dir: 'down', trend: spark(36, 24, 'down'), tone: 'positive' },
  { key: 'cpc',      label: 'Avg. CPC',       value: '£0.32',    delta: -5.4,  dir: 'down', trend: spark(37, 24, 'down'), tone: 'positive' },
  { key: 'frequency',label: 'Frequency',      value: '1.7',      delta: +6.8,  dir: 'up',   trend: spark(38, 24, 'flat'), tone: 'neutral' },
];

const META_ACCOUNTS = [
  { name: 'Evergreen Escapes', id: 'act_8472940', spend: '£552.40', status: 'Active' },
  { name: 'Evergreen Ownership',    id: 'act_9013182', spend: '£289.76', status: 'Active' },
];

const META_CAMPAIGNS = [
  { name: 'Spring Breaks · Conversions',     objective: 'Sales',     spend: 218.40, reach: 41200, conv: 4, cpr: 54.60, ctr: 2.1 },
  { name: 'Lookalike 1% — Past Guests',      objective: 'Sales',     spend: 162.30, reach: 28900, conv: 3, cpr: 54.10, ctr: 1.9 },
  { name: 'Cornwall Travel Inspo · Reels',   objective: 'Awareness', spend: 142.10, reach: 62400, conv: 1, cpr: 142.10, ctr: 0.8 },
  { name: 'Ownership · Lead Form',           objective: 'Leads',     spend: 138.66, reach: 18800, conv: 2, cpr: 69.33, ctr: 2.6 },
  { name: 'Retargeting · Site Visitors',     objective: 'Sales',     spend: 102.20, reach: 22100, conv: 1, cpr: 102.20, ctr: 1.4 },
  { name: 'Late Availability · Stories',     objective: 'Traffic',   spend: 78.50,  reach: 10800, conv: 0, cpr: 0,     ctr: 1.1 },
];

// Placement breakdown — share of spend by Meta surface
const META_PLACEMENTS = [
  { key: 'feed',        label: 'Feed',         share: 42, spend: 353.71, color: 'var(--primary)' },
  { key: 'reels',       label: 'Reels',        share: 28, spend: 235.80, color: 'var(--positive)' },
  { key: 'stories',     label: 'Stories',      share: 18, spend: 151.59, color: 'var(--warning)' },
  { key: 'marketplace', label: 'Marketplace',  share:  8, spend:  67.37, color: 'var(--text-muted)' },
  { key: 'audience',    label: 'Audience Net', share:  4, spend:  33.69, color: 'var(--text-faint)' },
];

const OBJECTIVE_TONE = {
  Sales:     { fg: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 14%, transparent)' },
  Leads:     { fg: 'var(--primary)',  bg: 'color-mix(in oklab, var(--primary) 14%, transparent)' },
  Traffic:   { fg: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 16%, transparent)' },
  Awareness: { fg: 'var(--text-muted)', bg: 'var(--surface-2)' },
};

const MetaSpendTrendCard = () => {
  const { AreaChart, Area, XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer } = window.Recharts;
  // Generate Meta-specific spend data — slightly higher variance than Google
  const data = SPEND_TREND.map((d, i) => ({ d: d.d, v: Math.round((d.v * 0.55 + Math.sin(i * 0.7) * 8) * 100) / 100 }));
  return (
    <Card padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>Spend Trend</div>
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Avg. weekly spend across both Meta accounts</div>
        </div>
        <Btn variant="ghost" size="sm" icon={I.download}>Export</Btn>
      </div>
      <div style={{ padding: '12px 8px 12px' }}>
        <ResponsiveContainer width="100%" height={240}>
          <AreaChart data={data} margin={{ top: 10, right: 16, left: 0, bottom: 0 }}>
            <defs>
              <linearGradient id="meta-spend-fill" x1="0" x2="0" y1="0" y2="1">
                <stop offset="0" stopColor="var(--primary)" stopOpacity={0.25}/>
                <stop offset="1" stopColor="var(--primary)" stopOpacity={0}/>
              </linearGradient>
            </defs>
            <CartesianGrid strokeDasharray="2 4" vertical={false} />
            <XAxis dataKey="d" tickLine={false} axisLine={false} dy={6} />
            <YAxis tickLine={false} axisLine={false} dx={-4} />
            <Tooltip contentStyle={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 6, fontSize: 12 }} />
            <Area type="monotone" dataKey="v" stroke="var(--primary)" strokeWidth={2} fill="url(#meta-spend-fill)" dot={{ r: 3, fill: 'var(--primary)' }} activeDot={{ r: 5 }} />
          </AreaChart>
        </ResponsiveContainer>
      </div>
      <div style={{ padding: '8px 18px 14px', display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-muted)' }}>
        <span style={{ width: 10, height: 2, background: 'var(--primary)', borderRadius: 2 }}/> Avg. weekly spend
      </div>
    </Card>
  );
};

const MetaPlacementsCard = () => (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div>
        <div style={{ fontWeight: 600, fontSize: 14 }}>Spend by placement</div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>Where your Meta budget actually ran · last 30 days</div>
      </div>
      <Btn variant="ghost" size="sm" iconRight={I.arrowRight}>Inspect</Btn>
    </div>
    <div style={{ padding: 18 }}>
      {/* Stacked horizontal bar */}
      <div style={{
        display: 'flex', height: 14, borderRadius: 99,
        overflow: 'hidden', background: 'var(--surface-2)',
        marginBottom: 14,
      }}>
        {META_PLACEMENTS.map(p => (
          <div key={p.key}
            title={`${p.label}: ${p.share}% · £${p.spend.toFixed(2)}`}
            style={{ width: `${p.share}%`, background: p.color }}/>
        ))}
      </div>

      {/* Legend rows */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {META_PLACEMENTS.map(p => (
          <div key={p.key} style={{ display: 'grid', gridTemplateColumns: '14px 1fr auto auto', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 10, height: 10, borderRadius: 2, background: p.color }}/>
            <span style={{ fontSize: 13, color: 'var(--text)' }}>{p.label}</span>
            <span style={{ fontSize: 11, color: 'var(--text-muted)', fontFamily: 'JetBrains Mono', minWidth: 36, textAlign: 'right' }}>{p.share}%</span>
            <span style={{ fontSize: 12, fontWeight: 600, fontVariantNumeric: 'tabular-nums', minWidth: 70, textAlign: 'right' }}>£{p.spend.toFixed(2)}</span>
          </div>
        ))}
      </div>
    </div>
  </Card>
);

const MetaLinkedAccountsCard = () => (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div style={{ fontWeight: 600, fontSize: 14 }}>Linked Accounts</div>
      <Badge tone="neutral">{META_ACCOUNTS.length}</Badge>
    </div>
    <div style={{ padding: 8 }}>
      {META_ACCOUNTS.map((a, i) => (
        <div key={i} style={{
          padding: 12, display: 'flex', flexDirection: 'column', gap: 8,
          borderRadius: 6, cursor: 'pointer',
        }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
        >
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--positive)' }}/>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</div>
              <div style={{ fontSize: 11, color: 'var(--text-faint)', fontFamily: 'JetBrains Mono' }}>{a.id}</div>
            </div>
            <span style={{ color: 'var(--text-faint)' }}>{I.external}</span>
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>30-day spend</span>
            <span style={{ fontSize: 14, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{a.spend}</span>
          </div>
        </div>
      ))}
      <button style={{
        width: '100%', padding: 10, marginTop: 4,
        background: 'transparent', border: '1px dashed var(--border-strong)',
        borderRadius: 6, color: 'var(--text-muted)', cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, fontSize: 12,
      }}>{I.plus} Connect another account</button>
    </div>
  </Card>
);

const MetaTopCampaignsCard = () => {
  const s = useTableSort(META_CAMPAIGNS, 'spend', 'desc');
  const cols = [
    { key: 'name',      label: 'Campaign',     align: 'left' },
    { key: 'objective', label: 'Objective',    align: 'left' },
    { key: 'spend',     label: 'Spend',        align: 'right' },
    { key: 'reach',     label: 'Reach',        align: 'right' },
    { key: 'conv',      label: 'Conv.',        align: 'right' },
    { key: 'cpr',       label: 'Cost / conv.', align: 'right' },
    { key: 'ctr',       label: 'CTR',          align: 'right' },
  ];
  return (
  <Card padding={0}>
    <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div>
        <div style={{ fontWeight: 600, fontSize: 14 }}>Top Campaigns</div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>By spend · last 30 days</div>
      </div>
      <Btn variant="ghost" size="sm" iconRight={I.arrowRight}>View all</Btn>
    </div>
    <div style={{ overflow: 'hidden' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
        <thead>
          <tr style={{ background: 'var(--surface-2)' }}>
            {cols.map(c => (
              <SortableTh key={c.key} sortKey={c.key} align={c.align} currentKey={s.sortKey} dir={s.sortDir} onSort={s.onSort}>{c.label}</SortableTh>
            ))}
          </tr>
        </thead>
        <tbody>
          {s.sorted.map((c, i) => {
            const tone = OBJECTIVE_TONE[c.objective] || OBJECTIVE_TONE.Sales;
            return (
              <tr key={i} style={{ borderBottom: i < s.sorted.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <td style={{ padding: '12px 14px', fontWeight: 500 }}>{c.name}</td>
                <td style={{ padding: '12px 14px' }}>
                  <span style={{
                    fontSize: 10.5, fontWeight: 600, padding: '2px 8px', borderRadius: 99,
                    background: tone.bg, color: tone.fg,
                  }}>{c.objective}</span>
                </td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>£{c.spend.toFixed(2)}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{c.reach.toLocaleString()}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>{c.conv}</td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>
                  {c.cpr > 0 ? '£' + c.cpr.toFixed(2) : '—'}
                </td>
                <td style={{ padding: '12px 14px', textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--text-muted)' }}>{c.ctr.toFixed(1)}%</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  </Card>
  );
};

const MetaAdsScreen = ({ sparkStyle }) => {
  const [range, setRange] = useState('Last 30 Days');
  const [openRange, setOpenRange] = useState(false);
  const ranges = ['Last 7 Days', 'Last 30 Days', 'Last 90 Days', 'Year to date'];

  return (
    <div>
      {/* Channel header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)', background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center',
          }}>{I.meta}</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Meta Ads</h1>
              <Badge tone="positive">● Linked</Badge>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
              Aggregated across {META_ACCOUNTS.length} ad accounts · Facebook + Instagram inventory
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, position: 'relative' }}>
          <Btn variant="secondary" size="sm" icon={I.plus}>Add Account</Btn>
          <div style={{ position: 'relative' }}>
            <Btn variant="secondary" size="sm" iconRight={I.chevDown} onClick={() => setOpenRange(o => !o)}>{range}</Btn>
            {openRange && (
              <div style={{
                position: 'absolute', right: 0, top: '110%', zIndex: 10,
                background: 'var(--surface)', border: '1px solid var(--border)',
                borderRadius: 'var(--radius)', boxShadow: 'var(--shadow-md)',
                minWidth: 160, padding: 4,
              }}>
                {ranges.map(r => (
                  <button key={r} onClick={() => { setRange(r); setOpenRange(false); }} style={{
                    display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 10px',
                    background: r === range ? 'var(--hover)' : 'transparent', border: 'none',
                    borderRadius: 4, cursor: 'pointer', fontSize: 13, color: 'var(--text)', textAlign: 'left',
                  }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = r === range ? 'var(--hover)' : 'transparent'}
                  >
                    <span style={{ width: 14, color: 'var(--primary)' }}>{r === range && I.check}</span>{r}
                  </button>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Section heading */}
      <div style={{ marginBottom: 14 }}>
        <h2 style={{ fontSize: 15, fontWeight: 600, margin: 0 }}>Overall Performance Overview</h2>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>Aggregated data across {META_ACCOUNTS.length} linked accounts · {range.toLowerCase()}</div>
      </div>

      {/* KPI grid — 4 columns × 2 rows */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 12, marginBottom: 20 }}>
        {META_KPIS.map(k => <KpiCard key={k.key} kpi={k} sparkStyle={sparkStyle} />)}
      </div>

      {/* Spend trend + placement breakdown */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 12, marginBottom: 20 }}>
        <MetaSpendTrendCard />
        <MetaPlacementsCard />
      </div>

      {/* Linked accounts + top campaigns */}
      <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 12 }}>
        <MetaLinkedAccountsCard />
        <MetaTopCampaignsCard />
      </div>
    </div>
  );
};

// ============================================================
// Request New Performance Target — modal triggered from the sidebar CTA
// and the All Performance Targets page header. Captures everything the
// account team needs to spec up a new CPT.
// ============================================================

const KPI_TYPES = [
  { id: 'count',   label: 'Volume / count',          example: 'Lodge bookings, leads, sign-ups' },
  { id: 'revenue', label: 'Revenue',                 example: 'Booking revenue, ownership sales' },
  { id: 'rate',    label: 'Rate or percentage',      example: 'Direct share, conversion rate' },
  { id: 'cost',    label: 'Cost / efficiency',       example: 'Cost per booking, CPL' },
  { id: 'roas',    label: 'Return / ROAS',           example: 'Paid ROAS, lifetime value ratio' },
  { id: 'other',   label: 'Something else',          example: 'Tell us what you want to track' },
];

const KPI_SOURCES = [
  { id: 'google-ads', label: 'Live · Google Ads', detail: 'Auto-pulled from your linked Google Ads accounts' },
  { id: 'meta-ads',   label: 'Live · Meta Ads',   detail: 'Auto-pulled from Meta business accounts' },
  { id: 'ga4',        label: 'Live · GA4',        detail: 'Pulled via Google Analytics 4 events' },
  { id: 'crm',        label: 'Live · CRM',        detail: 'HubSpot, Sykes, or your booking system' },
  { id: 'manual',     label: 'Manual',            detail: 'Account manager logs the value periodically' },
  { id: 'unsure',     label: 'Not sure yet',      detail: 'We\'ll figure out the source with you' },
];

const RequestPerformanceTargetModal = ({ onClose }) => {
  const [form, setForm] = useState({
    name: '',
    type: 'count',
    targetValue: '',
    unit: '',
    timeframe: 'This quarter (Q2 2026)',
    source: 'google-ads',
    why: '',
    notes: '',
  });
  const [sent, setSent] = useState(false);
  const submit = (e) => { e.preventDefault(); setSent(true); };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.55)',
      display: 'grid', placeItems: 'center', zIndex: 110, padding: 16,
      backdropFilter: 'blur(2px)',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 620, maxHeight: '92vh',
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--radius)', boxShadow: '0 18px 60px rgba(0,0,0,0.45)',
        overflow: 'auto',
      }}>
        <div style={{
          padding: '16px 22px', borderBottom: '1px solid var(--border)',
          display: 'flex', alignItems: 'center', gap: 14,
        }}>
          <div style={{
            width: 40, height: 40, borderRadius: 8,
            background: 'color-mix(in oklab, var(--primary) 12%, transparent)',
            color: 'var(--primary)',
            display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.6" fill="currentColor"/></svg>
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 16, fontWeight: 600 }}>Request new Performance Target</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
              Tell us what you'd like to track. Joe will scope and confirm with you.
            </div>
          </div>
          <button onClick={onClose} aria-label="Close" style={{
            width: 32, height: 32, border: 'none', background: 'transparent', color: 'var(--text-muted)',
            borderRadius: 6, cursor: 'pointer', display: 'grid', placeItems: 'center',
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
          </button>
        </div>

        {sent ? (
          <div style={{ padding: 36, textAlign: 'center' }}>
            <div style={{
              width: 56, height: 56, borderRadius: '50%', margin: '0 auto 16px',
              background: 'color-mix(in oklab, var(--positive) 18%, transparent)',
              color: 'var(--positive)', display: 'grid', placeItems: 'center',
            }}>{I.check}</div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>Request submitted</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 20, maxWidth: 380, margin: '0 auto 20px' }}>
              Joe will scope <strong style={{ color: 'var(--text)' }}>{form.name || 'this target'}</strong> and confirm the source and cadence with you within 1 working day.
            </div>
            <Btn variant="primary" onClick={onClose} style={{ margin: '0 auto' }}>Done</Btn>
          </div>
        ) : (
          <form onSubmit={submit} style={{ padding: 22, display: 'flex', flexDirection: 'column', gap: 16 }}>
            <FormField label="What do you want to track?" required>
              <input required value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
                placeholder="e.g. Repeat-guest bookings" style={inputStyle} />
            </FormField>

            <FormField label="Type">
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
                {KPI_TYPES.map(t => {
                  const on = form.type === t.id;
                  return (
                    <button key={t.id} type="button" onClick={() => setForm(f => ({ ...f, type: t.id }))} style={{
                      textAlign: 'left', padding: '10px 12px', borderRadius: 8,
                      background: on ? 'color-mix(in oklab, var(--primary) 10%, transparent)' : 'var(--surface)',
                      color: on ? 'var(--text)' : 'var(--text-muted)',
                      border: '1px solid ' + (on ? 'color-mix(in oklab, var(--primary) 40%, transparent)' : 'var(--border)'),
                      cursor: 'pointer', fontFamily: 'inherit',
                      transition: 'border-color 120ms ease, background 120ms ease',
                    }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: on ? 'var(--primary)' : 'var(--text)' }}>{t.label}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 2 }}>{t.example}</div>
                    </button>
                  );
                })}
              </div>
            </FormField>

            <div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr', gap: 12 }}>
              <FormField label="Target value">
                <input value={form.targetValue} onChange={e => setForm(f => ({ ...f, targetValue: e.target.value }))}
                  placeholder="e.g. 60" style={inputStyle} />
              </FormField>
              <FormField label="Unit">
                <input value={form.unit} onChange={e => setForm(f => ({ ...f, unit: e.target.value }))}
                  placeholder="£ / % / leads" style={inputStyle} />
              </FormField>
              <FormField label="Timeframe">
                <select value={form.timeframe} onChange={e => setForm(f => ({ ...f, timeframe: e.target.value }))} style={inputStyle}>
                  {['This quarter (Q2 2026)', 'Q3 2026', 'Annual 2026', 'Custom — discuss'].map(o => <option key={o}>{o}</option>)}
                </select>
              </FormField>
            </div>

            <FormField label="Where should the data come from?">
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                {KPI_SOURCES.map(s => {
                  const on = form.source === s.id;
                  return (
                    <button key={s.id} type="button" onClick={() => setForm(f => ({ ...f, source: s.id }))} style={{
                      textAlign: 'left', padding: '10px 12px', borderRadius: 8,
                      background: on ? 'color-mix(in oklab, var(--primary) 10%, transparent)' : 'var(--surface)',
                      border: '1px solid ' + (on ? 'color-mix(in oklab, var(--primary) 40%, transparent)' : 'var(--border)'),
                      cursor: 'pointer', fontFamily: 'inherit',
                      display: 'flex', alignItems: 'center', gap: 12,
                      transition: 'border-color 120ms ease, background 120ms ease',
                    }}>
                      <span style={{
                        width: 14, height: 14, borderRadius: '50%', flexShrink: 0,
                        background: on ? 'var(--primary)' : 'var(--surface)',
                        border: '2px solid ' + (on ? 'var(--primary)' : 'var(--border-strong)'),
                        boxShadow: on ? 'inset 0 0 0 2px var(--surface)' : 'none',
                      }}/>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 13, fontWeight: 600, color: on ? 'var(--primary)' : 'var(--text)' }}>{s.label}</div>
                        <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>{s.detail}</div>
                      </div>
                    </button>
                  );
                })}
              </div>
            </FormField>

            <FormField label="Why does this matter?">
              <textarea value={form.why} onChange={e => setForm(f => ({ ...f, why: e.target.value }))}
                rows={2} placeholder="What decision will this target inform? Who looks at it?" style={inputStyle} />
            </FormField>

            <FormField label="Anything else? (optional)">
              <textarea value={form.notes} onChange={e => setForm(f => ({ ...f, notes: e.target.value }))}
                rows={2} placeholder="Existing reports, baselines, links to context…" style={inputStyle} />
            </FormField>

            <div style={{
              display: 'flex', justifyContent: 'space-between', gap: 8,
              paddingTop: 8, borderTop: '1px solid var(--border)',
              alignItems: 'center',
            }}>
              <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>
                Goes to <strong style={{ color: 'var(--text-muted)' }}>Joe Marshall</strong> · scoped within 1 working day
              </span>
              <div style={{ display: 'flex', gap: 8 }}>
                <Btn variant="secondary" type="button" onClick={onClose}>Cancel</Btn>
                <Btn variant="primary" iconRight={I.send}>Submit request</Btn>
              </div>
            </div>
          </form>
        )}
      </div>
    </div>
  );
};

// ============================================================
// Account Insights — AI-driven cross-channel synthesis. Pulls signals
// from Performance Targets, paid channels, SEO, site health, tickets and
// invoices into a single narrative + structured wins / watchpoints / actions.
// ============================================================

const WholeAccountInsightsScreen = ({ setActive, openAskLightbox }) => {
  // Pull structured signals from the data we already have on window
  const kpis = window.AGREED_KPIS || [];
  const sites = (window.CLIENT?.sites || []).filter(s => s.status === 'active');
  const healthMap = SITE_HEALTH || {};
  const reqs = (window.CHANGE_REQUESTS || CHANGE_REQUESTS || []);
  const tickets = window.TICKETS || [];
  const invoices = window.INVOICES || [];
  const opps = window.GROWTH_OPPORTUNITIES || GROWTH_OPPORTUNITIES || [];

  // ---- WINS (positive signals) ----
  const wins = [];
  // CPTs ahead of pace
  const ahead = kpis.filter(k => k.status === 'ahead');
  ahead.forEach(k => wins.push({
    icon: KPI_ICONS[k.key] || I.target,
    title: `${k.label} · ${k.delta}`,
    detail: k.note || `${formatKpi(k.actual, k.unit)} of ${formatKpi(k.target, k.unit)} target`,
    link: { label: 'Open Performance Target', target: 'cpts' },
  }));
  // Strong uptime
  const avgUptime = sites.length ? sites.reduce((s, x) => s + (healthMap[x.id]?.uptime30 || 0), 0) / sites.length : 0;
  if (avgUptime >= 99.85) wins.push({
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12h4l2-6 4 12 2-6h6"/></svg>,
    title: `${avgUptime.toFixed(2)}% avg uptime across ${sites.length} sites`,
    detail: 'No major outages this month — automated checks all green.',
    link: { label: 'Open Maintenance', target: 'maintenance' },
  });

  // ---- WATCHPOINTS (risk signals) ----
  const watch = [];
  // Overdue / due-soon invoices
  const overdueInv = invoices.find(i => i.status === 'Overdue');
  const dueSoonInv = invoices.find(i => i.status === 'Due');
  if (overdueInv) watch.push({
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>,
    title: `Invoice ${overdueInv.id} overdue · ${overdueInv.amount}`,
    detail: 'Pay to keep services running without interruption.',
    tone: 'negative',
    link: { label: 'Open Billing', target: 'billing' },
  });
  else if (dueSoonInv) watch.push({
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>,
    title: `Invoice ${dueSoonInv.id} due ${dueSoonInv.due}`,
    detail: `Auto-charge will run on ${dueSoonInv.due}.`,
    tone: 'warning',
    link: { label: 'Open Billing', target: 'billing' },
  });
  // Pending CPTs
  const pendingKpis = kpis.filter(k => k.source === 'pending' || k.actual == null);
  pendingKpis.forEach(k => watch.push({
    icon: KPI_ICONS[k.key] || I.target,
    title: `${k.label} not yet tracking`,
    detail: k.note || 'Awaiting setup — needs source configuration.',
    tone: 'warning',
    link: { label: 'Open Performance Target', target: 'cpts' },
  }));
  // Watch / off-track CPTs
  kpis.filter(k => k.status === 'watch' || k.status === 'off' || k.status === 'behind').forEach(k => watch.push({
    icon: KPI_ICONS[k.key] || I.target,
    title: `${k.label} · ${k.delta}`,
    detail: k.note || `${formatKpi(k.actual, k.unit)} of ${formatKpi(k.target, k.unit)} — pacing behind quarter.`,
    tone: k.status === 'off' || k.status === 'behind' ? 'negative' : 'warning',
    link: { label: 'Open Performance Target', target: 'cpts' },
  }));
  // Awaiting-reply tickets
  const awaitingReply = tickets.filter(t => t.status === 'Awaiting reply');
  if (awaitingReply.length) watch.push({
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>,
    title: `${awaitingReply.length} ticket${awaitingReply.length === 1 ? '' : 's'} awaiting your reply`,
    detail: awaitingReply[0].subject,
    tone: 'warning',
    link: { label: 'Open Tickets', target: 'tickets' },
  });
  // Maintenance: SSL renewing soon, slow speed, overdue plugin updates
  sites.forEach(s => {
    const h = healthMap[s.id]; if (!h) return;
    if (h.ssl?.status === 'expiring') watch.push({
      icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>,
      title: `${s.name} · SSL renews in ${h.ssl.daysToExpiry}d`,
      detail: `Auto-renew configured · ${h.ssl.issuer}.`,
      tone: 'warning',
      link: { label: 'Open Maintenance', target: 'maintenance' },
    });
    if (h.perf?.score && h.perf.score < 80) watch.push({
      icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/><path d="m13.4 12.6 4.2-4.2"/><path d="M3.5 18A9 9 0 0 1 12 5a9 9 0 0 1 8.5 13"/></svg>,
      title: `${s.name} · slow page speed`,
      detail: `Score ${h.perf.score}/100 · LCP ${h.perf.lcp}s. Hurts conversion rate.`,
      tone: h.perf.score < 70 ? 'negative' : 'warning',
      link: { label: 'Open Maintenance', target: 'maintenance' },
    });
  });

  // ---- TOP RECOMMENDATIONS (top 3 growth opps by confidence) ----
  const topRecs = [...opps]
    .filter(o => !o.active)
    .sort((a, b) => (b.confidence || 0) - (a.confidence || 0))
    .slice(0, 3);

  // Composite account health score (mocked, blended)
  const onTrackKpis = kpis.filter(k => k.status === 'on-track' || k.status === 'ahead').length;
  const trackable   = kpis.filter(k => k.source !== 'pending' && k.actual != null).length;
  const kpiHealth   = trackable ? (onTrackKpis / trackable) * 100 : 0;
  const upHealth    = avgUptime >= 99.9 ? 100 : avgUptime >= 99 ? 80 : 60;
  const ticketHealth = tickets.filter(t => t.status === 'Resolved').length / Math.max(1, tickets.length) * 100;
  const composite = Math.round((kpiHealth * 0.5) + (upHealth * 0.25) + (ticketHealth * 0.25));

  return (
    <div>
      {/* AI-themed header — matches Ask Anything + Growth Opportunities */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 'var(--radius)',
            background: 'var(--surface)',
            border: '1px solid var(--border)', display: 'grid', placeItems: 'center',
            flexShrink: 0,
          }}>
            <img src="assets/ai-insights.svg" alt="" width="22" height="22" style={{ display: 'block' }} />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.02em' }}>Account Insights</h1>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 5,
                fontSize: 11, fontWeight: 500, color: 'var(--text-muted)',
                padding: '3px 8px', borderRadius: 99,
                background: 'var(--surface-2)', border: '1px solid var(--border)',
              }}>
                <GeminiMark size={16} /> Powered by Gemini
              </span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
              Monthly synthesis from ClickyAI™, reviewed and verified by your account team before it surfaces
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            fontSize: 11, color: 'var(--text-muted)',
            padding: '4px 10px', borderRadius: 99,
            background: 'var(--surface-2)', border: '1px solid var(--border)',
            fontVariantNumeric: 'tabular-nums',
          }}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={{ color: 'var(--text-faint)' }}><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
            Updated this month · next refresh 1 Jun
          </span>
        </div>
      </div>

      {/* Top recommendations + AI synthesis stacked on the LEFT (3/4),
          Joe's note on the RIGHT (1/4). Both rainbow-bordered AI panes
          sit alongside the methodology that explains them. */}
      <div style={{ display: 'grid', gridTemplateColumns: '3fr 1fr', gap: 16, marginBottom: 16, alignItems: 'stretch' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div className="clicky-ai-border" style={{
        borderRadius: 'var(--radius)',
        boxShadow: 'var(--shadow-sm)',
        overflow: 'hidden',
      }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, background: 'var(--surface)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
            <div style={{
              width: 32, height: 32, borderRadius: 8, flexShrink: 0,
              background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
            }}>
              <img src="assets/ai-opps.svg" alt="" width="18" height="18" />
            </div>
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Top Growth Opportunities</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
                The three highest-impact moves AI flagged this month — approved by your account team
              </div>
            </div>
          </div>
          <Btn variant="ghost" size="sm" iconRight={I.arrowRight} onClick={() => setActive && setActive('opportunities')}>See all opportunities</Btn>
        </div>
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 0, background: 'var(--surface)',
        }}>
          {topRecs.map((o, i) => {
            const accent = o.tone === 'positive' ? 'var(--positive)'
                         : o.tone === 'warning'  ? 'var(--warning)'
                         : o.tone === 'negative' ? 'var(--negative)'
                         : 'var(--primary)';
            return (
              <div key={o.id}
                onClick={() => setActive && setActive('opportunities')}
                style={{
                  padding: '16px 18px',
                  borderLeft: i === 0 ? 'none' : '1px solid var(--border)',
                  cursor: 'pointer',
                  display: 'flex', flexDirection: 'column', gap: 8,
                  transition: 'background 0.12s',
                }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  {o.serviceIcon && (
                    <span style={{
                      width: 22, height: 22, borderRadius: 5,
                      background: 'var(--surface-2)', border: '1px solid var(--border)',
                      display: 'inline-grid', placeItems: 'center',
                      color: 'var(--text-muted)', flexShrink: 0,
                    }} title={o.service || o.category}>{o.serviceIcon}</span>
                  )}
                  <span style={{
                    fontSize: 10, fontWeight: 700, padding: '2px 7px', borderRadius: 99,
                    background: `color-mix(in oklab, ${accent} 14%, transparent)`,
                    color: accent, textTransform: 'uppercase', letterSpacing: '0.04em',
                  }}>{o.category}</span>
                  <span style={{ fontSize: 10, color: 'var(--text-faint)', fontVariantNumeric: 'tabular-nums' }}>
                    {Math.round((o.confidence || 0) * 100)}% confidence
                  </span>
                </div>
                <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--text)', lineHeight: 1.3, textWrap: 'pretty' }}>{o.title}</div>
                <div style={{ fontSize: 14, fontWeight: 700, color: accent, fontVariantNumeric: 'tabular-nums' }}>
                  {o.impact?.range} <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-muted)' }}>/{o.impact?.cadence}</span>
                </div>
                <div style={{ fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.45 }}>{o.impact?.note}</div>
              </div>
            );
          })}
        </div>
      </div>

      {/* AI synthesis — narrative read, sits inside the LEFT 2/3 column
          stacked under Top recommendations so both rainbow AI panes share
          the methodology guide on the right. */}
      <div className="clicky-ai-border" style={{
        borderRadius: 'var(--radius)',
        boxShadow: 'var(--shadow-sm)',
        overflow: 'hidden',
      }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{
            width: 32, height: 32, borderRadius: 8, flexShrink: 0,
            background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
          }}>
            <img src="assets/ai-insights.svg" alt="" width="18" height="18" />
          </div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>What ClickyAI™ and our expert team are seeing across your account</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>
              Synthesised from Performance Targets, paid channels, SEO, site health, tickets and billing
            </div>
          </div>
        </div>
        <div style={{ padding: '18px 22px 20px', display: 'flex', flexDirection: 'column', gap: 18 }}>
          {(() => {
            const statements = [
              {
                reviewer: TEAM.find(p => p.name === 'Joe Marshall'),
                verdict: 'approved',
                date: '28 Apr 2026',
                theme: {
                  label: 'Headline · performance',
                  color: 'var(--positive)',
                  icon: <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9V2h12v7"/><path d="M6 22V12h12v10"/><path d="M6 9a4 4 0 0 1-4-4M18 9a4 4 0 0 0 4-4"/></svg>,
                },
                body: (
                  <><strong style={{ color: 'var(--positive)' }}>Strong quarter so far.</strong> {onTrackKpis} of {trackable} Performance Targets are on or ahead of pace, paid + organic combined are driving <strong>97 bookings this month</strong> at an all-in cost-per-booking of <strong>£47.35</strong> — down 9.5% on the previous 30 days. Meta Ads is pulling its weight in the mix at 35% of paid spend, +18.3% MoM.</>
                ),
              },
              {
                reviewer: TEAM.find(p => p.name === 'Hayley Roberts'),
                verdict: 'disagreed',
                date: '30 Apr 2026',
                theme: {
                  label: 'Watchpoints · 3 areas',
                  color: 'var(--warning)',
                  icon: <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>,
                },
                note: "I don't buy that Sykes commission is the main driver of direct-share lag — our user research points to the booking flow stalling at the date-picker step (~22% drop-off). Fixing the funnel UX gets us further than fighting OTAs on price. Park Experience speed I agree with — that's on Nathan's queue.",
                body: (
                  <>The watchpoints worth your attention: <strong style={{ color: 'var(--warning)' }}>Direct booking share</strong> is sitting 6pp below target as Sykes commission ticks up, <strong style={{ color: 'var(--warning)' }}>Ownership enquiries</strong> still aren't tracking (HubSpot pipeline pending), and <strong style={{ color: 'var(--warning)' }}>Park Experience</strong> page speed is hurting conversion. None are emergencies — but together they explain why bookings could be even higher.</>
                ),
              },
              {
                reviewer: TEAM.find(p => p.name === 'Matt Jones'),
                verdict: 'approved',
                date: '1 May 2026',
                theme: {
                  label: 'Channel opportunity · Microsoft Ads',
                  color: 'var(--primary)',
                  icon: I.microsoft,
                },
                body: (
                  <>Top opportunity right now: Microsoft Ads is the single biggest gap — 18% of branded UK search demand is happening on Bing where we have no presence, and our analysis suggests <strong>+£800–£1,400/mo incremental bookings</strong> at low risk.</>
                ),
              },
            ];
            const verdictMeta = {
              approved:  { label: 'Approved by',  fg: 'var(--positive)', bg: 'color-mix(in oklab, var(--positive) 16%, transparent)',
                icon: <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg> },
              disagreed: { label: 'Different view from', fg: 'var(--warning)',  bg: 'color-mix(in oklab, var(--warning) 18%, transparent)',
                icon: <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M12 8v5M12 16h.01"/></svg> },
            };
            return statements.map((s, i) => {
              const meta = verdictMeta[s.verdict] || verdictMeta.approved;
              return (
                <div key={i} style={{
                  display: 'flex', gap: 16, alignItems: 'flex-start',
                  paddingTop: i === 0 ? 0 : 18,
                  borderTop: i === 0 ? 'none' : '1px solid var(--border)',
                }}>
                  {s.theme && (
                    <div style={{
                      width: 52, height: 52, borderRadius: 12, flexShrink: 0,
                      background: `color-mix(in oklab, ${s.theme.color} 12%, transparent)`,
                      border: `1px solid color-mix(in oklab, ${s.theme.color} 24%, var(--border))`,
                      color: s.theme.color,
                      display: 'grid', placeItems: 'center',
                    }}>
                      <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 26, height: 26 }}>
                        {React.cloneElement(s.theme.icon, {
                          width: 26, height: 26,
                          style: { width: 26, height: 26, ...(s.theme.icon.props.style || {}) },
                        })}
                      </span>
                    </div>
                  )}
                  <div style={{ minWidth: 0, flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
                    {s.theme && (
                      <div style={{
                        fontSize: 10.5, fontWeight: 700,
                        color: s.theme.color,
                        letterSpacing: '0.06em', textTransform: 'uppercase',
                      }}>
                        {s.theme.label}
                      </div>
                    )}
                    <p style={{
                      margin: 0,
                      fontSize: i === 0 ? 14 : 13.5,
                      color: i === 0 ? 'var(--text)' : 'var(--text-muted)',
                      lineHeight: 1.6,
                    }}>{s.body}</p>
                  {s.reviewer && (
                    <div style={{
                      display: 'inline-flex', alignItems: 'center', gap: 8,
                      fontSize: 11, color: 'var(--text-muted)',
                    }}>
                      <PersonAvatar name={s.reviewer.name} size={22} hue={s.reviewer.hue} src={s.reviewer.src} />
                      <span style={{
                        width: 14, height: 14, borderRadius: '50%',
                        background: meta.bg, color: meta.fg,
                        display: 'inline-grid', placeItems: 'center', flexShrink: 0,
                      }}>
                        {meta.icon}
                      </span>
                      {meta.label} <strong style={{ color: 'var(--text)', fontWeight: 600 }}>{s.reviewer.name}</strong>
                      <span style={{ color: 'var(--text-faint)' }}>·</span>
                      <span>{s.reviewer.role}</span>
                      {s.date && (
                        <>
                          <span style={{ color: 'var(--text-faint)' }}>·</span>
                          <span style={{
                            display: 'inline-flex', alignItems: 'center', gap: 4,
                            color: 'var(--text-faint)', fontVariantNumeric: 'tabular-nums',
                          }}>
                            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>
                            {s.date}
                          </span>
                        </>
                      )}
                    </div>
                  )}
                  {s.verdict === 'disagreed' && s.note && (
                    <div style={{
                      marginTop: 2, padding: '10px 14px',
                      background: 'color-mix(in oklab, var(--warning) 7%, var(--surface))',
                      border: '1px solid color-mix(in oklab, var(--warning) 25%, var(--border))',
                      borderRadius: 8, borderLeft: '3px solid var(--warning)',
                      fontSize: 12.5, color: 'var(--text)', lineHeight: 1.55,
                      display: 'flex', gap: 10,
                    }}>
                      <span style={{ color: 'var(--warning)', flexShrink: 0, marginTop: 2 }}>
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3 21V11c0-2 1-7 7-9l1 2c-3 1-4 3-4 5h3v12H3zm12 0V11c0-2 1-7 7-9l1 2c-3 1-4 3-4 5h3v12h-7z"/></svg>
                      </span>
                      <span><strong style={{ color: 'var(--warning)', textTransform: 'uppercase', letterSpacing: '0.04em', fontSize: 10, fontWeight: 700, marginRight: 6 }}>{s.reviewer.name.split(' ')[0]} pushed back:</strong>{s.note}</span>
                    </div>
                  )}
                  </div>{/* /content column */}
                </div>
              );
            });
          })()}
        </div>
      </div>
      </div>{/* /left column flex */}

      {/* How this is built — sits in the right column as supplementary
          help, framed as a personal note from the account manager. No
          card chrome so it reads as guidance rather than another data pane. */}
      {(() => {
        const am = TEAM.find(p => p.primary) || TEAM.find(p => p.name === 'Joe Marshall');
        const firstName = am?.name?.split(' ')[0] || 'your AM';
        return (
          <div style={{ padding: '4px 8px 8px', display: 'flex', flexDirection: 'column', gap: 10 }}>
            {/* AM byline — feels like a note from a person, not a system message */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              {am && <PersonAvatar name={am.name} size={40} hue={am.hue} src={am.src} />}
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 10.5, color: 'var(--text-faint)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                  A note from {firstName}
                </div>
                <div style={{ fontSize: 13, color: 'var(--text)', fontWeight: 600, marginTop: 1 }}>{am?.name || 'Your account manager'}</div>
              </div>
            </div>

            {/* Speech bubble — tail points up at Joe's avatar. Standard
                two-triangle CSS technique: an outer triangle in the border
                colour, with an inner triangle in the fill colour stacked
                1px in front so the slanted edges read as a 1px stroke that
                joins the bubble seamlessly. */}
            <div style={{ position: 'relative', marginLeft: 24, paddingTop: 8 }}>
              {/* Outer triangle (border) */}
              <div style={{
                position: 'absolute', top: 0, left: 16,
                width: 0, height: 0,
                borderLeft: '9px solid transparent',
                borderRight: '9px solid transparent',
                borderBottom: '9px solid color-mix(in oklab, var(--primary) 22%, var(--border))',
              }}/>
              {/* Inner triangle (fill) — 1px smaller, 1px down/right so a
                  1px sliver of the outer triangle remains visible as the
                  border stroke on each slanted edge. */}
              <div style={{
                position: 'absolute', top: 1, left: 17,
                width: 0, height: 0,
                borderLeft: '8px solid transparent',
                borderRight: '8px solid transparent',
                borderBottom: '8px solid color-mix(in oklab, var(--primary) 5%, var(--surface))',
                zIndex: 2,
              }}/>

              <div style={{
                position: 'relative',
                padding: '14px 16px 12px',
                background: 'color-mix(in oklab, var(--primary) 5%, var(--surface))',
                border: '1px solid color-mix(in oklab, var(--primary) 22%, var(--border))',
                borderRadius: 14,
                display: 'flex', flexDirection: 'column', gap: 12,
              }}>
                <p style={{ margin: 0, fontSize: 12.5, lineHeight: 1.6, color: 'var(--text)' }}>
                  Hi {CLIENT.contact?.split(' ')[0] || 'there'} — what you're reading here is a <strong>narrative read</strong> of your account, not raw numbers. Each month I work with ClickyAI™ to surface the things actually worth your attention.
                </p>

                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {[
                    {
                      title: 'Signals collected',
                      desc: 'I pull from your Performance Targets, every paid channel, SEO health, site uptime/speed, support tickets and billing.',
                    },
                    {
                      title: 'AI drafts the read',
                      desc: 'Gemini stitches the signals into plain English — wins, watchpoints, and a recommended next move.',
                    },
                    {
                      title: 'I review every line',
                      desc: "Matt, Hayley and I read it before you do. We approve, push back, or rewrite. If any of us disagree, you'll see our note next to that line.",
                    },
                  ].map((s, i) => (
                    <div key={i} style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
                      <div style={{
                        width: 4, height: 4, borderRadius: '50%',
                        background: 'var(--primary)', flexShrink: 0, marginTop: 7, opacity: 0.7,
                      }}/>
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--text)' }}>{s.title}</div>
                        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1, lineHeight: 1.5 }}>{s.desc}</div>
                      </div>
                    </div>
                  ))}
                </div>

                <p style={{ margin: 0, fontSize: 12, lineHeight: 1.55, color: 'var(--text)' }}>
                  Nothing on this page goes live without my sign-off. If something doesn't sit right with you, message me — I'd rather know.
                </p>

                <div style={{
                  fontSize: 12, color: 'var(--text-muted)', fontStyle: 'italic',
                  marginTop: -2,
                }}>
                  — {firstName}
                </div>
              </div>
            </div>

            <div style={{
              marginLeft: 24,
              fontSize: 10.5, color: 'var(--text-faint)',
              display: 'flex', alignItems: 'center', gap: 6,
              paddingTop: 4,
            }}>
              <GeminiMark size={11} />
              <span>Powered by Gemini · refreshed monthly · next refresh 1 Jun</span>
            </div>
          </div>
        );
      })()}
      </div>

      {/* Wins / Watchpoints two-up */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginBottom: 16 }}>
        {/* Wins */}
        <Card padding={0}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{
                width: 28, height: 28, borderRadius: 6,
                background: 'color-mix(in oklab, var(--positive) 14%, transparent)',
                color: 'var(--positive)', display: 'grid', placeItems: 'center',
              }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>
              </span>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Where you're winning</div>
            </div>
            <span style={{ fontSize: 11, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{wins.length}</span>
          </div>
          <div style={{ padding: 6 }}>
            {wins.length === 0 ? (
              <div style={{ padding: 24, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>
                Nothing strongly outperforming yet — consistency is its own win.
              </div>
            ) : (
              wins.map((w, i) => (
                <div key={i} style={{
                  display: 'grid', gridTemplateColumns: '28px 1fr auto', alignItems: 'center', gap: 12,
                  padding: '10px 12px', borderRadius: 6, cursor: 'pointer',
                  transition: 'background 0.12s',
                }}
                  onClick={() => w.link && setActive && setActive(w.link.target)}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                >
                  <div style={{
                    width: 28, height: 28, borderRadius: 6,
                    background: 'color-mix(in oklab, var(--positive) 12%, transparent)',
                    color: 'var(--positive)', display: 'grid', placeItems: 'center', flexShrink: 0,
                  }}>{w.icon}</div>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{w.title}</div>
                    <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.4 }}>{w.detail}</div>
                  </div>
                  <span style={{ color: 'var(--text-faint)', flexShrink: 0 }}>{I.arrowRight}</span>
                </div>
              ))
            )}
          </div>
        </Card>

        {/* Watchpoints */}
        <Card padding={0}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{
                width: 28, height: 28, borderRadius: 6,
                background: 'color-mix(in oklab, var(--warning) 16%, transparent)',
                color: 'var(--warning)', display: 'grid', placeItems: 'center',
              }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
              </span>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Where to focus</div>
            </div>
            <span style={{ fontSize: 11, color: 'var(--text-muted)', fontVariantNumeric: 'tabular-nums' }}>{watch.length}</span>
          </div>
          <div style={{ padding: 6 }}>
            {watch.length === 0 ? (
              <div style={{ padding: 24, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>
                Nothing critical — everything's running clean.
              </div>
            ) : (
              watch.map((w, i) => {
                const accent = w.tone === 'negative' ? 'var(--negative)' : 'var(--warning)';
                return (
                  <div key={i} style={{
                    display: 'grid', gridTemplateColumns: '28px 1fr auto', alignItems: 'center', gap: 12,
                    padding: '10px 12px', borderRadius: 6, cursor: 'pointer',
                    transition: 'background 0.12s',
                  }}
                    onClick={() => w.link && setActive && setActive(w.link.target)}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                  >
                    <div style={{
                      width: 28, height: 28, borderRadius: 6,
                      background: `color-mix(in oklab, ${accent} 14%, transparent)`,
                      color: accent, display: 'grid', placeItems: 'center', flexShrink: 0,
                    }}>{w.icon}</div>
                    <div style={{ minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{w.title}</div>
                      <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 2, lineHeight: 1.4 }}>{w.detail}</div>
                    </div>
                    <span style={{ color: 'var(--text-faint)', flexShrink: 0 }}>{I.arrowRight}</span>
                  </div>
                );
              })
            )}
          </div>
        </Card>
      </div>

      {/* Methodology footer */}
      <div style={{
        marginTop: 16, padding: '14px 18px',
        borderRadius: 'var(--radius)', border: '1px dashed var(--border)',
        fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5,
        display: 'flex', alignItems: 'flex-start', gap: 12,
      }}>
        <div style={{
          width: 28, height: 28, borderRadius: 6, flexShrink: 0,
          background: 'var(--surface-2)', display: 'grid', placeItems: 'center',
        }}><img src="assets/ai-opps.svg" alt="" width="16" height="16" /></div>
        <div>
          <div style={{ color: 'var(--text)', fontWeight: 600, marginBottom: 2 }}>How this read is built</div>
          ClickyAI™ scans every signal on your account — Performance Targets vs pace, paid channel deltas, organic momentum, site health checks, ticket sentiment and billing status — and your account team reviews every story before it surfaces. Want to dig into anything specific? <button onClick={() => setActive && setActive('ask')} style={{
            background: 'none', border: 'none', color: 'var(--primary)', fontWeight: 600,
            cursor: 'pointer', padding: 0, fontSize: 12,
          }}>Ask ClickyAI →</button>
        </div>
      </div>
    </div>
  );
};

Object.assign(window, {
  DashboardScreen, DashboardV2Screen, GoogleAdsScreen, ReportsScreen, TicketsScreen, AskScreen, BillingScreen, ContractDetailScreen,
  ChannelsScreen, PaidMediaScreen, AddPaidMediaChannelsScreen, AddSeoScreen, AddMaintenanceScreen, SeoScreen, CptsIndexScreen, MaintenanceScreen, TeamScreen,
  GrowthOpportunitiesScreen, MetaAdsScreen,
  WholeAccountInsightsScreen,
  RequestPerformanceTargetModal,
  TEAM, EVENTS, GROWTH_OPPORTUNITIES,
});
