/* Central Rewards Club — shared UI components. Exports to window. */

// ── Icons (Lucide-style, 24px, currentColor stroke) ──────────────────
const CRC_ICONS = {
  home: 'M3 10.5L12 3l9 7.5M5 9.5V21h5v-6h4v6h5V9.5',
  gift: 'M20 12v9H4v-9M2 7h20v5H2zM12 22V7M12 7S11 2 8 2 5 5 8 7M12 7s1-5 4-5 3 3 0 5',
  scan: 'M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2M7 12h10',
  tag: 'M9 5H5a2 2 0 0 0-2 2v4l9 9 6-6-9-9zM7.5 8.5h.01',
  user: 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
  bell: 'M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0',
  chevR: 'M9 18l6-6-6-6',
  chevL: 'M15 18l-6-6 6-6',
  chevD: 'M6 9l6 6 6-6',
  x: 'M18 6L6 18M6 6l12 12',
  instagram: 'M2 2h20v20H2zM16 11.4a4 4 0 1 1-7.9 1.2 4 4 0 0 1 7.9-1.2zM17.5 6.5h.01',
  video: 'M9 8l8 4-8 4V8zM5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z',
  star: 'M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8L12 17.8 5.8 21l1.2-6.8-5-4.9 6.9-1z',
  pin: 'M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0zM12 12a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z',
  plus: 'M12 5v14M5 12h14',
  check: 'M20 6L9 17l-5-5',
  checkBig: 'M20 6L9 17l-5-5',
  sparkle: 'M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9zM19 3v4M21 5h-4',
  arrowUp: 'M12 19V5M5 12l7-7 7 7',
  settings: 'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-2.7 1.1V21a2 2 0 1 1-4 0v-.1A1.6 1.6 0 0 0 6.6 19l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1A1.6 1.6 0 0 0 3 13.4H3a2 2 0 1 1 0-4h.1A1.6 1.6 0 0 0 5 6.6l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1A1.6 1.6 0 0 0 10.6 3H11a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 2.7 1.1l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0-.3 1.8V9a2 2 0 1 1 0 4h-.1z',
  share: 'M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13',
  clock: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 7v5l3 2',
  calendar: 'M8 2v4M16 2v4M3 9h18M5 5h14a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z',
  crown: 'M3 18h18M5 18l-2-9 5 4 4-7 4 7 5-4-2 9',
  wallet: 'M19 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2M21 12h-6a2 2 0 0 0 0 4h6V12zM16 14h.01',
  camera: 'M14.5 4l1.5 2h3a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3l1.5-2zM12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
  search: 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3',
  copy: 'M9 9h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2zM5 15a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2',
  lock: 'M5 11h14a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2zM8 11V7a4 4 0 0 1 8 0v4',
  shield: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10zM9 12l2 2 4-4',
  globe: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM3 12h18M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18z',
  card: 'M3 6h18a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM2 10h20M6 15h4',
  heart: 'M19 14c1.5-1.5 3-3.4 3-5.5A4.5 4.5 0 0 0 12 5 4.5 4.5 0 0 0 2 8.5c0 2.1 1.5 4 3 5.5l7 7z',
  flame: 'M12 2s4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-3 .5 2 2 2 2 0 0-2-2-3 1-5zM12 22a6 6 0 0 0 6-6c0-2-1-4-2-5',
  store: 'M3 9l1.5-5h15L21 9M4 9v11h16V9M4 9a2 2 0 0 0 4 0 2 2 0 0 0 4 0 2 2 0 0 0 4 0 2 2 0 0 0 4 0M9 20v-5h6v5',
  info: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 16v-4M12 8h.01',
  logout: 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9',
  edit: 'M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z',
  ticket: 'M3 8a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2 2 2 0 0 0 0 4 2 2 0 0 1-2 2H5a2 2 0 0 1-2-2 2 2 0 0 0 0-4zM12 6v0M12 12v0M12 18v0',
  coffee: 'M17 8h1a4 4 0 1 1 0 8h-1M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V8zM6 2v2M10 2v2M14 2v2',
  refresh: 'M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5',
  qr: 'M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h3v3h-3zM20 14h1v1M14 20h1v1M20 20h1v1M17 17h1v1',
  phone: 'M5 4h4l2 5-3 2a11 11 0 0 0 5 5l2-3 5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z',
  mail: 'M4 4h16a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zM3 6l9 6 9-6',
  arrowR: 'M5 12h14M13 6l6 6-6 6',
};

