// AI Labs page — components: lab cards, deploy modal (T&C + token allocation),
// community feed, chat companion, filter row.

const formatTokens = (n) => {
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
  if (n >= 1_000)     return `${(n / 1_000).toFixed(0)}K`;
  return `${n}`;
};

const LabFilterRow = ({ active, setActive, query, setQuery }) => (
  <div data-screen-label="Lab Filter" style={{
    padding: '14px 16px',
    background: 'white',
    border: '1px solid var(--line)',
    borderRadius: 14,
    display: 'flex', alignItems: 'center', gap: 12,
    marginBottom: 18,
  }}>
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8,
      padding: '7px 12px',
      background: 'var(--bg-subtle)',
      borderRadius: 9,
      flex: 1, minWidth: 0,
    }}>
      <I.Search size={13} stroke="var(--muted)" />
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Search labs, sponsors, model families…"
        style={{
          flex: 1, border: 'none', background: 'transparent', outline: 'none',
          fontSize: 13, fontFamily: 'inherit',
        }}/>
    </div>
    <div className="row" style={{ gap: 4, padding: 3, background: 'var(--bg-subtle)', borderRadius: 9 }}>
      {LAB_FILTERS.map(f => (
        <button
          key={f.id}
          onClick={() => setActive(f.id)}
          style={{
            padding: '5px 10px',
            borderRadius: 6,
            border: 'none',
            background: active === f.id ? 'white' : 'transparent',
            boxShadow: active === f.id ? '0 1px 2px rgba(0,0,0,0.06)' : 'none',
            color: active === f.id ? 'var(--ink)' : 'var(--muted)',
            fontSize: 12, fontWeight: 600, cursor: 'pointer',
            fontFamily: 'inherit',
            display: 'flex', alignItems: 'center', gap: 5,
          }}>
          {f.label}
          <span className="mono" style={{
            fontSize: 9.5,
            padding: '0 5px',
            background: active === f.id ? 'var(--bg-sunken)' : 'transparent',
            borderRadius: 3,
            color: active === f.id ? 'var(--muted)' : 'var(--muted-2)',
          }}>{f.count}</span>
        </button>
      ))}
    </div>
  </div>
);

// ---------- Lab card ----------
const LabCard = ({ lab, onDeploy, onMore, featured }) => {
  const seatsPct = (lab.seatsTaken / lab.seats) * 100;

  return (
    <article style={{
      position: 'relative',
      background: 'white',
      border: `1px solid var(--line)`,
      borderRadius: 14,
      padding: 18,
      display: 'flex', flexDirection: 'column', gap: 12,
      cursor: 'default',
      transition: 'all 0.15s',
    }}
      onMouseEnter={e => { e.currentTarget.style.borderColor = lab.accent; e.currentTarget.style.transform = 'translateY(-1px)'; }}
      onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--line)'; e.currentTarget.style.transform = 'translateY(0)'; }}>

      {/* Accent strip */}
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0, height: 3,
        background: lab.accent, borderTopLeftRadius: 14, borderTopRightRadius: 14,
      }}/>

      {/* Header */}
      <div className="row" style={{ alignItems: 'flex-start', gap: 12 }}>
        <SponsorMark lab={lab} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
            {lab.sponsor}
          </div>
          <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--ink)', letterSpacing: '-0.01em', marginTop: 1 }}>
            {lab.name}
          </div>
          <div className="row" style={{ gap: 5, marginTop: 4, flexWrap: 'wrap' }}>
            <span className="mono" style={{
              fontSize: 10.5, padding: '1px 6px',
              background: lab.accentSoft, color: lab.accentInk,
              borderRadius: 4, fontWeight: 600,
            }}>{lab.family}</span>
            <span className="badge badge-zinc" style={{ fontSize: 9.5 }}>{lab.tag}</span>
          </div>
        </div>
        {lab.badge && (
          <span style={{
            padding: '3px 8px', borderRadius: 999,
            background: 'white', border: `1.5px solid ${lab.badge.color}`,
            color: lab.badge.color,
            fontSize: 9.5, fontWeight: 700, letterSpacing: '0.04em',
            textTransform: 'uppercase', fontFamily: 'JetBrains Mono, monospace',
            flex: 'none',
          }}>{lab.badge.text}</span>
        )}
      </div>

      {/* Blurb + bullets */}
      <p style={{ margin: 0, color: 'var(--ink-2)', fontSize: 12.5, lineHeight: 1.55 }} className="text-pretty">
        {lab.blurb}
      </p>
      <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'grid', gap: 4 }}>
        {lab.bullets.slice(0, 2).map((b, i) => (
          <li key={i} style={{ fontSize: 11.5, color: 'var(--muted)', display: 'flex', alignItems: 'flex-start', gap: 6 }}>
            <I.Check size={10} stroke={lab.accent} strokeWidth={3} style={{ marginTop: 3, flex: 'none' }} />
            <span>{b}</span>
          </li>
        ))}
      </ul>

      {/* Stats strip */}
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8,
        padding: 10, background: 'var(--bg-subtle)', borderRadius: 9,
      }}>
        <Stat label="Token grant" value={formatTokens(lab.tokenGrant)} accent={lab.accent} />
        <Stat label="Pods" value={lab.podsIncluded} />
        <Stat label="KB · GB" value={lab.kbGB} />
      </div>

      {/* Seats + data sharing */}
      <div>
        <div className="row" style={{ justifyContent: 'space-between', marginBottom: 4 }}>
          <span style={{ fontSize: 11, color: 'var(--muted)' }}>
            <span className="mono" style={{ color: 'var(--ink-2)', fontWeight: 600 }}>{lab.seatsTaken}</span>
            {' / '}{lab.seats} seats
          </span>
          <DataSharingBadge mode={lab.dataSharing} />
        </div>
        <div style={{ height: 4, background: 'var(--bg-sunken)', borderRadius: 999, overflow: 'hidden' }}>
          <div style={{
            width: `${seatsPct}%`, height: '100%',
            background: seatsPct > 90 ? '#dc2626' : lab.accent,
          }} />
        </div>
      </div>

      {/* CTA row */}
      <div className="row" style={{ gap: 8, marginTop: 'auto' }}>
        <button
          onClick={() => onDeploy(lab)}
          style={{
            flex: 1, padding: '8px 12px', borderRadius: 8,
            background: lab.accent, color: 'white', border: 'none',
            fontSize: 12.5, fontWeight: 600, cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
            fontFamily: 'inherit',
          }}>
          <I.Sparkles size={12} /> Deploy lab
        </button>
        <button
          onClick={() => onMore(lab)}
          className="btn btn-sm"
          style={{ padding: '7px 10px' }}>
          Details <I.ArrowRight size={11} />
        </button>
      </div>
    </article>
  );
};

