/* Mereka v2 — design tokens & primitives */
const { useState, useEffect, useRef, useMemo, createContext, useContext } = React;

/* ---------- Icons (lightweight inline) ---------- */
const ICONS = {
  search: <path d="M11 19a8 8 0 1 1 5.292-1.999l4.353 4.353-1.414 1.414-4.353-4.353A7.965 7.965 0 0 1 11 19Zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z"/>,
  bell: <path d="M12 22a2.5 2.5 0 0 1-2.45-2h4.9A2.5 2.5 0 0 1 12 22Zm8-3H4v-2l2-1v-5a6 6 0 0 1 4-5.659V5a2 2 0 1 1 4 0v.341A6 6 0 0 1 18 11v5l2 1v2Z"/>,
  chat: <path d="M7.291 20.824 2 22l1.176-5.291A9 9 0 1 1 7.29 20.824Z"/>,
  user: <path d="M12 12a5 5 0 1 1 0-10 5 5 0 0 1 0 10Zm0 2c5.523 0 10 2.239 10 5v3H2v-3c0-2.761 4.477-5 10-5Z"/>,
  heart: <path d="M12 21-1.41-1.32C5.6 14.99 2 11.85 2 7.95 2 5.13 4.21 3 7 3c1.74 0 3.41.81 4.5 2.09C12.59 3.81 14.26 3 16 3c2.79 0 5 2.13 5 4.95 0 3.9-3.6 7.04-8.59 11.74L12 21Z"/>,
  star: <path d="m12 17.27 5.18 3.13-1.37-5.89L20.39 9l-6.06-.51L12 3 9.67 8.49 3.61 9l4.58 4.51-1.37 5.89L12 17.27Z"/>,
  calendar: <path d="M19 4h-1V2h-2v2H8V2H6v2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2Zm0 16H5V10h14v10ZM5 8V6h14v2H5Z"/>,
  chevronRight: <path d="m9 6 6 6-6 6"/>,
  chevronLeft: <path d="m15 6-6 6 6 6"/>,
  chevronDown: <path d="m6 9 6 6 6-6"/>,
  chevronUp: <path d="m18 15-6-6-6 6"/>,
  arrowRight: <path d="M5 12h14m0 0-6-6m6 6-6 6"/>,
  arrowUpRight: <path d="M7 17 17 7m0 0H8m9 0v9"/>,
  plus: <path d="M12 5v14m-7-7h14"/>,
  close: <path d="M6 6l12 12M6 18 18 6"/>,
  check: <path d="m4 12 5 5L20 6"/>,
  filter: <path d="M3 6h18M6 12h12M10 18h4"/>,
  briefcase: <><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2"/></>,
  building: <><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></>,
  compass: <><circle cx="12" cy="12" r="10"/><path d="m16.24 7.76-2.12 6.36-6.36 2.12 2.12-6.36z"/></>,
  message: <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>,
  external: <path d="M14 3h7v7M21 3l-9 9M5 5h6v-2H3v18h18v-8h-2v6H5z"/>,
  settings: <><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z"/></>,
  card: <><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20"/></>,
  graduation: <path d="M22 10v6m-10 5L2 16V8l10-5 10 5-10 5-10-5"/>,
  globe: <><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10 15 15 0 0 1 4-10z"/></>,
  map: <path d="M9 4 3 7v13l6-3 6 3 6-3V4l-6 3-6-3Zm0 0v13m6-10v13"/>,
  clock: <><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></>,
  document: <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></>,
  video: <><rect x="2" y="6" width="14" height="12" rx="2"/><path d="m22 8-6 4 6 4z"/></>,
  phone: <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/>,
  trending: <path d="m22 7-9 9-5-5L2 17M16 7h6v6"/>,
  dollar: <path d="M12 2v20M17 5H9.5a3.5 3.5 0 1 0 0 7h5a3.5 3.5 0 1 1 0 7H6"/>,
  upload: <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-7 5-5 5 5m-5-5v12"/>,
  download: <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5 5 5 5-5m-5 5V3"/>,
  pin: <><path d="M12 22s8-7.58 8-13a8 8 0 1 0-16 0c0 5.42 8 13 8 13z"/><circle cx="12" cy="9" r="3"/></>,
  play: <path d="M5 3v18l15-9z"/>,
  pause: <path d="M6 4h4v16H6zM14 4h4v16h-4z"/>,
  menu: <path d="M4 6h16M4 12h16M4 18h16"/>,
  more: <><circle cx="12" cy="6" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="18" r="1.5"/></>,
  edit: <path d="m12 20 9-9-3-3-9 9v3h3zM18 8l-4-4"/>,
  trash: <path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14z"/>,
  eye: <><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></>,
  copy: <><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></>,
  shield: <path d="M12 22s8-4 8-12V5l-8-3-8 3v5c0 8 8 12 8 12Z"/>,
  receipt: <path d="M19 21V3l-2 1-2-1-2 1-2-1-2 1-2-1-2 1v18l2-1 2 1 2-1 2 1 2-1 2 1 2-1zM8 7h8M8 11h8M8 15h6"/>,
  spark: <path d="M12 3v3m0 12v3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1M3 12h3m12 0h3M5.6 18.4l2.1-2.1m8.6-8.6 2.1-2.1"/>,
  layers: <path d="m12 2 10 6-10 6L2 8l10-6Zm0 10 10 6-10 6L2 18l10-6Z"/>,
  bookmark: <path d="m19 21-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16Z"/>,
  send: <path d="m22 2-7 20-4-9-9-4 20-7Z"/>,
  mail: <><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 7 10 6 10-6"/></>,
  image: <><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></>,
  camera: <><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></>,
  save: <><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8M7 3v5h8"/></>,
  book: <><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V3H6.5A2.5 2.5 0 0 0 4 5.5v14Z"/><path d="M9 3v11"/></>,
  refresh: <><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v5h-5"/></>,
  hub: <><circle cx="6" cy="6" r="2.4"/><circle cx="18" cy="7" r="2.4"/><circle cx="12" cy="17" r="2.6"/><path d="M7.6 7.6 10.4 15M16.7 8.9 13.4 15.2"/></>,
  userPlus: <><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="M19 8v6M22 11h-6"/></>,
  layout: <><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></>,
  barChart: <><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6"/><rect x="12" y="7" width="3" height="10"/><rect x="17" y="13" width="3" height="4"/></>,
  clipboard: <><rect x="5" y="4" width="14" height="17" rx="2"/><path d="M9 4.5h6V7H9zM9 11h6M9 15h4"/></>,
  switchArrows: <><path d="M7 4 3 8l4 4"/><path d="M3 8h13"/><path d="m17 20 4-4-4-4"/><path d="M21 16H8"/></>,
  userStar: <><circle cx="9" cy="8" r="4"/><path d="M2 21c0-3.5 3.1-6 7-6"/><path d="m17 13 1.2 2.4 2.6.4-1.9 1.8.4 2.6L17 19l-2.3 1.2.4-2.6-1.9-1.8 2.6-.4z"/></>,
  paperclip: <path d="m21 12-8.485 8.485a5 5 0 0 1-7.071-7.07l8.485-8.486a3.5 3.5 0 1 1 4.95 4.95l-7.778 7.778a2 2 0 0 1-2.828-2.828L15.5 8"/>,
  smile: <><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01"/></>,
  award: <><circle cx="12" cy="8" r="6"/><path d="M16 13.5V22l-4-3-4 3v-8.5"/></>,
  dashboardGrid: <><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></>,
  programme: <><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"/><path d="M10 2v8l3-2 3 2V2"/></>,
  courses: <><rect x="7" y="3" width="13" height="16" rx="2"/><path d="M4 7v12a2 2 0 0 0 2 2h10"/><path d="M11 8h5M11 12h5M11 16h3"/></>,
  calendarStar: <><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M16 2v4M8 2v4M3 9h18"/><path d="m12 12.4 1.1 2.2 2.4.3-1.8 1.7.5 2.4-2.2-1.2-2.2 1.2.5-2.4-1.8-1.7 2.4-.3 1.1-2.2Z"/></>,
  briefcaseGear: <><path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M20 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h6.3"/><circle cx="18" cy="18" r="2.6"/><path d="M18 14.4v1.1m0 5v1.1M21.6 18h-1.1m-4.9 0h-1.1M20.5 15.5l-.8.8M15.5 20.5l-.8.8M20.5 20.5l-.8-.8M15.5 15.5l-.8-.8"/></>,
  programmeGear: <><path d="M13 3H6.5A2.5 2.5 0 0 0 4 5.5v14A2.5 2.5 0 0 0 6.5 22H12"/><path d="M9.5 3v8l2.5-1.6L14.5 11V3"/><circle cx="18" cy="17" r="2.6"/><path d="M18 13.4v1m0 5.2v1M21.6 17h-1m-5 0h-1M20.5 14.5l-.8.8M15.5 19.5l-.8.8M20.5 19.5l-.8-.8M15.5 14.5l-.8-.8"/></>,
  formsBars: <><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8.5 16.5v-3.5M12 16.5V8M15.5 16.5v-5.5"/></>,
  broadcast: <><path d="M21 14.5a2 2 0 0 1-2 2H8l-5 4v-15a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z"/><path d="M7 8.5h10M7 12h6"/></>,
};