function CRCIcon({ name, size = 22, color = 'currentColor', stroke = 2, fill = 'none', style = {} }) {
  const d = CRC_ICONS[name] || '';
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke={color}
      strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
      style={{ display: 'block', flexShrink: 0, ...style }}>
      {d.split('M').filter(Boolean).map((seg, i) => <path key={i} d={'M' + seg} />)}
    </svg>
  );
}

// ── Buttons ──────────────────────────────────────────────────────────
function CRCButton({ children, onClick, variant = 'primary', size = 'md', icon, full, disabled, style = {} }) {
  const pads = { sm: '8px 14px', md: '13px 20px', lg: '16px 22px' };
  const fs = { sm: 13, md: 15, lg: 16 };
  const base = {
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    fontFamily: 'var(--crc-font)', fontWeight: 600, fontSize: fs[size], lineHeight: 1.1,
    padding: pads[size], borderRadius: 999, border: 'none', cursor: disabled ? 'default' : 'pointer',
    width: full ? '100%' : undefined, opacity: disabled ? 0.45 : 1,
    transition: 'transform .15s ease, box-shadow .2s ease, background .2s ease',
    letterSpacing: '-0.01em', ...style,
  };
  const variants = {
    primary: { background: 'var(--crc-primary)', color: '#fff', boxShadow: 'var(--crc-sh-brand)' },
    gold: { background: 'linear-gradient(135deg,var(--crc-gold) 0%,var(--crc-gold-deep) 100%)', color: '#3a2c0a', boxShadow: '0 8px 22px rgba(168,134,60,.32)' },
    dark: { background: 'var(--crc-ink)', color: '#fff' },
    secondary: { background: 'var(--crc-primary-soft)', color: 'var(--crc-primary)' },
    ghost: { background: 'transparent', color: 'var(--crc-primary)' },
    outline: { background: '#fff', color: 'var(--crc-ink)', boxShadow: 'inset 0 0 0 1.5px var(--crc-line)' },
  };
  const press = (e) => { if (!disabled) e.currentTarget.style.transform = 'scale(0.97)'; };
  const rel = (e) => { e.currentTarget.style.transform = ''; };
  return (
    <button onClick={disabled ? undefined : onClick} style={{ ...base, ...variants[variant] }}
      onPointerDown={press} onPointerUp={rel} onPointerLeave={rel}>
      {icon && <CRCIcon name={icon} size={size === 'sm' ? 17 : 19} stroke={2.2} />}
      {children}
    </button>
  );
}

// ── Tier badge ───────────────────────────────────────────────────────
function TierBadge({ tier, size = 'md' }) {
  const T = window.CRC.TIERS[tier];
  const small = size === 'sm';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: small ? '3px 9px' : '4px 11px', borderRadius: 999,
      background: T.card, color: tier === 'gold' || tier === 'platinum' ? '#3a2c0a' : '#fff',
      fontWeight: 700, fontSize: small ? 11 : 12, letterSpacing: '0.02em',
      boxShadow: 'inset 0 0 0 1px rgba(255,255,255,.25)',
    }}>
      <CRCIcon name="crown" size={small ? 12 : 13} stroke={2.4} />
      {T.name.toUpperCase()}
    </span>
  );
}

// ── Section header ───────────────────────────────────────────────────
function SectionHead({ title, action, onAction }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', margin: '0 0 12px' }}>
      <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700, letterSpacing: '-0.02em' }}>{title}</h2>
      {action && <button onClick={onAction} style={{ background: 'none', border: 'none', color: 'var(--crc-primary)', fontWeight: 600, fontSize: 13, fontFamily: 'var(--crc-font)', cursor: 'pointer', padding: 0 }}>{action}</button>}
    </div>
  );
}

