// Components.jsx — Symposia mobile UI primitives
// All visuals reference CSS vars from ../colors_and_type.css

// ──────────────────────────────────────────────────────────────
// Icon — inline Lucide SVGs (single-weight 1.5 stroke)
// ──────────────────────────────────────────────────────────────
const ICON_PATHS = {
  'chevron-left':   <path d="m15 18-6-6 6-6"/>,
  'chevron-right':  <path d="m9 18 6-6-6-6"/>,
  'plus':           <path d="M12 5v14M5 12h14"/>,
  'x':              <path d="m18 6-12 12M6 6l12 12"/>,
  'check':          <path d="M20 6 9 17l-5-5"/>,
  'search':         <g><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></g>,
  'home':           <g><path d="M3 12 12 3l9 9"/><path d="M5 10v10h14V10"/></g>,
  'calendar-days':  <g><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></g>,
  'calendar':       <g><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></g>,
  'bell':           <g><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></g>,
  'user-round':     <g><circle cx="12" cy="8" r="4"/><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6"/></g>,
  'mic':            <g><rect x="9" y="2" width="6" height="13" rx="3"/><path d="M19 10a7 7 0 0 1-14 0M12 19v3"/></g>,
  'globe':          <g><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></g>,
  'building-2':     <g><path d="M3 21V7l9-4 9 4v14"/><path d="M9 21V12h6v9"/></g>,
  'map-pin':        <g><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 1 1 16 0Z"/><circle cx="12" cy="10" r="3"/></g>,
  'paperclip':      <path d="m21 11.5-8.6 8.6a5 5 0 0 1-7.1-7.1L13.9 4.5a3.5 3.5 0 0 1 5 5L10.3 18a2 2 0 1 1-2.8-2.8L15 7.5"/>,
  'pencil':         <path d="M12 20h9M16.5 3.5a2.12 2.12 0 1 1 3 3L7 19l-4 1 1-4Z"/>,
  'trash-2':        <path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>,
  'hourglass':      <path d="M5 22h14M5 2h14M17 22v-4.2a3 3 0 0 0-1-2.3L12 12l-4 3.5a3 3 0 0 0-1 2.3V22M7 2v4.2a3 3 0 0 0 1 2.3L12 12l4-3.5a3 3 0 0 0 1-2.3V2"/>,
  'badge-check':    <g><path d="m3.85 8.62 4.7-3.4a3 3 0 0 1 3 0l4.7 3.4a3 3 0 0 1 1.1 1.9l1.1 5.7a3 3 0 0 1-.6 2.3l-3.7 4.6a3 3 0 0 1-2.1 1.1H8.8a3 3 0 0 1-2.1-1.1l-3.7-4.6a3 3 0 0 1-.6-2.3l1.1-5.7a3 3 0 0 1 1.1-1.9Z"/><path d="m9 12 2 2 4-4"/></g>,
  'clock':          <g><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></g>,
  'arrow-right':    <path d="M5 12h14m-6-6 6 6-6 6"/>,
  'circle':         <circle cx="12" cy="12" r="9"/>,
  'sliders':        <g><path d="M4 6h16M4 12h10M4 18h16"/><circle cx="17" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="14" cy="18" r="2"/></g>,
  'users':          <g><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.9"/><path d="M16 3.9a4 4 0 0 1 0 7.8"/></g>,
  'ticket':         <g><path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M13 5v2"/><path d="M13 17v2"/><path d="M13 11v2"/></g>,
};

function Icon({ name, size = 20, color = 'currentColor', strokeWidth = 1.5, style = {} }) {
  const p = ICON_PATHS[name];
  if (!p) return null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
         stroke={color} strokeWidth={strokeWidth}
         strokeLinecap="round" strokeLinejoin="round"
         style={{ display: 'inline-block', verticalAlign: 'middle', flex: 'none', ...style }}>
      {p}
    </svg>
  );
}