const SponsorMark = ({ lab }) => (
  <div style={{
    width: 42, height: 42, borderRadius: 10,
    background: lab.sponsorColor, color: 'white',
    display: 'grid', placeItems: 'center',
    fontSize: 15, fontWeight: 800,
    fontFamily: 'JetBrains Mono, monospace',
    letterSpacing: '-0.02em',
    flex: 'none',
  }}>{lab.sponsorMark}</div>
);

const Stat = ({ label, value, accent }) => (
  <div>
    <div className="tabular" style={{
      fontSize: 14, fontWeight: 700,
      color: accent || 'var(--ink)',
      letterSpacing: '-0.01em',
    }}>{value}</div>
    <div style={{ fontSize: 9.5, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
      {label}
    </div>
  </div>
);

const DataSharingBadge = ({ mode }) => {
  const cfg = {
    optional: { label: 'Sharing · optional', bg: 'var(--violet-soft)', fg: 'var(--violet-ink)', dot: '#7c3aed' },
    required: { label: 'Sharing · required', bg: 'var(--amber-soft)', fg: '#92400e',            dot: '#d97706' },
    never:    { label: 'Sharing · never',    bg: 'var(--emerald-soft)', fg: '#064e3b',           dot: '#059669' },
  }[mode];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '1px 7px', borderRadius: 999,
      background: cfg.bg, color: cfg.fg,
      fontSize: 10, fontWeight: 600,
    }}>
      <span className="dot" style={{ background: cfg.dot }}></span>
      {cfg.label}
    </span>
  );
};