function Icon({ name, size = 18, className = '', strokeWidth = 1.75, fill = 'none' }) {
  const path = ICONS[name];
  if (!path) return null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke="currentColor"
         strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round"
         className={className} aria-hidden="true">
      {path}
    </svg>
  );
}

/* ---------- Logo ---------- */
function MerekaLogo({ className = '', dark = false }) {
  return (
    <img
      src={dark ? '/mereka-logo-white.svg' : '/mereka-logo.svg'}
      alt="Mereka"
      className={className}
      style={{ height: '100%', display: 'block' }}
    />
  );
}

/* ---------- Hash router ---------- */
/* ---------- Path router (clean URLs, no hash) ---------- */
function _currentPath() {
  if (typeof location === 'undefined') return '/web';
  const p = location.pathname || '/';
  if (p === '/' || p === '') return '/web';
  return p.replace(/\/+$/, '') || '/web';
}

function useHashRoute() {
  const [path, setPath] = useState(_currentPath);
  useEffect(() => {
    const onChange = () => setPath(_currentPath());
    window.addEventListener('popstate', onChange);
    window.addEventListener('locationchange', onChange);
    return () => {
      window.removeEventListener('popstate', onChange);
      window.removeEventListener('locationchange', onChange);
    };
  }, []);
  return path;
}

