// Shared chat data — departments, agents (6 per dept + Nalar master), retro robot avatar.

const NX_DEPTS = [
  { id: 'finance',     name: 'Finance',     tone: 'oklch(0.52 0.15 268)', accent: 'oklch(0.96 0.025 268)' },
  { id: 'procurement', name: 'Procurement', tone: 'oklch(0.62 0.16 50)',  accent: 'oklch(0.96 0.04 50)' },
  { id: 'risk',        name: 'Risk',        tone: 'oklch(0.58 0.18 25)',  accent: 'oklch(0.97 0.03 25)' },
  { id: 'compliance',  name: 'Compliance',  tone: 'oklch(0.6 0.13 155)',  accent: 'oklch(0.96 0.03 155)' },
  { id: 'people',      name: 'People',      tone: 'oklch(0.58 0.16 320)', accent: 'oklch(0.96 0.03 320)' },
  { id: 'it',          name: 'IT',          tone: 'oklch(0.58 0.13 215)', accent: 'oklch(0.96 0.03 215)' },
];

// Each dept has 6 agents: the first is the dept "master" (featured), rest are specialized.
// tone/accent inherited from dept later.
const _NX_AGENTS_RAW = [
  // ── Finance ──
  { id: 'fin-master',  name: 'Finance',         dept: 'finance', master: true,
    owner: 'Aditya P.', face: 'classic',
    desc: 'Catch-all for spend, budgets, P&L variance, and vendor invoicing.',
    exampleQ: 'What was our Q2 spend by cost center vs plan?',
    sources: ['SAP Ariba', 'Coupa', 'BigQuery', 'NetSuite'], convos: 1247 },
  { id: 'fin-spend',   name: 'Spend Analytics', dept: 'finance', owner: 'Bobby K.', face: 'tv',
    desc: 'Slice spend by category, team, vendor, quarter. Knows your cost centers.',
    exampleQ: 'Top 10 vendors by spend growth YoY',
    sources: ['SAP', 'BigQuery'], convos: 412 },
  { id: 'fin-budget',  name: 'Budget Variance', dept: 'finance', owner: 'Aditya P.', face: 'visor',
    desc: 'Actuals vs plan, drill into deltas, surface drivers automatically.',
    exampleQ: 'Which APAC cost centers are >10% over plan?',
    sources: ['NetSuite', 'GDrive · plans'], convos: 234 },
  { id: 'fin-ap',      name: 'AP Helper',       dept: 'finance', owner: 'Lina M.', face: 'classic',
    desc: 'Match invoices to POs, flag duplicates, chase missing receipts.',
    exampleQ: 'Show invoices over $10k without matching PO',
    sources: ['Coupa', 'SharePoint'], convos: 89 },
  { id: 'fin-treasury',name: 'Treasury Pulse',  dept: 'finance', owner: 'Dimas A.', face: 'tv',
    desc: 'Cash position, FX exposure, intercompany flows — refreshed daily.',
    exampleQ: 'What\'s our IDR cash position today vs 30d ago?',
    sources: ['SAP', 'Webhook · banking'], convos: 67 },
  { id: 'fin-fpa',     name: 'FP&A Copilot',    dept: 'finance', owner: 'Bobby K.', face: 'visor',
    desc: 'Forecast scenarios with assumption tracking. Great for board prep.',
    exampleQ: 'Build me a Q4 forecast assuming 8% revenue growth',
    sources: ['NetSuite', 'GDrive · models'], convos: 156 },

  // ── Procurement ──
  { id: 'proc-master', name: 'Procurement',     dept: 'procurement', master: true, owner: 'Aditya P.', face: 'classic',
    desc: 'Compare vendors, surface contract risk, flag maverick spend.',
    exampleQ: 'Which vendors should we consolidate this quarter?',
    sources: ['Coupa', 'SharePoint', 'Postgres'], convos: 482 },
  { id: 'proc-cmp',    name: 'Vendor Compare',  dept: 'procurement', owner: 'Sari L.', face: 'tv',
    desc: 'Side-by-side vendor benchmark with TCO, SLA, and terms.',
    exampleQ: 'Compare laptop unit prices across our top 4 vendors',
    sources: ['Coupa'], convos: 198 },
  { id: 'proc-risk',   name: 'Contract Risk',   dept: 'procurement', owner: 'Maya S.', face: 'visor',
    desc: 'Read your contracts, spot termination traps and auto-renewals.',
    exampleQ: 'Which contracts auto-renew in the next 60 days?',
    sources: ['SharePoint'], convos: 76 },
  { id: 'proc-po',     name: 'PO Tracker',      dept: 'procurement', owner: 'Aditya P.', face: 'classic',
    desc: 'Pending POs, approval delays, stuck workflows.',
    exampleQ: 'POs over $50k pending approval for more than 5 days',
    sources: ['SAP Ariba'], convos: 142 },
  { id: 'proc-mav',    name: 'Maverick Spend',  dept: 'procurement', owner: 'Bobby K.', face: 'tv',
    desc: 'Off-contract purchases caught in real time.',
    exampleQ: 'Off-contract purchases over $5k this month',
    sources: ['SAP', 'Coupa'], convos: 53 },
  { id: 'proc-source', name: 'Sourcing Helper', dept: 'procurement', owner: 'Lina M.', face: 'visor',
    desc: 'Draft RFPs, score responses, suggest negotiation tactics.',
    exampleQ: 'Draft an RFP for cloud monitoring tools',
    sources: ['SharePoint', 'GDrive'], convos: 28 },

  // ── Risk ──
  { id: 'risk-master', name: 'Risk',            dept: 'risk', master: true, owner: 'Sari L.', face: 'visor',
    desc: 'Live transaction monitoring with velocity, device, and merchant patterns.',
    exampleQ: 'Suspicious transactions over $10k in the last 24h',
    sources: ['Postgres · txn', 'BigQuery · device_fp', 'Webhook'], convos: 893 },
  { id: 'risk-vel',    name: 'Velocity Watch',  dept: 'risk', owner: 'Sari L.', face: 'tv',
    desc: 'Transactions tripping velocity rules — review queue with decision support.',
    exampleQ: 'Show velocity-rule flags from the last hour',
    sources: ['Postgres'], convos: 312 },
  { id: 'risk-dev',    name: 'Device Pattern',  dept: 'risk', owner: 'Bayu T.', face: 'classic',
    desc: 'Device fingerprint clustering, account sharing detection.',
    exampleQ: 'Devices shared across 3+ new accounts (<48h old)',
    sources: ['BigQuery'], convos: 187 },
  { id: 'risk-mer',    name: 'Merchant Risk',   dept: 'risk', owner: 'Sari L.', face: 'visor',
    desc: 'MCC distribution analysis, high-risk merchant exposure.',
    exampleQ: 'Top merchants by chargeback rate this month',
    sources: ['Postgres', 'BigQuery'], convos: 94 },
  { id: 'risk-aml',    name: 'AML Screen',      dept: 'risk', owner: 'Maya S.', face: 'tv',
    desc: 'Suspicious activity reporting and customer screening helper.',
    exampleQ: 'Customers triggering AML rules this week',
    sources: ['Postgres', 'SharePoint'], convos: 64 },
  { id: 'risk-cb',     name: 'Chargeback Bot',  dept: 'risk', owner: 'Lina M.', face: 'classic',
    desc: 'Dispute pattern surfacing and recovery playbooks.',
    exampleQ: 'Chargebacks linked to refund-then-purchase pattern',
    sources: ['Webhook · psp', 'Postgres'], convos: 41 },

  // ── Compliance ──
  { id: 'comp-master', name: 'Compliance',      dept: 'compliance', master: true, owner: 'Reza H.', face: 'tv',
    desc: 'Pull SOC 2 / ISO evidence in minutes. Maps controls to system events.',
    exampleQ: 'Pull SOC 2 access review evidence for Q2',
    sources: ['Okta', 'JIRA', 'SharePoint'], convos: 214 },
  { id: 'comp-soc2',   name: 'SOC 2 Pull',      dept: 'compliance', owner: 'Reza H.', face: 'classic',
    desc: 'Evidence packages for each control, annotated.',
    exampleQ: 'Evidence pack for control AC-2 — Q2',
    sources: ['Okta', 'SharePoint'], convos: 89 },
  { id: 'comp-access', name: 'Access Review',   dept: 'compliance', owner: 'Maya S.', face: 'visor',
    desc: 'Quarterly access reviews and approver chase, automated.',
    exampleQ: 'Reviewers who missed the Q2 14-day SLA',
    sources: ['Okta', 'Workday'], convos: 142 },
  { id: 'comp-dpa',    name: 'Vendor DPA',      dept: 'compliance', owner: 'Reza H.', face: 'tv',
    desc: 'Track DPAs, data processing risk, GDPR/UU PDP scope.',
    exampleQ: 'Vendors processing PII without DPA on file',
    sources: ['SharePoint'], convos: 33 },
  { id: 'comp-policy', name: 'Policy Q&A',      dept: 'compliance', owner: 'Bayu T.', face: 'classic',
    desc: 'Answer policy questions with citations back to the source.',
    exampleQ: 'What\'s our policy on third-party AI tools?',
    sources: ['SharePoint', 'Confluence'], convos: 178 },
  { id: 'comp-reg',    name: 'Reg Watch',       dept: 'compliance', owner: 'Reza H.', face: 'visor',
    desc: 'OJK and BI regulatory updates mapped to your obligations.',
    exampleQ: 'OJK rule changes that affect us this quarter',
    sources: ['Web', 'SharePoint'], convos: 56 },

  // ── People ──
  { id: 'ppl-master',  name: 'People',          dept: 'people', master: true, owner: 'Maya S.', face: 'classic',
    desc: 'Headcount, attrition, comp bands, and hiring funnel — privacy-aware.',
    exampleQ: 'Which teams grew >20% YoY?',
    sources: ['Workday', 'Greenhouse', 'GDrive'], convos: 156 },
  { id: 'ppl-hiring',  name: 'Hiring Funnel',   dept: 'people', owner: 'Lina M.', face: 'tv',
    desc: 'Pipeline health, stage conversion, source effectiveness.',
    exampleQ: 'Stage conversion for engineering roles last 90d',
    sources: ['Greenhouse'], convos: 87 },
  { id: 'ppl-attr',    name: 'Attrition Watch', dept: 'people', owner: 'Maya S.', face: 'visor',
    desc: 'Early-warning signals by team. Confidential by default.',
    exampleQ: 'Teams trending toward elevated attrition risk',
    sources: ['Workday', 'Lattice'], convos: 42 },
  { id: 'ppl-comp',    name: 'Comp Bands',      dept: 'people', owner: 'Dimas A.', face: 'classic',
    desc: 'Detect band drift, equity gaps, level mis-mappings.',
    exampleQ: 'L4 engineers in APAC outside salary band',
    sources: ['Workday', 'GDrive'], convos: 28 },
  { id: 'ppl-train',   name: 'Training Tracker',dept: 'people', owner: 'Bobby K.', face: 'tv',
    desc: 'Annual training completion, overdue list by manager.',
    exampleQ: 'Employees overdue on annual compliance training',
    sources: ['LMS', 'Workday'], convos: 61 },
  { id: 'ppl-org',     name: 'Org Insights',    dept: 'people', owner: 'Maya S.', face: 'visor',
    desc: 'Span of control, manager load, layer-cake health.',
    exampleQ: 'Managers with span of control > 12 reports',
    sources: ['Workday'], convos: 19 },

  // ── IT ──
  { id: 'it-master',   name: 'IT',              dept: 'it', master: true, owner: 'Bayu T.', face: 'tv',
    desc: 'Provisioning, access, SSO troubleshooting. Talks to Okta + ITSM.',
    exampleQ: 'How do I get access to the Snowflake warehouse?',
    sources: ['Okta', 'JIRA Service Desk', 'Slack'], convos: 342 },
  { id: 'it-prov',     name: 'Provisioning Bot',dept: 'it', owner: 'Bayu T.', face: 'classic',
    desc: 'New-hire access bundles, offboarding checklists.',
    exampleQ: 'New-hire access bundle for an Analyst — Finance',
    sources: ['Okta', 'JIRA'], convos: 124 },
  { id: 'it-sso',      name: 'SSO Troubleshoot',dept: 'it', owner: 'Dimas A.', face: 'visor',
    desc: 'Walk users through MFA, SAML, and SCIM issues.',
    exampleQ: 'I\'m stuck in an SSO loop — help me debug',
    sources: ['Okta', 'Slack'], convos: 67 },
  { id: 'it-req',      name: 'Access Request',  dept: 'it', owner: 'Bayu T.', face: 'classic',
    desc: 'Self-serve access requests with approver routing.',
    exampleQ: 'Request access to fraud_alerts schema',
    sources: ['Okta', 'JIRA'], convos: 198 },
  { id: 'it-tools',    name: 'Tool Inventory',  dept: 'it', owner: 'Lina M.', face: 'tv',
    desc: 'Which licenses are paid for vs actually used.',
    exampleQ: 'Idle Adobe licenses we\'re still paying for',
    sources: ['Okta', 'Finance'], convos: 31 },
  { id: 'it-inc',      name: 'Incident Helper', dept: 'it', owner: 'Bayu T.', face: 'visor',
    desc: 'Triage P1s, runbooks, postmortem drafting.',
    exampleQ: 'Help me write the postmortem for last week\'s P1',
    sources: ['JIRA', 'Slack', 'PagerDuty'], convos: 76 },
];