// ---------- Deploy modal — T&C, data-sharing toggle, token confirmation ----------
const DeployModal = ({ lab, onClose, onConfirm }) => {
  const [acceptTerms, setAcceptTerms] = React.useState(false);
  const [shareData, setShareData] = React.useState(lab.dataSharing === 'required');
  const [deploying, setDeploying] = React.useState(false);
  const [deployed, setDeployed] = React.useState(false);

  const dataLocked = lab.dataSharing === 'required' || lab.dataSharing === 'never';
  const effectiveShare = lab.dataSharing === 'required' ? true
                        : lab.dataSharing === 'never'    ? false
                        : shareData;

  const grantWithoutShare = Math.floor(lab.tokenGrant * 0.25);
  const effectiveGrant = effectiveShare ? lab.tokenGrant : grantWithoutShare;

  const canDeploy = acceptTerms && !deploying;

  const deploy = () => {
    setDeploying(true);
    setTimeout(() => { setDeployed(true); setDeploying(false); }, 1600);
  };

  if (!lab) return null;
  return (
    <>
      <div onClick={onClose} style={{
        position: 'fixed', inset: 0,
        background: 'rgba(15, 10, 26, 0.5)',
        backdropFilter: 'blur(2px)', zIndex: 70,
      }} />
      <div style={{
        position: 'fixed',
        top: '50%', left: '50%',
        transform: 'translate(-50%, -50%)',
        width: 720, maxWidth: 'calc(100vw - 32px)',
        maxHeight: 'calc(100vh - 32px)',
        overflow: 'hidden',
        display: 'flex', flexDirection: 'column',
        background: 'white',
        borderRadius: 16,
        boxShadow: '0 24px 60px rgba(15, 10, 26, 0.25)',
        zIndex: 80,
      }}>
        {/* Header */}
        <div style={{
          padding: '18px 22px',
          background: `linear-gradient(135deg, ${lab.accentSoft} 0%, white 100%)`,
          borderBottom: '1px solid var(--line)',
          display: 'flex', alignItems: 'flex-start', gap: 14,
        }}>
          <SponsorMark lab={lab} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
              Deploying {lab.sponsor} lab
            </div>
            <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: '-0.01em', marginTop: 1 }}>{lab.name}</div>
            <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 3 }}>{lab.tagline}</div>
          </div>
          <button onClick={onClose} className="icon-btn"><I.X /></button>
        </div>

        {/* Body — scrollable */}
        {!deployed ? (
          <div style={{ padding: 22, overflow: 'auto', display: 'grid', gap: 18 }}>

            {/* What you get */}
            <Block icon="Sparkle2" title="What spins up">
              <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'grid', gap: 6 }}>
                {lab.bullets.map((b, i) => (
                  <li key={i} style={{ fontSize: 12.5, color: 'var(--ink-2)', display: 'flex', alignItems: 'flex-start', gap: 8 }}>
                    <span style={{
                      width: 16, height: 16, borderRadius: 4,
                      background: lab.accentSoft, color: lab.accent,
                      display: 'grid', placeItems: 'center', flex: 'none', marginTop: 1,
                    }}><I.Check size={10} strokeWidth={3} /></span>
                    {b}
                  </li>
                ))}
              </ul>
              <div className="row" style={{ marginTop: 12, gap: 6, flexWrap: 'wrap' }}>
                <FactChip label="Spin-up" value={`~${lab.spinupSec}s`} />
                <FactChip label="Pods" value={lab.podsIncluded} />
                <FactChip label="KB" value={`${lab.kbGB} GB`} />
                <FactChip label="Model family" value={lab.family} mono />
              </div>
            </Block>

            {/* Data sharing */}
            <Block icon="Shield" title="Data sharing with sponsor">
              <p style={{ margin: 0, fontSize: 12.5, color: 'var(--muted)', lineHeight: 1.55 }} className="text-pretty">
                The {lab.sponsor} team can read anonymised telemetry from your Castle — prompts, completions, tool-call latencies,
                error traces. Used to improve their model family. {lab.dataSharing === 'never' && 'This lab guarantees zero data leaves your perimeter.'}
              </p>
              <div style={{
                marginTop: 10, padding: 14,
                background: effectiveShare ? lab.accentSoft : 'var(--bg-subtle)',
                border: `1px solid ${effectiveShare ? lab.accent + '55' : 'var(--line)'}`,
                borderRadius: 10,
                display: 'grid', gridTemplateColumns: '1fr auto', gap: 14,
                alignItems: 'center',
              }}>
                <div>
                  <div className="row" style={{ gap: 6, marginBottom: 4 }}>
                    <span style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)' }}>
                      Share telemetry with {lab.sponsor}
                    </span>
                    {dataLocked && (
                      <span className="badge badge-amber" style={{ fontSize: 9.5 }}>
                        {lab.dataSharing === 'required' ? 'required by this lab' : 'disabled by this lab'}
                      </span>
                    )}
                  </div>
                  <div style={{ fontSize: 11.5, color: 'var(--muted)' }}>
                    {effectiveShare
                      ? `Full ${formatTokens(lab.tokenGrant)} token grant unlocked.`
                      : `Privacy-only mode. Token grant drops to ${formatTokens(grantWithoutShare)} (25%).`}
                  </div>
                </div>
                <Switch
                  on={effectiveShare}
                  onChange={() => !dataLocked && setShareData(!shareData)}
                  accent={lab.accent}
                  disabled={dataLocked}
                />
              </div>
            </Block>

            {/* Token grant */}
            <Block icon="Zap" title="Sponsor token allocation">
              <div style={{
                padding: 16,
                background: 'linear-gradient(135deg, #fef3c7 0%, #fff7ed 100%)',
                border: '1px solid #fde68a', borderRadius: 12,
                display: 'flex', alignItems: 'center', gap: 18,
              }}>
                <div style={{
                  width: 56, height: 56, borderRadius: 14,
                  background: 'white', color: '#d97706',
                  display: 'grid', placeItems: 'center', flex: 'none',
                  border: '1.5px solid #fde68a',
                }}>
                  <I.Zap size={26} />
                </div>
                <div style={{ flex: 1 }}>
                  <div className="tabular" style={{ fontSize: 26, fontWeight: 800, color: '#78350f', letterSpacing: '-0.02em' }}>
                    {formatTokens(effectiveGrant)}{' '}
                    <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--muted)' }}>tokens / experiment</span>
                  </div>
                  <div style={{ fontSize: 11.5, color: '#92400e', marginTop: 2 }}>
                    Funded by {lab.sponsor}. Renewable on benchmark submission. Auto-expires in 30 days.
                  </div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <div style={{ fontSize: 10, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
                    your wallet
                  </div>
                  <div className="tabular" style={{ fontSize: 13, fontWeight: 700, color: 'var(--violet)' }}>
                    {formatTokens(PROFILE_USER.wallet || 240_000)}
                  </div>
                </div>
              </div>
            </Block>

            {/* T&C */}
            <Block icon="Lock" title="Terms & conditions">
              <div style={{
                padding: 12,
                background: 'var(--bg-subtle)',
                border: '1px solid var(--line)',
                borderRadius: 9,
                fontSize: 11.5, color: 'var(--muted)', lineHeight: 1.6,
                maxHeight: 100, overflow: 'auto',
              }}>
                By deploying the {lab.name}, you accept the {lab.sponsor} Lab Experimenter Agreement v1.4.
                Voltron may emit benchmark results to the sponsor when an ActionList completes.
                You may delete the lab at any time; the token grant is non-refundable after the first hour.
                Yellow Lion enforces standard Charter rules irrespective of sponsor configuration.
              </div>
              <label style={{
                marginTop: 10, padding: '10px 12px',
                border: `1.5px solid ${acceptTerms ? lab.accent : 'var(--line)'}`,
                background: acceptTerms ? lab.accentSoft : 'white',
                borderRadius: 10,
                display: 'flex', alignItems: 'center', gap: 10,
                cursor: 'pointer',
              }}>
                <span style={{
                  width: 18, height: 18, borderRadius: 5,
                  border: `1.5px solid ${acceptTerms ? lab.accent : 'var(--line)'}`,
                  background: acceptTerms ? lab.accent : 'white',
                  display: 'grid', placeItems: 'center', flex: 'none',
                }}>
                  {acceptTerms && <I.Check size={11} stroke="white" strokeWidth={3} />}
                </span>
                <input type="checkbox" checked={acceptTerms} onChange={e => setAcceptTerms(e.target.checked)} style={{ display: 'none' }}/>
                <div style={{ fontSize: 12.5 }}>
                  I accept the <strong>{lab.sponsor} Lab Experimenter Agreement</strong> and the ActionBoard Charter.
                </div>
              </label>
            </Block>

          </div>
        ) : (
          // Deployed state
          <div style={{ padding: 36, display: 'grid', placeItems: 'center', gap: 14, textAlign: 'center' }}>
            <div style={{
              width: 64, height: 64, borderRadius: 18,
              background: `linear-gradient(135deg, ${lab.accent} 0%, ${lab.accentInk} 100%)`,
              color: 'white', display: 'grid', placeItems: 'center',
            }}>
              <I.CheckCircle size={30} />
            </div>
            <div>
              <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: '-0.01em' }}>
                {lab.name} is live.
              </div>
              <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 4 }}>
                Castle forming with {lab.podsIncluded} pods · {formatTokens(effectiveGrant)} tokens granted · KB indexed.
              </div>
            </div>
            <div className="row" style={{ gap: 8 }}>
              <button className="btn" onClick={onClose}>Close</button>
              <button className="btn btn-primary" style={{ background: lab.accent, borderColor: lab.accent }}>
                Open lab <I.ArrowRight />
              </button>
            </div>
          </div>
        )}

        {/* CTA footer */}
        {!deployed && (
          <div style={{
            padding: '14px 22px',
            borderTop: '1px solid var(--line)',
            background: 'var(--bg-subtle)',
            display: 'flex', alignItems: 'center', gap: 12,
          }}>
            <div style={{ flex: 1, fontSize: 11.5, color: 'var(--muted)' }}>
              <I.Lock size={11} style={{ verticalAlign: -2, marginRight: 4 }} stroke="var(--muted)" />
              Charter rules enforced regardless of sponsor configuration.
            </div>
            <button className="btn" onClick={onClose}>Cancel</button>
            <button
              onClick={deploy}
              disabled={!canDeploy}
              style={{
                padding: '8px 16px', borderRadius: 8,
                background: canDeploy ? lab.accent : 'var(--bg-sunken)',
                color: canDeploy ? 'white' : 'var(--muted-2)',
                border: 'none',
                fontSize: 13, fontWeight: 600,
                cursor: canDeploy ? 'pointer' : 'not-allowed',
                display: 'flex', alignItems: 'center', gap: 6,
                fontFamily: 'inherit',
              }}>
              {deploying ? (
                <><span className="dot pulse" style={{ background: 'white' }}></span> Spinning up lab…</>
              ) : (
                <><I.Sparkles size={13} /> Deploy lab · {formatTokens(effectiveGrant)} tokens</>
              )}
            </button>
          </div>
        )}
      </div>
    </>
  );
};