// ── Card shell ───────────────────────────────────────────────────────
function Surface({ children, style = {}, onClick, pad = 16 }) {
  return (
    <div onClick={onClick} style={{
      background: 'var(--crc-surface)', borderRadius: 'var(--crc-r-lg)',
      boxShadow: 'var(--crc-sh-sm)', padding: pad,
      cursor: onClick ? 'pointer' : 'default', ...style,
    }}>{children}</div>
  );
}

// ── Progress bar ─────────────────────────────────────────────────────
function ProgressBar({ value, color = 'var(--crc-tier)', height = 8, track = '#EDEDED' }) {
  return (
    <div style={{ height, background: track, borderRadius: 999, overflow: 'hidden' }}>
      <div style={{ width: Math.min(100, Math.max(0, value)) + '%', height: '100%', background: color, borderRadius: 999, transition: 'width .8s cubic-bezier(.2,.8,.2,1)' }} />
    </div>
  );
}

// ── Chip ─────────────────────────────────────────────────────────────
function Chip({ label, active, onClick, icon }) {
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, whiteSpace: 'nowrap',
      padding: '8px 14px', borderRadius: 999, fontFamily: 'var(--crc-font)',
      fontSize: 13, fontWeight: 600, cursor: 'pointer', transition: 'all .18s ease',
      border: 'none',
      background: active ? 'var(--crc-primary)' : '#fff',
      color: active ? '#fff' : 'var(--crc-ink-2)',
      boxShadow: active ? 'var(--crc-sh-brand)' : 'inset 0 0 0 1px var(--crc-line)',
    }}>
      {icon && <CRCIcon name={icon} size={15} stroke={2.2} />}
      {label}
    </button>
  );
}

// ── Bottom sheet ─────────────────────────────────────────────────────
function BottomSheet({ open, onClose, children, height, full }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 200, display: 'flex', alignItems: 'flex-end', background: 'rgba(26,8,12,0.45)', animation: 'crc-fade .22s ease' }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: '100%', background: 'var(--crc-bg)', borderRadius: full ? '0' : '24px 24px 0 0',
        height: full ? '100%' : height, maxHeight: full ? '100%' : '92%', overflow: 'hidden',
        display: 'flex', flexDirection: 'column', animation: 'crc-sheet-up .32s cubic-bezier(.2,.8,.2,1)',
        boxShadow: '0 -10px 40px rgba(0,0,0,.2)',
      }}>
        {!full && <div style={{ padding: '10px 0 4px', display: 'flex', justifyContent: 'center', flexShrink: 0 }}>
          <div style={{ width: 38, height: 5, borderRadius: 999, background: '#D8D8D8' }} />
        </div>}
        {children}
      </div>
    </div>
  );
}

// ── Toast ────────────────────────────────────────────────────────────
function Toast({ toast }) {
  if (!toast) return null;
  const colors = { success: 'var(--crc-success)', info: 'var(--crc-ink)', warning: 'var(--crc-warning)', error: 'var(--crc-error)' };
  return (
    <div style={{
      position: 'absolute', top: 64, left: 16, right: 16, zIndex: 400,
      display: 'flex', alignItems: 'center', gap: 10, padding: '13px 16px',
      background: colors[toast.type] || 'var(--crc-ink)', color: '#fff', borderRadius: 14,
      boxShadow: '0 12px 30px rgba(0,0,0,.25)', animation: 'crc-rise .3s cubic-bezier(.2,.8,.2,1)',
      fontSize: 14, fontWeight: 600,
    }}>
      <CRCIcon name={toast.type === 'success' ? 'check' : 'sparkle'} size={19} stroke={2.4} />
      {toast.msg}
    </div>
  );
}