// ──────────────────────────────────────────────────────────────
// Button
// ──────────────────────────────────────────────────────────────
function Button({ variant = 'primary', size = 'md', icon, iconRight, full, disabled, onClick, children, style = {} }) {
  const [pressed, setPressed] = React.useState(false);

  const sizing = {
    sm: { padding: '6px 12px',  fontSize: 12, height: 32, radius: 8 },
    md: { padding: '8px 14px', fontSize: 13, height: 36, radius: 10 },
    lg: { padding: '10px 16px', fontSize: 14, height: 40, radius: 12 },
  }[size];

  let bg = 'transparent', color = 'var(--action)', border = '1px solid transparent';
  let shadow = 'none';
  if (variant === 'primary') {
    bg = pressed ? 'var(--action-press)' : 'var(--action)';
    color = 'var(--action-fg)';
    shadow = 'var(--shadow-inset)';
  } else if (variant === 'secondary') {
    border = '1px solid var(--action)';
    bg = pressed ? 'var(--action-soft)' : 'transparent';
    color = 'var(--action)';
  } else if (variant === 'ghost') {
    bg = pressed ? 'var(--stone-100)' : 'transparent';
    color = 'var(--action)';
  } else if (variant === 'danger') {
    bg = pressed ? 'var(--crimson-600)' : 'var(--crimson-500)';
    color = '#fff';
  } else if (variant === 'soft') {
    bg = pressed ? 'var(--parchment-200)' : 'var(--parchment-100)';
    color = 'var(--action)';
    border = '1px solid var(--border-1)';
  }

  return (
    <button
      onClick={disabled ? undefined : onClick}
      onPointerDown={() => !disabled && setPressed(true)}
      onPointerUp={() => setPressed(false)}
      onPointerLeave={() => setPressed(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        padding: sizing.padding, height: sizing.height,
        fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: sizing.fontSize,
        letterSpacing: 0, lineHeight: 1,
        background: disabled ? 'var(--stone-100)' : bg,
        color: disabled ? 'var(--fg-4)' : color,
        border, borderRadius: sizing.radius,
        boxShadow: variant === 'primary' && !disabled ? shadow : 'none',
        width: full ? '100%' : 'auto',
        cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'background var(--dur-fast) var(--ease-out)',
        ...style,
      }}>
      {icon && <Icon name={icon} size={18}/>}
      <span>{children}</span>
      {iconRight && <Icon name={iconRight} size={18}/>}
    </button>
  );
}