function _toPath(to) {
  if (!to || to === '#') return null;
  let t = to.startsWith('#') ? to.slice(1) : to;
  if (!t || t === '/') t = '/web';
  if (!t.startsWith('/')) t = '/' + t;
  return t;
}

function navigate(to) {
  const t = _toPath(to);
  if (t === null) return;
  const url = (t === '/web') ? '/' : t;   // home lives at the clean root
  if (location.pathname !== url) {
    history.pushState({}, '', url);
    window.dispatchEvent(new Event('locationchange'));
  }
  window.scrollTo({ top: 0, behavior: 'instant' });
}

function Link({ to, className = '', children, onClick, ...rest }) {
  const t = _toPath(to);
  const href = t === null ? '#' : (t === '/web' ? '/' : t);
  const handleClick = (e) => {
    e.preventDefault();
    onClick && onClick(e);
    navigate(to);
  };
  return <a href={href} className={className} onClick={handleClick} {...rest}>{children}</a>;
}

/* ---------- Buttons ---------- */
function Button({ variant = 'primary', size = 'md', children, className = '', leftIcon, rightIcon, ...rest }) {
  const sizes = {
    sm: 'h-8 text-xs px-3',
    md: 'h-10 text-sm px-4',
    lg: 'h-12 text-sm px-6',
  };
  const variants = {
    primary: 'bg-primary text-white hover:bg-primary/90',
    dark: 'bg-neutral-900 text-white hover:bg-neutral-800',
    secondary: 'bg-white text-neutral-900 border border-neutral-300 hover:bg-neutral-50',
    ghost: 'text-neutral-700 hover:bg-neutral-100',
    danger: 'bg-error text-white hover:opacity-90',
    purple: 'bg-purple-600 text-white hover:bg-purple-700',
    outline: 'border border-primary text-primary hover:bg-primary/5',
  };
  return (
    <button {...rest} className={`inline-flex items-center justify-center gap-1.5 rounded-full font-medium transition-colors ${sizes[size]} ${variants[variant]} ${className}`}>
      {leftIcon && <Icon name={leftIcon} size={size === 'sm' ? 14 : 16} />}
      {children}
      {rightIcon && <Icon name={rightIcon} size={size === 'sm' ? 14 : 16} />}
    </button>
  );
}

