// Numo Paper — The actual product primitives
// These are the components documented in the design system.
// Kept deliberately simple so docs can wrap them with spec tables.

const { useState: npUseState, useEffect: npUseEffect, useRef: npUseRef, useMemo: npUseMemo } = React;

/* ==========================================================
   ICONS — Lucide-style strokes, 1.7px stroke at 16px
   Named the same across the codebase.
   ========================================================== */
const NIcon = ({ d, size = 16, sw = 1.7, fill = 'none' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}
       stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"
       style={{ display: 'block', flexShrink: 0 }}>
    {Array.isArray(d) ? d.map((p, i) => <path key={i} d={p} />) : <path d={d} />}
  </svg>
);

// All icons we've used in the product. Stroke-only, 24×24.
const ICONS = {
  search:     'M10 4a6 6 0 1 1-4.24 10.24M20 20l-4-4',
  bell:       'M6 9a6 6 0 1 1 12 0v4l1.5 3h-15L6 13V9zM10 19a2 2 0 0 0 4 0',
  sidebar:    ['M4 5h16v14H4z', 'M10 5v14'],
  check:      'M4 12l5 5L20 6',
  x:          ['M6 6l12 12', 'M18 6L6 18'],
  arrow:      ['M5 12h14', 'M13 6l6 6-6 6'],
  arrowLeft:  ['M19 12H5', 'M11 6l-6 6 6 6'],
  sparkle:    'M12 3l1.8 4.9L18 10l-4.2 2L12 17l-1.8-5L6 10l4.2-2z',
  clock:      ['M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z', 'M12 7v5l3 2'],
  shield:     'M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z',
  info:       ['M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z', 'M12 8h.01', 'M11 12h1v5h1'],
  chevronDown:'M6 9l6 6 6-6',
  chevronUp:  'M6 15l6-6 6 6',
  chevronR:   'M9 6l6 6-6 6',
  chevronL:   'M15 6l-6 6 6 6',
  plus:       ['M12 5v14', 'M5 12h14'],
  minus:      'M5 12h14',
  bolt:       'M13 3 4 14h6l-1 7 9-11h-6z',
  grid:       ['M4 4h7v7H4z', 'M13 4h7v7h-7z', 'M4 13h7v7H4z', 'M13 13h7v7h-7z'],
  bank:       ['M3 21h18', 'M5 10V21', 'M9 10V21', 'M15 10V21', 'M19 10V21', 'M2 10l10-6 10 6'],
  coin:       ['M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z', 'M9 9h5a2 2 0 1 1 0 4h-4a2 2 0 1 0 0 4h5'],
  calendar:   ['M4 6h16v14H4z', 'M4 10h16', 'M9 3v4', 'M15 3v4'],
  download:   ['M12 4v11', 'M7 11l5 5 5-5', 'M4 20h16'],
  upload:     ['M12 20V9', 'M7 13l5-5 5 5', 'M4 4h16'],
  settings:   ['M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z', 'M19.4 15a1.65 1.65 0 0 0 .3 1.8l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.8-.3 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.1a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.8.3l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .3-1.8 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.1a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.3-1.8l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.8.3h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.1a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.8-.3l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.3 1.8v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.1a1.65 1.65 0 0 0-1.51 1z'],
  user:       ['M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2', 'M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z'],
  building:   ['M3 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16', 'M17 9h2a2 2 0 0 1 2 2v10', 'M9 8h2', 'M9 12h2', 'M9 16h2', 'M3 21h18'],
  file:       ['M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z', 'M14 3v6h6'],
  link:       ['M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1.5 1.5', 'M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 1 0 7.07 7.07l1.5-1.5'],
  filter:     'M3 4h18l-7 9v6l-4-2v-4z',
  more:       ['M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2z', 'M19 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2z', 'M5 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2z'],
  eye:        ['M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z', 'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'],
  trash:      ['M4 7h16', 'M10 11v6', 'M14 11v6', 'M5 7l1 13a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-13', 'M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3'],
  star:       'M12 3l2.9 6.2 6.6.7-5 4.6 1.5 6.5L12 17.8 6 20.9l1.5-6.5-5-4.6 6.6-.7z',
};

const Icon = ({ name, size = 16, sw = 1.7, style }) => (
  <span style={{ display: 'inline-flex', ...style }}>
    <NIcon d={ICONS[name]} size={size} sw={sw} />
  </span>
);

/* ==========================================================
   LOCKUP
   ========================================================== */