// ── Confetti ─────────────────────────────────────────────────────────
function Confetti({ show }) {
  if (!show) return null;
  const colors = ['#C9A961', '#7A1F2B', '#FF6B5B', '#2E8B57', '#E6A817'];
  const bits = Array.from({ length: 36 }, (_, i) => i);
  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 350, pointerEvents: 'none', overflow: 'hidden' }}>
      {bits.map((i) => {
        const left = Math.random() * 100, delay = Math.random() * 0.3, dur = 1 + Math.random() * 0.9;
        const sz = 6 + Math.random() * 7;
        return <div key={i} style={{
          position: 'absolute', top: -20, left: left + '%', width: sz, height: sz * (Math.random() > .5 ? 1 : 0.5),
          background: colors[i % colors.length], borderRadius: Math.random() > .5 ? '50%' : 2,
          animation: `crc-confetti ${dur}s ${delay}s cubic-bezier(.3,.6,.4,1) forwards`,
        }} />;
      })}
    </div>
  );
}

// ── QR block (decorative deterministic) ──────────────────────────────
function QRBlock({ size = 150, fg = '#1A1A1A', bg = '#fff', seed = 'CRC' }) {
  const n = 21;
  let h = 0; for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) >>> 0;
  const rnd = (i) => { const x = Math.sin(h + i * 12.9898) * 43758.5453; return x - Math.floor(x); };
  const cell = size / n;
  const isFinder = (r, c) => (r < 7 && c < 7) || (r < 7 && c >= n - 7) || (r >= n - 7 && c < 7);
  const rects = [];
  for (let r = 0; r < n; r++) for (let c = 0; c < n; c++) {
    if (isFinder(r, c)) continue;
    if (rnd(r * n + c) > 0.52) rects.push(<rect key={r + '-' + c} x={c * cell} y={r * cell} width={cell} height={cell} fill={fg} />);
  }
  const finder = (x, y) => (
    <g key={x + ',' + y}>
      <rect x={x * cell} y={y * cell} width={cell * 7} height={cell * 7} fill={fg} />
      <rect x={(x + 1) * cell} y={(y + 1) * cell} width={cell * 5} height={cell * 5} fill={bg} />
      <rect x={(x + 2) * cell} y={(y + 2) * cell} width={cell * 3} height={cell * 3} fill={fg} />
    </g>
  );
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ borderRadius: 8, display: 'block' }}>
      <rect width={size} height={size} fill={bg} />
      {rects}
      {finder(0, 0)}{finder(n - 7, 0)}{finder(0, n - 7)}
    </svg>
  );
}