// ──────────────────────────────────────────────────────────────
// Text field
// ──────────────────────────────────────────────────────────────
function TextField({ label, value, onChange, placeholder, error, helper, type = 'text', prefix, suffix, readOnly, multiline, autoFocus }) {
  const [focus, setFocus] = React.useState(false);
  const borderColor = error ? 'var(--crimson-500)' : (focus ? 'var(--action)' : 'var(--border-1)');
  const ring = focus
    ? `0 0 0 2px ${error ? 'rgba(178,58,42,.16)' : 'var(--action-ring)'}`
    : 'none';
  const Tag = multiline ? 'textarea' : 'input';
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {label && <label style={{ fontSize: 13, fontWeight: 500, color: 'var(--fg-1)' }}>{label}</label>}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10,
        background: '#fff', border: `1px solid ${borderColor}`, borderRadius: 12,
        padding: multiline ? '12px 14px' : '0 14px',
        height: multiline ? 'auto' : 48,
        boxShadow: ring, transition: 'all var(--dur-fast) var(--ease-out)',
      }}>
        {prefix && <span style={{ color: 'var(--fg-2)', fontSize: 15 }}>{prefix}</span>}
        <Tag
          type={type}
          value={value || ''}
          onChange={e => onChange?.(e.target.value)}
          placeholder={placeholder}
          readOnly={readOnly}
          autoFocus={autoFocus}
          onFocus={() => setFocus(true)}
          onBlur={() => setFocus(false)}
          rows={multiline ? 4 : undefined}
          style={{
            flex: 1, border: 'none', outline: 'none', background: 'transparent',
            fontFamily: 'var(--font-sans)', fontSize: 15, color: '#fff',
            padding: multiline ? 0 : '13px 0', resize: multiline ? 'vertical' : 'none',
            lineHeight: 1.4, minWidth: 0,
          }}
        />
        {suffix}
      </div>
      {(helper || error) && (
        <span style={{ fontSize: 12, color: error ? 'var(--crimson-600)' : 'var(--fg-3)' }}>
          {error || helper}
        </span>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// OTP — 6-digit verification input
// ──────────────────────────────────────────────────────────────
function OTPInput({ value = '', length = 6, onChange, autoFocus }) {
  const cells = Array.from({ length }, (_, i) => value[i] || '');
  const activeIdx = Math.min(value.length, length - 1);
  const ref = React.useRef(null);
  React.useEffect(() => { if (autoFocus) ref.current?.focus(); }, [autoFocus]);
  return (
    <div style={{ position: 'relative' }}>
      <input
        ref={ref}
        value={value}
        onChange={e => onChange?.(e.target.value.replace(/\D/g, '').slice(0, length))}
        inputMode="numeric"
        autoComplete="one-time-code"
        style={{
          position: 'absolute', inset: 0, opacity: 0, zIndex: 1,
          width: '100%', height: '100%', border: 'none', background: 'transparent',
        }}
      />
      <div style={{ display: 'flex', gap: 10 }}>
        {cells.map((c, i) => (
          <div key={i} style={{
            flex: 1, height: 56, borderRadius: 12,
            background: '#fff',
            border: `1px solid ${i === activeIdx && value.length < length ? 'var(--action)' : 'var(--border-1)'}`,
            boxShadow: i === activeIdx && value.length < length ? '0 0 0 2px var(--action-ring)' : 'none',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontFamily: 'var(--font-mono)', fontSize: 24, fontWeight: 500, color: 'var(--fg-1)',
            transition: 'all var(--dur-fast) var(--ease-out)',
          }}>
            {c || (i === activeIdx && value.length < length ? <span style={{ width: 2, height: 24, background: 'var(--action)', animation: 'blink 1s steps(1) infinite' }}/> : '')}
          </div>
        ))}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Status pill
// ──────────────────────────────────────────────────────────────
function Pill({ kind = 'neutral', children, icon }) {
  const styles = {
    neutral:   { bg: '#fff',                color: 'var(--fg-2)',      border: 'var(--border-1)' },
    review:    { bg: 'var(--parchment-100)',color: 'var(--stone-600)', border: 'var(--stone-200)' },
    approved:  { bg: 'var(--moss-50)',      color: 'var(--moss-600)',  border: '#cfdec2' },
    rejected:  { bg: 'var(--crimson-50)',   color: 'var(--crimson-600)', border: 'var(--crimson-100)' },
    external:  { bg: 'var(--brass-50)',     color: 'var(--brass-500)', border: 'var(--brass-100)' },
    internal:  { bg: 'var(--ink-50)',       color: 'var(--ink-700)',   border: 'var(--ink-100)' },
    keynote:   { bg: 'var(--ink-800)',      color: 'var(--parchment-50)', border: 'var(--ink-800)' },
  }[kind] || { bg: '#fff', color: 'var(--fg-2)', border: 'var(--border-1)' };
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 11,
      letterSpacing: '.04em', textTransform: 'uppercase',
      padding: '4px 10px', borderRadius: 999,
      background: styles.bg, color: styles.color, border: `1px solid ${styles.border}`,
      whiteSpace: 'nowrap', flex: 'none',
    }}>
      {icon && <Icon name={icon} size={12}/>}
      {children}
    </span>
  );
}

// ──────────────────────────────────────────────────────────────
// Avatar
// ──────────────────────────────────────────────────────────────
function Avatar({ name = '', size = 40, accent }) {
  const initials = name.split(' ').map(s => s[0]).filter(Boolean).slice(0, 2).join('').toUpperCase() || '·';
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: accent === 'external' ? 'var(--brass-50)' : 'var(--parchment-200)',
      color: accent === 'external' ? 'var(--brass-500)' : 'var(--ink-700)',
      fontFamily: 'var(--font-serif)', fontWeight: 500, fontSize: size * 0.42,
      display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 'none',
      fontVariationSettings: '"opsz" 24',
      border: accent === 'external' ? '1px solid var(--brass-100)' : 'none',
    }}>{initials}</div>
  );
}

// ──────────────────────────────────────────────────────────────
// List + ListRow
// ──────────────────────────────────────────────────────────────
function List({ children, style = {} }) {
  return (
    <div style={{
      background: '#fff', border: '1px solid var(--border-1)', borderRadius: 12,
      overflow: 'hidden', ...style,
    }}>{children}</div>
  );
}