const Block = ({ icon, title, children }) => {
  const Icon = I[icon] || I.Sparkle2;
  return (
    <div>
      <div className="row" style={{ gap: 6, marginBottom: 8 }}>
        <Icon size={13} stroke="var(--muted)" />
        <span style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)', letterSpacing: '-0.01em' }}>{title}</span>
      </div>
      {children}
    </div>
  );
};

const FactChip = ({ label, value, mono }) => (
  <span style={{
    padding: '3px 8px',
    background: 'white',
    border: '1px solid var(--line)',
    borderRadius: 6,
    fontSize: 11,
    display: 'inline-flex', alignItems: 'center', gap: 6,
  }}>
    <span style={{ color: 'var(--muted)' }}>{label}</span>
    <span className={mono ? 'mono' : ''} style={{ fontWeight: 600, color: 'var(--ink)' }}>{value}</span>
  </span>
);

const Switch = ({ on, onChange, accent = 'var(--violet)', disabled }) => (
  <button
    onClick={disabled ? undefined : onChange}
    role="switch"
    aria-checked={on}
    style={{
      width: 40, height: 22,
      borderRadius: 999,
      background: on ? accent : 'var(--line)',
      border: 'none',
      position: 'relative',
      cursor: disabled ? 'not-allowed' : 'pointer',
      flex: 'none',
      opacity: disabled ? 0.6 : 1,
      transition: 'background 0.15s',
    }}>
    <span style={{
      position: 'absolute',
      top: 2, left: on ? 20 : 2,
      width: 18, height: 18,
      background: 'white',
      borderRadius: 999,
      boxShadow: '0 1px 2px rgba(0,0,0,0.18)',
      transition: 'left 0.15s',
    }} />
  </button>
);