const Lockup = ({ height = 20 }) => <DSLockup height={height} />;

/* ==========================================================
   BUTTON
   ========================================================== */
const Button = ({
  label, variant = 'primary', size = 'md',
  icon, iconRight, block = false, disabled = false, loading = false,
  onClick, type = 'button', style, ariaLabel,
}) => {
  const pad = size === 'sm' ? '8px 12px' : size === 'lg' ? '14px 22px' : '10px 16px';
  const fs  = size === 'sm' ? 12.5      : size === 'lg' ? 14.5       : 13.5;
  const iconSize = size === 'sm' ? 13 : size === 'lg' ? 16 : 14;

  const palettes = {
    primary: {
      bg: 'var(--btn-primary-bg)', fg: 'var(--btn-primary-fg)',
      border: 'var(--btn-primary-bg)', shadow: 'var(--shadow-btn-primary)',
      hoverBg: 'var(--btn-primary-bg-hover)',
    },
    accent: {
      bg: 'var(--btn-accent-bg)', fg: 'var(--btn-accent-fg)',
      border: 'var(--btn-accent-bg)', shadow: 'var(--shadow-btn-accent)',
      hoverBg: 'var(--btn-accent-bg-hover)',
    },
    ghost: {
      bg: 'var(--btn-ghost-bg)', fg: 'var(--btn-ghost-fg)',
      border: 'var(--btn-ghost-border)', shadow: 'none',
      hoverBg: 'var(--btn-ghost-bg-hover)',
    },
    quiet: {
      bg: 'transparent', fg: 'var(--btn-quiet-fg)',
      border: 'transparent', shadow: 'none',
      hoverBg: 'var(--btn-quiet-bg-hover)',
    },
    danger: {
      bg: 'var(--status-danger)', fg: '#FFFFFF',
      border: 'var(--status-danger)', shadow: 'var(--shadow-btn-primary)',
      hoverBg: '#A33D3D',
    },
  };
  const p = palettes[variant] || palettes.primary;
  const [hover, setHover] = npUseState(false);

  return (
    <button
      onClick={onClick} type={type} disabled={disabled || loading}
      aria-label={ariaLabel}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: block ? 'flex' : 'inline-flex',
        alignItems: 'center', justifyContent: 'center', gap: 8,
        padding: pad,
        borderRadius: 'var(--radius-sm)',
        fontSize: fs, fontWeight: 600, letterSpacing: '0.005em',
        background: hover && !disabled ? p.hoverBg : p.bg,
        color: p.fg,
        border: `1px solid ${p.border}`,
        boxShadow: p.shadow,
        width: block ? '100%' : 'auto',
        opacity: disabled ? 0.5 : 1,
        cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out)',
        transform: hover && !disabled ? 'translateY(-1px)' : 'translateY(0)',
        ...style,
      }}
    >
      {loading
        ? <span style={{ width: iconSize, height: iconSize, border: '2px solid currentColor', borderRightColor: 'transparent', borderRadius: '50%', animation: 'spin 700ms linear infinite' }} />
        : icon && <Icon name={icon} size={iconSize} />}
      {label}
      {iconRight && <Icon name={iconRight} size={iconSize} />}
    </button>
  );
};

/* ==========================================================
   INPUT
   ========================================================== */
const Input = ({
  value, onChange, placeholder, disabled, error,
  prefix, suffix, mono, type = 'text', size = 'md', style,
}) => {
  const height = size === 'sm' ? 32 : size === 'lg' ? 48 : 40;
  const [focus, setFocus] = npUseState(false);

  let borderColor = 'var(--input-border)';
  if (error)  borderColor = 'var(--status-danger)';
  else if (focus) borderColor = 'var(--input-border-focus)';

  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8,
      border: `1px solid ${borderColor}`,
      borderRadius: 'var(--radius-sm)',
      background: disabled ? 'var(--surface-sunk)' : 'var(--input-bg)',
      padding: '0 12px', height,
      opacity: disabled ? 0.6 : 1,
      boxShadow: focus && !error ? 'var(--shadow-focus)' : 'none',
      transition: 'border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out)',
      ...style,
    }}>
      {prefix && <span style={{ fontSize: 13, color: 'var(--text-tertiary)', fontWeight: 500 }}>{prefix}</span>}
      <input
        type={type} value={value ?? ''} disabled={disabled}
        onChange={e => onChange?.(e.target.value)}
        onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
        placeholder={placeholder}
        style={{
          flex: 1, border: 'none', outline: 'none', background: 'transparent',
          fontSize: size === 'sm' ? 13 : 14,
          fontFamily: mono ? 'var(--font-mono)' : 'inherit',
          color: 'var(--input-fg)', minWidth: 0,
        }}
      />
      {suffix && <span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontWeight: 600 }}>{suffix}</span>}
    </div>
  );
};