/* ---------- Avatar ---------- */
const AVATAR_PALETTE = [
  ['#FDE68A', '#92400E'], ['#BFDBFE', '#1E40AF'], ['#FBCFE8', '#9D174D'],
  ['#BBF7D0', '#166534'], ['#DDD6FE', '#5B21B6'], ['#FECACA', '#991B1B'],
  ['#FED7AA', '#9A3412'], ['#A5F3FC', '#155E75'],
];
/* ---------- Unsplash placeholder pools (verified stable photo IDs) ---------- */
const UNSPLASH_PEOPLE = ['1494790108377-be9c29b29330','1500648767791-00dcc994a43e','1438761681033-6461ffad8d80','1472099645785-5658abf4ff4e','1507003211169-0a1dd7228f2d','1534528741775-53994a69daeb','1506794778202-cad84cf45f1d','1544005313-94ddf0286df2','1517841905240-472988babdf9','1531427186611-ecfd6d936c79','1524504388940-b1c1722653e1','1573496359142-b8d87734a5a2'];
const UNSPLASH_SCENES = ['1452860606245-08befc0ff44b','1556910103-1c02745aae4d','1565193566173-7a0ee3dbe261','1513364776144-60967b0f800f','1441974231531-c6227db76b6e','1509440159596-0249088772ff','1452587925148-ce544e77e70d','1517180102446-f3ece451e9d8','1552664730-d307ca884978','1561070791-2526d30994b5'];
function _hashStr(s) { let h = 0; s = String(s == null ? '' : s); for (let i = 0; i < s.length; i++) { h = (h * 31 + s.charCodeAt(i)) >>> 0; } return h; }
function personPhoto(name, size = 80) { const id = UNSPLASH_PEOPLE[_hashStr(name) % UNSPLASH_PEOPLE.length]; const px = Math.max(64, Math.round(size * 2)); return `https://images.unsplash.com/photo-${id}?w=${px}&h=${px}&fit=crop&crop=faces&auto=format&q=70`; }
function scenePhoto(seed, w = 400, h = 300) { const id = UNSPLASH_SCENES[_hashStr(seed) % UNSPLASH_SCENES.length]; return `https://images.unsplash.com/photo-${id}?w=${w}&h=${h}&fit=crop&auto=format&q=70`; }
function personPhotoWH(name, w = 400, h = 500) { const id = UNSPLASH_PEOPLE[_hashStr(name) % UNSPLASH_PEOPLE.length]; return `https://images.unsplash.com/photo-${id}?w=${w}&h=${h}&fit=crop&crop=faces&auto=format&q=70`; }

function Avatar({ name = '', src, size = 40, className = '' }) {
  const initials = (name || '?').split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase() || '?';
  const idx = (name?.charCodeAt(0) || 0) % AVATAR_PALETTE.length;
  const [bg, fg] = AVATAR_PALETTE[idx];
  const [imgErr, setImgErr] = useState(false);
  const isHub = typeof HUB_NAMES !== 'undefined' && HUB_NAMES.indexOf(name) >= 0;
  const photo = src || (!isHub && name ? personPhoto(name, size) : null);
  if (photo && !imgErr) {
    return <img src={photo} alt={name} onError={() => setImgErr(true)} className={`rounded-full object-cover flex-shrink-0 ${className}`} style={{ width: size, height: size }} />;
  }
  return (
    <div className={`rounded-full inline-flex items-center justify-center font-semibold flex-shrink-0 ${className}`}
         style={{ width: size, height: size, background: bg, color: fg, fontSize: size * 0.38 }}>
      {initials}
    </div>
  );
}