// Hydrate tone/accent from dept
const _deptById = Object.fromEntries(NX_DEPTS.map(d => [d.id, d]));
const NX_AGENTS = _NX_AGENTS_RAW.map(a => {
  const d = _deptById[a.dept];
  return { ...a, tone: d.tone, accent: d.accent };
});

// Master Nalar agent — the catch-all default when no dept context
const NX_NALAR_AGENT = {
  id: 'nalar', name: 'Nalar', dept: null, master: true, owner: 'NalarX', face: 'tv',
  desc: 'The master agent. Searches every connected source across all departments.',
  tone: 'oklch(0.32 0.04 268)',
  accent: 'oklch(0.96 0.015 268)',
  sources: ['All 18 sources'], convos: 5432,
};

// Lookup
const NX_AGENT_BY_ID = Object.fromEntries(
  [NX_NALAR_AGENT, ...NX_AGENTS].map(a => [a.id, a])
);

// Reuse-friendly chat history — history items reference agent IDs.
const NX_CHAT_HISTORY = {
  Today: [
    { id: 'h0', title: 'Vendor report — PDF demo', agent: 'proc-master', when: '3:20 PM',
      script: [
        { role: 'user', content: 'Buatkan laporan vendor consolidation versi PDF' },
        {
          role: 'ai', routedAgentId: 'proc-master',
          steps: ['Read PDF skill', 'Ran 2 commands · created a file'],
          lead: 'Done — I compiled the analysis into a report. Open it below to review, or download it as a PDF.',
          bullets: [
            { text: 'Synnex offers the lowest blended unit price across the 4 connected vendors.' },
            { text: 'Consolidating to 2 primary vendors saves an est. Rp 1.4B / year.' },
          ],
          artifact: {
            id: 'rpt-demo', title: 'Vendor Consolidation Report', kind: 'PDF',
            meta: 'Generated by Nalar · Procurement · 4 connected vendors', date: 'May 26, 2026',
            sections: [
              { type: 'h', text: 'Executive summary' },
              { type: 'p', text: 'Across 4 connected vendors, Dell Latitude 5450 unit prices ranged from $1,184 to $1,402 in 2025. Consolidating spend toward the two lowest-cost, most reliable suppliers reduces blended cost and tightens renewal leverage.' },
              { type: 'h', text: 'Key findings' },
              { type: 'ul', items: [
                'Synnex offered the lowest avg. price ($1,184) on volumes of 50+ units.',
                'Ingram Micro pricing rose 4.8% YoY, primarily on Q2 SKUs.',
                'A pending PO with TechData ($1,402/unit, qty 30) is 11% above category median.',
              ] },
              { type: 'h', text: 'Pricing by vendor' },
              { type: 'table', cols: ['Vendor', 'Avg unit', 'YoY', 'Note'], rows: [
                ['Synnex', '$1,184', '-1.2%', 'Lowest at scale'],
                ['Ingram Micro', '$1,251', '+4.8%', 'Rising on Q2 SKUs'],
                ['TechData', '$1,402', '+2.1%', 'Above median'],
                ['Dicker Data', '$1,310', '+0.4%', 'Stable'],
              ] },
              { type: 'h', text: 'Recommendation' },
              { type: 'p', text: 'Award ~70% of laptop volume to Synnex under a 12-month committed-volume deal, keep Ingram Micro as secondary for supply resilience, and let the TechData PO lapse at the September renewal.' },
            ],
          },
        },
      ],
    },
    { id: 'h1', title: 'Q2 vendor consolidation analysis',     agent: 'proc-master', when: '2:14 PM',
      script: [
        { role: 'user', content: 'Q2 vendor consolidation analysis' },
        {
          role: 'ai', routedAgentId: 'proc-master',
          lead: 'Across 47 active vendors in Q2, the top 5 drove 68% of spend — and 9 vendors overlap on the same SKU categories. Consolidating just the laptop suppliers could save ~Rp 1.4 B/year.',
          bullets: [
            { text: 'Synnex, Ingram Micro & TechData all supply the same laptop SKUs — a 3-way overlap on Rp 8.2 B of spend.', cite: 1 },
            { text: '12 tail vendors each bill under Rp 50 M/yr — admin cost outweighs the value, prime candidates to cut.', cite: 2 },
            { text: 'Off-contract (maverick) spend climbed to 14% in Q2, up from 9% in Q1.', cite: 3 },
          ],
          chart: {
            title: 'Spend by vendor · Q2 2025', unit: 'Rp B',
            series: [
              { label: 'Synnex', value: 3.2, highlight: true },
              { label: 'Ingram', value: 2.8, highlight: true },
              { label: 'TechData', value: 2.2, highlight: true },
              { label: 'CDW', value: 1.1 },
              { label: 'Others', value: 2.9 },
            ],
          },
          citations: [
            { source: 'SAP Ariba', label: 'PO #4471209 · Q2 vendor ledger' },
            { source: 'Coupa', label: 'Vendor Catalog 2025' },
            { source: 'SharePoint', label: 'finance-ops › Q2-vendor-review.pdf' },
          ],
        },
        { role: 'user', content: 'Which of the overlapping laptop contracts renew before September?' },
        {
          role: 'ai', routedAgentId: 'proc-risk',
          lead: '3 of the overlapping contracts auto-renew before Sep 30 — consolidating before renewal is the difference between having negotiating leverage and being locked in for another term.',
          bullets: [
            { text: 'Ingram Micro — renews Aug 14, 60-day notice. Decision needed by Jun 15.', cite: 1 },
            { text: 'TechData — renews Sep 2, auto-renew clause, 90-day notice (window closing soon).', cite: 1 },
            { text: 'Synnex — renews Nov 20, more runway to negotiate from strength.', cite: 2 },
          ],
          citations: [
            { source: 'SharePoint', label: 'Contracts › laptop-suppliers-2024.pdf' },
            { source: 'Coupa', label: 'Contract registry · renewal dates' },
          ],
        },
        { role: 'user', content: 'Draft the consolidation recommendation for the CFO' },
        {
          role: 'ai', routedAgentId: 'proc-master',
          lead: 'Recommendation: make Synnex the primary laptop supplier, keep Ingram as backup, and let TechData lapse at its Sep 2 renewal. Net estimated saving Rp 1.4 B/yr at current volumes.',
          bullets: [
            { text: 'Award ~70% of laptop volume to Synnex (lowest unit price at scale) under a 12-month committed-volume deal.', cite: 1 },
            { text: 'Keep Ingram Micro as secondary for supply resilience — renegotiate to match Synnex pricing before the Jun 15 deadline.', cite: 2 },
            { text: 'Let TechData lapse at the Sep 2 renewal; migrate the 2 open POs (Rp 0.6 B) before the notice window.', cite: 3 },
          ],
          citations: [
            { source: 'SAP Ariba', label: 'Spend analysis · Q2 2025' },
            { source: 'SharePoint', label: 'Contracts registry' },
            { source: 'Coupa', label: 'Vendor scorecards' },
          ],
        },
      ],
    },
    { id: 'h2', title: 'Velocity rule — false positive review', agent: 'risk-vel',    when: '11:08 AM' },
    { id: 'h3', title: 'Laptop unit prices across vendors',    agent: 'proc-cmp',    when: '9:42 AM' },
  ],
  Yesterday: [
    { id: 'h4', title: 'SOC 2 access review Q2 evidence',     agent: 'comp-soc2',  when: '5:21 PM' },
    { id: 'h5', title: 'Engineering attrition by team — 90d', agent: 'ppl-attr',   when: '3:04 PM' },
    { id: 'h6', title: 'Budget vs actuals — APAC',            agent: 'fin-budget', when: '11:30 AM' },
  ],
  'Last week': [
    { id: 'h7',  title: 'Pending POs over $50k > 5 days',      agent: 'proc-po',    when: 'Tue' },
    { id: 'h8',  title: 'Dormant accounts reactivated 24h',    agent: 'risk-vel',   when: 'Tue' },
    { id: 'h9',  title: 'Salary band outliers L4 APAC',        agent: 'ppl-comp',   when: 'Mon' },
    { id: 'h10', title: 'Contracts up for Q3 renewal',         agent: 'proc-risk',  when: 'Mon' },
    { id: 'h11', title: 'NetSuite access review owner',        agent: 'comp-access',when: 'Sun' },
    { id: 'h12', title: 'Q1 PnL variance by cost center',      agent: 'fin-fpa',    when: 'Sun' },
  ],
};