/* ==========================================================
   SELECT
   ========================================================== */
const PaperSelect = ({ value, onChange, options, placeholder, disabled }) => (
  <div style={{
    position: 'relative',
    border: '1px solid var(--input-border)',
    borderRadius: 'var(--radius-sm)',
    background: disabled ? 'var(--surface-sunk)' : 'var(--input-bg)',
    height: 40, display: 'flex', alignItems: 'center', paddingRight: 32,
    opacity: disabled ? 0.6 : 1,
  }}>
    <select value={value ?? ''} onChange={e => onChange?.(e.target.value)} disabled={disabled}
      style={{
        appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none',
        border: 'none', outline: 'none', background: 'transparent',
        width: '100%', padding: '0 12px',
        fontSize: 14, color: 'var(--input-fg)',
        cursor: disabled ? 'not-allowed' : 'pointer',
      }}>
      {placeholder && <option value="">{placeholder}</option>}
      {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
    </select>
    <span style={{ position: 'absolute', right: 10, top: 12, pointerEvents: 'none', color: 'var(--text-tertiary)' }}>
      <Icon name="chevronDown" size={14} />
    </span>
  </div>
);

/* ==========================================================
   CHECKBOX + RADIO
   ========================================================== */
const Checkbox = ({ checked, onChange, label, disabled }) => (
  <label style={{ display: 'inline-flex', alignItems: 'center', gap: 10, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.5 : 1 }}>
    <span style={{
      width: 16, height: 16, borderRadius: 'var(--radius-xs)',
      border: `1.5px solid ${checked ? 'var(--brand-primary)' : 'var(--rule-strong)'}`,
      background: checked ? 'var(--brand-primary)' : 'transparent',
      display: 'grid', placeItems: 'center',
      transition: 'background var(--dur-instant) var(--ease-out), border-color var(--dur-instant) var(--ease-out)',
    }}>
      {checked && <NIcon d="M4 12l5 5L20 6" size={10} sw={3} />}
    </span>
    <input type="checkbox" checked={checked} onChange={e => onChange?.(e.target.checked)} disabled={disabled} style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
    {label && <span style={{ fontSize: 13.5, color: 'var(--text-primary)' }}>{label}</span>}
  </label>
);

const Radio = ({ checked, onChange, label, name, value, disabled }) => (
  <label style={{ display: 'inline-flex', alignItems: 'center', gap: 10, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.5 : 1 }}>
    <span style={{
      width: 16, height: 16, borderRadius: '50%',
      border: `1.5px solid ${checked ? 'var(--brand-primary)' : 'var(--rule-strong)'}`,
      display: 'grid', placeItems: 'center',
      transition: 'border-color var(--dur-instant) var(--ease-out)',
    }}>
      {checked && <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--brand-primary)' }} />}
    </span>
    <input type="radio" name={name} value={value} checked={checked} onChange={e => onChange?.(e.target.value)} disabled={disabled} style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
    {label && <span style={{ fontSize: 13.5, color: 'var(--text-primary)' }}>{label}</span>}
  </label>
);

/* ==========================================================
   TOGGLE
   ========================================================== */
const Toggle = ({ checked, onChange, label, disabled }) => (
  <label style={{ display: 'inline-flex', alignItems: 'center', gap: 10, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.5 : 1 }}>
    <button type="button" onClick={() => !disabled && onChange?.(!checked)} style={{
      width: 32, height: 18, borderRadius: 999,
      background: checked ? 'var(--brand-primary)' : 'var(--rule-strong)',
      position: 'relative',
      transition: 'background var(--dur-fast) var(--ease-out)',
    }}>
      <span style={{
        position: 'absolute', top: 2, left: checked ? 16 : 2,
        width: 14, height: 14, borderRadius: '50%', background: '#FFFFFF',
        transition: 'left var(--dur-fast) var(--ease-out)',
        boxShadow: '0 1px 2px rgba(0,0,0,0.2)',
      }} />
    </button>
    {label && <span style={{ fontSize: 13.5, color: 'var(--text-primary)' }}>{label}</span>}
  </label>
);

/* ==========================================================
   BADGES & PILLS
   ========================================================== */
const Badge = ({ label, tone = 'neutral', strong = false }) => {
  const tones = {
    neutral: { bg: 'var(--surface-code)', fg: 'var(--text-secondary)' },
    brand:   { bg: 'var(--brand-tint)',   fg: 'var(--text-accent)' },
    success: { bg: 'var(--status-success-bg)', fg: 'var(--status-success)' },
    warn:    { bg: 'var(--status-warn-bg)',    fg: 'var(--status-warn)' },
    danger:  { bg: 'var(--status-danger-bg)',  fg: 'var(--status-danger)' },
    accent:  { bg: 'var(--butter-100)',   fg: '#7A5B00' },
  };
  const t = tones[tone] || tones.neutral;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '3px 8px', borderRadius: 'var(--radius-sharp)',
      background: t.bg, color: t.fg,
      fontSize: strong ? 10.5 : 11.5,
      fontWeight: 700,
      letterSpacing: strong ? '0.08em' : '0.02em',
      textTransform: strong ? 'uppercase' : 'none',
      whiteSpace: 'nowrap',
    }}>
      {strong && <span style={{ width: 5, height: 5, background: t.fg, borderRadius: 1 }} />}
      {label}
    </span>
  );
};