// ---------- Community feed ----------
const CommunityFeed = ({ posts, onAskAbout, onDeployFromPost }) => (
  <section data-screen-label="Community" className="card" style={{ padding: 20 }}>
    <div className="card-header" style={{ marginBottom: 14 }}>
      <div>
        <div className="section-eyebrow"><I.Globe size={11} /> curated · last 7d</div>
        <div className="card-title">Recent research & community</div>
        <div className="card-sub">Papers, sponsor announcements, and threads. Each linked to the labs they affect.</div>
      </div>
      <button className="btn btn-sm">
        <I.Refresh size={11} /> Refresh
      </button>
    </div>
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 10 }}>
      {posts.map(p => (
        <PostCard key={p.id} post={p} onAskAbout={onAskAbout} onDeployFromPost={onDeployFromPost} />
      ))}
    </div>
  </section>
);

const PostCard = ({ post, onAskAbout, onDeployFromPost }) => {
  const kindCfg = {
    paper:        { icon: 'Book', color: '#6d28d9', bg: 'var(--violet-soft)', label: 'paper' },
    announcement: { icon: 'Zap',  color: '#dc2626', bg: 'var(--rose-soft)',   label: 'announcement' },
    community:    { icon: 'MessageCircle', color: '#0284c7', bg: 'var(--sky-soft)', label: 'community' },
    news:         { icon: 'Globe', color: '#059669', bg: 'var(--emerald-soft)', label: 'news' },
  }[post.kind] || { icon: 'Sparkle2', color: '#71717a', bg: 'var(--bg-subtle)', label: post.kind };
  const Icon = I[kindCfg.icon] || I.Sparkle2;
  const labs = post.relatedLabs.map(id => SPONSOR_LABS.find(l => l.id === id)).filter(Boolean);

  return (
    <article style={{
      padding: 14,
      background: 'white',
      border: '1px solid var(--line)',
      borderRadius: 12,
      display: 'flex', flexDirection: 'column', gap: 8,
    }}>
      <div className="row" style={{ gap: 8 }}>
        <span style={{
          padding: '2px 7px', borderRadius: 5,
          background: kindCfg.bg, color: kindCfg.color,
          fontSize: 10, fontWeight: 700,
          display: 'inline-flex', alignItems: 'center', gap: 4,
        }}>
          <Icon size={9} /> {kindCfg.label}
        </span>
        {post.hot && (
          <span style={{
            padding: '2px 6px', borderRadius: 5,
            background: '#fef2f2', color: '#dc2626',
            fontSize: 9.5, fontWeight: 700,
            display: 'inline-flex', alignItems: 'center', gap: 3,
          }}>
            <span style={{ width: 5, height: 5, borderRadius: 999, background: '#dc2626' }} className="pulse" />
            hot
          </span>
        )}
        <span style={{ flex: 1 }} />
        <span className="mono" style={{ fontSize: 10, color: 'var(--muted)' }}>{post.posted}</span>
      </div>
      <div style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--ink)', letterSpacing: '-0.01em', lineHeight: 1.35 }}>
        {post.title}
      </div>
      <div style={{ fontSize: 11, color: 'var(--muted)' }}>
        {post.venue} · {post.author}
      </div>
      <p style={{ margin: 0, fontSize: 12, color: 'var(--ink-2)', lineHeight: 1.5 }} className="text-pretty">
        {post.excerpt}
      </p>
      <div className="row" style={{ gap: 4, flexWrap: 'wrap' }}>
        {post.tags.map(t => (
          <span key={t} className="mono" style={{
            fontSize: 9.5, padding: '1px 6px',
            background: 'var(--bg-subtle)', border: '1px solid var(--line)',
            borderRadius: 4, color: 'var(--muted)',
          }}>#{t}</span>
        ))}
      </div>
      {labs.length > 0 && (
        <div className="row" style={{ gap: 5, paddingTop: 6, borderTop: '1px solid var(--line-2)', flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10.5, color: 'var(--muted)' }}>Affects:</span>
          {labs.map(l => (
            <button
              key={l.id}
              onClick={() => onDeployFromPost(l)}
              style={{
                padding: '2px 7px', borderRadius: 999,
                background: 'white', border: `1px solid ${l.accent}55`,
                color: l.accentInk,
                fontSize: 10, fontWeight: 600,
                display: 'inline-flex', alignItems: 'center', gap: 4,
                cursor: 'pointer', fontFamily: 'inherit',
              }}>
              <span className="dot" style={{ background: l.accent }} />
              {l.name}
            </button>
          ))}
          <span style={{ flex: 1 }} />
          <button onClick={() => onAskAbout(post)} className="btn btn-ghost btn-sm" style={{ padding: '2px 7px', fontSize: 10.5 }}>
            Ask AI <I.ArrowRight size={9} />
          </button>
        </div>
      )}
    </article>
  );
};

