// V2/src/primitives.jsx
// Shared UI atoms — Badge, Pill, EmptyState, ErrorCard, Loader, Tooltip, Pagination.
// All colors from tokens.css via var(--token). 44px hit-target on Pagination Prev/Next + ErrorCard Retry.
// No import statements. Exposes atoms on window.primitives AND window directly.

(function () {
  'use strict';

  // ─── Inject primitives style sheet once ──────────────────────────────────
  // All color tinting uses CSS variables only. No hex values here.
  if (!document.getElementById('primitives-styles')) {
    var styleEl = document.createElement('style');
    styleEl.id = 'primitives-styles';
    styleEl.textContent = [
      // ── Badge base ─────────────────────────────────────────────────────────
      '.prim-badge {',
      '  display: inline-flex; align-items: center; justify-content: center;',
      '  font-family: var(--font-mono); font-weight: 600; letter-spacing: 0.06em;',
      '  text-transform: uppercase; white-space: nowrap; border-radius: var(--r-pill);',
      '  border: 1px solid var(--prim-badge-border, var(--g-border-strong));',
      '  background: var(--prim-badge-bg, var(--g-frosted));',
      '  color: var(--prim-badge-color, var(--text));',
      '  line-height: 1;',
      '}',
      '.prim-badge-sm { font-size: var(--text-3xs); padding: 3px 7px; }',
      '.prim-badge-md { font-size: var(--text-2xs); padding: 5px 10px; }',
      // Tier: gold (CTK Q8 — discrete tokens, retire color-mix on brand tokens)
      '.prim-badge-tier-gold {',
      '  --prim-badge-bg: var(--gold-bg);',
      '  --prim-badge-border: var(--gold-tx);',
      '  --prim-badge-color: var(--gold-tx);',
      '}',
      // Tier: silver (slate)
      '.prim-badge-tier-silver {',
      '  --prim-badge-bg: var(--slv-bg);',
      '  --prim-badge-border: var(--slv-tx);',
      '  --prim-badge-color: var(--slv-tx);',
      '}',
      // Tier: bronze — uses emerging palette (warm orange) since V1 has no
      // discrete bronze token; bronze and emerging share the same hue family.
      '.prim-badge-tier-bronze {',
      '  --prim-badge-bg: var(--emg-bg);',
      '  --prim-badge-border: var(--emg-tx);',
      '  --prim-badge-color: var(--emg-tx);',
      '}',
      // Tier: emerging
      '.prim-badge-tier-emerging {',
      '  --prim-badge-bg: var(--emg-bg);',
      '  --prim-badge-border: var(--emg-tx);',
      '  --prim-badge-color: var(--emg-tx);',
      '}',
      // Color overrides (alternative direct token)
      '.prim-badge-color-teal {',
      '  --prim-badge-bg: color-mix(in srgb, var(--teal) 12%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--teal) 40%, transparent);',
      '  --prim-badge-color: var(--teal);',
      '}',
      '.prim-badge-color-amber {',
      '  --prim-badge-bg: color-mix(in srgb, var(--amber) 14%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--amber-warm) 50%, transparent);',
      '  --prim-badge-color: var(--amber);',
      '}',
      '.prim-badge-color-rose {',
      '  --prim-badge-bg: color-mix(in srgb, var(--rose) 12%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--rose) 40%, transparent);',
      '  --prim-badge-color: var(--rose);',
      '}',
      '.prim-badge-color-blue {',
      '  --prim-badge-bg: color-mix(in srgb, var(--blue) 12%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--blue) 40%, transparent);',
      '  --prim-badge-color: var(--blue);',
      '}',
      '.prim-badge-color-purple {',
      '  --prim-badge-bg: color-mix(in srgb, var(--purple) 12%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--purple) 40%, transparent);',
      '  --prim-badge-color: var(--purple);',
      '}',
      '.prim-badge-color-indigo {',
      '  --prim-badge-bg: color-mix(in srgb, var(--indigo) 12%, transparent);',
      '  --prim-badge-border: color-mix(in srgb, var(--indigo) 40%, transparent);',
      '  --prim-badge-color: var(--indigo);',
      '}',
      // ── Pill base ──────────────────────────────────────────────────────────
      '.prim-pill {',
      '  display: inline-flex; align-items: center; justify-content: center;',
      '  font-family: var(--font-mono); font-weight: 500; letter-spacing: 0.04em;',
      '  font-size: var(--text-3xs); white-space: nowrap; border-radius: var(--r-pill);',
      '  line-height: 1;',
      '}',
      '.prim-pill-soft {',
      '  background: color-mix(in srgb, var(--prim-pill-accent, var(--teal)) 12%, transparent);',
      '  border: 1px solid color-mix(in srgb, var(--prim-pill-accent, var(--teal)) 35%, transparent);',
      '  color: var(--prim-pill-accent, var(--teal));',
      '  padding: 2px 7px;',
      '}',
      '.prim-pill-solid {',
      '  background: var(--prim-pill-accent, var(--teal));',
      '  border: 1px solid transparent;',
      '  color: var(--bg);',
      '  padding: 2px 7px;',
      '}',
      '.prim-pill-outline {',
      '  background: transparent;',
      '  border: 1px solid var(--prim-pill-accent, var(--teal));',
      '  color: var(--prim-pill-accent, var(--teal));',
      '  padding: 2px 7px;',
      '}',
      // Pill color accent custom props (set on element via style attr using var refs)
      '.prim-pill-accent-teal   { --prim-pill-accent: var(--teal); }',
      '.prim-pill-accent-amber  { --prim-pill-accent: var(--amber); }',
      '.prim-pill-accent-rose   { --prim-pill-accent: var(--rose); }',
      '.prim-pill-accent-blue   { --prim-pill-accent: var(--blue); }',
      '.prim-pill-accent-purple { --prim-pill-accent: var(--purple); }',
      '.prim-pill-accent-indigo { --prim-pill-accent: var(--indigo); }',
      '.prim-pill-accent-slate  { --prim-pill-accent: var(--text-faint); }',
      // ── EmptyState ─────────────────────────────────────────────────────────
      '.prim-empty {',
      '  display: flex; flex-direction: column; align-items: center; justify-content: center;',
      '  gap: var(--s-2); padding: var(--s-8) var(--s-4); text-align: center;',
      '}',
      '.prim-empty-icon {',
      '  opacity: 0.30; margin-bottom: var(--s-1);',
      '  color: var(--text-faint);',
      '}',
      '.prim-empty-title {',
      '  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600;',
      '  color: var(--text-muted); margin: 0;',
      '}',
      '.prim-empty-sub {',
      '  font-family: var(--font-body); font-size: var(--text-xs); color: var(--text-faint);',
      '  margin: 0; max-width: 280px;',
      '}',
      '.prim-empty-cta {',
      '  margin-top: var(--s-3); font-family: var(--font-mono); font-size: var(--text-xs);',
      '  font-weight: 500; letter-spacing: 0.04em; cursor: pointer; border-radius: var(--r-md);',
      '  padding: var(--s-2) var(--s-4); border: 1px solid var(--g-border-strong);',
      '  background: var(--g-frosted); color: var(--text-muted); transition: all var(--t-fast);',
      '}',
      '.prim-empty-cta:hover { background: var(--g-elevated); color: var(--text); }',
      // ── ErrorCard ──────────────────────────────────────────────────────────
      '.prim-error {',
      '  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-2);',
      '  padding: var(--s-4); border-radius: var(--r-lg);',
      '  background: color-mix(in srgb, var(--rose) 8%, var(--g-ground));',
      '  border: 1px solid color-mix(in srgb, var(--rose) 25%, transparent);',
      '}',
      '.prim-error-header {',
      '  display: flex; align-items: center; gap: var(--s-2);',
      '}',
      '.prim-error-icon {',
      '  flex-shrink: 0; color: var(--rose);',
      '}',
      '.prim-error-title {',
      '  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 700;',
      '  color: var(--rose); margin: 0;',
      '}',
      '.prim-error-detail {',
      '  font-family: var(--font-body); font-size: var(--text-xs); color: var(--text-muted);',
      '  margin: 0; line-height: 1.5;',
      '}',
      '.prim-error-retry {',
      '  display: inline-flex; align-items: center; justify-content: center;',
      '  gap: var(--s-1); margin-top: var(--s-1);',
      '  min-height: 44px; min-width: 44px;',
      '  padding: var(--s-2) var(--s-4); border-radius: var(--r-md);',
      '  border: 1px solid color-mix(in srgb, var(--rose) 35%, transparent);',
      '  background: color-mix(in srgb, var(--rose) 10%, transparent);',
      '  color: var(--rose); font-family: var(--font-mono); font-size: var(--text-xs);',
      '  font-weight: 600; letter-spacing: 0.04em; cursor: pointer;',
      '  transition: background var(--t-fast);',
      '}',
      '.prim-error-retry:hover {',
      '  background: color-mix(in srgb, var(--rose) 18%, transparent);',
      '}',
      // ── Loader ─────────────────────────────────────────────────────────────
      '.prim-loader {',
      '  display: flex; flex-direction: column; align-items: center; justify-content: center;',
      '  gap: var(--s-3); padding: var(--s-8) var(--s-4); text-align: center;',
      '}',
      '.prim-loader-ring {',
      '  width: 36px; height: 36px; border-radius: 50%;',
      '  border: 2px solid color-mix(in srgb, var(--teal) 20%, transparent);',
      '  border-top-color: var(--teal);',
      '  animation: prim-spin 900ms linear infinite;',
      '}',
      '@keyframes prim-spin { to { transform: rotate(360deg); } }',
      '@keyframes prim-pulse { 0%,100% { opacity: 0.5; } 50% { opacity: 1; } }',
      '.prim-loader-label {',
      '  font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600;',
      '  letter-spacing: 0.10em; text-transform: uppercase; color: var(--teal);',
      '  animation: prim-pulse 2s ease-in-out infinite;',
      '}',
      '.prim-loader-detail {',
      '  font-family: var(--font-body); font-size: var(--text-xs); color: var(--text-faint);',
      '  margin: 0;',
      '}',
      // ── Tooltip ────────────────────────────────────────────────────────────
      '.prim-tooltip-wrap {',
      '  position: relative; display: inline-flex;',
      '}',
      '.prim-tooltip-bubble {',
      '  position: absolute; z-index: 9999;',
      '  background: var(--g-solid); border: 1px solid var(--g-border-strong);',
      '  color: var(--text); font-family: var(--font-body); font-size: var(--text-xs);',
      '  line-height: 1.45; border-radius: var(--r-md); padding: var(--s-2) var(--s-3);',
      '  max-width: 220px; white-space: normal; pointer-events: none;',
      '  box-shadow: var(--sh-2);',
      '  opacity: 0; transition: opacity 120ms ease;',
      '}',
      '.prim-tooltip-bubble.prim-tt-visible { opacity: 1; }',
      // Sides
      '.prim-tt-top    { bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); }',
      '.prim-tt-bottom { top: calc(100% + 6px);    left: 50%; transform: translateX(-50%); }',
      '.prim-tt-left   { right: calc(100% + 6px);  top: 50%;  transform: translateY(-50%); }',
      '.prim-tt-right  { left: calc(100% + 6px);   top: 50%;  transform: translateY(-50%); }',
      // ── Pagination ─────────────────────────────────────────────────────────
      '.prim-pager {',
      '  display: flex; align-items: center; justify-content: center;',
      '  gap: var(--s-3); padding: var(--s-2) 0;',
      '}',
      '.prim-pager-btn {',
      '  display: inline-flex; align-items: center; justify-content: center;',
      '  min-height: 44px; min-width: 44px;',
      '  border-radius: var(--r-md); border: 1px solid var(--g-border-strong);',
      '  background: var(--g-frosted); color: var(--text-muted); cursor: pointer;',
      '  font-size: var(--text-sm); transition: all var(--t-fast);',
      '}',
      '.prim-pager-btn:not([aria-disabled="true"]):hover {',
      '  background: var(--g-elevated); color: var(--text);',
      '}',
      '.prim-pager-btn[aria-disabled="true"] {',
      '  opacity: 0.4; cursor: default; pointer-events: none;',
      '}',
      '.prim-pager-info {',
      '  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted);',
      '  letter-spacing: 0.04em;',
      '}',
      '.prim-pager-count {',
      '  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-faint);',
      '  margin-left: var(--s-1);',
      '}',
    ].join('\n');
    document.head.appendChild(styleEl);
  }

  // ─── Icon helpers (inline SVG — icons.jsx may not be loaded yet) ──────────
  // These are tiny private helpers, NOT exported as part of the 7 atoms.

  function _iconAlert(size) {
    size = size || 18;
    if (typeof window.AlertIcon !== 'undefined') return React.createElement(window.AlertIcon, { size: size });
    return React.createElement('svg', {
      width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
      stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round',
      'aria-hidden': 'true',
    },
      React.createElement('path', { d: 'M10.29 3.86L1.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' }),
      React.createElement('line', { x1: '12', y1: '9', x2: '12', y2: '13' }),
      React.createElement('line', { x1: '12', y1: '17', x2: '12.01', y2: '17' })
    );
  }

  function _iconRefresh(size) {
    size = size || 16;
    if (typeof window.RefreshIcon !== 'undefined') return React.createElement(window.RefreshIcon, { size: size });
    return React.createElement('svg', {
      width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
      stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round',
      'aria-hidden': 'true',
    },
      React.createElement('polyline', { points: '23 4 23 10 17 10' }),
      React.createElement('polyline', { points: '1 20 1 14 7 14' }),
      React.createElement('path', { d: 'M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15' })
    );
  }

  function _iconChevronLeft(size) {
    size = size || 16;
    if (typeof window.ChevronLeftIcon !== 'undefined') return React.createElement(window.ChevronLeftIcon, { size: size });
    return React.createElement('svg', {
      width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
      stroke: 'currentColor', strokeWidth: '2.5', strokeLinecap: 'round', strokeLinejoin: 'round',
      'aria-hidden': 'true',
    },
      React.createElement('polyline', { points: '15 18 9 12 15 6' })
    );
  }

  function _iconChevronRight(size) {
    size = size || 16;
    if (typeof window.ChevronRightIcon !== 'undefined') return React.createElement(window.ChevronRightIcon, { size: size });
    return React.createElement('svg', {
      width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
      stroke: 'currentColor', strokeWidth: '2.5', strokeLinecap: 'round', strokeLinejoin: 'round',
      'aria-hidden': 'true',
    },
      React.createElement('polyline', { points: '9 18 15 12 9 6' })
    );
  }

  // ─── 1. Badge ─────────────────────────────────────────────────────────────
  // Confidence tier pills: GOLD / SILVER / BRONZE / EMERGING.
  // Color alternative: teal | amber | rose | blue | purple | indigo.
  // All tints map to tokens via CSS classes injected above.

  function Badge({ label, tier, color, size = 'sm', className = '' }) {
    var sizeClass = size === 'md' ? 'prim-badge-md' : 'prim-badge-sm';
    var tierClass = tier ? 'prim-badge-tier-' + tier : '';
    var colorClass = (!tier && color) ? 'prim-badge-color-' + color : '';
    var classes = ['prim-badge', sizeClass, tierClass, colorClass, className]
      .filter(Boolean).join(' ');
    return React.createElement('span', { className: classes }, label);
  }

  // ─── 2. Pill ──────────────────────────────────────────────────────────────
  // Smaller inline label: org category (PHARMA/BIOTECH), TA labels, entity pills.
  // variant: solid | outline | soft (default soft).

  function Pill({ label, color, variant = 'soft', className = '' }) {
    var variantClass = 'prim-pill-' + variant;
    var accentClass = color ? 'prim-pill-accent-' + color : '';
    var classes = ['prim-pill', variantClass, accentClass, className]
      .filter(Boolean).join(' ');
    return React.createElement('span', { className: classes }, label);
  }

  // ─── 3. EmptyState ────────────────────────────────────────────────────────
  // Centered layout: faded icon, title, sub-line, optional CTA button.
  // Source examples: "No competitors match filters" / "No opportunities match current filters".

  function EmptyState({ title, sub, icon, cta, className = '' }) {
    var classes = ['prim-empty', className].filter(Boolean).join(' ');
    return React.createElement('div', { className: classes, role: 'status' },
      icon
        ? React.createElement('div', { className: 'prim-empty-icon', 'aria-hidden': 'true' }, icon)
        : null,
      title
        ? React.createElement('p', { className: 'prim-empty-title' }, title)
        : null,
      sub
        ? React.createElement('p', { className: 'prim-empty-sub' }, sub)
        : null,
      cta && cta.label && cta.onClick
        ? React.createElement('button', {
            className: 'prim-empty-cta',
            type: 'button',
            onClick: cta.onClick,
          }, cta.label)
        : null
    );
  }

  // ─── 4. ErrorCard ─────────────────────────────────────────────────────────
  // Rose-tinted card with alert icon. Retry button: 44×44 minimum hit target.
  // Source examples: "Strategy Data Timeout", "Failed to load drug profile. Please try again.",
  // "Failed to load scatter data", "Failed to load opportunities".

  function ErrorCard({ title = 'Something went wrong', detail, onRetry, className = '' }) {
    var classes = ['prim-error', className].filter(Boolean).join(' ');
    return React.createElement('div', { className: classes, role: 'alert' },
      React.createElement('div', { className: 'prim-error-header' },
        React.createElement('span', { className: 'prim-error-icon', 'aria-hidden': 'true' },
          _iconAlert(18)
        ),
        React.createElement('p', { className: 'prim-error-title' }, title)
      ),
      detail
        ? React.createElement('p', { className: 'prim-error-detail' }, detail)
        : null,
      onRetry
        ? React.createElement('button', {
            className: 'prim-error-retry',
            type: 'button',
            onClick: onRetry,
            'aria-label': 'Retry',
          },
            _iconRefresh(14),
            React.createElement('span', null, 'Retry')
          )
        : null
    );
  }

  // ─── 5. Loader ────────────────────────────────────────────────────────────
  // Centered spinner + pulsing uppercase mono label.
  // Source: universalLoaderHTML('EVALUATING PARTNERS', detail) pattern.

  function Loader({ label, detail, className = '' }) {
    var classes = ['prim-loader', className].filter(Boolean).join(' ');
    return React.createElement('div', { className: classes, role: 'status', 'aria-live': 'polite' },
      React.createElement('div', { className: 'prim-loader-ring', 'aria-hidden': 'true' }),
      label
        ? React.createElement('span', { className: 'prim-loader-label' }, label)
        : null,
      detail
        ? React.createElement('p', { className: 'prim-loader-detail' }, detail)
        : null
    );
  }

  // ─── 6. Tooltip ───────────────────────────────────────────────────────────
  // Hover + keyboard focus tooltip. Wraps children in a relative container.
  // Content: string or React element. Side: top | bottom | left | right.
  // A11y: focus/blur events alongside mouseenter/mouseleave.

  function Tooltip({ content, children, side = 'top', className = '' }) {
    var [visible, setVisible] = React.useState(false);
    var sideClass = 'prim-tt-' + side;
    var bubbleClasses = ['prim-tooltip-bubble', sideClass, visible ? 'prim-tt-visible' : '']
      .filter(Boolean).join(' ');
    var wrapClasses = ['prim-tooltip-wrap', className].filter(Boolean).join(' ');

    function show() { setVisible(true); }
    function hide() { setVisible(false); }

    return React.createElement('span', {
      className: wrapClasses,
      onMouseEnter: show,
      onMouseLeave: hide,
      onFocus: show,
      onBlur: hide,
    },
      children,
      React.createElement('span', {
        className: bubbleClasses,
        role: 'tooltip',
        'aria-hidden': !visible,
      }, content)
    );
  }

  // ─── 7. Pagination ────────────────────────────────────────────────────────
  // Layout: [Prev] [n / totalPages] [Next]. Optional "(N items)" suffix.
  // Prev/Next MUST have min-height: 44px and min-width: 44px (touch target).
  // Does NOT render if totalPages <= 1.
  // Disabled: aria-disabled="true", opacity 0.4, cursor default (via CSS).

  function Pagination({ page, totalPages, totalItems, pageSize, onChange, className = '' }) {
    if (totalPages <= 1) return null;

    var isFirst = page <= 1;
    var isLast = page >= totalPages;

    function handlePrev() {
      if (!isFirst && typeof onChange === 'function') onChange(page - 1);
    }

    function handleNext() {
      if (!isLast && typeof onChange === 'function') onChange(page + 1);
    }

    var classes = ['prim-pager', className].filter(Boolean).join(' ');

    return React.createElement('nav', {
      className: classes,
      role: 'navigation',
      'aria-label': 'Pagination',
    },
      React.createElement('button', {
        className: 'prim-pager-btn',
        type: 'button',
        onClick: handlePrev,
        'aria-label': 'Previous page',
        'aria-disabled': isFirst ? 'true' : 'false',
        disabled: isFirst,
        style: { minHeight: '44px', minWidth: '44px' },
      },
        _iconChevronLeft(16)
      ),
      React.createElement('span', { className: 'prim-pager-info' },
        page + ' / ' + totalPages
      ),
      typeof totalItems === 'number'
        ? React.createElement('span', { className: 'prim-pager-count' },
            '(' + totalItems + ' items)'
          )
        : null,
      React.createElement('button', {
        className: 'prim-pager-btn',
        type: 'button',
        onClick: handleNext,
        'aria-label': 'Next page',
        'aria-disabled': isLast ? 'true' : 'false',
        disabled: isLast,
        style: { minHeight: '44px', minWidth: '44px' },
      },
        _iconChevronRight(16)
      )
    );
  }

  // ─── confidenceTierPill (helper, not one of the 7 atoms) ─────────────────
  // Returns a Badge colored by GOLD/SILVER/BRONZE tier rules.
  // Rule (partneriq.md L86): GOLD if evBreadth >= 4 && evDepth >= 10,
  //                           SILVER if >= 2 && >= 5, else BRONZE.

  function confidenceTierPill({ evBreadth = 0, evDepth = 0 }) {
    var tier = 'bronze';
    var label = 'BRONZE';
    if (evBreadth >= 4 && evDepth >= 10) {
      tier = 'gold';
      label = 'GOLD';
    } else if (evBreadth >= 2 && evDepth >= 5) {
      tier = 'silver';
      label = 'SILVER';
    }
    return React.createElement(Badge, { tier: tier, label: label });
  }

  // ─── Expose on window ─────────────────────────────────────────────────────

  var primitives = {
    Badge: Badge,
    Pill: Pill,
    EmptyState: EmptyState,
    ErrorCard: ErrorCard,
    Loader: Loader,
    Tooltip: Tooltip,
    Pagination: Pagination,
    confidenceTierPill: confidenceTierPill,
  };

  Object.assign(window, {
    Badge: Badge,
    Pill: Pill,
    EmptyState: EmptyState,
    ErrorCard: ErrorCard,
    Loader: Loader,
    Tooltip: Tooltip,
    Pagination: Pagination,
    confidenceTierPill: confidenceTierPill,
    primitives: primitives,
  });

}());