// Currency pill — mono, compact
const CurrencyPill = ({ ccy }) => (
  <span style={{
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    minWidth: 28, height: 18, padding: '0 6px',
    borderRadius: 'var(--radius-xs)',
    fontSize: 10, fontWeight: 700, letterSpacing: '0.06em',
    background: 'var(--surface-code)', color: 'var(--text-secondary)',
    fontFamily: 'var(--font-mono)',
  }}>{ccy}</span>
);

// Risk pill — for instrument tiers
const RiskTier = ({ tier }) => {
  const map = {
    'Ultra-low': { bg: 'var(--status-success-bg)', fg: 'var(--status-success)' },
    'Low':       { bg: 'var(--brand-tint)',        fg: 'var(--text-accent)' },
    'Moderate':  { bg: 'var(--status-warn-bg)',    fg: 'var(--status-warn)' },
    'High':      { bg: 'var(--status-danger-bg)',  fg: 'var(--status-danger)' },
  };
  const c = map[tier] || map['Low'];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '3px 8px', borderRadius: 'var(--radius-sharp)',
      background: c.bg, color: c.fg,
      fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase',
    }}>
      <span style={{ width: 5, height: 5, background: c.fg, borderRadius: 1 }} />
      {tier}
    </span>
  );
};

/* ==========================================================
   SEGMENTED CONTROL
   ========================================================== */
const Segmented = ({ value, onChange, items }) => (
  <div style={{
    display: 'inline-flex', padding: 3, background: 'var(--surface-code)',
    borderRadius: 'var(--radius-md)', gap: 2,
  }}>
    {items.map(it => {
      const on = value === it.id;
      return (
        <button key={it.id} onClick={() => onChange?.(it.id)} style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '5px 12px', borderRadius: 'var(--radius-sm)',
          background: on ? 'var(--surface-card)' : 'transparent',
          color: on ? 'var(--text-primary)' : 'var(--text-secondary)',
          fontSize: 12, fontWeight: on ? 600 : 500,
          boxShadow: on ? '0 1px 2px rgba(61,60,95,0.08), 0 0 0 1px var(--rule-subtle)' : 'none',
          transition: 'background var(--dur-fast) var(--ease-out)',
        }}>
          {it.icon && <Icon name={it.icon} size={12} />}
          {it.label}
        </button>
      );
    })}
  </div>
);

/* ==========================================================
   TABS (horizontal, Move-style)
   ========================================================== */
const Tabs = ({ value, onChange, items }) => (
  <div style={{ display: 'flex', gap: 4, borderBottom: '1px solid var(--rule-subtle)' }}>
    {items.map(it => {
      const on = value === it.id;
      return (
        <button key={it.id} onClick={() => onChange?.(it.id)} style={{
          padding: '10px 14px',
          fontSize: 13, fontWeight: on ? 600 : 500,
          color: on ? 'var(--text-primary)' : 'var(--text-tertiary)',
          borderBottom: `2px solid ${on ? 'var(--brand-primary)' : 'transparent'}`,
          marginBottom: -1,
          transition: 'color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)',
        }}>
          {it.label}
          {it.count != null && (
            <span style={{
              marginLeft: 6, fontSize: 11, color: 'var(--text-quiet)',
              fontFamily: 'var(--font-mono)', fontWeight: 500,
            }}>{it.count}</span>
          )}
        </button>
      );
    })}
  </div>
);