/* ---------- Image placeholder ---------- */
function ImageBlock({ aspect = '4/3', tone = 'auto', label, className = '', seed = 0, person }) {
  // tone determines hue
  const hues = [275, 220, 25, 170, 340, 290, 200];
  const h = hues[seed % hues.length];
  const bg = `linear-gradient(135deg, oklch(0.92 0.05 ${h}), oklch(0.86 0.08 ${h+30}))`;
  return (
    <div className={`relative overflow-hidden rounded-xl ${className}`} style={{ aspectRatio: aspect, background: bg }}>
      <div className="absolute inset-0" style={{
        backgroundImage: `radial-gradient(circle at 30% 30%, oklch(0.97 0.04 ${h}) 0%, transparent 40%), radial-gradient(circle at 70% 80%, oklch(0.78 0.12 ${h+60}) 0%, transparent 50%)`,
      }} />
      <img src={person ? personPhotoWH(person, 600, 700) : scenePhoto(seed, 640, 480)} alt="" loading="lazy" onError={e => { e.currentTarget.style.display = 'none'; }} className="absolute inset-0 w-full h-full object-cover" />
      {label && <span className="absolute bottom-2 right-2 text-[11px] font-mono uppercase tracking-wide px-2 py-1 bg-black/30 text-white rounded z-10">{label}</span>}
    </div>
  );
}