// ── Generated on-brand visual (stands in for photography in the demo) ──
// Deterministic gradient + motif per slot so every card looks designed,
// never an empty placeholder. Keeps the <image-slot> id so real photos can
// still be dropped in the omelette runtime if desired.
const SLOT_ART = {
  'onb-hero':      { g: ['#8a2433', '#4D1019'], icon: 'sparkle', tone: 'light' },
  'share-content': { g: ['#FF7A6B', '#c0392b'], icon: 'camera', tone: 'light' },
  'promo-sneakers':{ g: ['#7A1F2B', '#3d0f16'], icon: 'tag', tone: 'light' },
  'promo-lebaran': { g: ['#E3C887', '#9A7B33'], icon: 'crown', tone: 'dark' },
  'promo-beauty':  { g: ['#FF8FA3', '#C2185B'], icon: 'heart', tone: 'light' },
  'promo-night':   { g: ['#2b2b2b', '#0e0e0e'], icon: 'crown', tone: 'light' },
  'promo-tech':    { g: ['#3b6ea5', '#14223D'], icon: 'flame', tone: 'light' },
  'rw-voucher50':  { g: ['#7A1F2B', '#4D1019'], icon: 'ticket', tone: 'light' },
  'rw-voucher150': { g: ['#8a2433', '#4D1019'], icon: 'ticket', tone: 'light' },
  'rw-parfum':     { g: ['#6d4b8a', '#3a2658'], icon: 'sparkle', tone: 'light' },
  'rw-tote':       { g: ['#caa15f', '#8a6d2e'], icon: 'gift', tone: 'dark' },
  'rw-coffee':     { g: ['#9c6b4a', '#5a3a26'], icon: 'coffee', tone: 'light' },
  'rw-styling':    { g: ['#d98fa6', '#a04566'], icon: 'sparkle', tone: 'light' },
  'rw-valet':      { g: ['#3b6ea5', '#1f3d5c'], icon: 'card', tone: 'light' },
  'rw-lounge':     { g: ['#2b2b2b', '#0e0e0e'], icon: 'crown', tone: 'light' },
  'ev-night':      { g: ['#2b2b2b', '#0e0e0e'], icon: 'crown', tone: 'light' },
  'ev-trunk':      { g: ['#3a2658', '#1d1230'], icon: 'sparkle', tone: 'light' },
  'ev-beauty':     { g: ['#FF8FA3', '#C2185B'], icon: 'heart', tone: 'light' },
};
const ART_FALLBACK = [
  { g: ['#7A1F2B', '#4D1019'], icon: 'store', tone: 'light' },
  { g: ['#caa15f', '#8a6d2e'], icon: 'gift', tone: 'dark' },
  { g: ['#3b6ea5', '#14223D'], icon: 'tag', tone: 'light' },
  { g: ['#2E8B57', '#1f5e3b'], icon: 'sparkle', tone: 'light' },
];
function artFor(slot) {
  if (SLOT_ART[slot]) return SLOT_ART[slot];
  let h = 0; const s = slot || '';
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
  return ART_FALLBACK[h % ART_FALLBACK.length];
}

// Slots that have a generated SVG illustration in img/.
const ART_SLOTS = new Set([
  'avatar', 'onb-hero', 'share-content',
  'promo-sneakers', 'promo-lebaran', 'promo-beauty', 'promo-night', 'promo-tech',
  'rw-voucher50', 'rw-voucher150', 'rw-parfum', 'rw-tote', 'rw-coffee', 'rw-styling', 'rw-valet', 'rw-lounge',
  'ev-night', 'ev-trunk', 'ev-beauty',
]);

function Img({ id, slot, style = {}, radius = 12, placeholder = '' }) {
  const art = artFor(slot);
  const ink = art.tone === 'dark' ? 'rgba(58,44,10,.28)' : 'rgba(255,255,255,.30)';
  // Source fallback chain: generated photo → SVG illustration → gradient motif.
  const cands = [];
  const photo = (typeof window !== 'undefined' && window.CRC_PHOTOS && window.CRC_PHOTOS[slot]) || null;
  if (photo) cands.push(photo);
  if (ART_SLOTS.has(slot)) cands.push('img/' + slot + '.svg');
  const [idx, setIdx] = React.useState(0);
  React.useEffect(() => { setIdx(0); }, [slot, photo]);
  const src = cands[idx];
  return (
    <div style={{ position: 'relative', width: '100%', height: '100%', borderRadius: radius, overflow: 'hidden', background: `linear-gradient(150deg, ${art.g[0]}, ${art.g[1]})`, ...style }}>
      {src ? (
        <img src={src} alt="" loading="lazy" onError={() => setIdx((i) => i + 1)} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      ) : (
        <React.Fragment>
          <div style={{ position: 'absolute', top: '-35%', left: '-15%', width: '80%', height: '80%', borderRadius: '50%', background: 'radial-gradient(circle, rgba(255,255,255,.20), transparent 70%)' }} />
          <div style={{ position: 'absolute', right: '-18%', bottom: '-30%', width: '70%', height: '70%', borderRadius: '50%', background: art.tone === 'dark' ? 'rgba(0,0,0,.07)' : 'rgba(255,255,255,.09)' }} />
          <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <CRCIcon name={art.icon} size={54} color={ink} stroke={1.5} />
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

Object.assign(window, {
  CRCIcon, CRCButton, TierBadge, SectionHead, Surface, ProgressBar, Chip,
  BottomSheet, Toast, Confetti, QRBlock, Img,
});