// ---------- Sticky AI companion (sidebar chat) ----------
const LabsCompanion = ({ labs, onDeploy, currentMessage, setCurrentMessage }) => {
  const [messages, setMessages] = React.useState([
    {
      who: 'ai',
      text: "Hi — I'm your Labs guide. Tell me what you want to build and I'll pick a lab — or ask me to walk you through setting one up.",
      suggestions: SUGGESTED_PROMPTS,
    },
  ]);
  const [input, setInput] = React.useState('');
  const [thinking, setThinking] = React.useState(false);
  const endRef = React.useRef(null);

  React.useEffect(() => {
    endRef.current?.parentElement?.scrollTo({ top: 9999, behavior: 'smooth' });
  }, [messages, thinking]);

  // Allow external bus (community feed click) to inject a message
  React.useEffect(() => {
    if (currentMessage) {
      setInput(currentMessage);
      setCurrentMessage('');
    }
  }, [currentMessage]);

  const send = async (text) => {
    const q = (text ?? input).trim();
    if (!q) return;
    setMessages(m => [...m, { who: 'user', text: q }]);
    setInput('');
    setThinking(true);

    // Lightweight matching — recommend labs based on keywords
    const norm = q.toLowerCase();
    const candidates = labs
      .map(l => {
        let score = 0;
        const hay = `${l.name} ${l.sponsor} ${l.tag} ${l.family} ${l.blurb} ${l.bullets.join(' ')}`.toLowerCase();
        for (const word of norm.split(/\s+/)) {
          if (word.length > 2 && hay.includes(word)) score += 1;
        }
        if (norm.includes('sovereign') || norm.includes('gdpr') || norm.includes('private')) {
          if (l.dataSharing === 'never') score += 3;
        }
        if (norm.includes('open') || norm.includes('fine-tune') || norm.includes('lora')) {
          if (l.id === 'meta-llama-open') score += 3;
        }
        if (norm.includes('research') || norm.includes('long context') || norm.includes('paper')) {
          if (l.id === 'gemini-deepmind' || l.id === 'openai-gpt5') score += 2;
        }
        return { lab: l, score };
      })
      .filter(c => c.score > 0)
      .sort((a, b) => b.score - a.score)
      .slice(0, 3)
      .map(c => c.lab);

    // Setup-guidance intent — walk the user through standing a lab up
    const setupIntent = /(set ?up|setup|deploy|install|configure|get(ting)? started|spin ?up|onboard|walk me through|how do i (start|begin)|first lab|steps?)/.test(norm);
    const explicitLab = labs.find(l =>
      norm.includes(l.name.toLowerCase()) ||
      norm.includes(l.sponsor.toLowerCase()) ||
      norm.includes(l.family.toLowerCase())
    );
    const namedLab = explicitLab || (setupIntent ? (candidates[0] || null) : null);
    const steps = setupIntent
      ? SETUP_STEPS.map((s, i) => {
          const lab = namedLab;
          if (!lab) return s;
          if (i === 0) return { ...s, body: `${lab.name} runs on ${lab.family} with a ${formatTokens(lab.tokenGrant)} token grant.` };
          if (i === 1) return { ...s, body:
            lab.dataSharing === 'required' ? `Required here — telemetry is shared, so the full ${formatTokens(lab.tokenGrant)} grant stays unlocked.`
            : lab.dataSharing === 'never' ? 'This lab never shares data — nothing leaves your perimeter, full grant.'
            : `Optional here — decline and the grant drops to ${formatTokens(Math.floor(lab.tokenGrant * 0.25))} (25%).` };
          if (i === 3) return { ...s, body: `~${lab.spinupSec}s to spin up ${lab.podsIncluded} pods and index ${lab.kbGB} GB of KB.` };
          return s;
        })
      : null;

    let body = '';
    try {
      const labContext = labs.map(l => `- ${l.name} (${l.sponsor}, ${l.family}): ${l.blurb}`).join('\n');
      const prompt = setupIntent
        ? `You are the setup guide for ActionBoard.ai's AI Labs. The user asked: "${q}".${namedLab ? ` They mean the ${namedLab.name} (${namedLab.sponsor}, ${namedLab.family}, data-sharing ${namedLab.dataSharing}, ~${namedLab.spinupSec}s spin-up).` : ''} In 2 short sentences, warmly orient them and note that the numbered steps below cover the details. The flow: pick a lab, set data-sharing (declining an optional lab drops the grant to 25%), accept terms, deploy (the Castle forms with pods + KB + tokens), then form Voltron and run the RAOARA loop.`
        : `You are a Labs guide for ActionBoard.ai. The user asked: "${q}". Here are the available labs:\n${labContext}\n\nAnswer briefly (2-3 short sentences) and recommend 1-2 specific labs by name. Use a warm, expert tone.`;
      body = await window.claude.complete(prompt);
    } catch {
      body = setupIntent
        ? (namedLab
            ? `Here's how to get ${namedLab.name} running — five quick steps:`
            : "Standing up a lab takes about a minute. Here's the whole flow:")
        : (candidates.length > 0
            ? `Based on what you described, I'd start with ${candidates[0].name} from ${candidates[0].sponsor} — ${candidates[0].blurb}`
            : "Tell me a bit more — what are you trying to build, and do you have data-residency or model-family preferences?");
    }

    setThinking(false);
    setMessages(m => [...m, {
      who: 'ai',
      text: body.trim(),
      steps,
      labs: setupIntent ? (namedLab ? [namedLab] : []) : candidates,
    }]);
  };

  return (
    <aside data-screen-label="Labs Companion" style={{
      position: 'sticky', top: 76,
      background: 'white',
      border: '1px solid var(--line)',
      borderRadius: 14,
      overflow: 'hidden',
      display: 'flex', flexDirection: 'column',
      maxHeight: 'calc(100vh - 100px)',
    }}>
      {/* Header */}
      <div style={{
        padding: '14px 16px',
        borderBottom: '1px solid var(--line)',
        background: 'linear-gradient(135deg, #fef3c7 0%, white 100%)',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <div style={{
          width: 30, height: 30, borderRadius: 9,
          background: 'linear-gradient(135deg, #dc2626 0%, #eab308 100%)',
          color: 'white', display: 'grid', placeItems: 'center',
        }}>
          <I.Sparkles size={14} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--ink)' }}>Labs guide</div>
          <div className="row" style={{ gap: 4 }}>
            <span className="dot pulse" style={{ background: '#059669' }} />
            <span style={{ fontSize: 10.5, color: 'var(--muted)' }}>Trained on all 8 labs</span>
          </div>
        </div>
      </div>

      {/* Messages */}
      <div style={{
        padding: 14,
        overflow: 'auto', flex: 1,
        display: 'flex', flexDirection: 'column', gap: 12,
      }}>
        {messages.map((m, i) => (
          <MsgBubble key={i} msg={m} onDeploy={onDeploy} onSendSuggestion={(s) => send(s)} />
        ))}
        {thinking && <ThinkingBubble />}
        <div ref={endRef} />
      </div>

      {/* Input */}
      <div style={{
        padding: 10, borderTop: '1px solid var(--line)',
        background: 'var(--bg-subtle)',
        display: 'flex', alignItems: 'center', gap: 8,
      }}>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && !e.shiftKey && send()}
          placeholder="Ask about a lab — or how to set one up…"
          style={{
            flex: 1, padding: '8px 11px',
            border: '1px solid var(--line)', borderRadius: 8,
            background: 'white', outline: 'none',
            fontSize: 12.5, fontFamily: 'inherit',
          }}/>
        <button
          onClick={() => send()}
          disabled={!input.trim() || thinking}
          style={{
            padding: '7px 9px', borderRadius: 8,
            background: 'var(--violet)', color: 'white',
            border: 'none', cursor: 'pointer',
            opacity: (!input.trim() || thinking) ? 0.5 : 1,
          }}>
          <I.PaperPlane size={13} />
        </button>
      </div>
    </aside>
  );
};