function ListRow({ leading, title, subtitle, trailing, onClick, danger, isLast }) {
  const [pressed, setPressed] = React.useState(false);
  return (
    <div
      onClick={onClick}
      onPointerDown={() => setPressed(true)}
      onPointerUp={() => setPressed(false)}
      onPointerLeave={() => setPressed(false)}
      style={{
        display: 'flex', alignItems: 'center', gap: 14,
        padding: '14px 16px',
        borderBottom: isLast ? 'none' : '1px solid var(--border-2)',
        background: pressed ? 'var(--stone-50)' : 'transparent',
        cursor: onClick ? 'pointer' : 'default',
        transition: 'background var(--dur-fast) var(--ease-out)',
      }}>
      {leading}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 0, flex: 1 }}>
        <span style={{ fontSize: 15, fontWeight: 500, color: danger ? 'var(--crimson-500)' : 'var(--fg-1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{title}</span>
        {subtitle && <span style={{ fontSize: 13, color: 'var(--fg-2)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{subtitle}</span>}
      </div>
      {trailing}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Section header — overline
// ──────────────────────────────────────────────────────────────
function SectionHeader({ children, action }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', padding: '0 4px', marginBottom: 6 }}>
      <span style={{
        fontFamily: 'var(--font-sans)', fontSize: 11, fontWeight: 600,
        letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--fg-3)',
        whiteSpace: 'nowrap',
      }}>{children}</span>
      {action}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// App header — Symposia screen chrome (replaces IOSNavBar)
// ──────────────────────────────────────────────────────────────
function AppHeader({ title, leading, trailing, large, subtitle }) {
  return (
    <div style={{
      padding: large ? 'calc(8px + env(safe-area-inset-top, 20px)) 14px 10px' : 'calc(6px + env(safe-area-inset-top, 16px)) 10px 6px',
      background: '#0c7164',
      backdropFilter: 'blur(20px) saturate(1.4)',
      WebkitBackdropFilter: 'blur(20px) saturate(1.4)',
      borderBottom: large ? 'none' : '1px solid #0b5f54',
      position: 'sticky', top: 0, zIndex: 5,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', minHeight: 24, gap: 1 }}>
        <div style={{ minWidth: 28, display: 'flex', alignItems: 'center', flex: '0 0 auto' }}>{leading}</div>
        {!large && <div style={{
          flex: 1, textAlign: 'center', fontFamily: 'var(--font-sans)', fontWeight: 500,
          fontSize: 14, color: '#fff',
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          padding: '0 4px',
        }}>{title}</div>}
        {large && <div style={{ flex: 1 }}/>}
        <div style={{ minWidth: 32, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', whiteSpace: 'nowrap', flex: '0 0 auto' }}>{trailing}</div>
      </div>
      {large && (
        <div style={{ marginTop: 10, paddingLeft: 4 }}>
          <h1 style={{
            margin: 0, fontFamily: 'var(--font-sans)', fontWeight: 600,
            fontSize: 32, lineHeight: 1.12, letterSpacing: '-0.02em',
            color: '#fff',
          }}>{title}</h1>
          {subtitle && <div style={{ marginTop: 4, fontSize: 14, color: 'rgba(255,255,255,0.7)' }}>{subtitle}</div>}
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Tab bar
// ──────────────────────────────────────────────────────────────
function TabBar({ active = 'home', onChange }) {
  const tabs = [
    { id: 'home',     icon: 'home',          label: 'Forums' },
    { id: 'calendar', icon: 'calendar-days', label: 'Calendar' },
    { id: 'inbox',    icon: 'bell',          label: 'Inbox' },
    { id: 'me',       icon: 'user-round',    label: 'Profile' },
  ];
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 0,
      paddingBottom: 22, paddingTop: 8,
      background: 'rgba(250, 247, 241, 0.94)',
      backdropFilter: 'blur(20px) saturate(1.4)',
      WebkitBackdropFilter: 'blur(20px) saturate(1.4)',
      borderTop: '1px solid var(--border-2)',
      display: 'flex', justifyContent: 'space-around',
      zIndex: 4,
    }}>
      {tabs.map(t => (
        <button key={t.id} onClick={() => onChange?.(t.id)} style={{
          background: 'none', border: 'none', cursor: 'pointer',
          display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
          color: active === t.id ? 'var(--action)' : 'var(--fg-3)',
          padding: '4px 10px', fontFamily: 'var(--font-sans)',
        }}>
          <Icon name={t.icon} size={24} strokeWidth={active === t.id ? 1.75 : 1.5}/>
          <span style={{ fontSize: 10, fontWeight: 600, letterSpacing: '.02em' }}>{t.label}</span>
        </button>
      ))}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Bottom sheet
// ──────────────────────────────────────────────────────────────
function BottomSheet({ open, onClose, title, children }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 100,
      pointerEvents: open ? 'auto' : 'none',
    }}>
      <div onClick={onClose} style={{
        position: 'absolute', inset: 0,
        background: 'rgba(11, 21, 37, 0.45)',
        opacity: open ? 1 : 0,
        transition: 'opacity var(--dur-base) var(--ease-out)',
      }}/>
      <div style={{
        position: 'absolute', left: 0, right: 0, bottom: 0,
        background: 'var(--bg)',
        borderRadius: '20px 20px 0 0',
        boxShadow: 'var(--shadow-3)',
        transform: open ? 'translateY(0)' : 'translateY(100%)',
        transition: 'transform var(--dur-slow) var(--ease-out)',
        maxHeight: '85%', overflow: 'hidden',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ display: 'flex', justifyContent: 'center', padding: '8px 0 4px' }}>
          <div style={{ width: 40, height: 4, borderRadius: 999, background: 'var(--stone-200)' }}/>
        </div>
        {title && <div style={{
          padding: '8px 20px 14px', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          borderBottom: '1px solid var(--border-2)',
        }}>
          <span style={{ fontFamily: 'var(--font-sans)', fontWeight: 500, fontSize: 19, color: 'var(--fg-1)' }}>{title}</span>
          <button onClick={onClose} style={{
            background: 'none', border: 'none', cursor: 'pointer', padding: 6, color: 'var(--fg-2)',
          }}><Icon name="x" size={20}/></button>
        </div>}
        <div style={{ overflowY: 'auto', flex: 1 }}>{children}</div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Forum application card — used on home screen
// ──────────────────────────────────────────────────────────────
function ForumCard({ forum, onClick }) {
  const [pressed, setPressed] = React.useState(false);
  const statusKind = { draft: 'neutral', review: 'review', approved: 'approved', rejected: 'rejected' }[forum.status] || 'neutral';
  const statusLabel = { draft: 'Draft', review: 'Under review', approved: 'Approved', rejected: 'Rejected' }[forum.status] || forum.status;
  const statusIcon = { draft: 'pencil', review: 'hourglass', approved: 'badge-check', rejected: 'x' }[forum.status];
  return (
    <div
      onClick={onClick}
      onPointerDown={() => setPressed(true)}
      onPointerUp={() => setPressed(false)}
      onPointerLeave={() => setPressed(false)}
      style={{
        background: '#fff', border: '1px solid var(--border-1)', borderRadius: 14,
        padding: 18, display: 'flex', flexDirection: 'column', gap: 12,
        boxShadow: pressed ? 'var(--shadow-2)' : 'none',
        transform: pressed ? 'translateY(-1px)' : 'translateY(0)',
        transition: 'all var(--dur-fast) var(--ease-out)',
        cursor: 'pointer',
      }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <Pill kind={statusKind} icon={statusIcon}>{statusLabel}</Pill>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-3)' }}>#{forum.id}</span>
      </div>
      <div style={{
        fontFamily: 'var(--font-sans)', fontWeight: 500, fontSize: 20,
        lineHeight: 1.22, letterSpacing: '-0.01em', color: 'var(--fg-1)',
      }}>{forum.title}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--fg-2)', flexWrap: 'wrap' }}>
        <Icon name="calendar" size={14} color="var(--fg-3)"/>
        <span>{forum.date}</span>
        <span style={{ color: 'var(--fg-4)' }}>·</span>
        <Icon name="map-pin" size={14} color="var(--fg-3)"/>
        <span>{forum.location}</span>
        <span style={{ color: 'var(--fg-4)' }}>·</span>
        <span>{forum.sessions} sessions</span>
      </div>
    </div>
  );
}

Object.assign(window, {
  Icon, Button, TextField, OTPInput, Pill, Avatar,
  List, ListRow, SectionHeader, AppHeader, TabBar, BottomSheet, ForumCard,
});