// ─────────────────────────────────────────────────────────
// Retro robot avatar
// ─────────────────────────────────────────────────────────

const NXRobotAvatar = ({ agent, size = 36 }) => {
  const s = size;
  const t = agent?.tone || 'var(--ink-2)';
  const variant = agent?.face || 'classic';
  const screen = '#1a1815';

  const antenna = (
    <g>
      <line x1={s * 0.5} y1={s * 0.02} x2={s * 0.5} y2={s * 0.16}
        stroke={t} strokeWidth={Math.max(1.2, s * 0.05)} strokeLinecap="round" />
      <circle cx={s * 0.5} cy={s * 0.04} r={Math.max(1.6, s * 0.06)} fill={t} />
    </g>
  );
  const ears = (
    <g>
      <rect x={s * 0.04} y={s * 0.4} width={s * 0.08} height={s * 0.18} rx={s * 0.02} fill={t} opacity="0.85" />
      <rect x={s * 0.88} y={s * 0.4} width={s * 0.08} height={s * 0.18} rx={s * 0.02} fill={t} opacity="0.85" />
      <rect x={s * 0.06} y={s * 0.44} width={s * 0.04} height={s * 0.1} fill="rgba(0,0,0,.35)" />
      <rect x={s * 0.9}  y={s * 0.44} width={s * 0.04} height={s * 0.1} fill="rgba(0,0,0,.35)" />
    </g>
  );
  const bolt = (cx, cy) => (
    <g key={`${cx}-${cy}`}>
      <circle cx={cx} cy={cy} r={s * 0.035} fill="rgba(0,0,0,.4)" />
      <circle cx={cx} cy={cy} r={s * 0.018} fill="rgba(255,255,255,.6)" />
    </g>
  );
  const mouth = (
    <g>
      <rect x={s * 0.32} y={s * 0.75} width={s * 0.36} height={s * 0.08} rx={s * 0.015} fill={screen} />
      {[0.38, 0.45, 0.52, 0.59].map(x => (
        <line key={x} x1={s * x} y1={s * 0.76} x2={s * x} y2={s * 0.82}
          stroke="rgba(255,255,255,.32)" strokeWidth={0.7} />
      ))}
    </g>
  );

  let screenContent;
  const sx = s * 0.22, sy = s * 0.36, sw = s * 0.56, sh = s * 0.3;
  if (variant === 'visor') {
    screenContent = (
      <g>
        <rect x={sx} y={sy + sh * 0.18} width={sw} height={sh * 0.5} rx={s * 0.04} fill={screen} />
        <rect x={sx + sw * 0.08} y={sy + sh * 0.32} width={sw * 0.18} height={sh * 0.18} fill={t} />
        <rect x={sx + sw * 0.74} y={sy + sh * 0.32} width={sw * 0.18} height={sh * 0.18} fill={t} />
        <rect x={sx + sw * 0.36} y={sy + sh * 0.36} width={sw * 0.28} height={sh * 0.1} fill="rgba(255,255,255,.5)" opacity="0.6" />
      </g>
    );
  } else if (variant === 'tv') {
    screenContent = (
      <g>
        <rect x={sx} y={sy} width={sw} height={sh} rx={s * 0.08} fill={screen} />
        <rect x={sx + sw * 0.18} y={sy + sh * 0.3} width={sw * 0.16} height={sh * 0.32} fill={t} />
        <rect x={sx + sw * 0.66} y={sy + sh * 0.3} width={sw * 0.16} height={sh * 0.32} fill={t} />
        {[0.2, 0.4, 0.6, 0.8].map(y => (
          <line key={y} x1={sx + sw * 0.05} y1={sy + sh * y} x2={sx + sw * 0.95} y2={sy + sh * y}
            stroke="rgba(255,255,255,.08)" strokeWidth={0.6} />
        ))}
        <rect x={sx + sw * 0.08} y={sy + sh * 0.08} width={sw * 0.35} height={sh * 0.1} fill="rgba(255,255,255,.12)" rx={s * 0.02} />
      </g>
    );
  } else {
    screenContent = (
      <g>
        <rect x={sx + sw * 0.18} y={sy + sh * 0.25} width={sw * 0.18} height={sh * 0.4} fill="#f4f4f3" />
        <rect x={sx + sw * 0.64} y={sy + sh * 0.25} width={sw * 0.18} height={sh * 0.4} fill="#f4f4f3" />
        <rect x={sx + sw * 0.23} y={sy + sh * 0.38} width={sw * 0.08} height={sh * 0.18} fill={screen} />
        <rect x={sx + sw * 0.69} y={sy + sh * 0.38} width={sw * 0.08} height={sh * 0.18} fill={screen} />
      </g>
    );
  }

  return (
    <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`}
      style={{ display: 'block', flexShrink: 0 }}
      shapeRendering={s <= 28 ? 'crispEdges' : 'auto'}
    >
      {antenna}
      <rect x={s * 0.14} y={s * 0.2} width={s * 0.72} height={s * 0.72} rx={s * 0.1} fill={t} />
      <rect x={s * 0.14} y={s * 0.2} width={s * 0.72} height={s * 0.72} rx={s * 0.1} fill="none" stroke="rgba(0,0,0,.25)" strokeWidth={0.8} />
      <rect x={s * 0.2}  y={s * 0.24} width={s * 0.6}  height={s * 0.04} rx={s * 0.015} fill="rgba(255,255,255,.18)" />
      {ears}
      {bolt(s * 0.22, s * 0.28)}
      {bolt(s * 0.78, s * 0.28)}
      {bolt(s * 0.22, s * 0.84)}
      {bolt(s * 0.78, s * 0.84)}
      {screenContent}
      {mouth}
    </svg>
  );
};

window.NX_DEPTS = NX_DEPTS;
window.NX_AGENTS = NX_AGENTS;
window.NX_NALAR_AGENT = NX_NALAR_AGENT;
window.NX_AGENT_BY_ID = NX_AGENT_BY_ID;
window.NX_CHAT_HISTORY = NX_CHAT_HISTORY;
window.NXRobotAvatar = NXRobotAvatar;