/* ==========================================================
   EYEBROW + LABEL
   ========================================================== */
const Eyebrow = ({ children, color = 'var(--text-tertiary)' }) => (
  <span style={{
    fontFamily: 'Open Sans', fontWeight: 700,
    fontSize: 10.5, letterSpacing: '0.14em',
    textTransform: 'uppercase', color,
  }}>{children}</span>
);

const FieldLabel = ({ children, hint, required, htmlFor }) => (
  <label htmlFor={htmlFor} style={{
    display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
    marginBottom: 6, fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)',
  }}>
    <span>{children}{required && <span style={{ color: 'var(--status-danger)', marginLeft: 4 }}>*</span>}</span>
    {hint && <span style={{ fontSize: 11, color: 'var(--text-tertiary)', fontWeight: 500 }}>{hint}</span>}
  </label>
);

const FieldHint = ({ children, error }) => (
  <div style={{
    marginTop: 6, fontSize: 11.5,
    color: error ? 'var(--status-danger)' : 'var(--text-tertiary)',
  }}>{children}</div>
);

/* ==========================================================
   SPARKLINE
   ========================================================== */
const Sparkline = ({ points, width = 72, height = 20, color = 'var(--brand-primary)' }) => {
  const min = Math.min(...points), max = Math.max(...points);
  const dx = width / (points.length - 1);
  const scale = v => height - ((v - min) / (max - min || 1)) * (height - 2) - 1;
  const d = points.map((v, i) => `${i === 0 ? 'M' : 'L'}${i * dx},${scale(v)}`).join(' ');
  return (
    <svg width={width} height={height} style={{ display: 'block' }}>
      <path d={d} fill="none" stroke={color} strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
};

/* ==========================================================
   ALLOCATION BAR
   ========================================================== */
const AllocationBar = ({ segments, height = 10 }) => (
  <div style={{
    display: 'flex', width: '100%', height, borderRadius: 'var(--radius-pill)',
    overflow: 'hidden', background: 'var(--surface-code)',
    boxShadow: 'inset 0 0 0 1px var(--rule-subtle)',
  }}>
    {segments.map((s, i) => (
      <div key={i} title={`${s.label} · ${(s.pct * 100).toFixed(1)}%`}
        style={{ width: `${s.pct * 100}%`, background: s.color }} />
    ))}
  </div>
);

/* ==========================================================
   STAT CELL — "naked number" dashboard style
   ========================================================== */
const StatCell = ({ label, value, caption, accent }) => (
  <div style={{ minWidth: 0 }}>
    <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontWeight: 500, marginBottom: 10 }}>
      {label}
    </div>
    <div style={{
      fontSize: 30, fontWeight: 700, color: accent || 'var(--text-primary)',
      letterSpacing: '-0.018em', lineHeight: 1,
      fontFeatureSettings: '"tnum" 1',
    }}>{value}</div>
    {caption && <div style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 8 }}>{caption}</div>}
  </div>
);

/* ==========================================================
   KEY-VALUE ROW (for drawers)
   ========================================================== */
const KV = ({ k, v, mono }) => (
  <div style={{
    display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
    padding: '8px 0', borderBottom: '1px dashed var(--rule-subtle)',
  }}>
    <span style={{
      fontFamily: 'Open Sans', fontWeight: 700, fontSize: 10,
      letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--text-tertiary)',
    }}>{k}</span>
    <span style={{
      fontSize: 13, fontWeight: 600, color: 'var(--text-primary)',
      fontFamily: mono ? 'var(--font-mono)' : 'inherit',
    }}>{v}</span>
  </div>
);

/* ==========================================================
   Global keyframes
   ========================================================== */
const _keyframes = document.createElement('style');
_keyframes.textContent = `
  @keyframes spin { to { transform: rotate(360deg); } }
  @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
  @keyframes slide-up { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }
  @keyframes shimmer { from { background-position: -200px 0; } to { background-position: 200px 0; } }
`;
document.head.appendChild(_keyframes);

Object.assign(window, {
  NIcon, Icon, ICONS, Lockup,
  Button, Input, PaperSelect, Checkbox, Radio, Toggle,
  Badge, CurrencyPill, RiskTier,
  Segmented, Tabs, Eyebrow, FieldLabel, FieldHint,
  Sparkline, AllocationBar, StatCell, KV,
});