/* ---------- Badge / Chip ---------- */
function Badge({ children, tone = 'neutral', className = '' }) {
  const tones = {
    neutral: 'bg-neutral-100 text-neutral-700',
    dark: 'bg-neutral-900 text-white',
    success: 'bg-green-100 text-green-700',
    warning: 'bg-amber-100 text-amber-700',
    error: 'bg-red-100 text-red-700',
    info: 'bg-blue-100 text-blue-700',
    purple: 'bg-purple-100 text-purple-700',
    primaryLight: 'bg-primary/10 text-primary',
  };
  return <span className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded ${tones[tone]} ${className}`}>{children}</span>;
}

function Chip({ children, active = false, className = '', onClick }) {
  return (
    <button onClick={onClick} className={`inline-flex items-center gap-1.5 h-9 px-4 text-sm rounded-full border transition-colors ${active ? 'bg-neutral-900 text-white border-neutral-900' : 'bg-white text-neutral-700 border-neutral-300 hover:border-neutral-400'} ${className}`}>
      {children}
    </button>
  );
}

/* ---------- Stars ---------- */
function Stars({ rating = 0, size = 14, className = '', showNumber = true }) {
  return (
    <span className={`inline-flex items-center gap-1 text-neutral-900 ${className}`}>
      <Icon name="star" size={size} fill="currentColor" strokeWidth={0} />
      {showNumber && <span className="text-sm font-medium num-tabular">{rating.toFixed(1)}</span>}
    </span>
  );
}

/* ---------- Card primitives ---------- */
function Card({ children, className = '', padding = 'p-5' }) {
  return <div className={`bg-white rounded-xl border border-neutral-200 ${padding} ${className}`}>{children}</div>;
}

/* ---------- Search input ---------- */
function SearchInput({ placeholder = 'What are you looking for?', className = '', size = 'md' }) {
  const heights = { sm: 'h-10', md: 'h-12', lg: 'h-14' };
  return (
    <div className={`relative ${className}`}>
      <Icon name="search" className="absolute left-4 top-1/2 -translate-y-1/2 text-neutral-400" size={18} />
      <input type="text" placeholder={placeholder}
             className={`${heights[size]} w-full pl-12 pr-4 rounded-full bg-white border border-neutral-200 text-sm placeholder:text-neutral-400 focus:outline-none focus:border-neutral-400`} />
    </div>
  );
}

/* ---------- Tabs ---------- */
function Tabs({ items, value, onChange, className = '' }) {
  return (
    <div className={`flex items-center gap-6 border-b border-neutral-200 ${className}`}>
      {items.map(it => (
        <button key={it.value} onClick={() => onChange(it.value)}
                className={`pb-3 -mb-px text-sm font-medium border-b-2 transition-colors ${value === it.value ? 'border-neutral-900 text-neutral-900' : 'border-transparent text-neutral-500 hover:text-neutral-700'}`}>
          {it.label}
          {it.count != null && <span className={`ml-1.5 text-xs ${value === it.value ? 'text-neutral-600' : 'text-neutral-400'}`}>{it.count}</span>}
        </button>
      ))}
    </div>
  );
}

/* ---------- Progress ---------- */
function Progress({ value = 0, tone = 'dark', className = '' }) {
  const tones = { dark: 'bg-neutral-900', purple: 'bg-purple-600', primary: 'bg-primary' };
  return (
    <div className={`h-1.5 bg-neutral-200 rounded-full overflow-hidden ${className}`}>
      <div className={`h-full ${tones[tone]} rounded-full transition-all`} style={{ width: `${value}%` }} />
    </div>
  );
}

/* ---------- Section heading ---------- */
function SectionHeading({ children, accent, className = '' }) {
  return (
    <h2 className={`text-2xl md:text-3xl font-bold tracking-tight ${className}`}>
      {children} {accent && <span className="heading-accent">{accent}</span>}
    </h2>
  );
}

/* ---------- Auth state (prototype: toggle logged-in / logged-out) ---------- */
let _merekaAuthed = true; // default: logged in (keeps existing app behaviour)
const _merekaAuthSubs = new Set();
function setAuth(v) {
  _merekaAuthed = !!v;
  _merekaAuthSubs.forEach(fn => fn(_merekaAuthed));
}
function useAuth() {
  const [a, setA] = useState(_merekaAuthed);
  useEffect(() => {
    const fn = (val) => setA(val);
    _merekaAuthSubs.add(fn);
    setA(_merekaAuthed);
    return () => _merekaAuthSubs.delete(fn);
  }, []);
  return a;
}

/* ---------- Active hub (shared across the dashboard/manage pages) ---------- */
const HUB_NAMES = ['Biji-biji Initiative', 'Mereka', 'Studio Kuala'];
let _merekaHub = (() => { try { return localStorage.getItem('mereka_hub') || HUB_NAMES[0]; } catch (e) { return HUB_NAMES[0]; } })();
const _hubSubs = new Set();
function setHub(h) {
  _merekaHub = h;
  try { localStorage.setItem('mereka_hub', h); } catch (e) {}
  _hubSubs.forEach(fn => fn(h));
}
function getHub() { return _merekaHub; }
function hubIdx(h) { const i = HUB_NAMES.indexOf(h || _merekaHub); return i < 0 ? 0 : i; }
function useHub() {
  const [h, setH] = useState(_merekaHub);
  useEffect(() => {
    const fn = (v) => setH(v);
    _hubSubs.add(fn);
    setH(_merekaHub);
    return () => _hubSubs.delete(fn);
  }, []);
  return h;
}

/* ---------- Active programme (admin management context) ---------- */
let _activeProg = (() => { try { return JSON.parse(localStorage.getItem('mereka_prog')); } catch (e) { return null; } })()
  || { name: 'AI4U Programme', owner: 'Christ Wales', focus: ['Flagship', 'Applied AI'], status: 'Active', duration: '12 weeks', cohorts: 6, enrolled: 1509, completion: 68, rating: 4.5 };
const _progSubs = new Set();
function setProg(p) {
  _activeProg = p;
  try { localStorage.setItem('mereka_prog', JSON.stringify(p)); } catch (e) {}
  _progSubs.forEach(fn => fn(p));
}
function getProg() { return _activeProg; }
function useProg() {
  const [p, setP] = useState(_activeProg);
  useEffect(() => {
    const fn = (v) => setP(v);
    _progSubs.add(fn);
    setP(_activeProg);
    return () => _progSubs.delete(fn);
  }, []);
  return p;
}


/* Reusable copy-to-clipboard button with "Copied!" feedback */
function CopyButton({ text, label = 'Copy link', icon = 'external', className = '' }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    const t = String(text || '');
    try {
      if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(t);
      else { const ta = document.createElement('textarea'); ta.value = t; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); }
    } catch (e) {}
    setCopied(true); setTimeout(() => setCopied(false), 1800);
  };
  return (
    <button onClick={copy} className={'inline-flex items-center gap-2 ' + className}>
      {(copied || icon) && <Icon name={copied ? 'check' : icon} size={15} />}
      {copied ? 'Copied!' : label}
    </button>
  );
}

Object.assign(window, {
  Icon, MerekaLogo, useHashRoute, navigate, Link, useAuth, setAuth, _currentPath, useHub, setHub, getHub, hubIdx, HUB_NAMES, useProg, setProg, getProg,
  Button, Avatar, ImageBlock, Badge, Chip, Stars, Card, SearchInput, Tabs, Progress, SectionHeading, CopyButton,
});