const MsgBubble = ({ msg, onDeploy, onSendSuggestion }) => {
  const isUser = msg.who === 'user';
  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      alignItems: isUser ? 'flex-end' : 'flex-start',
      gap: 6,
    }}>
      <div style={{
        maxWidth: '90%',
        padding: '8px 12px',
        borderRadius: isUser ? '12px 12px 4px 12px' : '12px 12px 12px 4px',
        background: isUser ? 'var(--violet)' : 'var(--bg-subtle)',
        color: isUser ? 'white' : 'var(--ink-2)',
        fontSize: 12.5, lineHeight: 1.5,
      }}>
        {msg.text}
      </div>
      {msg.steps?.length > 0 && (
        <div style={{ width: '100%', display: 'grid', gap: 6 }}>
          {msg.steps.map((s, i) => (
            <div key={i} style={{
              display: 'flex', gap: 9, alignItems: 'flex-start',
              padding: '7px 10px', background: 'white',
              border: '1px solid var(--line)', borderRadius: 9,
            }}>
              <span className="mono" style={{
                width: 18, height: 18, borderRadius: 999,
                background: 'var(--violet-soft)', color: 'var(--violet)',
                fontSize: 10.5, fontWeight: 700,
                display: 'grid', placeItems: 'center', flex: 'none', marginTop: 1,
              }}>{i + 1}</span>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink)' }}>{s.title}</div>
                <div style={{ fontSize: 11.5, color: 'var(--muted)', lineHeight: 1.45 }}>{s.body}</div>
              </div>
            </div>
          ))}
        </div>
      )}
      {msg.labs?.length > 0 && (
        <div style={{ display: 'grid', gap: 5, width: '100%' }}>
          {msg.labs.map(l => (
            <button
              key={l.id}
              onClick={() => onDeploy(l)}
              style={{
                textAlign: 'left',
                padding: '7px 10px',
                border: `1px solid ${l.accent}55`,
                background: l.accentSoft,
                borderRadius: 9,
                cursor: 'pointer', fontFamily: 'inherit',
                display: 'flex', alignItems: 'center', gap: 9,
              }}>
              <SponsorMark lab={l} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12, fontWeight: 700, color: l.accentInk }}>{l.name}</div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--muted)' }}>{l.family} · {formatTokens(l.tokenGrant)} tokens</div>
              </div>
              <I.ArrowRight size={12} stroke={l.accent} />
            </button>
          ))}
        </div>
      )}
      {msg.suggestions?.length > 0 && (
        <div style={{ display: 'grid', gap: 4, width: '100%' }}>
          {msg.suggestions.map((s, i) => (
            <button
              key={i}
              onClick={() => onSendSuggestion(s)}
              style={{
                textAlign: 'left',
                padding: '5px 9px',
                background: 'white',
                border: '1px solid var(--line)',
                borderRadius: 7,
                cursor: 'pointer', fontFamily: 'inherit',
                fontSize: 11.5, color: 'var(--ink-2)',
                display: 'flex', alignItems: 'center', gap: 6,
              }}>
              <I.Sparkle2 size={9} stroke="var(--violet)" />
              {s}
            </button>
          ))}
        </div>
      )}
    </div>
  );
};

const ThinkingBubble = () => (
  <div style={{
    alignSelf: 'flex-start',
    padding: '10px 14px',
    borderRadius: '12px 12px 12px 4px',
    background: 'var(--bg-subtle)',
    display: 'flex', alignItems: 'center', gap: 4,
  }}>
    {[0,1,2].map(i => (
      <span key={i} className="dot pulse" style={{
        background: 'var(--muted)',
        animationDelay: `${i * 0.15}s`,
      }} />
    ))}
  </div>
);

Object.assign(window, {
  LabFilterRow, LabCard, DeployModal, CommunityFeed, LabsCompanion,
  formatTokens,
});
